<commit_before>define([
        '../ThirdParty/when',
        './Credit',
        './defaultValue',
        './defined',
        './defineProperties',
        './DeveloperError',
        './Ellipsoid',
        './Event',
        './GeographicTilingScheme',
        './getImagePixels',
        './HeightmapTerrainData',
        './Math',
        './Rectangle',
        './Resource',
        './TerrainProvider',
        './TileProviderError'
    ], function(
        when,
        Credit,
        defaultValue,
        defined,
        defineProperties,
        DeveloperError,
        Ellipsoid,
        Event,
        GeographicTilingScheme,
        getImagePixels,
        HeightmapTerrainData,
        CesiumMath,
        Rectangle,
        Resource,
        TerrainProvider,
        TileProviderError) {
    'use strict';

    function DataRectangle(rectangle, maxLevel) {
        this.rectangle = rectangle;
        this.maxLevel = maxLevel;
    }

    /**
     * A {@link TerrainProvider} that produces terrain geometry by tessellating height maps
     * retrieved from a {@link http://vr-theworld.com/|VT MÄK VR-TheWorld server}.
     *
     * @alias VRTheWorldTerrainProvider
     * @constructor
     *
     * @param {Object} options Object with the following properties:
     * @param {Resource|String} options.url The URL of the VR-TheWorld TileMap.
     * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid.  If this parameter is not
     *                    specified, the WGS84 ellipsoid is used.
     * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
     *
     *
     * @example
     * var terrainProvider = new Cesium.VRTheWorldTerrainProvider({
     *   url : 'https://www.vr-theworld.com/vr-theworld/tiles1.0.0/73/'
     * });
     * viewer.terrainProvider = terrainProvider;
     *
     * @see TerrainProvider
     */
    function VRTheWorldTerrainProvider(options) {
        options = defaultValue(options, defaultValue.EMPTY_OBJECT);
        //>>includeStart('debug', pragmas.debug);
        if (!defined(options.url)) {
            throw new DeveloperError('options.url is required.');
        }
        //>>includeEnd('debug');

        var resource = Resource.createIfNeeded(options.url);

        this._resource = resource;

        this._errorEvent = new Event();
        this._ready = false;
        this._readyPromise = when.defer();

        this._terrainDataStructure = {
            heightScale : 1.0 / 1000.0,
            heightOffset : -1000.0,
            elementsPerHeight : 3,
            stride : 4,
            elementMultiplier : 256.0,
            isBigEndian : true,
            lowestEncodedHeight : 0,
            highestEncodedHeight : 256 * 256 * 256 - 1
        };

        var credit = options.credit;
        if (typeof credit === 'string') {
            credit = new Credit(credit);
        }
        this._credit = credit;

        this._tilingScheme = undefined;
        this._rectangles = [];

        var that = this;
        var metadataError;
        var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);

        function metadataSuccess(xml) {
            var srs = xml.getElementsByTagName('SRS')[0].textContent;
            if (srs === 'EPSG:4326') {
                that._tilingScheme = new GeographicTilingScheme({ellipsoid : ellipsoid});
            } else {
                metadataFailure('SRS ' + srs + ' is not supported.');
                return;
            }

            var tileFormat = xml.getElementsByTagName('TileFormat')[0];
            that._heightmapWidth = parseInt(tileFormat.getAttribute('width'), 10);
            that._heightmapHeight = parseInt(tileFormat.getAttribute('height'), 10);
            that._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(ellipsoid, Math.min(that._heightmapWidth, that._heightmapHeight), that._tilingScheme.getNumberOfXTilesAtLevel(0));

            var dataRectangles = xml.getElementsByTagName('DataExtent');

            for (var i = 0; i < dataRectangles.length; ++i) {
                var dataRectangle = dataRectangles[i];

                var west = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('minx')));
                var south = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('miny')));
                var east = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('maxx')));
                var north = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('maxy')));
                var maxLevel = parseInt(dataRectangle.getAttribute('maxlevel'), 10);

                that._rectangles.push(new DataRectangle(new Rectangle(west, south, east, north), maxLevel));
            }

            that._ready = true;
            that._readyPromise.resolve(true);
        }

        function metadataFailure(e) {
            var message = defaultValue(e, 'An error occurred while accessing ' + that._resource.url + '.');
            metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
        }

        function requestMetadata() {
            when(that._resource.fetchXML(), metadataSuccess, metadataFailure);
        }

        requestMetadata();
    }

    defineProperties(VRTheWorldTerrainProvider.prototype, {
        /**
         * Gets an event that is raised when the terrain provider encounters an asynchronous error.  By subscribing
         * to the event, you will be notified of the error and can potentially recover from it.  Event listeners
         * are passed an instance of {@link TileProviderError}.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Event}
         */
        errorEvent : {
            get : function() {
                return this._errorEvent;
            }
        },

        /**
         * Gets the credit to display when this terrain provider is active.  Typically this is used to credit
         * the source of the terrain.  This function should not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Credit}
         */
        credit : {
            get : function() {
                return this._credit;
            }
        },

        /**
         * Gets the tiling scheme used by this provider.  This function should
         * not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {GeographicTilingScheme}
         */
        tilingScheme : {
            get : function() {
                //>>includeStart('debug', pragmas.debug);
                if (!this.ready) {
                    throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
                }
                //>>includeEnd('debug');

                return this._tilingScheme;
            }
        },

        /**
         * Gets a value indicating whether or not the provider is ready for use.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Boolean}
         */
        ready : {
            get : function() {
                return this._ready;
            }
        },

        /**
         * Gets a promise that resolves to true when the provider is ready for use.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Promise.<Boolean>}
         * @readonly
         */
        readyPromise : {
            get : function() {
                return this._readyPromise.promise;
            }
        },

        /**
         * Gets a value indicating whether or not the provider includes a water mask.  The water mask
         * indicates which areas of the globe are water rather than land, so they can be rendered
         * as a reflective surface with animated waves.  This function should not be
         * called before {@link VRTheWorldTerrainProvider#ready} returns true.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Boolean}
         */
        hasWaterMask : {
            get : function() {
                return false;
            }
        },

        /**
         * Gets a value indicating whether or not the requested tiles include vertex normals.
         * This function should not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Boolean}
         */
        hasVertexNormals : {
            get : function() {
                return false;
            }
        }
    });

    /**
     * Requests the geometry for a given tile.  This function should not be called before
     * {@link VRTheWorldTerrainProvider#ready} returns true.  The result includes terrain
     * data and indicates that all child tiles are available.
     *
     * @param {Number} x The X coordinate of the tile for which to request geometry.
     * @param {Number} y The Y coordinate of the tile for which to request geometry.
     * @param {Number} level The level of the tile for which to request geometry.
     * @param {Request} [request] The request object. Intended for internal use only.
     * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry.  If this method
     *          returns undefined instead of a promise, it is an indication that too many requests are already
     *          pending and the request will be retried later.
     */
    VRTheWorldTerrainProvider.prototype.requestTileGeometry = function(x, y, level, request) {
        //>>includeStart('debug', pragmas.debug);
        if (!this.ready) {
            throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
        }
        //>>includeEnd('debug');

        var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level);
        var resource = this._resource.getDerivedResource({
            url : level + '/' + x + '/' + (yTiles - y - 1) + '.tif',
            queryParameters : {
                cesium : true
            },
            request : request
        });
        var promise = resource.fetchImage();
        if (!defined(promise)) {
            return undefined;
        }

        var that = this;
        return when(promise)
            .then(function(image) {
                return new HeightmapTerrainData({
                    buffer : getImagePixels(image),
                    width : that._heightmapWidth,
                    height : that._heightmapHeight,
                    childTileMask : getChildMask(that, x, y, level),
                    structure : that._terrainDataStructure
                });
            });
    };

    /**
     * Gets the maximum geometric error allowed in a tile at a given level.
     *
     * @param {Number} level The tile level for which to get the maximum geometric error.
     * @returns {Number} The maximum geometric error.
     */
    VRTheWorldTerrainProvider.prototype.getLevelMaximumGeometricError = function(level) {
        //>>includeStart('debug', pragmas.debug);
        if (!this.ready) {
            throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
        }
        //>>includeEnd('debug');
        return this._levelZeroMaximumGeometricError / (1 << level);
    };

    var rectangleScratch = new Rectangle();

    function getChildMask(provider, x, y, level) {
        var tilingScheme = provider._tilingScheme;
        var rectangles = provider._rectangles;
        var parentRectangle = tilingScheme.tileXYToRectangle(x, y, level);

        var childMask = 0;

        for (var i = 0; i < rectangles.length && childMask !== 15; ++i) {
            var rectangle = rectangles[i];
            if (rectangle.maxLevel <= level) {
                continue;
            }

            var testRectangle = rectangle.rectangle;

            var intersection = Rectangle.intersection(testRectangle, parentRectangle, rectangleScratch);
            if (defined(intersection)) {
                // Parent tile is inside this rectangle, so at least one child is, too.
                if (isTileInRectangle(tilingScheme, testRectangle, x * 2, y * 2, level + 1)) {
                    childMask |= 4; // northwest
                }
                if (isTileInRectangle(tilingScheme, testRectangle, x * 2 + 1, y * 2, level + 1)) {
                    childMask |= 8; // northeast
                }
                if (isTileInRectangle(tilingScheme, testRectangle, x * 2, y * 2 + 1, level + 1)) {
                    childMask |= 1; // southwest
                }
                if (isTileInRectangle(tilingScheme, testRectangle, x * 2 + 1, y * 2 + 1, level + 1)) {
                    childMask |= 2; // southeast
                }
            }
        }

        return childMask;
    }

    function isTileInRectangle(tilingScheme, rectangle, x, y, level) {
        var tileRectangle = tilingScheme.tileXYToRectangle(x, y, level);
        return defined(Rectangle.intersection(tileRectangle, rectangle, rectangleScratch));
    }

    /**
     * Determines whether data for a tile is available to be loaded.
     *
     * @param {Number} x The X coordinate of the tile for which to request geometry.
     * @param {Number} y The Y coordinate of the tile for which to request geometry.
     * @param {Number} level The level of the tile for which to request geometry.
     * @returns {Boolean} Undefined if not supported, otherwise true or false.
     */
    VRTheWorldTerrainProvider.prototype.getTileDataAvailable = function(x, y, level) {
        return undefined;
    };

    /**
     * Makes sure we load availability data for a tile
     *
     * @param {Number} x The X coordinate of the tile for which to request geometry.
     * @param {Number} y The Y coordinate of the tile for which to request geometry.
     * @param {Number} level The level of the tile for which to request geometry.
     * @returns {undefined|Promise} Undefined if nothing need to be loaded or a Promise that resolves when all required tiles are loaded
     */
    VRTheWorldTerrainProvider.prototype.loadTileDataAvailability = function(x, y, level) {
        return undefined;
    };

    return VRTheWorldTerrainProvider;
});
<commit_msg>Fix VRTheWorld terrain geometry with ImageBitmap<commit_after>define([
        '../ThirdParty/when',
        './Credit',
        './defaultValue',
        './defined',
        './defineProperties',
        './DeveloperError',
        './Ellipsoid',
        './Event',
        './GeographicTilingScheme',
        './getImagePixels',
        './HeightmapTerrainData',
        './Math',
        './Rectangle',
        './Resource',
        './TerrainProvider',
        './TileProviderError'
    ], function(
        when,
        Credit,
        defaultValue,
        defined,
        defineProperties,
        DeveloperError,
        Ellipsoid,
        Event,
        GeographicTilingScheme,
        getImagePixels,
        HeightmapTerrainData,
        CesiumMath,
        Rectangle,
        Resource,
        TerrainProvider,
        TileProviderError) {
    'use strict';

    function DataRectangle(rectangle, maxLevel) {
        this.rectangle = rectangle;
        this.maxLevel = maxLevel;
    }

    /**
     * A {@link TerrainProvider} that produces terrain geometry by tessellating height maps
     * retrieved from a {@link http://vr-theworld.com/|VT MÄK VR-TheWorld server}.
     *
     * @alias VRTheWorldTerrainProvider
     * @constructor
     *
     * @param {Object} options Object with the following properties:
     * @param {Resource|String} options.url The URL of the VR-TheWorld TileMap.
     * @param {Ellipsoid} [options.ellipsoid=Ellipsoid.WGS84] The ellipsoid.  If this parameter is not
     *                    specified, the WGS84 ellipsoid is used.
     * @param {Credit|String} [options.credit] A credit for the data source, which is displayed on the canvas.
     *
     *
     * @example
     * var terrainProvider = new Cesium.VRTheWorldTerrainProvider({
     *   url : 'https://www.vr-theworld.com/vr-theworld/tiles1.0.0/73/'
     * });
     * viewer.terrainProvider = terrainProvider;
     *
     * @see TerrainProvider
     */
    function VRTheWorldTerrainProvider(options) {
        options = defaultValue(options, defaultValue.EMPTY_OBJECT);
        //>>includeStart('debug', pragmas.debug);
        if (!defined(options.url)) {
            throw new DeveloperError('options.url is required.');
        }
        //>>includeEnd('debug');

        var resource = Resource.createIfNeeded(options.url);

        this._resource = resource;

        this._errorEvent = new Event();
        this._ready = false;
        this._readyPromise = when.defer();

        this._terrainDataStructure = {
            heightScale : 1.0 / 1000.0,
            heightOffset : -1000.0,
            elementsPerHeight : 3,
            stride : 4,
            elementMultiplier : 256.0,
            isBigEndian : true,
            lowestEncodedHeight : 0,
            highestEncodedHeight : 256 * 256 * 256 - 1
        };

        var credit = options.credit;
        if (typeof credit === 'string') {
            credit = new Credit(credit);
        }
        this._credit = credit;

        this._tilingScheme = undefined;
        this._rectangles = [];

        var that = this;
        var metadataError;
        var ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);

        function metadataSuccess(xml) {
            var srs = xml.getElementsByTagName('SRS')[0].textContent;
            if (srs === 'EPSG:4326') {
                that._tilingScheme = new GeographicTilingScheme({ellipsoid : ellipsoid});
            } else {
                metadataFailure('SRS ' + srs + ' is not supported.');
                return;
            }

            var tileFormat = xml.getElementsByTagName('TileFormat')[0];
            that._heightmapWidth = parseInt(tileFormat.getAttribute('width'), 10);
            that._heightmapHeight = parseInt(tileFormat.getAttribute('height'), 10);
            that._levelZeroMaximumGeometricError = TerrainProvider.getEstimatedLevelZeroGeometricErrorForAHeightmap(ellipsoid, Math.min(that._heightmapWidth, that._heightmapHeight), that._tilingScheme.getNumberOfXTilesAtLevel(0));

            var dataRectangles = xml.getElementsByTagName('DataExtent');

            for (var i = 0; i < dataRectangles.length; ++i) {
                var dataRectangle = dataRectangles[i];

                var west = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('minx')));
                var south = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('miny')));
                var east = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('maxx')));
                var north = CesiumMath.toRadians(parseFloat(dataRectangle.getAttribute('maxy')));
                var maxLevel = parseInt(dataRectangle.getAttribute('maxlevel'), 10);

                that._rectangles.push(new DataRectangle(new Rectangle(west, south, east, north), maxLevel));
            }

            that._ready = true;
            that._readyPromise.resolve(true);
        }

        function metadataFailure(e) {
            var message = defaultValue(e, 'An error occurred while accessing ' + that._resource.url + '.');
            metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
        }

        function requestMetadata() {
            when(that._resource.fetchXML(), metadataSuccess, metadataFailure);
        }

        requestMetadata();
    }

    defineProperties(VRTheWorldTerrainProvider.prototype, {
        /**
         * Gets an event that is raised when the terrain provider encounters an asynchronous error.  By subscribing
         * to the event, you will be notified of the error and can potentially recover from it.  Event listeners
         * are passed an instance of {@link TileProviderError}.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Event}
         */
        errorEvent : {
            get : function() {
                return this._errorEvent;
            }
        },

        /**
         * Gets the credit to display when this terrain provider is active.  Typically this is used to credit
         * the source of the terrain.  This function should not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Credit}
         */
        credit : {
            get : function() {
                return this._credit;
            }
        },

        /**
         * Gets the tiling scheme used by this provider.  This function should
         * not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {GeographicTilingScheme}
         */
        tilingScheme : {
            get : function() {
                //>>includeStart('debug', pragmas.debug);
                if (!this.ready) {
                    throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
                }
                //>>includeEnd('debug');

                return this._tilingScheme;
            }
        },

        /**
         * Gets a value indicating whether or not the provider is ready for use.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Boolean}
         */
        ready : {
            get : function() {
                return this._ready;
            }
        },

        /**
         * Gets a promise that resolves to true when the provider is ready for use.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Promise.<Boolean>}
         * @readonly
         */
        readyPromise : {
            get : function() {
                return this._readyPromise.promise;
            }
        },

        /**
         * Gets a value indicating whether or not the provider includes a water mask.  The water mask
         * indicates which areas of the globe are water rather than land, so they can be rendered
         * as a reflective surface with animated waves.  This function should not be
         * called before {@link VRTheWorldTerrainProvider#ready} returns true.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Boolean}
         */
        hasWaterMask : {
            get : function() {
                return false;
            }
        },

        /**
         * Gets a value indicating whether or not the requested tiles include vertex normals.
         * This function should not be called before {@link VRTheWorldTerrainProvider#ready} returns true.
         * @memberof VRTheWorldTerrainProvider.prototype
         * @type {Boolean}
         */
        hasVertexNormals : {
            get : function() {
                return false;
            }
        }
    });

    /**
     * Requests the geometry for a given tile.  This function should not be called before
     * {@link VRTheWorldTerrainProvider#ready} returns true.  The result includes terrain
     * data and indicates that all child tiles are available.
     *
     * @param {Number} x The X coordinate of the tile for which to request geometry.
     * @param {Number} y The Y coordinate of the tile for which to request geometry.
     * @param {Number} level The level of the tile for which to request geometry.
     * @param {Request} [request] The request object. Intended for internal use only.
     * @returns {Promise.<TerrainData>|undefined} A promise for the requested geometry.  If this method
     *          returns undefined instead of a promise, it is an indication that too many requests are already
     *          pending and the request will be retried later.
     */
    VRTheWorldTerrainProvider.prototype.requestTileGeometry = function(x, y, level, request) {
        //>>includeStart('debug', pragmas.debug);
        if (!this.ready) {
            throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
        }
        //>>includeEnd('debug');

        var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level);
        var resource = this._resource.getDerivedResource({
            url : level + '/' + x + '/' + (yTiles - y - 1) + '.tif',
            queryParameters : {
                cesium : true
            },
            request : request
        });
        var promise = resource.fetchImage({
            flipY : false
        });
        if (!defined(promise)) {
            return undefined;
        }

        var that = this;
        return when(promise)
            .then(function(image) {
                return new HeightmapTerrainData({
                    buffer : getImagePixels(image),
                    width : that._heightmapWidth,
                    height : that._heightmapHeight,
                    childTileMask : getChildMask(that, x, y, level),
                    structure : that._terrainDataStructure
                });
            });
    };

    /**
     * Gets the maximum geometric error allowed in a tile at a given level.
     *
     * @param {Number} level The tile level for which to get the maximum geometric error.
     * @returns {Number} The maximum geometric error.
     */
    VRTheWorldTerrainProvider.prototype.getLevelMaximumGeometricError = function(level) {
        //>>includeStart('debug', pragmas.debug);
        if (!this.ready) {
            throw new DeveloperError('requestTileGeometry must not be called before ready returns true.');
        }
        //>>includeEnd('debug');
        return this._levelZeroMaximumGeometricError / (1 << level);
    };

    var rectangleScratch = new Rectangle();

    function getChildMask(provider, x, y, level) {
        var tilingScheme = provider._tilingScheme;
        var rectangles = provider._rectangles;
        var parentRectangle = tilingScheme.tileXYToRectangle(x, y, level);

        var childMask = 0;

        for (var i = 0; i < rectangles.length && childMask !== 15; ++i) {
            var rectangle = rectangles[i];
            if (rectangle.maxLevel <= level) {
                continue;
            }

            var testRectangle = rectangle.rectangle;

            var intersection = Rectangle.intersection(testRectangle, parentRectangle, rectangleScratch);
            if (defined(intersection)) {
                // Parent tile is inside this rectangle, so at least one child is, too.
                if (isTileInRectangle(tilingScheme, testRectangle, x * 2, y * 2, level + 1)) {
                    childMask |= 4; // northwest
                }
                if (isTileInRectangle(tilingScheme, testRectangle, x * 2 + 1, y * 2, level + 1)) {
                    childMask |= 8; // northeast
                }
                if (isTileInRectangle(tilingScheme, testRectangle, x * 2, y * 2 + 1, level + 1)) {
                    childMask |= 1; // southwest
                }
                if (isTileInRectangle(tilingScheme, testRectangle, x * 2 + 1, y * 2 + 1, level + 1)) {
                    childMask |= 2; // southeast
                }
            }
        }

        return childMask;
    }

    function isTileInRectangle(tilingScheme, rectangle, x, y, level) {
        var tileRectangle = tilingScheme.tileXYToRectangle(x, y, level);
        return defined(Rectangle.intersection(tileRectangle, rectangle, rectangleScratch));
    }

    /**
     * Determines whether data for a tile is available to be loaded.
     *
     * @param {Number} x The X coordinate of the tile for which to request geometry.
     * @param {Number} y The Y coordinate of the tile for which to request geometry.
     * @param {Number} level The level of the tile for which to request geometry.
     * @returns {Boolean} Undefined if not supported, otherwise true or false.
     */
    VRTheWorldTerrainProvider.prototype.getTileDataAvailable = function(x, y, level) {
        return undefined;
    };

    /**
     * Makes sure we load availability data for a tile
     *
     * @param {Number} x The X coordinate of the tile for which to request geometry.
     * @param {Number} y The Y coordinate of the tile for which to request geometry.
     * @param {Number} level The level of the tile for which to request geometry.
     * @returns {undefined|Promise} Undefined if nothing need to be loaded or a Promise that resolves when all required tiles are loaded
     */
    VRTheWorldTerrainProvider.prototype.loadTileDataAvailability = function(x, y, level) {
        return undefined;
    };

    return VRTheWorldTerrainProvider;
});
<|endoftext|>


<commit_before>class Logger extends React.Component {
  constructor(props) {
    super(props);
    console.log('constructor');
  }
  componentWillMount() {
    console.log('componentWillMount is triggered');
  }
  componentDidMount(e) {
    console.log('componentDidMount is triggered');
    console.log('DOM node: ', ReactDOM.findDOMNode(this));
  }
  componentWillReceiveProps(newProps) {
    console.log('componentWillReceiveProps is triggered');
    console.log('new props: ', newProps);
  }
  shouldComponentUpdate(newProps, newState) {
    console.log('shouldComponentUpdate is triggered');
    console.log('new props: ', newProps);
    console.log('new state: ', newState);
    return true;
  }
  componentWillUpdate(newProps, newState) {
    console.log('componentWillUpdate is triggered');
    console.log('new props: ', newProps);
    console.log('new state: ', newState);
  }
  componentDidUpdate(oldProps, oldState) {
    console.log('componentDidUpdate is triggered');
    console.log('new props: ', oldProps);
    console.log('old props: ', oldState);
  }
  componentWillUnmount() {
    console.log('componentWillUnmount');
  }
  render() {
    // console.log('rendering... Display')
    return React.createElement(
      'div',
      null,
      this.props.time
    );
  }
}<commit_msg>This is typying error? new => old<commit_after>class Logger extends React.Component {
  constructor(props) {
    super(props);
    console.log('constructor');
  }
  componentWillMount() {
    console.log('componentWillMount is triggered');
  }
  componentDidMount(e) {
    console.log('componentDidMount is triggered');
    console.log('DOM node: ', ReactDOM.findDOMNode(this));
  }
  componentWillReceiveProps(newProps) {
    console.log('componentWillReceiveProps is triggered');
    console.log('new props: ', newProps);
  }
  shouldComponentUpdate(newProps, newState) {
    console.log('shouldComponentUpdate is triggered');
    console.log('new props: ', newProps);
    console.log('new state: ', newState);
    return true;
  }
  componentWillUpdate(newProps, newState) {
    console.log('componentWillUpdate is triggered');
    console.log('new props: ', newProps);
    console.log('new state: ', newState);
  }
  componentDidUpdate(oldProps, oldState) {
    console.log('componentDidUpdate is triggered');
    console.log('old props: ', oldProps);
    console.log('old props: ', oldState);
  }
  componentWillUnmount() {
    console.log('componentWillUnmount');
  }
  render() {
    // console.log('rendering... Display')
    return React.createElement(
      'div',
      null,
      this.props.time
    );
  }
}
<|endoftext|>


<commit_before>import moment from 'moment';
import DayPicker from 'react-day-picker';
import React from 'react';
import Popout from '../../admin/client/components/Popout';
import { FormInput } from 'elemental';

let lastId = 0;

module.exports = React.createClass({

	displayName: 'DateInput',

	// set default properties
	getDefaultProps () {
		return {
			format: 'YYYY-MM-DD',
		};
	},

	getInitialState () {
		return {
			selectedDay: this.props.value,
			id: `_DateInput_${++lastId}`,
			pickerIsOpen: false,
		};
	},

	// componentWillReceiveProps: function(newProps) {
	// 	console.log(moment(newProps.value).format("ddd MMMM DD YYYY hh:mm:ss a Z"));
	// 	if (newProps.value === this.state.selectedDay) return;
	// 	this.setState({
	// 		selectedDay: moment(newProps.value).format("ddd MMMM DD YYYY hh:mm:ss a Z")
	// 	});
	// },

	handleChange (e, day) {
		this.setState({
			selectedDay: day
		}, () => {
			setTimeout(() => {
				this.setState({
					pickerIsOpen: false
				});
			}, 200);
		});
	},

	handleFocus (e) {
		this.setState({
			pickerIsOpen: true
		});
	},

	handleBlur (e) {
	},

	render () {
		let { selectedDay } = this.state;

		let modifiers = {
			'selected': (day) => moment(selectedDay).isSame(day)
		};

		return (

				<FormInput
					autoComplete="off"
					id={this.state.id}
					name={this.props.name}
					onBlur={this.handleBlur}
					onFocus={this.handleFocus}
					onChange={this.handleChange}
					placeholder={this.props.format}
					value={moment(selectedDay).format(this.props.format)} />
				<Popout
					isOpen={this.state.pickerIsOpen}
					onCancel={() => this.setState({ pickerIsOpen: false })}
					relativeToID={this.state.id}
					width={260}>
					<DayPicker
						modifiers={ modifiers }
						onDayClick={ this.handleChange }
						tabIndex={-1} />
				</Popout>

		);
		// return <FormInput name={this.props.name} value={this.state.value} placeholder={this.props.format} onChange={this.handleChange} onBlur={this.handleBlur} autoComplete="off" />;
	}

});
<commit_msg>Cleaning up Focus & Blur behaviour in the DateInput Component<commit_after>import moment from 'moment';
import DayPicker from 'react-day-picker';
import React from 'react';
import ReactDOM from 'react-dom';
import Popout from '../../admin/client/components/Popout';
import { FormInput } from 'elemental';

let lastId = 0;

module.exports = React.createClass({

	displayName: 'DateInput',

	// set default properties
	getDefaultProps () {
		return {
			format: 'YYYY-MM-DD',
		};
	},

	getInitialState () {
		return {
			selectedDay: this.props.value,
			id: `_DateInput_${++lastId}`,
			pickerIsOpen: false,
		};
	},

	// componentWillReceiveProps: function(newProps) {
	// 	console.log(moment(newProps.value).format("ddd MMMM DD YYYY hh:mm:ss a Z"));
	// 	if (newProps.value === this.state.selectedDay) return;
	// 	this.setState({
	// 		selectedDay: moment(newProps.value).format("ddd MMMM DD YYYY hh:mm:ss a Z")
	// 	});
	// },

	focus () {
		if (!this.refs.input) return;
		this.refs.input.focus();
	},

	handleChange (e, day) {
		this.setState({
			selectedDay: day
		}, () => {
			setTimeout(() => {
				this.setState({
					pickerIsOpen: false
				});
			}, 200);
		});
	},

	handleFocus (e) {
		if (this.state.pickerIsOpen) return;
		this.setState({
			pickerIsOpen: true,
		});
	},

	handleBlur (e) {
		let rt = e.relatedTarget;
		let popout = this.refs.popout.getPortalDOMNode();
		while (rt) {
			if (rt === popout) return;
			rt = rt.parentNode;
		}
		this.setState({
			pickerIsOpen: false
		});
	},

	render () {
		let { selectedDay } = this.state;

		let modifiers = {
			selected: (day) => moment(selectedDay).isSame(day),
		};

		return (

				<FormInput
					autoComplete="off"
					id={this.state.id}
					name={this.props.name}
					onBlur={this.handleBlur}
					onFocus={this.handleFocus}
					onChange={this.handleChange}
					placeholder={this.props.format}
					ref="input"
					value={moment(selectedDay).format(this.props.format)} />
				<Popout
					ref="popout"
					isOpen={this.state.pickerIsOpen}
					onCancel={() => this.setState({ pickerIsOpen: false })}
					relativeToID={this.state.id}
					width={260}>
					<DayPicker
						modifiers={modifiers}
						onDayClick={this.handleChange}
						tabIndex={-1} />
				</Popout>

		);
		// return <FormInput name={this.props.name} value={this.state.value} placeholder={this.props.format} onChange={this.handleChange} onBlur={this.handleBlur} autoComplete="off" />;
	}

});
<|endoftext|>


<commit_before>(function() {
  'use strict';

  /**
   * usage:

   *
   *    extra options:
   *      quill: pass as a string
   *
   */

  var scripts = document.getElementsByTagName("script"),
    currentScriptPath = scripts[scripts.length - 1].src;

  angular.module('angular-quill', [])
    .directive("quill", ['$timeout', function($timeout) {
      return {
        restrict: 'A',
        require: "ngModel",
        replace: true,
        templateUrl: 'global/base/layouts/quill/angular-quill.html',
        controller: function() {},
        link: function(scope, element, attrs, ngModel) {

          var updateModel = function updateModel(value) {
              scope.$apply(function() {
                ngModel.$setViewValue(value);
              });
            },
            options = {
              modules: {
                'toolbar': {
                  container: '.toolbar'
                },
                'image-tooltip': true,
                'link-tooltip': true,
                'placeholder': {
                  text: attrs.placeholder || ''
                }
              },
              theme: 'snow'
            },
            extraOptions = attrs.quill ?
              scope.$eval(attrs.quill) : {},
            editor;

          angular.extend(options, extraOptions);

          $timeout(function() {

            editor = new Quill(element.children()[1], options);

            ngModel.$render();

            if (attrs.hasplaceholder){
              console.log('hasplaceholder');
              editor.on('focus', function(delta, source) {
                console.log('focus?');
                _.once( function(){ updateModel('') });
              });
            }

            editor.on('text-change', function(delta, source) {
              updateModel(this.getHTML());
            });

            editor.once('selection-change', function(hasFocus) {
              if (attrs.hasplaceholder){
               updateModel('');
              }
              $(editor).toggleClass('focus', hasFocus);
            });

          });

          ngModel.$render = function() {
            if (angular.isDefined(editor)) {
              $timeout(function() {
                editor.setHTML(ngModel.$viewValue || '');
              });
            }

          };

        }
      };
    }]);
})();
<commit_msg>Testing chil<commit_after>(function() {
  'use strict';

  /**
   * usage:

   *
   *    extra options:
   *      quill: pass as a string
   *
   */

  var scripts = document.getElementsByTagName("script"),
    currentScriptPath = scripts[scripts.length - 1].src;

  angular.module('angular-quill', [])
    .directive("quill", ['$timeout', function($timeout) {
      return {
        restrict: 'A',
        require: "ngModel",
        replace: true,
        templateUrl: 'global/base/layouts/quill/angular-quill.html',
        controller: function() {},
        link: function(scope, element, attrs, ngModel) {

          var updateModel = function updateModel(value) {
              scope.$apply(function() {
                ngModel.$setViewValue(value);
              });
            },
            options = {
              modules: {
                'toolbar': {
                  container: '.toolbar'
                },
                'image-tooltip': true,
                'link-tooltip': true,
                'placeholder': {
                  text: attrs.placeholder || ''
                }
              },
              theme: 'snow'
            },
            extraOptions = attrs.quill ?
              scope.$eval(attrs.quill) : {},
            editor;

          angular.extend(options, extraOptions);

          $timeout(function() {

            editor = new Quill(element.children()[1], options);

            ngModel.$render();

            if (attrs.hasplaceholder){
              console.log('hasplaceholder');
              editor.on('focus', function(delta, source) {
                console.log(element.children());
                console.log('focus?');
                _.once( function(){ updateModel('') });
              });
            }

            editor.on('text-change', function(delta, source) {
              updateModel(this.getHTML());
            });

            editor.once('selection-change', function(hasFocus) {
              if (attrs.hasplaceholder){
               updateModel('');
              }
              $(editor).toggleClass('focus', hasFocus);
            });

          });

          ngModel.$render = function() {
            if (angular.isDefined(editor)) {
              $timeout(function() {
                editor.setHTML(ngModel.$viewValue || '');
              });
            }

          };

        }
      };
    }]);
})();
<|endoftext|>


<commit_before>'use strict';

let http = require('http');

http.createServer((request, response) => {
// 傳送 HTTP header
// HTTP Status: 200 : OK
// Content Type: text/plain
response.writeHead(200, {
'Content-Type': 'text/plain'
});

// 傳送回應內容。
response.end('Hello World!\n');

console.log('request.headers: \n', request.headers)
}).listen(8088);
// log message to Console
console.log(' 伺服器啓動，連線 url: http://127.0.0.1:8088/');
<commit_msg>11/3  02<commit_after>'use strict';

let http = require('http');

http.createServer((request, response) => {
  request.on('end', () => {
    console.log('Request method: ' + request.method);
    console.log('Request url: ' + request.url);
  });

  // 傳送 HTTP header
  // HTTP Status: 200 : OK
  // Content Type: text/plain
  response.writeHead(200, {
    'Content-Type': 'text/plain'
  });

  // 傳送回應內容。
  response.end('Hello World!\n');
}).listen(8088);

// log message to Console
console.log('Server running at http://127.0.0.1:8088/');
<|endoftext|>


<commit_before>/**
* saves selected training population ids to cookie
* @author Isaak Y Tecle <iyt2@cornell.edu>
*
*/

JSAN.use("jquery");
JSAN.use("Prototype");
JSAN.use('jquery.blockUI');

var getCookieName =  function (trId) {
    return 'trait_' + trId + '_populations';
};

var getPopIds =  function() {
    jQuery("input:checkbox[name='project']").change(function() {

            var trId = getTraitId();
            var cookieName = getCookieName(trId);
            var cookieArrayData = [];

            if (jQuery(this).attr('checked')) {

                var popId = jQuery(this).val();

                var existingPopIds = jQuery.cookie(cookieName);

                if (!existingPopIds) {

                    cookieArrayData.push(popId);
                    jQuery.cookie(cookieName, cookieArrayData, {path: '/'});
                }
                else {

                    var cookieData = jQuery.cookie(cookieName);

                    if (cookieData) {
                       cookieArrayData = cookieData.split(",");
                    }

                    var indexPopId = jQuery.inArray(popId, cookieArrayData);
                    if (indexPopId == -1) {

                        cookieArrayData.push(popId);
                        cookieArrayData =  cookieArrayData.unique();

                        jQuery.cookie(cookieName, cookieArrayData, {path: '/'});
                    }
                }
            }
            else  {
                var popId = jQuery(this).val();

                var cookieData =  jQuery.cookie(cookieName);
                cookieArrayData = cookieData.split(",");

                var indexPopId = jQuery.inArray(popId, cookieArrayData);

                if(indexPopId != -1) {
                    cookieArrayData.splice(indexPopId, 1);
                }

                cookieArrayData = cookieArrayData.unique();
                jQuery.cookie(cookieName, cookieArrayData, {path: '/'});

             }
        });
    };

var selectedPops = function () {
            var trId       = getTraitId();
            var cookieName = getCookieName(trId);
            var cookieData = jQuery.cookie(cookieName);
            var cookieArrayData = [];

            if (cookieData) {
                cookieArrayData = cookieData.split(",");
                cookieArrayData = cookieArrayData.unique();
            }

            if (cookieArrayData.length == 1) {
                var redirectUrl =  '/solgs/trait/' + trId + '/population/' + cookieData;

                jQuery.blockUI.defaults.applyPlatformOpacityRules = false;
                jQuery.blockUI({message: 'Please wait..'});

                jQuery.ajax({
                        type: 'POST',
                            dataType: "json",
                            url: redirectUrl,
                            data: 'source=ajaxredirect',
                            success: function(res) {
                            var suc = res.status;
                            if (suc == 'success') {
                                jQuery.cookie(cookieName, null, {expires: -1, path: '/'});
                                window.location.href = redirectUrl;
                            }
                        }

                    });
            }

            else if( cookieArrayData.length > 1 ) {

                var action = "/solgs/search/result/populations/" + trId;
                var selectedPops = trId + "=" + cookieArrayData + '&' + 'combine=confirm';
                jQuery.ajax({
                        type: 'POST',
                        dataType: "json",
                        url: action,
                        data: selectedPops,
                        success: function(res){
                              var suc = res.status;
                              if (suc == 'success') {
                                  var confirmPops = res.populations;
                                  var url = '/solgs/combine/populations/trait/confirm/' + trId;
                                  var form = jQuery('<form action="' + url + '" method="POST">' +
                                                    '<input type="hidden" name="confirm_populations" value="' + confirmPops + '" />' +
                                                    '</form>'
                                                    );
                                  jQuery('body').append(form);
                                  jQuery(form).submit();
                              }
                        }
                    });
            }
            else {
                alert('No populations were selected.' +
                      'Please make your selections.'
                      );

            }
};

var confirmSelections =  function() {
    var trId = getTraitId();
    var selections = [];

    jQuery("input:checkbox[name='project']:checked").each( function() {
            selections.push(jQuery(this).val());
        });

    var action = "/solgs/combine/populations/trait/" + trId;
    var selectedPops = trId + "=" + selections + '&' + 'combine=combine';

    jQuery.blockUI.defaults.applyPlatformOpacityRules = false;
    jQuery.blockUI({message: 'Please wait..'});

    jQuery.ajax({
            type: 'POST',
                dataType: "json",
                url: action,
                data: selectedPops,
                success: function(res) {
                var suc = res.status;

                if (suc) {
                    //alert('combined pops');
                    var comboPopsId = res.combo_pops_id;
                    var newUrl = '/solgs/model/combined/populations/' + comboPopsId + '/trait/' + trId;

                    var form = jQuery('<form action="' + newUrl + '" method="POST">' +
                                      '<input type="hidden" name="combined_populations" value="' +
                                       selections + '" />' + '</form>');

                    jQuery('body').append(form);
                    jQuery(form).submit();

                    jQuery.unblockUI();

                } else {

                    if(res.not_matching_pops ){
                        alert('populations ' + res.not_matching_pops +
                              ' were genotyped using different marker sets. ' +
                              'Please make new selections to combine.' );
                        window.location.href =  '/solgs/search/result/populations/' + trId;
                    }

                    if (res.redirect_url) {
                        window.location.href = res.redirect_url;
                    }
                }
            }
        });

    var trId = getTraitId();
    var cookieName = getCookieName(trId);
    jQuery.cookie(cookieName, null, {expires: -1, path: '/'});

};

Array.prototype.unique =
    function() {
    var a = [];
    var l = this.length;
    for(var i=0; i<l; i++) {
      for(var j=i+1; j<l; j++) {
        // If this[i] is found later in the array
        if (this[i] === this[j])
          j = ++i;
      }
      a.push(this[i]);
    }
    return a;
  };

var getTraitId = function () {
   var id = jQuery("input[name='trait_id']").val();
   return id;
};

<commit_msg>use id selector<commit_after>/**
* saves selected training population ids to cookie
* @author Isaak Y Tecle <iyt2@cornell.edu>
*
*/

JSAN.use("jquery");
JSAN.use("Prototype");
JSAN.use('jquery.blockUI');

var getCookieName =  function (trId) {
    return 'trait_' + trId + '_populations';
};

var getPopIds =  function() {
    jQuery("input:checkbox[name='project']").change(function() {

            var trId = getTraitId();
            var cookieName = getCookieName(trId);
            var cookieArrayData = [];

            if (jQuery(this).attr('checked')) {

                var popId = jQuery(this).val();

                var existingPopIds = jQuery.cookie(cookieName);

                if (!existingPopIds) {

                    cookieArrayData.push(popId);
                    jQuery.cookie(cookieName, cookieArrayData, {path: '/'});
                }
                else {

                    var cookieData = jQuery.cookie(cookieName);

                    if (cookieData) {
                       cookieArrayData = cookieData.split(",");
                    }

                    var indexPopId = jQuery.inArray(popId, cookieArrayData);
                    if (indexPopId == -1) {

                        cookieArrayData.push(popId);
                        cookieArrayData =  cookieArrayData.unique();

                        jQuery.cookie(cookieName, cookieArrayData, {path: '/'});
                    }
                }
            }
            else  {
                var popId = jQuery(this).val();

                var cookieData =  jQuery.cookie(cookieName);
                cookieArrayData = cookieData.split(",");

                var indexPopId = jQuery.inArray(popId, cookieArrayData);

                if(indexPopId != -1) {
                    cookieArrayData.splice(indexPopId, 1);
                }

                cookieArrayData = cookieArrayData.unique();
                jQuery.cookie(cookieName, cookieArrayData, {path: '/'});

             }
        });
    };

var selectedPops = function () {
            var trId       = getTraitId();
            var cookieName = getCookieName(trId);
            var cookieData = jQuery.cookie(cookieName);
            var cookieArrayData = [];

            if (cookieData) {
                cookieArrayData = cookieData.split(",");
                cookieArrayData = cookieArrayData.unique();
            }

            if (cookieArrayData.length == 1) {
                var redirectUrl =  '/solgs/trait/' + trId + '/population/' + cookieData;

                jQuery.blockUI.defaults.applyPlatformOpacityRules = false;
                jQuery.blockUI({message: 'Please wait..'});

                jQuery.ajax({
                        type: 'POST',
                            dataType: "json",
                            url: redirectUrl,
                            data: 'source=ajaxredirect',
                            success: function(res) {
                            var suc = res.status;
                            if (suc == 'success') {
                                jQuery.cookie(cookieName, null, {expires: -1, path: '/'});
                                window.location.href = redirectUrl;
                            }
                        }

                    });
            }

            else if( cookieArrayData.length > 1 ) {

                var action = "/solgs/search/result/populations/" + trId;
                var selectedPops = trId + "=" + cookieArrayData + '&' + 'combine=confirm';
                jQuery.ajax({
                        type: 'POST',
                        dataType: "json",
                        url: action,
                        data: selectedPops,
                        success: function(res){
                              var suc = res.status;
                              if (suc == 'success') {
                                  var confirmPops = res.populations;
                                  var url = '/solgs/combine/populations/trait/confirm/' + trId;
                                  var form = jQuery('<form action="' + url + '" method="POST">' +
                                                    '<input type="hidden" name="confirm_populations" value="' + confirmPops + '" />' +
                                                    '</form>'
                                                    );
                                  jQuery('body').append(form);
                                  jQuery(form).submit();
                              }
                        }
                    });
            }
            else {
                alert('No populations were selected.' +
                      'Please make your selections.'
                      );

            }
};

var confirmSelections =  function() {
    var trId = getTraitId();
    var selections = [];

    jQuery("input:checkbox[name='project']:checked").each( function() {
            selections.push(jQuery(this).val());
        });

    var action = "/solgs/combine/populations/trait/" + trId;
    var selectedPops = trId + "=" + selections + '&' + 'combine=combine';

    jQuery.blockUI.defaults.applyPlatformOpacityRules = false;
    jQuery.blockUI({message: 'Please wait..'});

    jQuery.ajax({
            type: 'POST',
                dataType: "json",
                url: action,
                data: selectedPops,
                success: function(res) {
                var suc = res.status;

                if (suc) {
                    //alert('combined pops');
                    var comboPopsId = res.combo_pops_id;
                    var newUrl = '/solgs/model/combined/populations/' + comboPopsId + '/trait/' + trId;

                    var form = jQuery('<form action="' + newUrl + '" method="POST">' +
                                      '<input type="hidden" name="combined_populations" value="' +
                                       selections + '" />' + '</form>');

                    jQuery('body').append(form);
                    jQuery(form).submit();

                    jQuery.unblockUI();

                } else {

                    if(res.not_matching_pops ){
                        alert('populations ' + res.not_matching_pops +
                              ' were genotyped using different marker sets. ' +
                              'Please make new selections to combine.' );
                        window.location.href =  '/solgs/search/result/populations/' + trId;
                    }

                    if (res.redirect_url) {
                        window.location.href = res.redirect_url;
                    }
                }
            }
        });

    var trId = getTraitId();
    var cookieName = getCookieName(trId);
    jQuery.cookie(cookieName, null, {expires: -1, path: '/'});

};

Array.prototype.unique =
    function() {
    var a = [];
    var l = this.length;
    for(var i=0; i<l; i++) {
      for(var j=i+1; j<l; j++) {
        // If this[i] is found later in the array
        if (this[i] === this[j])
          j = ++i;
      }
      a.push(this[i]);
    }
    return a;
  };

var getTraitId = function () {
   var id = jQuery("#trait_id").val();
   return id;
};

<|endoftext|>


<commit_before>var grammarForm = $('#grammarForm');

var serializeForm = function(form) {
	var fields = form.serializeArray();

	var data = {};

	fields.forEach(function(field) {
		data[field.name] = field.value;
	});

	return data;
};

var spinner = new Spinner().spin(document.body);

$(spinner.el).hide();

grammarForm.submit(function(event) {
	$(spinner.el).show();

	$.ajax({
		dataType: 'json',
		type: 'POST',
		url: '/validate-grammar',
		data: serializeForm(grammarForm)
	})
	.done(function(result) {
		var filterd = [];

		result.forEach(function(msg) {
			if (msg.indexOf('error(8)') == -1) {
				filterd.push(msg.replace(/error\(\d+\)\:\s\:/ig, 'Error at line '));
			}
		});

		$('.notifyjs-container').trigger('click');

		if (filterd.length > 0) {
			filterd.forEach(function(msg) {
				$.notify(msg, {
					autoHide: false,
					position: 'top'
				});
			});
		}
		else {
			$.notify('Grammar looks fine :)', {
				autoHide: false,
				className: 'success',
				position: 'top'
			});
		}

		$(spinner.el).hide();
	});

	event.preventDefault();
});<commit_msg>Only show antlr error messages.<commit_after>var grammarForm = $('#grammarForm');

var serializeForm = function(form) {
	var fields = form.serializeArray();

	var data = {};

	fields.forEach(function(field) {
		data[field.name] = field.value;
	});

	return data;
};

var spinner = new Spinner().spin(document.body);

$(spinner.el).hide();

grammarForm.submit(function(event) {
	$(spinner.el).show();

	$.ajax({
		dataType: 'json',
		type: 'POST',
		url: '/validate-grammar',
		data: serializeForm(grammarForm)
	})
	.done(function(result) {
		var filterd = [];

		result.forEach(function(msg) {
			if (/error\(\d+\)\:\s\:/ig.test(msg) &&  (msg.indexOf('error(8)') == -1)) {
				filterd.push(msg.replace(/error\(\d+\)\:\s\:/ig, 'Error at line '));
			}
		});

		$('.notifyjs-container').trigger('click');

		if (filterd.length > 0) {
			filterd.forEach(function(msg) {
				$.notify(msg, {
					autoHide: false,
					position: 'top'
				});
			});
		}
		else {
			$.notify('Grammar looks fine :)', {
				autoHide: false,
				className: 'success',
				position: 'top'
			});
		}

		$(spinner.el).hide();
	});

	event.preventDefault();
});<|endoftext|>


<commit_before>Package.describe({
  "summary": "Clustering solution for Meteor with load balancing and service discovery.",
  "version": "1.6.0",
  "git": "https://github.com/meteorhacks/cluster.git",
  "name": "meteorhacks:cluster"
});

Npm.depends({
  "cookies": "0.5.0",
  "http-proxy": "1.8.1",
  "portscanner": "1.0.0",
  // mongodb@1.4.32 with binary modules removed!
  // Stolen from Meteor's mongo package. see: http://goo.gl/GJJQ8e
  "mongodb": "https://github.com/meteor/node-mongodb-native/tarball/634759e6326dc19a228df66ddb309285532f3b8a"
});

Package.onTest(function(api) {
  configurePackage(api);
  api.use('tinytest');
  api.use('practicalmeteor:sinon@1.10.3_2');

  api.addFiles([
    'tests/server/utils.js',
    'tests/server/api.js',
    'tests/server/worker_pool.js',
    'tests/server/discovery_backends/mongo/store.js',
    'tests/server/discovery_backends/mongo/discovery.js',
    'tests/server/balancer/utils.js',
    'tests/server/balancer/route.js',
    'tests/server/balancer/workers.js',
  ], 'server');
});

Package.onUse(function(api) {
  configurePackage(api);
  api.export('Cluster');
});

function configurePackage(api) {
  api.versionsFrom('METEOR@0.9.2');
  api.use(['webapp'], 'server');
  api.use([
    'ddp', 'underscore'
  ], ['server', 'client']);

  api.addFiles([
    'lib/namespace.js',
    'lib/connection_watcher.js',
  ], ['server', 'client']);

  api.addFiles([
    'lib/server/api.js',
    'lib/server/discovery_backends/mongo/store.js',
    'lib/server/discovery_backends/mongo/discovery.js',
    'lib/server/utils.js',
    'lib/server/worker_pool.js',
    'lib/server/balancer/namespace.js',
    'lib/server/balancer/utils.js',
    'lib/server/balancer/workers.js',
    'lib/server/balancer/route.js',
    'lib/server/auto_connect.js'
  ], ['server']);

  api.addFiles([
    'lib/client/api.js'
  ], ['client']);
}
<commit_msg>Bump versions: 1.6.1<commit_after>Package.describe({
  "summary": "Clustering solution for Meteor with load balancing and service discovery.",
  "version": "1.6.1",
  "git": "https://github.com/meteorhacks/cluster.git",
  "name": "meteorhacks:cluster"
});

Npm.depends({
  "cookies": "0.5.0",
  "http-proxy": "1.8.1",
  "portscanner": "1.0.0",
  // mongodb@1.4.32 with binary modules removed!
  // Stolen from Meteor's mongo package. see: http://goo.gl/GJJQ8e
  "mongodb": "https://github.com/meteor/node-mongodb-native/tarball/634759e6326dc19a228df66ddb309285532f3b8a"
});

Package.onTest(function(api) {
  configurePackage(api);
  api.use('tinytest');
  api.use('practicalmeteor:sinon@1.10.3_2');

  api.addFiles([
    'tests/server/utils.js',
    'tests/server/api.js',
    'tests/server/worker_pool.js',
    'tests/server/discovery_backends/mongo/store.js',
    'tests/server/discovery_backends/mongo/discovery.js',
    'tests/server/balancer/utils.js',
    'tests/server/balancer/route.js',
    'tests/server/balancer/workers.js',
  ], 'server');
});

Package.onUse(function(api) {
  configurePackage(api);
  api.export('Cluster');
});

function configurePackage(api) {
  api.versionsFrom('METEOR@0.9.2');
  api.use(['webapp'], 'server');
  api.use([
    'ddp', 'underscore'
  ], ['server', 'client']);

  api.addFiles([
    'lib/namespace.js',
    'lib/connection_watcher.js',
  ], ['server', 'client']);

  api.addFiles([
    'lib/server/api.js',
    'lib/server/discovery_backends/mongo/store.js',
    'lib/server/discovery_backends/mongo/discovery.js',
    'lib/server/utils.js',
    'lib/server/worker_pool.js',
    'lib/server/balancer/namespace.js',
    'lib/server/balancer/utils.js',
    'lib/server/balancer/workers.js',
    'lib/server/balancer/route.js',
    'lib/server/auto_connect.js'
  ], ['server']);

  api.addFiles([
    'lib/client/api.js'
  ], ['client']);
}
<|endoftext|>


<commit_before>import Ember from 'ember';
import baseMixin from 'ember-data-offline/mixins/base';
import isObjectEmpty from 'ember-data-offline/utils/is-object-empty';
import debug from 'ember-data-offline/utils/debug';

export default Ember.Mixin.create(baseMixin, {
  shouldReloadAll() {
    return false;
  },
  shouldBackgroundReloadAll: function() {
    return false;
  },

  findAll: function(store, typeClass, sinceToken, fromJob) {
    debug('findAll online', typeClass.modelName);
    let adapterResp = this._super.apply(this, arguments);
    return adapterResp.then(resp => {
      //TODO Think about persistance this registry hash
      this.set(`lastTimeFetched.all$${typeClass.modelName}`, new Date());
      if (!fromJob) {
        this.createOfflineJob('findAll', [store, typeClass, sinceToken, adapterResp, true], store);
      }
      return resp;
    });
  },

  find: function(store, typeClass, id, snapshot, fromJob) {
    debug('find online', typeClass.modelName, id);
    let onlineResp = this._super.apply(this, arguments);
    return onlineResp.then(resp => {
      this.set(`lastTimeFetched.one$${typeClass.modelName}$${id}`, new Date());
      if (!fromJob) {
        this.createOfflineJob('find', [store, typeClass, id, snapshot, onlineResp, true], store);
      }
      return resp;
    }).catch(console.log.bind(console));
  },

  findQuery: function(store, type, query, fromJob) {
    debug('findQuery online', type.modelName);
    let onlineResp = this._super.apply(this, arguments);
    return onlineResp.then(resp => {
      if (!fromJob) {
        this.createOfflineJob('findQuery', [store, type, query, onlineResp, true], store);
      }
      return resp;
    });
  },

  findMany: function(store, type, ids, snapshots, fromJob) {
    debug('findMany online', type.modelName, ids);
    let onlineResp;
    let recordsInStore = store.peekAll(type.modelName);
    let inStoreIds = recordsInStore.map(record => {
      return !isObjectEmpty(record._internalModel._data) && record.id;
    });

    let idsDiff = ids.filter(item => inStoreIds.indexOf(item) < 0);

    if (!Ember.isEmpty(idsDiff)) {
      onlineResp = this._super(store, type, idsDiff, snapshots);
    }
    else {
      onlineResp = Ember.RSVP.resolve([]);
    }

    return onlineResp.then(resp => {
      if (!fromJob) {
        this.createOfflineJob('findMany', [store, type, ids, snapshots, onlineResp, true], store);
      }
      return resp;
    });
  },

  createRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('createRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  },

  updateRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('updateRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  },

  deleteRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('deleteRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  }
});
<commit_msg>back fix<commit_after>import Ember from 'ember';
import baseMixin from 'ember-data-offline/mixins/base';
import isObjectEmpty from 'ember-data-offline/utils/is-object-empty';
import debug from 'ember-data-offline/utils/debug';

export default Ember.Mixin.create(baseMixin, {
  shouldReloadAll() {
    return false;
  },
  shouldBackgroundReloadAll: function() {
    return false;
  },

  findAll: function(store, typeClass, sinceToken, fromJob) {
    debug('findAll online', typeClass.modelName);
    let adapterResp = this._super.apply(this, arguments);
    return adapterResp.then(resp => {
      //TODO Think about persistance this registry hash
      this.set(`lastTimeFetched.all$${typeClass.modelName}`, new Date());
      if (!fromJob) {
        this.createOfflineJob('findAll', [store, typeClass, sinceToken, adapterResp, true], store);
      }
      return resp;
    });
  },

  find: function(store, typeClass, id, snapshot, fromJob) {
    debug('find online', typeClass.modelName, id);
    let onlineResp = this._super.apply(this, arguments);
    return onlineResp.then(resp => {
      this.set(`lastTimeFetched.one$${typeClass.modelName}$${id}`, new Date());
      if (!fromJob) {
        this.createOfflineJob('find', [store, typeClass, id, snapshot, onlineResp, true], store);
      }
      return resp;
    }).catch(console.log.bind(console));
  },

  findQuery: function(store, type, query, fromJob) {
    debug('findQuery online', type.modelName);
    let onlineResp = this._super.apply(this, arguments);
    return onlineResp.then(resp => {
      if (!fromJob) {
        this.createOfflineJob('findQuery', [store, type, query, onlineResp, true], store);
      }
      return resp;
    });
  },

  findMany: function(store, type, ids, snapshots, fromJob) {
    debug('findMany online', type.modelName, ids);
    let onlineResp;
    // let recordsInStore = store.peekAll(type.modelName);
    // let inStoreIds = recordsInStore.map(record => {
    //   return !isObjectEmpty(record._internalModel._data) && record.id;
    // });

    // let idsDiff = ids.filter(item => inStoreIds.indexOf(item) < 0);

    // if (!Ember.isEmpty(idsDiff)) {
      onlineResp = this._super(store, type, idsDiff, snapshots);
    // }
    // else {
    //   onlineResp = Ember.RSVP.resolve([]);
    // }

    return onlineResp.then(resp => {
      if (!fromJob) {
        this.createOfflineJob('findMany', [store, type, ids, snapshots, onlineResp, true], store);
      }
      return resp;
    });
  },

  createRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('createRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  },

  updateRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('updateRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  },

  deleteRecord(store, type, snapshot, fromJob) {
    let onlineResp = this._super.apply(this, arguments);
    if (!fromJob) {
      this.createOfflineJob('deleteRecord', [store, type, snapshot, onlineResp, true], store);
    }
    return onlineResp;
  }
});
<|endoftext|>


<commit_before>import gql from 'graphql-tag';
import Link from 'next/link';
import { useEffect, useRef, useCallback, useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Box, Divider, Snackbar } from '@material-ui/core';
import { ngettext, msgid, t } from 'ttag';

import { useRouter } from 'next/router';
import { useQuery, useLazyQuery } from '@apollo/react-hooks';
import Head from 'next/head';

import withData from 'lib/apollo';
import useCurrentUser from 'lib/useCurrentUser';
import { nl2br, linkify, ellipsis } from 'lib/text';
import { usePushToDataLayer } from 'lib/gtm';

import { format, formatDistanceToNow } from 'lib/dateWithLocale';
import isValid from 'date-fns/isValid';

import AppLayout from 'components/AppLayout';
import Hyperlinks from 'components/Hyperlinks';
import CurrentReplies from 'components/CurrentReplies';
import ReplyRequestReason from 'components/ReplyRequestReason';
import CreateReplyRequestForm from 'components/CreateReplyRequestForm';
import NewReplySection from 'components/NewReplySection';
import ArticleItem from 'components/ArticleItem';
import ArticleInfo from 'components/ArticleInfo';
import ArticleCategories from 'components/ArticleCategories';
import cx from 'clsx';
import Trendline from 'components/Trendline';

const useStyles = makeStyles(theme => ({
  root: {
    display: 'flex',
    padding: '24px 0',
    flexDirection: 'column',
    [theme.breakpoints.up('md')]: {
      flexDirection: 'row',
      alignItems: 'baseline',
    },
  },
  card: {
    background: theme.palette.common.white,
    borderRadius: 8,
  },
  main: {
    flex: 1,
    marginRight: 0,
    [theme.breakpoints.up('md')]: {
      flex: 3,
      marginRight: 12,
    },
  },
  aside: {
    flex: 1,
    background: 'transparent',
    [theme.breakpoints.up('md')]: {
      padding: '21px 19px',
      background: theme.palette.common.white,
    },
    '& h4': {
      [theme.breakpoints.up('md')]: {
        paddingBottom: 10,
        borderBottom: `1px solid ${theme.palette.secondary[500]}`,
      },
    },
  },
  newReplyContainer: {
    position: 'fixed',
    zIndex: theme.zIndex.modal,
    height: '100%',
    width: '100%',
    top: 0,
    left: 0,
    background: theme.palette.common.white,
    [theme.breakpoints.up('md')]: {
      zIndex: 10,
      position: 'relative',
      padding: '28px 16px',
      marginTop: 24,
      borderRadius: 8,
    },
  },
  similarMessageContainer: {
    backgroundColor: theme.palette.common.white,
    minWidth: '100%',
    padding: '17px 19px',
    marginRight: theme.spacing(2),
    borderRadius: 8,
    textDecoration: 'none',
    color: 'inherit',
    [theme.breakpoints.up('md')]: {
      padding: '16px 0 0 0 ',
      margin: 0,
      width: 'auto',
      borderBottom: `1px solid ${theme.palette.secondary[100]}`,
      '&:last-child': {
        borderBottom: 'none',
      },
    },
  },
  text: {
    display: 'box',
    overflow: 'hidden',
    boxOrient: 'vertical',
    textOverflow: 'ellipsis',
    lineClamp: 5,
  },
}));

const LOAD_ARTICLE = gql`
  query LoadArticlePage($id: String!) {
    GetArticle(id: $id) {
      id
      text
      requestedForReply
      replyRequestCount
      replyCount
      createdAt
      references {
        type
      }
      hyperlinks {
        ...HyperlinkData
      }
      replyRequests {
        ...ReplyRequestInfo
      }
      articleReplies {
        ...CurrentRepliesData
      }
      ...RelatedArticleData
      similarArticles: relatedArticles {
        edges {
          node {
            ...ArticleItem
          }
        }
      }
      articleCategories {
        ...ArticleCategoryData
      }
    }
  }
  ${Hyperlinks.fragments.HyperlinkData}
  ${ReplyRequestReason.fragments.ReplyRequestInfo}
  ${CurrentReplies.fragments.CurrentRepliesData}
  ${NewReplySection.fragments.RelatedArticleData}
  ${ArticleItem.fragments.ArticleItem}
  ${ArticleCategories.fragments.ArticleCategoryData}
`;

const LOAD_ARTICLE_FOR_USER = gql`
  query LoadArticlePageForUser($id: String!) {
    GetArticle(id: $id) {
      id # Required, https://github.com/apollographql/apollo-client/issues/2510
      replyRequests {
        ...ReplyRequestInfoForUser
      }
      articleReplies {
        ...ArticleReplyForUser
      }
      articleCategories {
        ...ArticleCategoryDataForUser
      }
    }
  }
  ${ReplyRequestReason.fragments.ReplyRequestInfoForUser}
  ${CurrentReplies.fragments.ArticleReplyForUser}
  ${ArticleCategories.fragments.ArticleCategoryDataForUser}
`;

function ArticlePage() {
  const { query } = useRouter();
  const [showForm, setShowForm] = useState(false);
  const [flashMessage, setFlashMessage] = useState(0);
  const articleVars = { id: query.id };

  const { data, loading } = useQuery(LOAD_ARTICLE, {
    variables: articleVars,
  });
  const [
    loadArticleForUser,
    { refetch: refetchArticleForUser, called: articleForUserCalled },
  ] = useLazyQuery(LOAD_ARTICLE_FOR_USER, {
    variables: articleVars,
    fetchPolicy: 'network-only',
  });
  const currentUser = useCurrentUser();

  const replySectionRef = useRef(null);
  const classes = useStyles();

  useEffect(() => {
    if (!articleForUserCalled) {
      loadArticleForUser();
    } else {
      refetchArticleForUser();
    }
  }, [currentUser]);

  const handleNewReplySubmit = useCallback(() => {
    if (!replySectionRef.current) return;
    replySectionRef.current.scrollIntoView({ behavior: 'smooth' });
    setFlashMessage(t`Your reply has been submitted.`);
  }, []);

  const handleError = useCallback(error => {
    console.error(error);
    setFlashMessage(error.toString());
  }, []);

  const handleFormClose = () => setShowForm(false);

  const article = data?.GetArticle;

  usePushToDataLayer(!!article, { event: 'dataLoaded' });

  if (loading) {
    return (
      <AppLayout>

          <title>{t`Loading`}</title>

        Loading...
      </AppLayout>
    );
  }

  if (!article) {
    return (
      <AppLayout>

          <title>{t`Not found`}</title>

        {t`Message does not exist`}
      </AppLayout>
    );
  }

  const { replyRequestCount, text, hyperlinks } = article;
  const similarArticles = article?.similarArticles?.edges || [];

  const createdAt = article.createdAt
    ? new Date(article.createdAt)
    : new Date();

  const timeAgoStr = formatDistanceToNow(createdAt);

  return (
    <AppLayout>

        <title>
          {ellipsis(article.text, { wordCount: 100 })} | {t`Cofacts`}
        </title>

          <Box
            className={classes.card}
            position="relative"
            px={{ xs: '12px', md: '19px' }}
            py={{ xs: '13px', md: '21px' }}
          >
            <Box
              display="flex"
              justifyContent="space-between"
              alignItems="center"
            >

                {ngettext(
                  msgid`${replyRequestCount} person report this message`,
                  `${replyRequestCount} people report this message`,
                  replyRequestCount
                )}

              {isValid(createdAt) && (
                {t`First reported ${timeAgoStr} ago`}
              )}
            </Box>
            <Divider classes={{ root: classes.divider }} />
            <Box py={4} overflow="hidden">
              {nl2br(
                linkify(text, {
                  props: {
                    target: '_blank',
                  },
                })
              )}
              <Hyperlinks hyperlinks={hyperlinks} />
            </Box>
            <ArticleCategories
              articleId={article.id}
              articleCategories={article.articleCategories}
            />
            <Trendline />
            <Divider />

              {article.replyRequests.map((replyRequest, idx) => (
                <ReplyRequestReason
                  key={replyRequest.id}
                  articleId={article.id}
                  replyRequest={replyRequest}
                  isArticleCreator={idx === 0}
                />
              ))}
              <CreateReplyRequestForm
                requestedForReply={article.requestedForReply}
                articleId={article.id}
                onNewReplyButtonClick={() => {
                  setShowForm(true);
                }}
              />

          </Box>

          {showForm && (

              <NewReplySection
                article={article}
                existingReplyIds={(article?.articleReplies || []).map(
                  ({ replyId }) => replyId
                )}
                relatedArticles={article?.relatedArticles}
                onSubmissionComplete={handleNewReplySubmit}
                onError={handleError}
                onClose={handleFormClose}
              />

          )}

          <Box
            className={classes.card}
            position="relative"
            px={{ xs: '12px', md: '19px' }}
            py={{ xs: '13px', md: '21px' }}
            mt={3}
            id="current-replies"
            ref={replySectionRef}
          >

{t`${article.articleReplies.length} replies to the message`}

            <Divider classes={{ root: classes.divider }} />
            <CurrentReplies articleReplies={article.articleReplies} />
          </Box>

{t`Similar messages`}

          {similarArticles.length ? (
            <Box
              display="flex"
              flexDirection={{ xs: 'row', md: 'column' }}
              overflow="auto"
            >
              {similarArticles.map(({ node }) => (
                <Link key={node.id} href={`/article/${node.id}`}>

{node.text}

                    <Box pt={1.5} pb={2}>
                      <ArticleInfo article={node} />
                    </Box>

                </Link>
              ))}
            </Box>
          ) : (
            <Box
              textAlign="center"
              pt={4}
              pb={3}
            >{t`No similar messages found`}</Box>
          )}

      <Snackbar
        open={!!flashMessage}
        onClose={() => setFlashMessage('')}
        message={flashMessage}
      />
    </AppLayout>
  );
}

export default withData(ArticlePage);
<commit_msg>Fix flexbox width<commit_after>import gql from 'graphql-tag';
import Link from 'next/link';
import { useEffect, useRef, useCallback, useState } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { Box, Divider, Snackbar } from '@material-ui/core';
import { ngettext, msgid, t } from 'ttag';

import { useRouter } from 'next/router';
import { useQuery, useLazyQuery } from '@apollo/react-hooks';
import Head from 'next/head';

import withData from 'lib/apollo';
import useCurrentUser from 'lib/useCurrentUser';
import { nl2br, linkify, ellipsis } from 'lib/text';
import { usePushToDataLayer } from 'lib/gtm';

import { format, formatDistanceToNow } from 'lib/dateWithLocale';
import isValid from 'date-fns/isValid';

import AppLayout from 'components/AppLayout';
import Hyperlinks from 'components/Hyperlinks';
import CurrentReplies from 'components/CurrentReplies';
import ReplyRequestReason from 'components/ReplyRequestReason';
import CreateReplyRequestForm from 'components/CreateReplyRequestForm';
import NewReplySection from 'components/NewReplySection';
import ArticleItem from 'components/ArticleItem';
import ArticleInfo from 'components/ArticleInfo';
import ArticleCategories from 'components/ArticleCategories';
import cx from 'clsx';
import Trendline from 'components/Trendline';

const useStyles = makeStyles(theme => ({
  root: {
    display: 'flex',
    padding: '24px 0',
    flexDirection: 'column',
    [theme.breakpoints.up('md')]: {
      flexDirection: 'row',
      alignItems: 'baseline',
    },
  },
  card: {
    background: theme.palette.common.white,
    borderRadius: 8,
  },
  main: {
    flex: 1,
    marginRight: 0,
    minWidth: 0,
    [theme.breakpoints.up('md')]: {
      flex: 3,
      marginRight: 12,
    },
  },
  aside: {
    flex: 1,
    background: 'transparent',
    minWidth: 0,
    [theme.breakpoints.up('md')]: {
      padding: '21px 19px',
      background: theme.palette.common.white,
    },
    '& h4': {
      [theme.breakpoints.up('md')]: {
        paddingBottom: 10,
        borderBottom: `1px solid ${theme.palette.secondary[500]}`,
      },
    },
  },
  newReplyContainer: {
    position: 'fixed',
    zIndex: theme.zIndex.modal,
    height: '100%',
    width: '100%',
    top: 0,
    left: 0,
    background: theme.palette.common.white,
    [theme.breakpoints.up('md')]: {
      zIndex: 10,
      position: 'relative',
      padding: '28px 16px',
      marginTop: 24,
      borderRadius: 8,
    },
  },
  similarMessageContainer: {
    backgroundColor: theme.palette.common.white,
    minWidth: '100%',
    padding: '17px 19px',
    marginRight: theme.spacing(2),
    borderRadius: 8,
    textDecoration: 'none',
    color: 'inherit',
    [theme.breakpoints.up('md')]: {
      padding: '16px 0 0 0 ',
      margin: 0,
      width: 'auto',
      borderBottom: `1px solid ${theme.palette.secondary[100]}`,
      '&:last-child': {
        borderBottom: 'none',
      },
    },
  },
  text: {
    display: 'box',
    overflow: 'hidden',
    boxOrient: 'vertical',
    textOverflow: 'ellipsis',
    lineClamp: 5,
  },
}));

const LOAD_ARTICLE = gql`
  query LoadArticlePage($id: String!) {
    GetArticle(id: $id) {
      id
      text
      requestedForReply
      replyRequestCount
      replyCount
      createdAt
      references {
        type
      }
      hyperlinks {
        ...HyperlinkData
      }
      replyRequests {
        ...ReplyRequestInfo
      }
      articleReplies {
        ...CurrentRepliesData
      }
      ...RelatedArticleData
      similarArticles: relatedArticles {
        edges {
          node {
            ...ArticleItem
          }
        }
      }
      articleCategories {
        ...ArticleCategoryData
      }
    }
  }
  ${Hyperlinks.fragments.HyperlinkData}
  ${ReplyRequestReason.fragments.ReplyRequestInfo}
  ${CurrentReplies.fragments.CurrentRepliesData}
  ${NewReplySection.fragments.RelatedArticleData}
  ${ArticleItem.fragments.ArticleItem}
  ${ArticleCategories.fragments.ArticleCategoryData}
`;

const LOAD_ARTICLE_FOR_USER = gql`
  query LoadArticlePageForUser($id: String!) {
    GetArticle(id: $id) {
      id # Required, https://github.com/apollographql/apollo-client/issues/2510
      replyRequests {
        ...ReplyRequestInfoForUser
      }
      articleReplies {
        ...ArticleReplyForUser
      }
      articleCategories {
        ...ArticleCategoryDataForUser
      }
    }
  }
  ${ReplyRequestReason.fragments.ReplyRequestInfoForUser}
  ${CurrentReplies.fragments.ArticleReplyForUser}
  ${ArticleCategories.fragments.ArticleCategoryDataForUser}
`;

function ArticlePage() {
  const { query } = useRouter();
  const [showForm, setShowForm] = useState(false);
  const [flashMessage, setFlashMessage] = useState(0);
  const articleVars = { id: query.id };

  const { data, loading } = useQuery(LOAD_ARTICLE, {
    variables: articleVars,
  });
  const [
    loadArticleForUser,
    { refetch: refetchArticleForUser, called: articleForUserCalled },
  ] = useLazyQuery(LOAD_ARTICLE_FOR_USER, {
    variables: articleVars,
    fetchPolicy: 'network-only',
  });
  const currentUser = useCurrentUser();

  const replySectionRef = useRef(null);
  const classes = useStyles();

  useEffect(() => {
    if (!articleForUserCalled) {
      loadArticleForUser();
    } else {
      refetchArticleForUser();
    }
  }, [currentUser]);

  const handleNewReplySubmit = useCallback(() => {
    if (!replySectionRef.current) return;
    replySectionRef.current.scrollIntoView({ behavior: 'smooth' });
    setFlashMessage(t`Your reply has been submitted.`);
  }, []);

  const handleError = useCallback(error => {
    console.error(error);
    setFlashMessage(error.toString());
  }, []);

  const handleFormClose = () => setShowForm(false);

  const article = data?.GetArticle;

  usePushToDataLayer(!!article, { event: 'dataLoaded' });

  if (loading) {
    return (
      <AppLayout>

          <title>{t`Loading`}</title>

        Loading...
      </AppLayout>
    );
  }

  if (!article) {
    return (
      <AppLayout>

          <title>{t`Not found`}</title>

        {t`Message does not exist`}
      </AppLayout>
    );
  }

  const { replyRequestCount, text, hyperlinks } = article;
  const similarArticles = article?.similarArticles?.edges || [];

  const createdAt = article.createdAt
    ? new Date(article.createdAt)
    : new Date();

  const timeAgoStr = formatDistanceToNow(createdAt);

  return (
    <AppLayout>

        <title>
          {ellipsis(article.text, { wordCount: 100 })} | {t`Cofacts`}
        </title>

          <Box
            className={classes.card}
            position="relative"
            px={{ xs: '12px', md: '19px' }}
            py={{ xs: '13px', md: '21px' }}
          >
            <Box
              display="flex"
              justifyContent="space-between"
              alignItems="center"
            >

                {ngettext(
                  msgid`${replyRequestCount} person report this message`,
                  `${replyRequestCount} people report this message`,
                  replyRequestCount
                )}

              {isValid(createdAt) && (
                {t`First reported ${timeAgoStr} ago`}
              )}
            </Box>
            <Divider classes={{ root: classes.divider }} />
            <Box py={4} overflow="hidden">
              {nl2br(
                linkify(text, {
                  props: {
                    target: '_blank',
                  },
                })
              )}
              <Hyperlinks hyperlinks={hyperlinks} />
            </Box>
            <ArticleCategories
              articleId={article.id}
              articleCategories={article.articleCategories}
            />
            <Trendline />
            <Divider />

              {article.replyRequests.map((replyRequest, idx) => (
                <ReplyRequestReason
                  key={replyRequest.id}
                  articleId={article.id}
                  replyRequest={replyRequest}
                  isArticleCreator={idx === 0}
                />
              ))}
              <CreateReplyRequestForm
                requestedForReply={article.requestedForReply}
                articleId={article.id}
                onNewReplyButtonClick={() => {
                  setShowForm(true);
                }}
              />

          </Box>

          {showForm && (

              <NewReplySection
                article={article}
                existingReplyIds={(article?.articleReplies || []).map(
                  ({ replyId }) => replyId
                )}
                relatedArticles={article?.relatedArticles}
                onSubmissionComplete={handleNewReplySubmit}
                onError={handleError}
                onClose={handleFormClose}
              />

          )}

          <Box
            className={classes.card}
            position="relative"
            px={{ xs: '12px', md: '19px' }}
            py={{ xs: '13px', md: '21px' }}
            mt={3}
            id="current-replies"
            ref={replySectionRef}
          >

{t`${article.articleReplies.length} replies to the message`}

            <Divider classes={{ root: classes.divider }} />
            <CurrentReplies articleReplies={article.articleReplies} />
          </Box>

{t`Similar messages`}

          {similarArticles.length ? (
            <Box
              display="flex"
              flexDirection={{ xs: 'row', md: 'column' }}
              overflow="auto"
            >
              {similarArticles.map(({ node }) => (
                <Link key={node.id} href={`/article/${node.id}`}>

{node.text}

                    <Box pt={1.5} pb={2}>
                      <ArticleInfo article={node} />
                    </Box>

                </Link>
              ))}
            </Box>
          ) : (
            <Box
              textAlign="center"
              pt={4}
              pb={3}
            >{t`No similar messages found`}</Box>
          )}

      <Snackbar
        open={!!flashMessage}
        onClose={() => setFlashMessage('')}
        message={flashMessage}
      />
    </AppLayout>
  );
}

export default withData(ArticlePage);
<|endoftext|>


<commit_before>export default {
  isTest: false,
  server: {
    port: 3000,
    host: 'localhost'
  },
  bodyParser: {
    extended: true
  },
  mongodb: {
    uri: 'mongodb://localhost:27017/lettpost'
  }
};
<commit_msg>set for consign<commit_after>export default {
  isTest: false,
  server: {
    port: 3000,
    host: 'localhost'
  },
  bodyParser: {
    extended: true
  },
  mongodb: {
    uri: 'mongodb://localhost:27017/lett_database'
  },
  consign: [
    {
      cwd:'server',
      verbose:false
    }
  ]
};
<|endoftext|>


<commit_before>var config      = require('../../../gulp-config');
var gulp = require('gulp');
var plumber       = require('gulp-plumber');
var notify        = require('gulp-notify');
var sourcemaps = require('gulp-sourcemaps');
var browserify = require('browserify');
var babelify = require('babelify');
var concat = require('gulp-concat');
var gulpif = require('gulp-if');
var util = require('gulp-util');
var watchify = require('watchify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var browserSync = require('browser-sync');

var isFirstBuild = true;
module.exports = function(watch) {
    var isServer = process.argv[2] === 'serve';
    // Error notifications
    var handleError = function(task) {
        return function(err) {
            notify.onError({
                message: task + ' failed, check the logs..'
            })(err);
            util.log(util.colors.bgRed(task + ' error:'), util.colors.red(err));

            this.emit('end');
        };
    };

    var bundler = browserify( config.source.jsEntryFile, {
        debug: !util.env.production,
        cache: {},
        packageCache: {},
    }).transform(babelify);
    if(isServer) {
        bundler = watchify(bundler);
    }

    var bundle = function() {
        return bundler.bundle()
            .on('error', handleError('JS'))
            .pipe(source(config.destination.jsFileName))
            .pipe(buffer())
            .pipe(gulpif(util.env.production, uglify()))
            .pipe(gulp.dest(config.destination.assetsFolder + config.destination.jsFolderName))
            .pipe(gulpif(isServer, browserSync.stream({once: true})))
            .pipe(notify('Successfully compiled JS'));
    };
    if(isServer) {
        bundler.on('update', bundle);
    }
    return bundle();
};<commit_msg>[enhancement] BOILERPLATE-29: Ajout d'un log d'erreur pour uglify js'<commit_after>var config      = require('../../../gulp-config');
var gulp = require('gulp');
var plumber       = require('gulp-plumber');
var notify        = require('gulp-notify');
var sourcemaps = require('gulp-sourcemaps');
var browserify = require('browserify');
var babelify = require('babelify');
var concat = require('gulp-concat');
var gulpif = require('gulp-if');
var util = require('gulp-util');
var watchify = require('watchify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var uglify = require('gulp-uglify');
var browserSync = require('browser-sync');

var isFirstBuild = true;
module.exports = function(watch) {
    var isServer = process.argv[2] === 'serve';
    // Error notifications
    var handleError = function(task) {
        return function(err) {
            notify.onError({
                message: task + ' failed, check the logs..'
            })(err);
            util.log(util.colors.bgRed(task + ' error:'), util.colors.red(err));

            this.emit('end');
        };
    };

    var bundler = browserify( config.source.jsEntryFile, {
        debug: !util.env.production,
        cache: {},
        packageCache: {},
    }).transform(babelify);
    if(isServer) {
        bundler = watchify(bundler);
    }

    var bundle = function() {
        return bundler.bundle()
            .on('error', handleError('JS'))
            .pipe(source(config.destination.jsFileName))
            .pipe(buffer())
            .pipe(gulpif(util.env.production, uglify().on('error', function(err) {
                util.log(util.colors.bgRed('UglifyJS error:'), util.colors.red(err))
            })))
            .pipe(gulp.dest(config.destination.assetsFolder + config.destination.jsFolderName))
            .pipe(gulpif(isServer, browserSync.stream({once: true})))
            .pipe(notify('Successfully compiled JS'));
    };
    if(isServer) {
        bundler.on('update', bundle);
    }
    return bundle();
};<|endoftext|>