<commit_before>import ObjectRenderer from '../../renderers/webgl/utils/ObjectRenderer';
import WebGLRenderer from '../../renderers/webgl/WebGLRenderer';
import createIndicesForQuads from '../../utils/createIndicesForQuads';
import generateMultiTextureShader from './generateMultiTextureShader';
import checkMaxIfStatmentsInShader from '../../renderers/webgl/utils/checkMaxIfStatmentsInShader';
import Buffer from './BatchBuffer';
import settings from '../../settings';
import glCore from 'pixi-gl-core';
import bitTwiddle from 'bit-twiddle';

let TICK = 0;
let TEXTURE_TICK = 0;

/**
 * Renderer dedicated to drawing and batching sprites.
 *
 * @class
 * @private
 * @memberof PIXI
 * @extends PIXI.ObjectRenderer
 */
export default class SpriteRenderer extends ObjectRenderer
{
    /**
     * @param {PIXI.WebGLRenderer} renderer - The renderer this sprite batch works for.
     */
    constructor(renderer)
    {
        super(renderer);

        /**
         * Number of values sent in the vertex buffer.
         * positionX, positionY, colorR, colorG, colorB = 5
         *
         * @member {number}
         */
        this.vertSize = 5;

        /**
         * The size of the vertex information in bytes.
         *
         * @member {number}
         */
        this.vertByteSize = this.vertSize * 4;

        /**
         * The number of images in the SpriteRenderer before it flushes.
         *
         * @member {number}
         */
        this.size = settings.SPRITE_BATCH_SIZE; // 2000 is a nice balance between mobile / desktop

        // the total number of bytes in our batch
        // let numVerts = this.size * 4 * this.vertByteSize;

        this.buffers = [];
        for (let i = 1; i <= bitTwiddle.nextPow2(this.size); i *= 2)
        {
            this.buffers.push(new Buffer(i * 4 * this.vertByteSize));
        }

        /**
         * Holds the indices of the geometry (quads) to draw
         *
         * @member {Uint16Array}
         */
        this.indices = createIndicesForQuads(this.size);

        /**
         * The default shaders that is used if a sprite doesn't have a more specific one.
         * there is a shader for each number of textures that can be rendererd.
         * These shaders will also be generated on the fly as required.
         * @member {PIXI.Shader[]}
         */
        this.shader = null;

        this.currentIndex = 0;
        TICK = 0;
        this.groups = [];

        for (let k = 0; k < this.size; k++)
        {
            this.groups[k] = { textures: [], textureCount: 0, ids: [], size: 0, start: 0, blend: 0 };
        }

        this.sprites = [];

        this.vertexBuffers = [];
        this.vaos = [];

        this.vaoMax = 2;
        this.vertexCount = 0;

        this.renderer.on('prerender', this.onPrerender, this);
    }

    /**
     * Sets up the renderer context and necessary buffers.
     *
     * @private
     */
    onContextChange()
    {
        const gl = this.renderer.gl;

        // step 1: first check max textures the GPU can handle.
        this.MAX_TEXTURES = Math.min(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), settings.SPRITE_MAX_TEXTURES);

        // step 2: check the maximum number of if statements the shader can have too..
        this.MAX_TEXTURES = checkMaxIfStatmentsInShader(this.MAX_TEXTURES, gl);

        const shader = this.shader = generateMultiTextureShader(gl, this.MAX_TEXTURES);

        // create a couple of buffers
        this.indexBuffer = glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW);

        // we use the second shader as the first one depending on your browser may omit aTextureId
        // as it is not used by the shader so is optimized out.

        this.renderer.bindVao(null);

        for (let i = 0; i < this.vaoMax; i++)
        {
            this.vertexBuffers[i] = glCore.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW);

            /* eslint-disable max-len */

            // build the vao object that will render..
            this.vaos[i] = this.renderer.createVao()
                .addIndex(this.indexBuffer)
                .addAttribute(this.vertexBuffers[i], shader.attributes.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0)
                .addAttribute(this.vertexBuffers[i], shader.attributes.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4)
                .addAttribute(this.vertexBuffers[i], shader.attributes.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4)
                .addAttribute(this.vertexBuffers[i], shader.attributes.aTextureId, gl.FLOAT, false, this.vertByteSize, 4 * 4);

            /* eslint-disable max-len */
        }

        this.vao = this.vaos[0];
        this.currentBlendMode = 99999;

        this.boundTextures = new Array(this.MAX_TEXTURES);
    }

    /**
     * Called before the renderer starts rendering.
     *
     */
    onPrerender()
    {
        this.vertexCount = 0;
    }

    /**
     * Renders the sprite object.
     *
     * @param {PIXI.Sprite} sprite - the sprite to render when using this spritebatch
     */
    render(sprite)
    {
        // TODO set blend modes..
        // check texture..
        if (this.currentIndex >= this.size)
        {
            this.flush();
        }

        // get the uvs for the texture

        // if the uvs have not updated then no point rendering just yet!
        if (!sprite.texture._uvs)
        {
            return;
        }

        // push a texture.
        // increment the batchsize
        this.sprites[this.currentIndex++] = sprite;
    }

    /**
     * Renders the content and empties the current batch.
     *
     */
    flush()
    {
        if (this.currentIndex === 0)
        {
            return;
        }

        const gl = this.renderer.gl;
        const MAX_TEXTURES = this.MAX_TEXTURES;

        const np2 = bitTwiddle.nextPow2(this.currentIndex);
        const log2 = bitTwiddle.log2(np2);
        const buffer = this.buffers[log2];

        const sprites = this.sprites;
        const groups = this.groups;

        const float32View = buffer.float32View;
        const uint32View = buffer.uint32View;

        const boundTextures = this.boundTextures;
        const rendererBoundTextures = this.renderer.boundTextures;
        const touch = this.renderer.textureGC.count;

        let index = 0;
        let nextTexture;
        let currentTexture;
        let groupCount = 1;
        let textureCount = 0;
        let currentGroup = groups[0];
        let vertexData;
        let uvs;
        let blendMode = sprites[0].blendMode;

        currentGroup.textureCount = 0;
        currentGroup.start = 0;
        currentGroup.blend = blendMode;

        TICK++;

        let i;

        // copy textures..
        for (i = 0; i < MAX_TEXTURES; ++i)
        {
            boundTextures[i] = rendererBoundTextures[i];
            boundTextures[i]._virtalBoundId = i;
        }

        for (i = 0; i < this.currentIndex; ++i)
        {
            // upload the sprite elemetns...
            // they have all ready been calculated so we just need to push them into the buffer.
            const sprite = sprites[i];

            nextTexture = sprite._texture.baseTexture;

            if (blendMode !== sprite.blendMode)
            {
                // finish a group..
                blendMode = sprite.blendMode;

                // force the batch to break!
                currentTexture = null;
                textureCount = MAX_TEXTURES;
                TICK++;
            }

            if (currentTexture !== nextTexture)
            {
                currentTexture = nextTexture;

                if (nextTexture._enabled !== TICK)
                {
                    if (textureCount === MAX_TEXTURES)
                    {
                        TICK++;

                        currentGroup.size = i - currentGroup.start;

                        textureCount = 0;

                        currentGroup = groups[groupCount++];
                        currentGroup.blend = blendMode;
                        currentGroup.textureCount = 0;
                        currentGroup.start = i;
                    }

                    nextTexture.touched = touch;

                    if (nextTexture._virtalBoundId === -1)
                    {
                        for (let j = 0; j < MAX_TEXTURES; ++j)
                        {
                            const tIndex = (j + TEXTURE_TICK) % MAX_TEXTURES;

                            const t = boundTextures[tIndex];

                            if (t._enabled !== TICK)
                            {
                                TEXTURE_TICK++;

                                t._virtalBoundId = -1;

                                nextTexture._virtalBoundId = tIndex;

                                boundTextures[tIndex] = nextTexture;
                                break;
                            }
                        }
                    }

                    nextTexture._enabled = TICK;

                    currentGroup.textureCount++;
                    currentGroup.ids[textureCount] = nextTexture._virtalBoundId;
                    currentGroup.textures[textureCount++] = nextTexture;
                }
            }

            vertexData = sprite.vertexData;

            // TODO this sum does not need to be set each frame..
            uvs = sprite._texture._uvs.uvsUint32;

            if (this.renderer.roundPixels)
            {
                const resolution = this.renderer.resolution;

                // xy
                float32View[index] = ((vertexData[0] * resolution) | 0) / resolution;
                float32View[index + 1] = ((vertexData[1] * resolution) | 0) / resolution;

                // xy
                float32View[index + 5] = ((vertexData[2] * resolution) | 0) / resolution;
                float32View[index + 6] = ((vertexData[3] * resolution) | 0) / resolution;

                // xy
                float32View[index + 10] = ((vertexData[4] * resolution) | 0) / resolution;
                float32View[index + 11] = ((vertexData[5] * resolution) | 0) / resolution;

                // xy
                float32View[index + 15] = ((vertexData[6] * resolution) | 0) / resolution;
                float32View[index + 16] = ((vertexData[7] * resolution) | 0) / resolution;
            }
            else
            {
                // xy
                float32View[index] = vertexData[0];
                float32View[index + 1] = vertexData[1];

                // xy
                float32View[index + 5] = vertexData[2];
                float32View[index + 6] = vertexData[3];

                // xy
                float32View[index + 10] = vertexData[4];
                float32View[index + 11] = vertexData[5];

                // xy
                float32View[index + 15] = vertexData[6];
                float32View[index + 16] = vertexData[7];
            }

            uint32View[index + 2] = uvs[0];
            uint32View[index + 7] = uvs[1];
            uint32View[index + 12] = uvs[2];
            uint32View[index + 17] = uvs[3];

            uint32View[index + 3] = uint32View[index + 8] = uint32View[index + 13] = uint32View[index + 18] = sprite._tintRGB + (sprite.worldAlpha * 255 << 24);

            float32View[index + 4] = float32View[index + 9] = float32View[index + 14] = float32View[index + 19] = nextTexture._virtalBoundId;

            index += 20;
        }

        currentGroup.size = i - currentGroup.start;

        if (!settings.CAN_UPLOAD_SAME_BUFFER)
        {
            // this is still needed for IOS performance..
            // it really does not like uploading to  the same buffer in a single frame!
            if (this.vaoMax <= this.vertexCount)
            {
                this.vaoMax++;
                this.vertexBuffers[this.vertexCount] = glCore.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW);

                // build the vao object that will render..
                this.vaos[this.vertexCount] = this.renderer.createVao()
                    .addIndex(this.indexBuffer)
                    .addAttribute(this.vertexBuffers[this.vertexCount], this.shader.attributes.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0)
                    .addAttribute(this.vertexBuffers[this.vertexCount], this.shader.attributes.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4)
                    .addAttribute(this.vertexBuffers[this.vertexCount], this.shader.attributes.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4)
                    .addAttribute(this.vertexBuffers[this.vertexCount], this.shader.attributes.aTextureId, gl.FLOAT, false, this.vertByteSize, 4 * 4);
            }

            this.renderer.bindVao(this.vaos[this.vertexCount]);

            this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0, false);

            this.vertexCount++;
        }
        else
        {
            // lets use the faster option, always use buffer number 0
            this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0, true);
        }

        for (i = 0; i < MAX_TEXTURES; ++i)
        {
            rendererBoundTextures[i]._virtalBoundId = -1;
        }

        // render the groups..
        for (i = 0; i < groupCount; ++i)
        {
            const group = groups[i];
            const groupTextureCount = group.textureCount;

            for (let j = 0; j < groupTextureCount; j++)
            {
                currentTexture = group.textures[j];

                // reset virtual ids..
                // lets do a quick check..
                if (rendererBoundTextures[group.ids[j]] !== currentTexture)
                {
                    this.renderer.bindTexture(currentTexture, group.ids[j], true);
                }

                // reset the virtualId..
                currentTexture._virtalBoundId = -1;
            }

            // set the blend mode..
            this.renderer.state.setBlendMode(group.blend);

            gl.drawElements(gl.TRIANGLES, group.size * 6, gl.UNSIGNED_SHORT, group.start * 6 * 2);
        }

        // reset elements for the next flush
        this.currentIndex = 0;
    }

    /**
     * Starts a new sprite batch.
     */
    start()
    {
        this.renderer.bindShader(this.shader);

        if (settings.CAN_UPLOAD_SAME_BUFFER)
        {
            // bind buffer #0, we don't need others
            this.renderer.bindVao(this.vaos[this.vertexCount]);

            this.vertexBuffers[this.vertexCount].bind();
        }
    }

    /**
     * Stops and flushes the current batch.
     *
     */
    stop()
    {
        this.flush();
    }

    /**
     * Destroys the SpriteRenderer.
     *
     */
    destroy()
    {
        for (let i = 0; i < this.vaoMax; i++)
        {
            if (this.vertexBuffers[i])
            {
                this.vertexBuffers[i].destroy();
            }
            if (this.vaos[i])
            {
                this.vaos[i].destroy();
            }
        }

        if (this.indexBuffer)
        {
            this.indexBuffer.destroy();
        }

        this.renderer.off('prerender', this.onPrerender, this);

        super.destroy();

        if (this.shader)
        {
            this.shader.destroy();
            this.shader = null;
        }

        this.vertexBuffers = null;
        this.vaos = null;
        this.indexBuffer = null;
        this.indices = null;

        this.sprites = null;

        for (let i = 0; i < this.buffers.length; ++i)
        {
            this.buffers[i].destroy();
        }
    }
}

WebGLRenderer.registerPlugin('sprite', SpriteRenderer);
<commit_msg>Remove a needless space in annotation (#3497)<commit_after>import ObjectRenderer from '../../renderers/webgl/utils/ObjectRenderer';
import WebGLRenderer from '../../renderers/webgl/WebGLRenderer';
import createIndicesForQuads from '../../utils/createIndicesForQuads';
import generateMultiTextureShader from './generateMultiTextureShader';
import checkMaxIfStatmentsInShader from '../../renderers/webgl/utils/checkMaxIfStatmentsInShader';
import Buffer from './BatchBuffer';
import settings from '../../settings';
import glCore from 'pixi-gl-core';
import bitTwiddle from 'bit-twiddle';

let TICK = 0;
let TEXTURE_TICK = 0;

/**
 * Renderer dedicated to drawing and batching sprites.
 *
 * @class
 * @private
 * @memberof PIXI
 * @extends PIXI.ObjectRenderer
 */
export default class SpriteRenderer extends ObjectRenderer
{
    /**
     * @param {PIXI.WebGLRenderer} renderer - The renderer this sprite batch works for.
     */
    constructor(renderer)
    {
        super(renderer);

        /**
         * Number of values sent in the vertex buffer.
         * positionX, positionY, colorR, colorG, colorB = 5
         *
         * @member {number}
         */
        this.vertSize = 5;

        /**
         * The size of the vertex information in bytes.
         *
         * @member {number}
         */
        this.vertByteSize = this.vertSize * 4;

        /**
         * The number of images in the SpriteRenderer before it flushes.
         *
         * @member {number}
         */
        this.size = settings.SPRITE_BATCH_SIZE; // 2000 is a nice balance between mobile / desktop

        // the total number of bytes in our batch
        // let numVerts = this.size * 4 * this.vertByteSize;

        this.buffers = [];
        for (let i = 1; i <= bitTwiddle.nextPow2(this.size); i *= 2)
        {
            this.buffers.push(new Buffer(i * 4 * this.vertByteSize));
        }

        /**
         * Holds the indices of the geometry (quads) to draw
         *
         * @member {Uint16Array}
         */
        this.indices = createIndicesForQuads(this.size);

        /**
         * The default shaders that is used if a sprite doesn't have a more specific one.
         * there is a shader for each number of textures that can be rendererd.
         * These shaders will also be generated on the fly as required.
         * @member {PIXI.Shader[]}
         */
        this.shader = null;

        this.currentIndex = 0;
        TICK = 0;
        this.groups = [];

        for (let k = 0; k < this.size; k++)
        {
            this.groups[k] = { textures: [], textureCount: 0, ids: [], size: 0, start: 0, blend: 0 };
        }

        this.sprites = [];

        this.vertexBuffers = [];
        this.vaos = [];

        this.vaoMax = 2;
        this.vertexCount = 0;

        this.renderer.on('prerender', this.onPrerender, this);
    }

    /**
     * Sets up the renderer context and necessary buffers.
     *
     * @private
     */
    onContextChange()
    {
        const gl = this.renderer.gl;

        // step 1: first check max textures the GPU can handle.
        this.MAX_TEXTURES = Math.min(gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), settings.SPRITE_MAX_TEXTURES);

        // step 2: check the maximum number of if statements the shader can have too..
        this.MAX_TEXTURES = checkMaxIfStatmentsInShader(this.MAX_TEXTURES, gl);

        const shader = this.shader = generateMultiTextureShader(gl, this.MAX_TEXTURES);

        // create a couple of buffers
        this.indexBuffer = glCore.GLBuffer.createIndexBuffer(gl, this.indices, gl.STATIC_DRAW);

        // we use the second shader as the first one depending on your browser may omit aTextureId
        // as it is not used by the shader so is optimized out.

        this.renderer.bindVao(null);

        for (let i = 0; i < this.vaoMax; i++)
        {
            this.vertexBuffers[i] = glCore.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW);

            /* eslint-disable max-len */

            // build the vao object that will render..
            this.vaos[i] = this.renderer.createVao()
                .addIndex(this.indexBuffer)
                .addAttribute(this.vertexBuffers[i], shader.attributes.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0)
                .addAttribute(this.vertexBuffers[i], shader.attributes.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4)
                .addAttribute(this.vertexBuffers[i], shader.attributes.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4)
                .addAttribute(this.vertexBuffers[i], shader.attributes.aTextureId, gl.FLOAT, false, this.vertByteSize, 4 * 4);

            /* eslint-disable max-len */
        }

        this.vao = this.vaos[0];
        this.currentBlendMode = 99999;

        this.boundTextures = new Array(this.MAX_TEXTURES);
    }

    /**
     * Called before the renderer starts rendering.
     *
     */
    onPrerender()
    {
        this.vertexCount = 0;
    }

    /**
     * Renders the sprite object.
     *
     * @param {PIXI.Sprite} sprite - the sprite to render when using this spritebatch
     */
    render(sprite)
    {
        // TODO set blend modes..
        // check texture..
        if (this.currentIndex >= this.size)
        {
            this.flush();
        }

        // get the uvs for the texture

        // if the uvs have not updated then no point rendering just yet!
        if (!sprite.texture._uvs)
        {
            return;
        }

        // push a texture.
        // increment the batchsize
        this.sprites[this.currentIndex++] = sprite;
    }

    /**
     * Renders the content and empties the current batch.
     *
     */
    flush()
    {
        if (this.currentIndex === 0)
        {
            return;
        }

        const gl = this.renderer.gl;
        const MAX_TEXTURES = this.MAX_TEXTURES;

        const np2 = bitTwiddle.nextPow2(this.currentIndex);
        const log2 = bitTwiddle.log2(np2);
        const buffer = this.buffers[log2];

        const sprites = this.sprites;
        const groups = this.groups;

        const float32View = buffer.float32View;
        const uint32View = buffer.uint32View;

        const boundTextures = this.boundTextures;
        const rendererBoundTextures = this.renderer.boundTextures;
        const touch = this.renderer.textureGC.count;

        let index = 0;
        let nextTexture;
        let currentTexture;
        let groupCount = 1;
        let textureCount = 0;
        let currentGroup = groups[0];
        let vertexData;
        let uvs;
        let blendMode = sprites[0].blendMode;

        currentGroup.textureCount = 0;
        currentGroup.start = 0;
        currentGroup.blend = blendMode;

        TICK++;

        let i;

        // copy textures..
        for (i = 0; i < MAX_TEXTURES; ++i)
        {
            boundTextures[i] = rendererBoundTextures[i];
            boundTextures[i]._virtalBoundId = i;
        }

        for (i = 0; i < this.currentIndex; ++i)
        {
            // upload the sprite elemetns...
            // they have all ready been calculated so we just need to push them into the buffer.
            const sprite = sprites[i];

            nextTexture = sprite._texture.baseTexture;

            if (blendMode !== sprite.blendMode)
            {
                // finish a group..
                blendMode = sprite.blendMode;

                // force the batch to break!
                currentTexture = null;
                textureCount = MAX_TEXTURES;
                TICK++;
            }

            if (currentTexture !== nextTexture)
            {
                currentTexture = nextTexture;

                if (nextTexture._enabled !== TICK)
                {
                    if (textureCount === MAX_TEXTURES)
                    {
                        TICK++;

                        currentGroup.size = i - currentGroup.start;

                        textureCount = 0;

                        currentGroup = groups[groupCount++];
                        currentGroup.blend = blendMode;
                        currentGroup.textureCount = 0;
                        currentGroup.start = i;
                    }

                    nextTexture.touched = touch;

                    if (nextTexture._virtalBoundId === -1)
                    {
                        for (let j = 0; j < MAX_TEXTURES; ++j)
                        {
                            const tIndex = (j + TEXTURE_TICK) % MAX_TEXTURES;

                            const t = boundTextures[tIndex];

                            if (t._enabled !== TICK)
                            {
                                TEXTURE_TICK++;

                                t._virtalBoundId = -1;

                                nextTexture._virtalBoundId = tIndex;

                                boundTextures[tIndex] = nextTexture;
                                break;
                            }
                        }
                    }

                    nextTexture._enabled = TICK;

                    currentGroup.textureCount++;
                    currentGroup.ids[textureCount] = nextTexture._virtalBoundId;
                    currentGroup.textures[textureCount++] = nextTexture;
                }
            }

            vertexData = sprite.vertexData;

            // TODO this sum does not need to be set each frame..
            uvs = sprite._texture._uvs.uvsUint32;

            if (this.renderer.roundPixels)
            {
                const resolution = this.renderer.resolution;

                // xy
                float32View[index] = ((vertexData[0] * resolution) | 0) / resolution;
                float32View[index + 1] = ((vertexData[1] * resolution) | 0) / resolution;

                // xy
                float32View[index + 5] = ((vertexData[2] * resolution) | 0) / resolution;
                float32View[index + 6] = ((vertexData[3] * resolution) | 0) / resolution;

                // xy
                float32View[index + 10] = ((vertexData[4] * resolution) | 0) / resolution;
                float32View[index + 11] = ((vertexData[5] * resolution) | 0) / resolution;

                // xy
                float32View[index + 15] = ((vertexData[6] * resolution) | 0) / resolution;
                float32View[index + 16] = ((vertexData[7] * resolution) | 0) / resolution;
            }
            else
            {
                // xy
                float32View[index] = vertexData[0];
                float32View[index + 1] = vertexData[1];

                // xy
                float32View[index + 5] = vertexData[2];
                float32View[index + 6] = vertexData[3];

                // xy
                float32View[index + 10] = vertexData[4];
                float32View[index + 11] = vertexData[5];

                // xy
                float32View[index + 15] = vertexData[6];
                float32View[index + 16] = vertexData[7];
            }

            uint32View[index + 2] = uvs[0];
            uint32View[index + 7] = uvs[1];
            uint32View[index + 12] = uvs[2];
            uint32View[index + 17] = uvs[3];

            uint32View[index + 3] = uint32View[index + 8] = uint32View[index + 13] = uint32View[index + 18] = sprite._tintRGB + (sprite.worldAlpha * 255 << 24);

            float32View[index + 4] = float32View[index + 9] = float32View[index + 14] = float32View[index + 19] = nextTexture._virtalBoundId;

            index += 20;
        }

        currentGroup.size = i - currentGroup.start;

        if (!settings.CAN_UPLOAD_SAME_BUFFER)
        {
            // this is still needed for IOS performance..
            // it really does not like uploading to the same buffer in a single frame!
            if (this.vaoMax <= this.vertexCount)
            {
                this.vaoMax++;
                this.vertexBuffers[this.vertexCount] = glCore.GLBuffer.createVertexBuffer(gl, null, gl.STREAM_DRAW);

                // build the vao object that will render..
                this.vaos[this.vertexCount] = this.renderer.createVao()
                    .addIndex(this.indexBuffer)
                    .addAttribute(this.vertexBuffers[this.vertexCount], this.shader.attributes.aVertexPosition, gl.FLOAT, false, this.vertByteSize, 0)
                    .addAttribute(this.vertexBuffers[this.vertexCount], this.shader.attributes.aTextureCoord, gl.UNSIGNED_SHORT, true, this.vertByteSize, 2 * 4)
                    .addAttribute(this.vertexBuffers[this.vertexCount], this.shader.attributes.aColor, gl.UNSIGNED_BYTE, true, this.vertByteSize, 3 * 4)
                    .addAttribute(this.vertexBuffers[this.vertexCount], this.shader.attributes.aTextureId, gl.FLOAT, false, this.vertByteSize, 4 * 4);
            }

            this.renderer.bindVao(this.vaos[this.vertexCount]);

            this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0, false);

            this.vertexCount++;
        }
        else
        {
            // lets use the faster option, always use buffer number 0
            this.vertexBuffers[this.vertexCount].upload(buffer.vertices, 0, true);
        }

        for (i = 0; i < MAX_TEXTURES; ++i)
        {
            rendererBoundTextures[i]._virtalBoundId = -1;
        }

        // render the groups..
        for (i = 0; i < groupCount; ++i)
        {
            const group = groups[i];
            const groupTextureCount = group.textureCount;

            for (let j = 0; j < groupTextureCount; j++)
            {
                currentTexture = group.textures[j];

                // reset virtual ids..
                // lets do a quick check..
                if (rendererBoundTextures[group.ids[j]] !== currentTexture)
                {
                    this.renderer.bindTexture(currentTexture, group.ids[j], true);
                }

                // reset the virtualId..
                currentTexture._virtalBoundId = -1;
            }

            // set the blend mode..
            this.renderer.state.setBlendMode(group.blend);

            gl.drawElements(gl.TRIANGLES, group.size * 6, gl.UNSIGNED_SHORT, group.start * 6 * 2);
        }

        // reset elements for the next flush
        this.currentIndex = 0;
    }

    /**
     * Starts a new sprite batch.
     */
    start()
    {
        this.renderer.bindShader(this.shader);

        if (settings.CAN_UPLOAD_SAME_BUFFER)
        {
            // bind buffer #0, we don't need others
            this.renderer.bindVao(this.vaos[this.vertexCount]);

            this.vertexBuffers[this.vertexCount].bind();
        }
    }

    /**
     * Stops and flushes the current batch.
     *
     */
    stop()
    {
        this.flush();
    }

    /**
     * Destroys the SpriteRenderer.
     *
     */
    destroy()
    {
        for (let i = 0; i < this.vaoMax; i++)
        {
            if (this.vertexBuffers[i])
            {
                this.vertexBuffers[i].destroy();
            }
            if (this.vaos[i])
            {
                this.vaos[i].destroy();
            }
        }

        if (this.indexBuffer)
        {
            this.indexBuffer.destroy();
        }

        this.renderer.off('prerender', this.onPrerender, this);

        super.destroy();

        if (this.shader)
        {
            this.shader.destroy();
            this.shader = null;
        }

        this.vertexBuffers = null;
        this.vaos = null;
        this.indexBuffer = null;
        this.indices = null;

        this.sprites = null;

        for (let i = 0; i < this.buffers.length; ++i)
        {
            this.buffers[i].destroy();
        }
    }
}

WebGLRenderer.registerPlugin('sprite', SpriteRenderer);
<|endoftext|>


<commit_before>var React    = window.React = require('react'), // assign it to window for react chrome extension
    App = {};

var OfficialPlugin = React.createClass({
    render: function() {
        return (

        );
    }
})

var SupportedPlatforms = React.createClass({
    render: function() {
        var keywords = this.props.keywords;
        var platformsSupported = [];
        // remove windows8 & windows dupe
        if (keywords.indexOf('cordova-windows') > -1 && keywords.indexOf('cordova-windows8') > -1) {
            keywords.splice(keywords.indexOf('cordova-windows8'), 1);
        }
        keywords.forEach(function(keyword) {
            switch (keyword) {
                case 'cordova-firefoxos':
                    platformsSupported.push(
FirefoxOS
);
                    break;
                case 'cordova-android':
                    platformsSupported.push(
Android
);
                    break;
                case 'cordova-amazon-fireos':
                    platformsSupported.push(
FireOS
);
                    break;
                case 'cordova-ubuntu':
                    platformsSupported.push(
Ubuntu
);
                    break;
                case 'cordova-ios':
                    platformsSupported.push(
iOS
);
                    break;
                case 'cordova-blackberry10':
                    platformsSupported.push(
Blackberry10
);
                    break;
                case 'cordova-wp7':
                    platformsSupported.push(
Windows Phone 7
);
                    break;
                case 'cordova-wp8':
                    platformsSupported.push(
Windows Phone 8
);
                    break;
                case 'cordova-windows8':
                case 'cordova-windows':
                    platformsSupported.push(
Windows
);
                    break;
                case 'cordova-browser':
                    platformsSupported.push(
Browser
);
                    break;
            }
        });
        return (

{platformsSupported}

        );
    }
})

var SearchBar = React.createClass({
    handleChange: function() {
        this.props.onUserInput(
            this.refs.filterTextInput.getDOMNode().value
        )
    },
    render: function() {
        return (

                    <input
                        className="searchBox"
                        type="search"
                        autoComplete="off"
                        placeholder={this.props.placeHolderText}
                        value={this.props.filterText}
                        ref="filterTextInput"
                        onChange={this.handleChange}
                    />

        );
    }
})

var Plugin = React.createClass({
    render: function() {
        var license = this.props.plugin.license;
        if (license && license.length > 1) {
            license = license[0];
        }
        var officialPlugin = this.props.plugin.isOfficial;
        return (

                    {officialPlugin ? <OfficialPlugin/> : ''}

{this.props.plugin.name} by {this.props.plugin.author} (last updated {this.props.plugin.modified} days ago)

{this.props.plugin.description}

                            <SupportedPlatforms keywords={this.props.plugin.keywords}/>

License: {license}

Version: {this.props.plugin.version}

        )
    }
})

var PluginList = React.createClass({
    render: function() {
        var plugins = [],
            filterText = this.props.filterText.toLowerCase();

        this.props.plugins.forEach(function(plugin) {
            if (plugin.name[0].indexOf(filterText) > -1) {
                plugins.push(<Plugin plugin={plugin} key={plugin.author + plugin.name}/>);
            }
        }.bind(this));
        return (

                    {plugins}

        );
    }
});

var App = React.createClass({
    getInitialState: function() {
        return {
            plugins: [],
            filterText: '',
            placeHolderText: 'Loading...'
        };
    },
    handleUserInput: function(filterText) {
        this.setState({
            filterText: filterText
        });
    },

    componentDidMount: function() {
        var plugins = [],
            officialPlugins = require('./official-plugins.json').plugins,
            pluginCount = 0,
            self = this,
            queryHost = "http://npmsearch.com/query",
            queryFields = "fields=name,keywords,license,description,author,modified,homepage,version",
            queryKeywords = "q=keywords:%22ecosystem:cordova%22",
            queryInitialSize = 300;

        xhrRequest(queryHost + "?" + queryFields + "&" + queryKeywords + "&size=" + queryInitialSize + "&start=0", function(xhrResult) {
            plugins = xhrResult.results;
            pluginCount = xhrResult.total;
            if (pluginCount <= queryInitialSize) {
                processPlugins.bind(self, officialPlugins, plugins)();
            } else {
                xhrRequest(queryHost + "?" + queryFields + "&" + queryKeywords + "&size=" + (pluginCount - queryInitialSize) + "&start=" + queryInitialSize, function(xhrResult) {
                        plugins = [].concat(plugins, xhrResult.results);
                        processPlugins.bind(self, officialPlugins, plugins)();
                }, function() { console.log('xhr err'); });
            }
        }, function() { console.log('xhr err'); });

        function processPlugins(officialPlugins, plugins) {
            var pluginCount = plugins.length,
                dateNow = new Date(),
                oneDay = 1000*60*60*24;

            officialPlugins.forEach(function(plugin) {
                for (var i = 0; i < plugins.length; i++) {
                    // Check if plugin name is in official list
                    if (plugins[i].name[0] === plugin) {
                        plugins[i].isOfficial = true;
                        return;
                    }
                };
            });

            for (var i = 0; i < plugins.length; i++) {
                // Calculate last time plugin is modified (in days)
                plugins[i].modified = Math.ceil((dateNow - new Date(plugins[i].modified)) / oneDay);
            };

            if (this.isMounted()) {
                this.setState({
                  plugins: plugins,
                  placeHolderText: 'Search ' + pluginCount + ' plugins...'
                });
            }
        }
    },

    render: function() {
        return (

Search Cordova

Plugins

                    <SearchBar
                        filterText={this.state.filterText}
                        placeHolderText={this.state.placeHolderText}
                        onUserInput={this.handleUserInput}
                    />

                    <PluginList
                        plugins={this.state.plugins}
                        filterText={this.state.filterText}
                    />

        );
    }
});

App.start = function() {
    React.render(
        <App />,
        document.getElementById('container')
    )
};

function xhrRequest(url, success, fail) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == XMLHttpRequest.DONE ) {
            if(xhr.status == 200){
                success(JSON.parse(xhr.responseText));
                return;
            } else {
                fail();
                return;
            }
        }
    }.bind(this)
    xhr.open("GET", url, true);
    xhr.send();
}

module.exports = window.App = App;
<commit_msg>CB-9165 Adding download count for plugin list<commit_after>var React    = window.React = require('react'), // assign it to window for react chrome extension
    App = {};

var OfficialPlugin = React.createClass({
    render: function() {
        return (

        );
    }
})

var SupportedPlatforms = React.createClass({
    render: function() {
        var keywords = this.props.keywords;
        var platformsSupported = [];
        // remove windows8 & windows dupe
        if (keywords.indexOf('cordova-windows') > -1 && keywords.indexOf('cordova-windows8') > -1) {
            keywords.splice(keywords.indexOf('cordova-windows8'), 1);
        }
        keywords.forEach(function(keyword) {
            switch (keyword) {
                case 'cordova-firefoxos':
                    platformsSupported.push(
FirefoxOS
);
                    break;
                case 'cordova-android':
                    platformsSupported.push(
Android
);
                    break;
                case 'cordova-amazon-fireos':
                    platformsSupported.push(
FireOS
);
                    break;
                case 'cordova-ubuntu':
                    platformsSupported.push(
Ubuntu
);
                    break;
                case 'cordova-ios':
                    platformsSupported.push(
iOS
);
                    break;
                case 'cordova-blackberry10':
                    platformsSupported.push(
Blackberry10
);
                    break;
                case 'cordova-wp7':
                    platformsSupported.push(
Windows Phone 7
);
                    break;
                case 'cordova-wp8':
                    platformsSupported.push(
Windows Phone 8
);
                    break;
                case 'cordova-windows8':
                case 'cordova-windows':
                    platformsSupported.push(
Windows
);
                    break;
                case 'cordova-browser':
                    platformsSupported.push(
Browser
);
                    break;
            }
        });
        return (

{platformsSupported}

        );
    }
})

var SearchBar = React.createClass({
    handleChange: function() {
        this.props.onUserInput(
            this.refs.filterTextInput.getDOMNode().value
        )
    },
    render: function() {
        return (

                    <input
                        className="searchBox"
                        type="search"
                        autoComplete="off"
                        placeholder={this.props.placeHolderText}
                        value={this.props.filterText}
                        ref="filterTextInput"
                        onChange={this.handleChange}
                    />

        );
    }
})

var Plugin = React.createClass({
    render: function() {
        var license = this.props.plugin.license;
        if (license && license.length > 1) {
            license = license[0];
        }
        var officialPlugin = this.props.plugin.isOfficial;
        var downloadField;
        if(this.props.plugin.downloadCount)
            downloadField =
 {this.props.plugin.downloadCount} downloads last month
;
        return (

                    {officialPlugin ? <OfficialPlugin/> : ''}

{this.props.plugin.name} by {this.props.plugin.author} (last updated {this.props.plugin.modified} days ago)

{this.props.plugin.description}

                            <SupportedPlatforms keywords={this.props.plugin.keywords}/>

                                {downloadField}

License: {license}

Version: {this.props.plugin.version}

        )
    }
})

var PluginList = React.createClass({
    render: function() {
        var plugins = [],
            filterText = this.props.filterText.toLowerCase();

        this.props.plugins.forEach(function(plugin) {
            if (plugin.name[0].indexOf(filterText) > -1) {
                plugins.push(<Plugin plugin={plugin} key={plugin.author + plugin.name}/>);
            }
        }.bind(this));
        return (

                    {plugins}

        );
    }
});

var App = React.createClass({
    getInitialState: function() {
        return {
            plugins: [],
            filterText: '',
            placeHolderText: 'Loading...'
        };
    },
    handleUserInput: function(filterText) {
        this.setState({
            filterText: filterText
        });
    },

    componentDidMount: function() {
        var plugins = [],
            officialPlugins = require('./official-plugins.json').plugins,
            pluginCount = 0,
            self = this,
            queryHost = "http://npmsearch.com/query",
            queryFields = "fields=name,keywords,license,description,author,modified,homepage,version",
            queryKeywords = "q=keywords:%22ecosystem:cordova%22",
            queryInitialSize = 300;

        xhrRequest(queryHost + "?" + queryFields + "&" + queryKeywords + "&size=" + queryInitialSize + "&start=0", function(xhrResult) {
            plugins = xhrResult.results;
            pluginCount = xhrResult.total;
            if (pluginCount <= queryInitialSize) {
                processPlugins.bind(self, officialPlugins, plugins)();
            } else {
                xhrRequest(queryHost + "?" + queryFields + "&" + queryKeywords + "&size=" + (pluginCount - queryInitialSize) + "&start=" + queryInitialSize, function(xhrResult) {
                        plugins = [].concat(plugins, xhrResult.results);
                        processPlugins.bind(self, officialPlugins, plugins)();
                }, function() { console.log('xhr err'); });
            }
        }, function() { console.log('xhr err'); });

        var getDownloadCount = function(plugins,that) {
            var packageNames = "";
            for(var index=0; index < plugins.length; index++)
            {
                packageNames += plugins[index].name + ",";
                if(index%50 === 0 || index === plugins.length -1)
                {
                    xhrRequest("https://api.npmjs.org/downloads/point/last-month/" + packageNames, function(xhrResult) {
                        plugins.forEach(function(plugin) {
                            if(xhrResult[plugin.name])
                                plugin.downloadCount = xhrResult[plugin.name].downloads;
                        });
                        that.setState({
                            plugins: plugins
                        });
                    }.bind(self), function() { console.log('xhr err'); });
                    packageNames = "";
                }
            }
        }

        function processPlugins(officialPlugins, plugins) {
            var pluginCount = plugins.length,
                dateNow = new Date(),
                oneDay = 1000*60*60*24;

            officialPlugins.forEach(function(plugin) {
                for (var i = 0; i < plugins.length; i++) {
                    // Check if plugin name is in official list
                    if (plugins[i].name[0] === plugin) {
                        plugins[i].isOfficial = true;
                        return;
                    }
                };
            });

            for (var i = 0; i < plugins.length; i++) {
                // Calculate last time plugin is modified (in days)
                plugins[i].modified = Math.ceil((dateNow - new Date(plugins[i].modified)) / oneDay);
            };

            if (this.isMounted()) {
                this.setState({
                  plugins: plugins,
                  placeHolderText: 'Search ' + pluginCount + ' plugins...'
                });
                getDownloadCount(plugins,this);
            }
        }
    },

    render: function() {
        return (

Search Cordova

Plugins

                    <SearchBar
                        filterText={this.state.filterText}
                        placeHolderText={this.state.placeHolderText}
                        onUserInput={this.handleUserInput}
                    />

                    <PluginList
                        plugins={this.state.plugins}
                        filterText={this.state.filterText}
                    />

        );
    }
});

App.start = function() {
    React.render(
        <App />,
        document.getElementById('container')
    )
};

function xhrRequest(url, success, fail) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == XMLHttpRequest.DONE ) {
            if(xhr.status == 200){
                success(JSON.parse(xhr.responseText));
                return;
            } else {
                fail();
                return;
            }
        }
    }.bind(this)
    xhr.open("GET", url, true);
    xhr.send();
}

module.exports = window.App = App;
<|endoftext|>


<commit_before>module.exports = (core, adapter) => {
  const coreconfig = core.config(core.path.join(__dirname, 'defaults.json'))

  return config => {
    const userconfig = adapter && core.exists(adapter.configfile) ? core.config(adapter.configfile) : {}
    const defaults = core.merge({}, coreconfig, userconfig)

    const common = core.merge({}, defaults.common, config.common)
    const options = core.merge({}, defaults.options, config.options)
    const names = core.merge({}, defaults.options.overrides.names, options.overrides.names)

    const configuration = {
      common: common,
      options: options,

      builds: {},
      deployments: {},
      packages: {},
      watches: {}
    }

    const destination = dest => {
      if (!dest) return common.dest
      if (typeof dest === 'function') return dest()
      if (typeof dest === 'string' && common.desinations[dest]) return common.destinations[dest]
      return dest
    }

    const source = src => {
      if (!src) return []
      if (typeof src === 'function') return src()
      if (typeof src === 'string' && common.sources[src]) return common.sources[src]
      return src
    }

    const task = (key, value) => {
      const name = core.taskname(names.build, key)
      const conf = configuration.builds[key] = {
        build: value.build || value,
        name: name,
        source: core.array(source(key) || source(value.src)),
        target: destination(value.dest)
      }
      return conf
    }

    const watch = (key, value) => {
      const name = core.taskname(names.watch, key)
      const conf = configuration.watches[key] = {
        name: name,
        source: core.array(source(key) || source(value.src)),
        target: destination(value.dest)
      }
      return conf
    }

    const definitions = Object.keys(config).filter(key => ['common', 'options'].indexOf(key) < 0)
    definitions.map(key => task(key, config[key]))
    definitions.map(key => watch(key, config[key]))

    return configuration
  }
}
<commit_msg>adding plugins to ignore<commit_after>module.exports = (core, adapter) => {
  const coreconfig = core.config(core.path.join(__dirname, 'defaults.json'))

  return config => {
    const userconfig = adapter && core.exists(adapter.configfile) ? core.config(adapter.configfile) : {}
    const defaults = core.merge({}, coreconfig, userconfig)

    const common = core.merge({}, defaults.common, config.common)
    const options = core.merge({}, defaults.options, config.options)
    const names = core.merge({}, defaults.options.overrides.names, options.overrides.names)

    const configuration = {
      common: common,
      options: options,

      builds: {},
      deployments: {},
      packages: {},
      watches: {}
    }

    const destination = dest => {
      if (!dest) return common.dest
      if (typeof dest === 'function') return dest()
      if (typeof dest === 'string' && common.desinations[dest]) return common.destinations[dest]
      return dest
    }

    const source = src => {
      if (!src) return []
      if (typeof src === 'function') return src()
      if (typeof src === 'string' && common.sources[src]) return common.sources[src]
      return src
    }

    const task = (key, value) => {
      const name = core.taskname(names.build, key)
      const conf = configuration.builds[key] = {
        build: value.build || value,
        name: name,
        source: core.array(source(key) || source(value.src)),
        target: destination(value.dest)
      }
      return conf
    }

    const watch = (key, value) => {
      const name = core.taskname(names.watch, key)
      const conf = configuration.watches[key] = {
        name: name,
        source: core.array(source(key) || source(value.src)),
        target: destination(value.dest)
      }
      return conf
    }

    const definitions = Object.keys(config).filter(key => ['common', 'options', 'plugins'].indexOf(key) < 0)
    definitions.map(key => task(key, config[key]))
    definitions.map(key => watch(key, config[key]))

    return configuration
  }
}
<|endoftext|>


<commit_before>/**
 * The following tests are designed to run against a live redis-server instance.
 */

var expect    = require('expect.js');
var Promise   = require('bluebird');
var client    = require('redis').createClient();
var redislock = require('../../lib/redislock');

var LockAcquisitionError = redislock.LockAcquisitionError;
var LockReleaseError     = redislock.LockReleaseError;

Promise.promisifyAll(client);

describe('lock', function() {
  var lock;
  var key = 'integration:test';

  beforeEach(function() {
    lock = redislock.createLock(client);
  });

  afterEach(function(done) {
    client.del(key, done);
  });

  it('can be used multiple times', function(done) {
    lock.acquire(key)
    .then(function() {
      return lock.release();
    })
    .then(function() {
      return lock.acquire(key);
    })
    .then(function() {
      return client.getAsync(key);
    })
    .then(function(res) {
      expect(res).to.be(lock._id);
      done();
    })
    .catch(done);
  });

  describe('acquire', function() {
    it('sets the key if not held by another lock', function(done) {
      lock.acquire(key)
      .then(function() {
        return client.getAsync(key);
      })
      .then(function(res) {
        expect(res).to.be(lock._id);
        expect(lock._locked).to.be(true);
        expect(lock._key).to.be(key);
        done();
      })
      .catch(done);
    });

    it('throws an error if the key is already in use', function(done) {
      var lock2 = redislock.createLock(client);

      lock.acquire(key)
      .then(function() {
        return lock2.acquire(key);
      })
      .catch(function(err) {
        expect(err).to.be.an(LockAcquisitionError);
        expect(err.message).to.be('Could not acquire lock on "integration:test"');
        expect(lock2._locked).to.be(false);
        expect(lock2._key).to.be(null);
        done();
      });
    });
  });

  describe('release', function() {
    it('deletes the key if held by the current lock', function(done) {
      lock.acquire(key)
      .then(function() {
        return lock.release();
      })
      .then(function() {
        return client.getAsync(key);
      })
      .then(function(res) {
        expect(res).to.be(null);
        expect(lock._locked).to.be(false);
        expect(lock._key).to.be(null);
        done();
      })
      .catch(done);
    });

    it('throws an error if the key no longer belongs to the lock', function(done) {
      lock.acquire(key)
      .then(function() {
        return client.setAsync(key, 'mismatch');
      })
      .then(function() {
        return lock.release();
      })
      .catch(function(err) {
        expect(err).to.be.an(LockReleaseError);
        expect(err.message).to.be('Lock on "integration:test" had expired');
        expect(lock._locked).to.be(false);
        expect(lock._key).to.be(null);
        done();
      });
    });
  });
});
<commit_msg>Cleanup integration tests<commit_after>/**
 * The following tests are designed to run against a live redis-server instance.
 */

var expect    = require('expect.js');
var Promise   = require('bluebird');
var client    = require('redis').createClient();
var redislock = require('../../lib/redislock');

var LockAcquisitionError = redislock.LockAcquisitionError;
var LockReleaseError     = redislock.LockReleaseError;

Promise.promisifyAll(client);

describe('lock', function() {
  var lock;
  var key = 'integration:test';

  beforeEach(function() {
    lock = redislock.createLock(client);
  });

  afterEach(function(done) {
    client.del(key, done);
  });

  it('can be used multiple times', function() {
    return lock.acquire(key).then(function() {
      return lock.release();
    }).then(function() {
      return lock.acquire(key);
    }).then(function() {
      return client.getAsync(key);
    }).then(function(res) {
      expect(res).to.be(lock._id);
    });
  });

  describe('acquire', function() {
    it('sets the key if not held by another lock', function() {
      return lock.acquire(key).then(function() {
        return client.getAsync(key);
      }).then(function(res) {
        expect(res).to.be(lock._id);
        expect(lock._locked).to.be(true);
        expect(lock._key).to.be(key);
      });
    });

    it('throws an error if the key is already in use', function(done) {
      var lock2 = redislock.createLock(client);

      lock.acquire(key).then(function() {
        return lock2.acquire(key);
      }).catch(function(err) {
        expect(err).to.be.an(LockAcquisitionError);
        expect(err.message).to.be('Could not acquire lock on "integration:test"');
        expect(lock2._locked).to.be(false);
        expect(lock2._key).to.be(null);
        done();
      });
    });
  });

  describe('release', function() {
    it('deletes the key if held by the current lock', function() {
      return lock.acquire(key).then(function() {
        return lock.release();
      }).then(function() {
        return client.getAsync(key);
      }).then(function(res) {
        expect(res).to.be(null);
        expect(lock._locked).to.be(false);
        expect(lock._key).to.be(null);
      });
    });

    it('throws an error if the key no longer belongs to the lock', function(done) {
      lock.acquire(key).then(function() {
        return client.setAsync(key, 'mismatch');
      }).then(function() {
        return lock.release();
      }).catch(function(err) {
        expect(err).to.be.an(LockReleaseError);
        expect(err.message).to.be('Lock on "integration:test" had expired');
        expect(lock._locked).to.be(false);
        expect(lock._key).to.be(null);
        done();
      });
    });
  });
});
<|endoftext|>


<commit_before>function doHeaderAndContentsMenu(pageName, relativePath, r, g, b, data) {
    document.write("
");
    document.write("    "+pageName);
    document.write("
");
    document.write("");
    document.write("");
    document.write("");
    document.write("
");
    document.write("
");
    document.write("        ");
    document.write("
");

    for (i = 0; i < data.length; ++i)
        if (data[i].length) {
            // We are dealing with a menu item

            var path = data[i][3]?data[i][2]:relativePath+"/"+data[i][2];
            var indent = "";

            for (j = 0; j < data[i][0]; ++j)
                indent += "    "

            var currentMenuItem = false;

            if (   (data[i][1].toLowerCase() == pageName.toLowerCase())
                || ((pageName == "OpenCOR") && (data[i][1] == "Home")))
                currentMenuItem = true;

            if (i != data.length-1) {
                // A 'normal' menu item

                if (currentMenuItem)
                    document.write("
"+indent+""+data[i][1]+"
");
                else
                    document.write("
"+indent+data[i][1]+"
");
            } else {
                // The last menu item, so we have some special rendering for it

                if (currentMenuItem)
                    document.write("
"+indent+""+data[i][1]+"
");
                else
                    document.write("
"+indent+data[i][1]+"
");
            }
        } else {
            // We are dealing with a menu separator

            document.write("

");
        }

    document.write("
");
    document.write("
");
    document.write("
");
}

$(document).ready(function() {
    $("ul.contentsMenu > li").mouseenter(function() {
        $(this).find('ul').css('visibility', 'visible');
    });

    $("ul.contentsMenu > li").mouseleave(function() {
        $(this).find('ul').css('visibility', 'hidden');
    });
});

function copyright() {
    var date = new Date();

    document.write("
");
    document.write("    Copyright ©2011-"+date.getFullYear());
    document.write("
");
}
<commit_msg>Slight improvement to our documentation CSS menu.<commit_after>function doHeaderAndContentsMenu(pageName, relativePath, r, g, b, data) {
    document.write("
");
    document.write("    "+pageName);
    document.write("
");
    document.write("");
    document.write("");
    document.write("");
    document.write("
");
    document.write("
");
    document.write("        ");
    document.write("
");

    for (i = 0; i < data.length; ++i)
        if (data[i].length) {
            // We are dealing with a menu item

            var path = data[i][3]?data[i][2]:relativePath+"/"+data[i][2];
            var indent = "";

            for (j = 0; j < data[i][0]; ++j)
                indent += "    "

            var currentMenuItem = false;

            if (   (data[i][1].toLowerCase() == pageName.toLowerCase())
                || ((pageName == "OpenCOR") && (data[i][1] == "Home")))
                currentMenuItem = true;

            if (i != data.length-1) {
                // A 'normal' menu item

                if (currentMenuItem)
                    document.write("
"+indent+data[i][1]+"
");
                else
                    document.write("
"+indent+data[i][1]+"
");
            } else {
                // The last menu item, so we have some special rendering for it

                if (currentMenuItem)
                    document.write("
"+indent+data[i][1]+"
");
                else
                    document.write("
"+indent+data[i][1]+"
");
            }
        } else {
            // We are dealing with a menu separator

            document.write("

");
        }

    document.write("
");
    document.write("
");
    document.write("
");
}

$(document).ready(function() {
    $("ul.contentsMenu > li").mouseenter(function() {
        $(this).find('ul').css('visibility', 'visible');
    });

    $("ul.contentsMenu > li").mouseleave(function() {
        $(this).find('ul').css('visibility', 'hidden');
    });
});

function copyright() {
    var date = new Date();

    document.write("
");
    document.write("    Copyright ©2011-"+date.getFullYear());
    document.write("
");
}
<|endoftext|>


<commit_before>it("Should remove duplicate instances of class", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a a a";

	classList.remove("a");
	expect(classList.contains("a")).to.be(false);
	expect(el.className).to.be("");
});
<commit_msg>More classList/DOMTokenList tests<commit_after>
it("Should be able to add a class and returns true when a class is added", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	classList.toggle("classA");
	expect(classList.contains("classA")).to.be(true);
});

it("Should be able to remove a class and return false when a class is removed", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "classA";

	expect(classList.toggle("classA")).to.be(false);
});

it("Should allow classes to be added using #add", function() {
	var el = document.createElement("p");
	var classList = el.classList;

	classList.add("classA");
	expect(classList.contains("classA")).to.be(true);
});

it("Should force add a class using toggle if the second argument is true", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	classList.add("classA");
	classList.toggle("classA", true);
	expect(classList.contains("classA")).to.be(true);
});

it("Should remove duplicate instances of class", function() {
	var el = document.createElement("p");
	var classList = el.classList;
	el.className = "a a a";

	classList.remove("a");
	expect(classList.contains("a")).to.be(false);
	expect(el.className).to.be("");
});
<|endoftext|>


<commit_before>const HeadlessChrome = require('../index')

const browser = new HeadlessChrome({
  headless: false
})
async function navigateWebsite () {
  await browser.init()
  const mainTab = await browser.newTab({
    privateTab: false
  })
  await mainTab.goTo('https://github.com/LucianoGanga/simple-headless-chrome')

  await mainTab.close()
}
navigateWebsite()
<commit_msg>Change some stuff in basicNavigation example<commit_after>const HeadlessChrome = require('../index')

const browser = new HeadlessChrome({
  headless: true
})
async function navigateWebsite () {
  await browser.init()
  const mainTab = await browser.newTab({
    privateTab: false
  })
  await mainTab.goTo('https://github.com/LucianoGanga/simple-headless-chrome')

  await browser.close()
}
navigateWebsite()
<|endoftext|>


<commit_before>
var Sdk = require('./../../../lib/clc-sdk.js');

var vcr = require('nock-vcr-recorder-mocha');
var compute = new Sdk('cloud_user', 'cloud_user_password').computeServices();

var _ = require('underscore');
var assert = require('assert');

vcr.describe('Power operations server operation [UNIT]', function () {
    var DataCenter = compute.DataCenter;

    var timeout = 1000000;

    it('Should power off servers', function (done) {
        this.timeout(timeout);

        compute.servers()
            .powerOff(
            {
                dataCenter: DataCenter.DE_FRANKFURT,
                nameContains: 'web58'
            })
            .then(function (serverRefs) {
                assert.equal(serverRefs != null, true);

                return compute.servers().find(serverRefs);
            })
            .then(function(modifiedServers) {
                _.each(modifiedServers, _.partial(assertThatServerInState, _, "stopped"));
            })
            .then(done);
    });

    it('Should power on servers', function (done) {
        this.timeout(timeout);

        compute.servers()
            .powerOn(
            {
                dataCenter: DataCenter.DE_FRANKFURT,
                nameContains: 'web58'
            })
            .then(function (serverRefs) {
                assert.equal(serverRefs != null, true);

                return compute.servers().find(serverRefs);
            })
            .then(function(modifiedServers) {
                _.each(modifiedServers, _.partial(assertThatServerInState, _, "started"));
            })
            .then(done);
    });

    it('Should pause servers', function (done) {
        this.timeout(timeout);

        compute.servers()
            .pause({
                dataCenter: DataCenter.DE_FRANKFURT,
                nameContains: 'web58'
            })
            .then(function (serverRefs) {
                assert.equal(serverRefs != null, true);

                return compute.servers().find(serverRefs);
            })
            .then(function(modifiedServers) {
                _.each(modifiedServers, _.partial(assertThatServerInState, _, "paused"));
            })
            .then(done);
    });

    function assertThatServerInState(modifiedServer, state) {

        assert.equal(modifiedServer.details.powerState, state);
    }
});<commit_msg>minor code cleaning<commit_after>
var Sdk = require('./../../../lib/clc-sdk.js');

var vcr = require('nock-vcr-recorder-mocha');
var compute = new Sdk('cloud_user', 'cloud_user_password').computeServices();

var _ = require('underscore');
var assert = require('assert');

vcr.describe('Power operations server operation [UNIT]', function () {
    var DataCenter = compute.DataCenter;

    var timeout = 10000;

    it('Should power off servers', function (done) {
        this.timeout(timeout);

        compute.servers()
            .powerOff(
            {
                dataCenter: DataCenter.DE_FRANKFURT,
                nameContains: 'web58'
            })
            .then(function (serverRefs) {
                assert.equal(serverRefs != null, true);

                return compute.servers().find(serverRefs);
            })
            .then(function(modifiedServers) {
                _.each(modifiedServers, _.partial(assertThatServerInState, _, "stopped"));
            })
            .then(done);
    });

    it('Should power on servers', function (done) {
        this.timeout(timeout);

        compute.servers()
            .powerOn(
            {
                dataCenter: DataCenter.DE_FRANKFURT,
                nameContains: 'web58'
            })
            .then(function (serverRefs) {
                assert.equal(serverRefs != null, true);

                return compute.servers().find(serverRefs);
            })
            .then(function(modifiedServers) {
                _.each(modifiedServers, _.partial(assertThatServerInState, _, "started"));
            })
            .then(done);
    });

    it('Should pause servers', function (done) {
        this.timeout(timeout);

        compute.servers()
            .pause({
                dataCenter: DataCenter.DE_FRANKFURT,
                nameContains: 'web58'
            })
            .then(function (serverRefs) {
                assert.equal(serverRefs != null, true);

                return compute.servers().find(serverRefs);
            })
            .then(function(modifiedServers) {
                _.each(modifiedServers, _.partial(assertThatServerInState, _, "paused"));
            })
            .then(done);
    });

    function assertThatServerInState(modifiedServer, state) {

        assert.equal(modifiedServer.details.powerState, state);
    }
});<|endoftext|>


<commit_before>import React from "react";
import run from "../maki-interpreter/interpreter";
import System from "../runtime/System";
import runtime from "../runtime";
import Variable from "./Variable";
import Value from "./Value";
import Command from "./Command";
import { useDropzone } from "react-dropzone";

function readFileAsArrayBuffer(file) {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();
    fileReader.onload = () => {
      resolve(fileReader.result);
    };
    fileReader.onerror = reject;
    fileReader.readAsArrayBuffer(file);
  });
}

function Wrapper() {
  const [maki, setMaki] = React.useState(null);
  const onDrop = React.useCallback(async acceptedFiles => {
    if (acceptedFiles.length !== 1) {
      alert("Only drop one file at a time");
      return;
    }
    const file = acceptedFiles[0];
    const arrayBuffer = await readFileAsArrayBuffer(file);
    setMaki(arrayBuffer);
    // Do something with the files
  }, []);
  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
  return (

      {maki == null ? (
        <>

            Drop a .maki file here to debug

          <input {...getInputProps()} type="file" />
        </>
      ) : (
        <Debugger maki={maki} />
      )}

  );
}

const initialState = {
  variables: [],
  stack: [],
  commands: [],
  commandOffset: 0,
  messages: [],
};

// Given a generator and a handler function, returns a function `next` which,
// when called, will `.next` values off the generator and pass them to `handler`
// until `handler` returns `false`.
function useNextGeneratorValue(gen, handler) {
  return React.useMemo(() => {
    if (gen == null) {
      // TODO: Return null and disable the next button
      return () => {};
    }
    return () => {
      let ret = gen.next();
      while (!ret.done) {
        if (handler(ret.value) === false) {
          return;
        }
        ret = gen.next();
      }
    };
  }, [gen, handler]);
}

function reducer(state, action) {
  switch (action.type) {
    case "STEPPED":
      const { variables, commands, commandOffset, stack } = action;
      return {
        ...state,
        variables,
        commands,
        commandOffset,
        stack,
      };
    case "GOT_MESSAGE":
      return {
        ...state,
        messages: [...state.messages, action.message],
      };
    default:
      throw new Error("Unknown action type");
  }
}

function Debugger({ maki }) {
  const [gen, setGen] = React.useState(null);
  const [breakPoints, setBreakpoints] = React.useState(new Set([]));
  const [paused, setPaused] = React.useState(true);
  const [state, dispatch] = React.useReducer(reducer, initialState);

  const { variables, stack, commands, commandOffset, messages } = state;

  const system = React.useMemo(() => {
    const sys = new System();
    sys.messageBox = function(message, messageTitle, flag, notanymoreId) {
      dispatch({
        type: "GOT_MESSAGE",
        message: { message, messageTitle, flag, notanymoreId },
      });
    };
    return sys;
  }, [dispatch]);

  React.useEffect(() => {
    run({ runtime, data: maki, system, debugHandler: setGen });
  }, []);

  const nextValue = React.useCallback(
    value => {
      const { i, stack, program } = value;
      const { variables, commands } = program;
      dispatch({
        type: "STEPPED",
        variables,
        commands,
        commandOffset: i,
        stack,
      });
      if (paused) {
        return false;
      }
      if (breakPoints.has(i)) {
        setPaused(true);
        return;
      }

      return true;
    },
    [dispatch, paused, breakPoints, setPaused]
  );

  const next = useNextGeneratorValue(gen, nextValue);

  // When we unpause, we should resume
  React.useEffect(() => {
    if (!paused) next();
  }, [paused]);

  React.useEffect(() => {
    function handler(e) {
      switch (e.key) {
        case ";":
          next();
          break;
        default:
        // console.log(e.key);
      }
    }
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  });

  return (

          Messages{" "}

            {
              messages.filter(({ messageTitle }) => messageTitle === "Success")
                .length
            }

          /{messages.length}

            {messages.map(
              ({ message, messageTitle, flag, notanymoreId }, i) => (

                  {i}
                  {message}

                    {messageTitle}

                  {flag}
                  {notanymoreId}

              )
            )}

        <button onClick={next}>Next</button>
        {paused ? (
          <button
            onClick={() => {
              setPaused(false);
            }}
          >
            Play
          </button>
        ) : (
          <button onClick={() => setPaused(true)}>Pause</button>
        )}

Commands

            {commands != null &&
              commands.map((command, i) => (

                    {breakPoints.has(i) ? (
                      <button
                        onClick={() => {
                          const newBreakPoints = new Set(breakPoints);
                          newBreakPoints.delete(i);
                          setBreakpoints(newBreakPoints);
                        }}
                      >
                        Clear
                      </button>
                    ) : (
                      <button
                        onClick={() => {
                          const newBreakPoints = new Set(breakPoints);
                          newBreakPoints.add(i);
                          setBreakpoints(newBreakPoints);
                        }}
                      >
                        Pause
                      </button>
                    )}
                    {i}

                    <Command command={command} variables={variables} />

              ))}

Stack

            {stack != null &&
              stack.map((value, i) => (

                  {i}

                    <Value value={value} />

              ))}

Variables

            {variables != null &&
              variables.map((variable, i) => (

                  {i}

                    <Variable variable={variable} />

              ))}

  );
}

export default Wrapper;
<commit_msg>Move paused into the reducer<commit_after>import React from "react";
import run from "../maki-interpreter/interpreter";
import System from "../runtime/System";
import runtime from "../runtime";
import Variable from "./Variable";
import Value from "./Value";
import Command from "./Command";
import { useDropzone } from "react-dropzone";

function readFileAsArrayBuffer(file) {
  return new Promise((resolve, reject) => {
    const fileReader = new FileReader();
    fileReader.onload = () => {
      resolve(fileReader.result);
    };
    fileReader.onerror = reject;
    fileReader.readAsArrayBuffer(file);
  });
}

function Wrapper() {
  const [maki, setMaki] = React.useState(null);
  const onDrop = React.useCallback(async acceptedFiles => {
    if (acceptedFiles.length !== 1) {
      alert("Only drop one file at a time");
      return;
    }
    const file = acceptedFiles[0];
    const arrayBuffer = await readFileAsArrayBuffer(file);
    setMaki(arrayBuffer);
    // Do something with the files
  }, []);
  const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop });
  return (

      {maki == null ? (
        <>

            Drop a .maki file here to debug

          <input {...getInputProps()} type="file" />
        </>
      ) : (
        <Debugger maki={maki} />
      )}

  );
}

// Given a generator and a handler function, returns a function `next` which,
// when called, will `.next` values off the generator and pass them to `handler`
// until `handler` returns `false`.
function useNextGeneratorValue(gen, handler) {
  return React.useMemo(() => {
    if (gen == null) {
      // TODO: Return null and disable the next button
      return () => {};
    }
    return () => {
      let ret = gen.next();
      while (!ret.done) {
        if (handler(ret.value) === false) {
          return;
        }
        ret = gen.next();
      }
    };
  }, [gen, handler]);
}

const initialState = {
  variables: [],
  stack: [],
  commands: [],
  commandOffset: 0,
  messages: [],
  paused: true,
};

function reducer(state, action) {
  switch (action.type) {
    case "STEPPED":
      const { variables, commands, commandOffset, stack } = action;
      return {
        ...state,
        variables,
        commands,
        commandOffset,
        stack,
      };
    case "GOT_MESSAGE":
      return {
        ...state,
        messages: [...state.messages, action.message],
      };
    case "PAUSE":
      return { ...state, paused: true };
    case "UNPAUSE":
      return { ...state, paused: false };

    default:
      throw new Error("Unknown action type");
  }
}

function Debugger({ maki }) {
  const [gen, setGen] = React.useState(null);
  const [breakPoints, setBreakpoints] = React.useState(new Set([]));
  const [state, dispatch] = React.useReducer(reducer, initialState);

  const { variables, stack, commands, commandOffset, messages, paused } = state;

  const system = React.useMemo(() => {
    const sys = new System();
    sys.messageBox = function(message, messageTitle, flag, notanymoreId) {
      dispatch({
        type: "GOT_MESSAGE",
        message: { message, messageTitle, flag, notanymoreId },
      });
    };
    return sys;
  }, [dispatch]);

  React.useEffect(() => {
    run({ runtime, data: maki, system, debugHandler: setGen });
  }, []);

  const nextValue = React.useCallback(
    value => {
      const { i, stack, program } = value;
      const { variables, commands } = program;
      dispatch({
        type: "STEPPED",
        variables,
        commands,
        commandOffset: i,
        stack,
      });
      if (paused) {
        return false;
      }
      if (breakPoints.has(i)) {
        dispatch({ type: "PAUSE" });
        return;
      }

      return true;
    },
    [dispatch, paused, breakPoints]
  );

  const next = useNextGeneratorValue(gen, nextValue);

  // When we unpause, we should resume
  React.useEffect(() => {
    if (!paused) next();
  }, [paused]);

  React.useEffect(() => {
    function handler(e) {
      switch (e.key) {
        case ";":
          next();
          break;
        default:
        // console.log(e.key);
      }
    }
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  });

  return (

          Messages{" "}

            {
              messages.filter(({ messageTitle }) => messageTitle === "Success")
                .length
            }

          /{messages.length}

            {messages.map(
              ({ message, messageTitle, flag, notanymoreId }, i) => (

                  {i}
                  {message}

                    {messageTitle}

                  {flag}
                  {notanymoreId}

              )
            )}

        <button onClick={next}>Next</button>
        {paused ? (
          <button onClick={() => dispatch({ type: "UNPAUSE" })}>Play</button>
        ) : (
          <button onClick={() => dispatch({ type: "PAUSE" })}>Pause</button>
        )}

Commands

            {commands != null &&
              commands.map((command, i) => (

                    {breakPoints.has(i) ? (
                      <button
                        onClick={() => {
                          const newBreakPoints = new Set(breakPoints);
                          newBreakPoints.delete(i);
                          setBreakpoints(newBreakPoints);
                        }}
                      >
                        Clear
                      </button>
                    ) : (
                      <button
                        onClick={() => {
                          const newBreakPoints = new Set(breakPoints);
                          newBreakPoints.add(i);
                          setBreakpoints(newBreakPoints);
                        }}
                      >
                        Pause
                      </button>
                    )}
                    {i}

                    <Command command={command} variables={variables} />

              ))}

Stack

            {stack != null &&
              stack.map((value, i) => (

                  {i}

                    <Value value={value} />

              ))}

Variables

            {variables != null &&
              variables.map((variable, i) => (

                  {i}

                    <Variable variable={variable} />

              ))}

  );
}

export default Wrapper;
<|endoftext|>


<commit_before>function setupRoutes($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('login', {
            url: '/login',
            template: '<mc-login></mc-login>'
        })
        .state('projects', {
            url: '/projects',
            template: '<mc-projects></mc-projects>'
        })
        .state('user', {
            url: '/user',
            abstract: true,
            template: '

'
        })
        .state('user.apikey', {
            url: '/apikey',
            template: '<mc-user-apikey></mc-user-apikey>'
        })
        .state('user.password', {
            url: '/password',
            template: '<mc-user-password></mc-user-password>'
        })
        .state('project', {
            url: '/project/:project_id',
            template: '<mc-project></mc-project>',
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }],

                _templates: ["processTemplates", "templates", "_project",
                    function(processTemplates, templates, project) {
                        var projectTemplates = processTemplates.templates(project.process_templates, project.id);
                        templates.set(projectTemplates);
                        return projectTemplates;
                    }]
            }
        })
        .state('project.home', {
            url: '/home',
            template: '<mc-project-home></mc-project-home>'
        })
        .state('project.search', {
            url: '/search/:query',
            template: '<mc-project-search></mc-project-search>'
        })
        .state('project.processes', {
            url: '/processes',
            template: '<mc-project-processes></mc-project-processes>'
        })
        .state('project.processes.create', {
            url: '/create-process/:template_id',
            template: '<mc-process-create></mc-process-create>',
            resolve: {
                _template: ['templates', 'template', '$stateParams', 'projectsService',
                    function(templates, template, $stateParams, projectsService) {
                        if ($stateParams.process_id) {
                            return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                                .then(function(process) {
                                    var t = templates.loadTemplateFromProcess($stateParams.template_id, process);
                                    template.set(t);
                                    return t;
                                });
                        } else {
                            var t = templates.getTemplate($stateParams.template_id);
                            template.set(t);
                            return t;
                        }
                    }]
            }
        })
        .state('project.processes.process', {
            url: '/process/:process_id',
            template: '<mc-process></mc-process>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams',
                    function(process, projectsService, $stateParams) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(p) {
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.processes.edit', {
            url: '/edit/:process_id',
            template: '<mc-process-edit></mc-process-edit>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams', 'processEdit', 'templates',
                    function(process, projectsService, $stateParams, processEdit, templates) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(proc) {
                                var t = templates.getTemplate(proc.process_name);
                                var p = processEdit.fillProcess(t, proc);
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.samples', {
            url: '/samples',
            template: '<mc-project-samples></mc-project-samples>'
        })
        .state('project.samples.sample', {
            url: '/sample/:sample_id',
            template: '<mc-sample></mc-sample>'
        })
        .state('project.files', {
            url: '/files',
            template: '<mc-file-tree></mc-file-tree>'
        })
        .state('project.files.file', {
            url: '/file/:file_id',
            template: '<mc-file></mc-file>'
        })
        .state('project.files.dir', {
            url: '/dir/:dir_id',
            template: '<mc-dir></mc-dir>'
        })
        .state('project.settings', {
            url: '/settings',
            template: '<mc-project-settings></mc-project-settings>'
        });

    $urlRouterProvider.otherwise('/login');
}
<commit_msg>Force update of project in project.home route.<commit_after>function setupRoutes($stateProvider, $urlRouterProvider) {
    $stateProvider
        .state('login', {
            url: '/login',
            template: '<mc-login></mc-login>'
        })
        .state('projects', {
            url: '/projects',
            template: '<mc-projects></mc-projects>'
        })
        .state('user', {
            url: '/user',
            abstract: true,
            template: '

'
        })
        .state('user.apikey', {
            url: '/apikey',
            template: '<mc-user-apikey></mc-user-apikey>'
        })
        .state('user.password', {
            url: '/password',
            template: '<mc-user-password></mc-user-password>'
        })
        .state('project', {
            url: '/project/:project_id',
            template: '<mc-project></mc-project>',
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }],

                _templates: ["processTemplates", "templates", "_project",
                    function(processTemplates, templates, project) {
                        var projectTemplates = processTemplates.templates(project.process_templates, project.id);
                        templates.set(projectTemplates);
                        return projectTemplates;
                    }]
            }
        })
        .state('project.home', {
            url: '/home',
            template: '<mc-project-home></mc-project-home>',
            // hack to update project view
            resolve: {
                // Set the current project in the project service so all components
                // will resolve without having to worry if a promise has resolved.
                // The resolved object is ignored.
                _project: ["$stateParams", "projectsService", "project",
                    // Inject projects so that it resolves before looking up the project.
                    function($stateParams, projectsService, project) {
                        return projectsService.getProject($stateParams.project_id)
                            .then(function(proj) {
                                project.set(proj);
                                return proj;
                            });
                    }]
            }
        })
        .state('project.search', {
            url: '/search/:query',
            template: '<mc-project-search></mc-project-search>'
        })
        .state('project.processes', {
            url: '/processes',
            template: '<mc-project-processes></mc-project-processes>'
        })
        .state('project.processes.create', {
            url: '/create-process/:template_id',
            template: '<mc-process-create></mc-process-create>',
            resolve: {
                _template: ['templates', 'template', '$stateParams', 'projectsService',
                    function(templates, template, $stateParams, projectsService) {
                        if ($stateParams.process_id) {
                            return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                                .then(function(process) {
                                    var t = templates.loadTemplateFromProcess($stateParams.template_id, process);
                                    template.set(t);
                                    return t;
                                });
                        } else {
                            var t = templates.getTemplate($stateParams.template_id);
                            template.set(t);
                            return t;
                        }
                    }]
            }
        })
        .state('project.processes.process', {
            url: '/process/:process_id',
            template: '<mc-process></mc-process>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams',
                    function(process, projectsService, $stateParams) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(p) {
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.processes.edit', {
            url: '/edit/:process_id',
            template: '<mc-process-edit></mc-process-edit>',
            resolve: {
                _process: ['process', 'projectsService', '$stateParams', 'processEdit', 'templates',
                    function(process, projectsService, $stateParams, processEdit, templates) {
                        return projectsService.getProjectProcess($stateParams.project_id, $stateParams.process_id)
                            .then(function(proc) {
                                var t = templates.getTemplate(proc.process_name);
                                var p = processEdit.fillProcess(t, proc);
                                process.set(p);
                                return p;
                            });
                    }]
            }
        })
        .state('project.samples', {
            url: '/samples',
            template: '<mc-project-samples></mc-project-samples>'
        })
        .state('project.samples.sample', {
            url: '/sample/:sample_id',
            template: '<mc-sample></mc-sample>'
        })
        .state('project.files', {
            url: '/files',
            template: '<mc-file-tree></mc-file-tree>'
        })
        .state('project.files.file', {
            url: '/file/:file_id',
            template: '<mc-file></mc-file>'
        })
        .state('project.files.dir', {
            url: '/dir/:dir_id',
            template: '<mc-dir></mc-dir>'
        })
        .state('project.settings', {
            url: '/settings',
            template: '<mc-project-settings></mc-project-settings>'
        });

    $urlRouterProvider.otherwise('/login');
}
<|endoftext|>


<commit_before>import React, { useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/storage";
import DiaryEntry from "./DiaryEntry";

const useStyles = makeStyles({
  diaryPage: {
    width: "100vw",
    maxWidth: 600,
    display: "flex",
    flexDirection: "column",
    overflow: "hidden",
    padding: 30,
  },
});

function DiaryPage(props) {
  const { user } = props;
  const classes = useStyles();
  const [diaryList, setDiaryList] = useState([]);

  useEffect(() => {
    const db = firebase.firestore();
    //TODO: Filter by camera
    db.collection("users").doc(user.uid).collection("events").onSnapshot((snapshot) => {
        const data = [];
        snapshot.forEach((doc) => {
            data.push(doc.data());
        });
        setDiaryList(data);
    }, (err) => {
        console.log(`Err: ${err}`)
    });
  }, [user, setDiaryList]);

  return (

      {diaryList &&
        diaryList.map((row) => (
          <DiaryEntry
            key={row.dateTime}
            {...row}
            userId={user.uid}
          ></DiaryEntry>
        ))}

  );
}

export default DiaryPage;
<commit_msg>sort entries<commit_after>import React, { useEffect, useState } from "react";
import { makeStyles } from "@material-ui/core/styles";
import firebase from "firebase/app";
import "firebase/firestore";
import "firebase/storage";
import DiaryEntry from "./DiaryEntry";

const useStyles = makeStyles({
  diaryPage: {
    width: "100vw",
    maxWidth: 600,
    display: "flex",
    flexDirection: "column",
    overflow: "hidden",
    padding: 30,
  },
});

function DiaryPage(props) {
  const { user } = props;
  const classes = useStyles();
  const [diaryList, setDiaryList] = useState([]);

  useEffect(() => {
    const db = firebase.firestore();
    //TODO: Filter by camera
    db.collection("users").doc(user.uid).collection("events").onSnapshot((snapshot) => {
        let data = [];
        snapshot.forEach((doc) => {
            data.push(doc.data());
        });
        data = data.sort((a, b) => b.dateTime - a.dateTime);
        setDiaryList(data);
    }, (err) => {
        console.log(`Err: ${err}`)
    });
  }, [user, setDiaryList]);

  return (

      {diaryList &&
        diaryList.map((row) => (
          <DiaryEntry
            key={row.dateTime}
            {...row}
            userId={user.uid}
          ></DiaryEntry>
        ))}

  );
}

export default DiaryPage;
<|endoftext|>