<commit_before>(function(window, undefined) {

    function CDocMetaSelection()
    {
        this.Page1 = 0;
        this.Line1 = 0;
        this.Glyph1 = 0;

        this.Page2 = 0;
        this.Line2 = 0;
        this.Glyph2 = 0;

        this.IsSelection = false;
    }

    function CFile()
    {
    	this.nativeFile = 0;
    	this.pages = [];
    	this.zoom = 1;
    	this.isUse3d = false;
    	this.cacheManager = null;
    	this.logging = true;
    	this.Selection = new CDocMetaSelection();
    }

    // interface
    CFile.prototype.loadFromData = function(data) {};
    CFile.prototype.load = function(arrayBuffer)
    {
        return this.loadFromData(new Uint8Array(arrayBuffer));
    };

    CFile.prototype.getInfo = function() {};
    CFile.prototype.getPagePixmap = function(pageIndex, width, height) {};
    CFile.prototype.close = function() {};
    CFile.prototype.memory = function() {};
    CFile.prototype.free = function(pointer) {};

	CFile.prototype.getPage = function(pageIndex, width, height)
	{
		if (pageIndex < 0 || pageIndex >= this.pages.length)
			return null;
		if (!width) width = this.pages[pageIndex].W;
		if (!height) height = this.pages[pageIndex].H;
		var t0 = performance.now();
		var pixels = this.getPagePixmap(pageIndex, width, height);
		if (!pixels)
			return null;

		if (!this.logging)
		{
			var image = this._pixelsToCanvas(pixels, width, height);
		}
		else
		{
			var t1 = performance.now();
			var image = this._pixelsToCanvas(pixels, width, height);
			var t2 = performance.now();
			//console.log("time: " + (t1 - t0) + ", " + (t2 - t1));
		}
        /*
        if (this.pages[pageIndex].Lines)
        {
            var ctx = image.getContext("2d");
            for (let i = 0; i < this.pages[pageIndex].Lines.length; i++)
            {
                for (let j = 0; j < this.pages[pageIndex].Lines[i].Glyphs.length; j++)
                {
                    let glyph = this.pages[pageIndex].Lines[i].Glyphs[j];
                    ctx.font = glyph.fontSize + 'px ' + glyph.fontName;
                    ctx.fillText(glyph.UChar, glyph.X, glyph.Y);
                }
            }
        }
        */
        this.free(pixels);
        return image;
	};

    CFile.prototype.GetNearestPos = function(pageIndex, x, y)
    {
        var _line = -1;
        var _glyph = -1;
        var minDist = Number.MAX_SAFE_INTEGER;

        for (let i = 0; i < this.pages[pageIndex].Lines.length; i++)
        {
            let Y = this.pages[pageIndex].Lines[i].Glyphs[0].Y;
            if (Math.abs(Y - y) < minDist)
            {
                minDist = Math.abs(Y - y);
                _line   = i;
            }
        }
        minDist = Number.MAX_SAFE_INTEGER;
        for (let j = 0; j < this.pages[pageIndex].Lines[_line].Glyphs.length; j++)
        {
            let X = this.pages[pageIndex].Lines[_line].Glyphs[j].X;
            if (Math.abs(X - x) < minDist)
            {
                minDist = Math.abs(X - x);
                _glyph  = j;
            }
        }

        return { Line : _line, Glyph : _glyph };
    }

    CFile.prototype.OnUpdateSelection = function(Selection, width, height)
    {
        if (!this.Selection.IsSelection)
            return;

        var sel = this.Selection;
        var page1  = sel.Page1;
        var page2  = sel.Page2;
        var line1  = sel.Line1;
        var line2  = sel.Line2;
        var glyph1 = sel.Glyph1;
        var glyph2 = sel.Glyph2;
        if (page1 == page2 && line1 == line2 && glyph1 == glyph2)
        {
            Selection.IsSelection = false;
            return;
        }
        else if (page1 == page2 && line1 == line2)
        {
            glyph1 = Math.min(sel.Glyph1, sel.Glyph2);
            glyph2 = Math.max(sel.Glyph1, sel.Glyph2);
        }
        else if (page1 == page2)
        {
            if (line1 > line2)
            {
                line1  = sel.Line2;
                line2  = sel.Line1;
                glyph1 = sel.Glyph2;
                glyph2 = sel.Glyph1;
            }
        }

        if (this.cacheManager)
        {
            this.cacheManager.unlock(Selection.Image);
            Selection.Image = this.cacheManager.lock(width, height);
        }
        else
        {
            delete Selection.Image;
            Selection.Image = document.createElement("canvas");
            Selection.Image.width = width;
            Selection.Image.height = height;
        }
        let ctx = Selection.Image.getContext("2d");
        // TODO: После изменения размера экрана наложение областей выделения
        ctx.clearRect(0, 0, Selection.Image.width, Selection.Image.height);
        ctx.globalAlpha = 0.4;
        ctx.fillStyle = "#7070FF";

        for (let page = page1; page <= page2; page++)
        {
            let start = 0;
            let end   = this.pages[page].Lines.length;
            if (page == page1)
                start = line1;
            if (page == page2)
                end = line2;
            for (let line = start; line <= end; line++)
            {
                let Glyphs = this.pages[page].Lines[line].Glyphs;
                let x = Glyphs[0].X;
                let y = Glyphs[0].Y - Glyphs[0].fontSize;
                // первая строка на первой странице
                if (page == page1 && line == start)
                    x = Glyphs[glyph1].X;
                let w = Glyphs[Glyphs.length - 1].X - x;
                let h = Glyphs[0].fontSize;
                // последняя строка на последней странице
                if (page == page2 && line == end)
                    w = Glyphs[glyph2].X - x;

                ctx.fillRect(x, y, w, h);
            }
        }
        ctx.globalAlpha = 1;
        Selection.IsSelection = true;
    }

	CFile.prototype.OnMouseDown = function(pageIndex, Selection, x, y, w, h)
    {
        var ret = this.GetNearestPos(pageIndex, x, y);

        var sel = this.Selection;
        sel.Page1  = pageIndex;
        sel.Line1  = ret.Line;
        sel.Glyph1 = ret.Glyph;

        sel.Page2  = pageIndex;
        sel.Line2  = ret.Line;
        sel.Glyph2 = ret.Glyph;

        sel.IsSelection = true;
        this.OnUpdateSelection(Selection, w, h);
    }

    CFile.prototype.OnMouseMove = function(pageIndex, Selection, x, y, w, h)
    {
        if (false === this.Selection.IsSelection)
            return;
        var ret = this.GetNearestPos(pageIndex, x, y);

        var sel = this.Selection;
        sel.Page2  = pageIndex;
        sel.Line2  = ret.Line;
        sel.Glyph2 = ret.Glyph;

        this.OnUpdateSelection(Selection, w, h);
    }

    CFile.prototype.OnMouseUp = function()
    {
        this.Selection.IsSelection = false;
    }

    CFile.prototype.getPageBase64 = function(pageIndex, width, height)
	{
		var _canvas = this.getPage(pageIndex, width, height);
		if (!_canvas)
			return "";

		try
		{
			return _canvas.toDataURL("image/png");
		}
		catch (err)
		{
		}

		return "";
	};
	CFile.prototype.isValid = function()
	{
		return this.pages.length > 0;
	};

	// private functions
	CFile.prototype._pixelsToCanvas2d = function(pixels, width, height)
    {
        var canvas = null;
        if (this.cacheManager)
        {
            canvas = this.cacheManager.lock(width, height);
        }
        else
        {
            canvas = document.createElement("canvas");
            canvas.width = width;
            canvas.height = height;
        }

        var mappedBuffer = new Uint8ClampedArray(this.memory().buffer, pixels, 4 * width * height);
        var imageData = new ImageData(mappedBuffer, width, height);
        var ctx = canvas.getContext("2d");
        if (ctx)
            ctx.putImageData(imageData, 0, 0);
        return canvas;
    };

	CFile.prototype._pixelsToCanvas3d = function(pixels, width, height)
    {
        var vs_source = "\
attribute vec2 aVertex;\n\
attribute vec2 aTex;\n\
varying vec2 vTex;\n\
void main() {\n\
	gl_Position = vec4(aVertex, 0.0, 1.0);\n\
	vTex = aTex;\n\
}";

        var fs_source = "\
precision mediump float;\n\
uniform sampler2D uTexture;\n\
varying vec2 vTex;\n\
void main() {\n\
	gl_FragColor = texture2D(uTexture, vTex);\n\
}";
        var canvas = null;
        if (this.cacheManager)
        {
            canvas = this.cacheManager.lock(width, height);
        }
        else
        {
            canvas = document.createElement("canvas");
            canvas.width = width;
            canvas.height = height;
        }

        var gl = canvas.getContext('webgl', { preserveDrawingBuffer : true });
        if (!gl)
            throw new Error('FAIL: could not create webgl canvas context');

        var colorCorrect = gl.BROWSER_DEFAULT_WEBGL;
        gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, colorCorrect);
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

        gl.viewport(0, 0, canvas.width, canvas.height);
        gl.clearColor(0, 0, 0, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);

        if (gl.getError() != gl.NONE)
            throw new Error('FAIL: webgl canvas context setup failed');

        function createShader(source, type) {
            var shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
                throw new Error('FAIL: shader ' + id + ' compilation failed');
            return shader;
        }

        var program = gl.createProgram();
        gl.attachShader(program, createShader(vs_source, gl.VERTEX_SHADER));
        gl.attachShader(program, createShader(fs_source, gl.FRAGMENT_SHADER));
        gl.linkProgram(program);
        if (!gl.getProgramParameter(program, gl.LINK_STATUS))
            throw new Error('FAIL: webgl shader program linking failed');
        gl.useProgram(program);

        var texture = gl.createTexture();
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(this.memory().buffer, pixels, 4 * width * height));

        if (gl.getError() != gl.NONE)
            throw new Error('FAIL: creating webgl image texture failed');

        function createBuffer(data) {
            var buffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
            return buffer;
        }

        var vertexCoords = new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]);
        var vertexBuffer = createBuffer(vertexCoords);
        var location = gl.getAttribLocation(program, 'aVertex');
        gl.enableVertexAttribArray(location);
        gl.vertexAttribPointer(location, 2, gl.FLOAT, false, 0, 0);

        if (gl.getError() != gl.NONE)
            throw new Error('FAIL: vertex-coord setup failed');

        var texCoords = new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]);
        var texBuffer = createBuffer(texCoords);
        var location = gl.getAttribLocation(program, 'aTex');
        gl.enableVertexAttribArray(location);
        gl.vertexAttribPointer(location, 2, gl.FLOAT, false, 0, 0);

        if (gl.getError() != gl.NONE)
            throw new Error('FAIL: tex-coord setup setup failed');

        gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
        return canvas;
    };

    CFile.prototype._pixelsToCanvas = function(pixels, width, height)
    {
        if (!this.isUse3d)
        {
            return this._pixelsToCanvas2d(pixels, width, height);
        }

        try
        {
            return this._pixelsToCanvas3d(pixels, width, height);
        }
        catch (err)
        {
            this.isUse3d = false;
            if (this.cacheManager)
                this.cacheManager.clear();
            return this._pixelsToCanvas(pixels, width, height);
        }
    };

 	window["AscViewer"] = window["AscViewer"] || {};
    window["AscViewer"].IFile = CFile;

    window["AscViewer"].createFile = function(buffer)
    {
        var data = new Uint8Array(buffer);
        var file = null;
        if (data.length > 7 &&
            0x41 == data[0] && 0x54 == data[1] && 0x26 == data[2] && 0x54 == data[3] &&
            0x46 == data[4] && 0x4f == data[5] && 0x52 == data[6] && 0x4d == data[7])
        {
            file = new window["AscViewer"].DjVuFile();
        }

        if (!file)
        {
            var maxCheck = Math.min(100, data.length - 5);
            var pdfCheck = [
                "%".charCodeAt(0),
                "P".charCodeAt(0),
                "D".charCodeAt(0),
                "F".charCodeAt(0),
                "-".charCodeAt(0)
            ];
            var isPdf = false;
            for (var i = 0; i < maxCheck; i++)
            {
                if (data[i + 0] == pdfCheck[0] &&
                    data[i + 1] == pdfCheck[1] &&
                    data[i + 2] == pdfCheck[2] &&
                    data[i + 3] == pdfCheck[3] &&
                    data[i + 4] == pdfCheck[4])
                {
                    isPdf = true;
                    break;
                }
            }

            if (isPdf)
            {
                file = new window["AscViewer"].PdfFile();
                file.type = 0;
            }
        }

        if (!file)
        {
            file = new window["AscViewer"].XpsFile();
        }

		if (!file)
        {
            file = new window["AscViewer"].PdfFile();
            file.type = 1;
        }

        file.loadFromData(data);
        file.cacheManager = new window.CCacheManager();
        return file;
    };

})(window, undefined);
<commit_msg>fix for djvu, pdf<commit_after>(function(window, undefined) {

    function CDocMetaSelection()
    {
        this.Page1 = 0;
        this.Line1 = 0;
        this.Glyph1 = 0;

        this.Page2 = 0;
        this.Line2 = 0;
        this.Glyph2 = 0;

        this.IsSelection = false;
    }

    function CFile()
    {
    	this.nativeFile = 0;
    	this.pages = [];
    	this.zoom = 1;
    	this.isUse3d = false;
    	this.cacheManager = null;
    	this.logging = true;
    	this.Selection = new CDocMetaSelection();
    }

    // interface
    CFile.prototype.loadFromData = function(data) {};
    CFile.prototype.load = function(arrayBuffer)
    {
        return this.loadFromData(new Uint8Array(arrayBuffer));
    };

    CFile.prototype.getInfo = function() {};
    CFile.prototype.getPagePixmap = function(pageIndex, width, height) {};
    CFile.prototype.close = function() {};
    CFile.prototype.memory = function() {};
    CFile.prototype.free = function(pointer) {};

	CFile.prototype.getPage = function(pageIndex, width, height)
	{
		if (pageIndex < 0 || pageIndex >= this.pages.length)
			return null;
		if (!width) width = this.pages[pageIndex].W;
		if (!height) height = this.pages[pageIndex].H;
		var t0 = performance.now();
		var pixels = this.getPagePixmap(pageIndex, width, height);
		if (!pixels)
			return null;

		if (!this.logging)
		{
			var image = this._pixelsToCanvas(pixels, width, height);
		}
		else
		{
			var t1 = performance.now();
			var image = this._pixelsToCanvas(pixels, width, height);
			var t2 = performance.now();
			//console.log("time: " + (t1 - t0) + ", " + (t2 - t1));
		}
        /*
        if (this.pages[pageIndex].Lines)
        {
            var ctx = image.getContext("2d");
            for (let i = 0; i < this.pages[pageIndex].Lines.length; i++)
            {
                for (let j = 0; j < this.pages[pageIndex].Lines[i].Glyphs.length; j++)
                {
                    let glyph = this.pages[pageIndex].Lines[i].Glyphs[j];
                    ctx.font = glyph.fontSize + 'px ' + glyph.fontName;
                    ctx.fillText(glyph.UChar, glyph.X, glyph.Y);
                }
            }
        }
        */
        this.free(pixels);
        return image;
	};

    CFile.prototype.GetNearestPos = function(pageIndex, x, y)
    {
        var _line = -1;
        var _glyph = -1;
        var minDist = Number.MAX_SAFE_INTEGER;

        if (!this.pages[pageIndex].Lines)
            return { Line : _line, Glyph : _glyph };

        for (let i = 0; i < this.pages[pageIndex].Lines.length; i++)
        {
            let Y = this.pages[pageIndex].Lines[i].Glyphs[0].Y;
            if (Math.abs(Y - y) < minDist)
            {
                minDist = Math.abs(Y - y);
                _line   = i;
            }
        }
        minDist = Number.MAX_SAFE_INTEGER;
        for (let j = 0; j < this.pages[pageIndex].Lines[_line].Glyphs.length; j++)
        {
            let X = this.pages[pageIndex].Lines[_line].Glyphs[j].X;
            if (Math.abs(X - x) < minDist)
            {
                minDist = Math.abs(X - x);
                _glyph  = j;
            }
        }

        return { Line : _line, Glyph : _glyph };
    }

    CFile.prototype.OnUpdateSelection = function(Selection, width, height)
    {
        if (!this.Selection.IsSelection)
            return;

        var sel = this.Selection;
        var page1  = sel.Page1;
        var page2  = sel.Page2;
        var line1  = sel.Line1;
        var line2  = sel.Line2;
        var glyph1 = sel.Glyph1;
        var glyph2 = sel.Glyph2;
        if (page1 == page2 && line1 == line2 && glyph1 == glyph2)
        {
            Selection.IsSelection = false;
            return;
        }
        else if (page1 == page2 && line1 == line2)
        {
            glyph1 = Math.min(sel.Glyph1, sel.Glyph2);
            glyph2 = Math.max(sel.Glyph1, sel.Glyph2);
        }
        else if (page1 == page2)
        {
            if (line1 > line2)
            {
                line1  = sel.Line2;
                line2  = sel.Line1;
                glyph1 = sel.Glyph2;
                glyph2 = sel.Glyph1;
            }
        }

        if (this.cacheManager)
        {
            this.cacheManager.unlock(Selection.Image);
            Selection.Image = this.cacheManager.lock(width, height);
        }
        else
        {
            delete Selection.Image;
            Selection.Image = document.createElement("canvas");
            Selection.Image.width = width;
            Selection.Image.height = height;
        }
        let ctx = Selection.Image.getContext("2d");
        // TODO: После изменения размера экрана наложение областей выделения
        ctx.clearRect(0, 0, Selection.Image.width, Selection.Image.height);
        ctx.globalAlpha = 0.4;
        ctx.fillStyle = "#7070FF";

        for (let page = page1; page <= page2; page++)
        {
            let start = 0;
            let end   = this.pages[page].Lines.length;
            if (page == page1)
                start = line1;
            if (page == page2)
                end = line2;
            for (let line = start; line <= end; line++)
            {
                let Glyphs = this.pages[page].Lines[line].Glyphs;
                let x = Glyphs[0].X;
                let y = Glyphs[0].Y - Glyphs[0].fontSize;
                // первая строка на первой странице
                if (page == page1 && line == start)
                    x = Glyphs[glyph1].X;
                let w = Glyphs[Glyphs.length - 1].X - x;
                let h = Glyphs[0].fontSize;
                // последняя строка на последней странице
                if (page == page2 && line == end)
                    w = Glyphs[glyph2].X - x;

                ctx.fillRect(x, y, w, h);
            }
        }
        ctx.globalAlpha = 1;
        Selection.IsSelection = true;
    }

	CFile.prototype.OnMouseDown = function(pageIndex, Selection, x, y, w, h)
    {
        var ret = this.GetNearestPos(pageIndex, x, y);

        var sel = this.Selection;
        sel.Page1  = pageIndex;
        sel.Line1  = ret.Line;
        sel.Glyph1 = ret.Glyph;

        sel.Page2  = pageIndex;
        sel.Line2  = ret.Line;
        sel.Glyph2 = ret.Glyph;

        sel.IsSelection = true;
        this.OnUpdateSelection(Selection, w, h);
    }

    CFile.prototype.OnMouseMove = function(pageIndex, Selection, x, y, w, h)
    {
        if (false === this.Selection.IsSelection)
            return;
        var ret = this.GetNearestPos(pageIndex, x, y);

        var sel = this.Selection;
        sel.Page2  = pageIndex;
        sel.Line2  = ret.Line;
        sel.Glyph2 = ret.Glyph;

        this.OnUpdateSelection(Selection, w, h);
    }

    CFile.prototype.OnMouseUp = function()
    {
        this.Selection.IsSelection = false;
    }

    CFile.prototype.getPageBase64 = function(pageIndex, width, height)
	{
		var _canvas = this.getPage(pageIndex, width, height);
		if (!_canvas)
			return "";

		try
		{
			return _canvas.toDataURL("image/png");
		}
		catch (err)
		{
		}

		return "";
	};
	CFile.prototype.isValid = function()
	{
		return this.pages.length > 0;
	};

	// private functions
	CFile.prototype._pixelsToCanvas2d = function(pixels, width, height)
    {
        var canvas = null;
        if (this.cacheManager)
        {
            canvas = this.cacheManager.lock(width, height);
        }
        else
        {
            canvas = document.createElement("canvas");
            canvas.width = width;
            canvas.height = height;
        }

        var mappedBuffer = new Uint8ClampedArray(this.memory().buffer, pixels, 4 * width * height);
        var imageData = new ImageData(mappedBuffer, width, height);
        var ctx = canvas.getContext("2d");
        if (ctx)
            ctx.putImageData(imageData, 0, 0);
        return canvas;
    };

	CFile.prototype._pixelsToCanvas3d = function(pixels, width, height)
    {
        var vs_source = "\
attribute vec2 aVertex;\n\
attribute vec2 aTex;\n\
varying vec2 vTex;\n\
void main() {\n\
	gl_Position = vec4(aVertex, 0.0, 1.0);\n\
	vTex = aTex;\n\
}";

        var fs_source = "\
precision mediump float;\n\
uniform sampler2D uTexture;\n\
varying vec2 vTex;\n\
void main() {\n\
	gl_FragColor = texture2D(uTexture, vTex);\n\
}";
        var canvas = null;
        if (this.cacheManager)
        {
            canvas = this.cacheManager.lock(width, height);
        }
        else
        {
            canvas = document.createElement("canvas");
            canvas.width = width;
            canvas.height = height;
        }

        var gl = canvas.getContext('webgl', { preserveDrawingBuffer : true });
        if (!gl)
            throw new Error('FAIL: could not create webgl canvas context');

        var colorCorrect = gl.BROWSER_DEFAULT_WEBGL;
        gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, colorCorrect);
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);

        gl.viewport(0, 0, canvas.width, canvas.height);
        gl.clearColor(0, 0, 0, 1);
        gl.clear(gl.COLOR_BUFFER_BIT);

        if (gl.getError() != gl.NONE)
            throw new Error('FAIL: webgl canvas context setup failed');

        function createShader(source, type) {
            var shader = gl.createShader(type);
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))
                throw new Error('FAIL: shader ' + id + ' compilation failed');
            return shader;
        }

        var program = gl.createProgram();
        gl.attachShader(program, createShader(vs_source, gl.VERTEX_SHADER));
        gl.attachShader(program, createShader(fs_source, gl.FRAGMENT_SHADER));
        gl.linkProgram(program);
        if (!gl.getProgramParameter(program, gl.LINK_STATUS))
            throw new Error('FAIL: webgl shader program linking failed');
        gl.useProgram(program);

        var texture = gl.createTexture();
        gl.activeTexture(gl.TEXTURE0);
        gl.bindTexture(gl.TEXTURE_2D, texture);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, new Uint8Array(this.memory().buffer, pixels, 4 * width * height));

        if (gl.getError() != gl.NONE)
            throw new Error('FAIL: creating webgl image texture failed');

        function createBuffer(data) {
            var buffer = gl.createBuffer();
            gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
            gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
            return buffer;
        }

        var vertexCoords = new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]);
        var vertexBuffer = createBuffer(vertexCoords);
        var location = gl.getAttribLocation(program, 'aVertex');
        gl.enableVertexAttribArray(location);
        gl.vertexAttribPointer(location, 2, gl.FLOAT, false, 0, 0);

        if (gl.getError() != gl.NONE)
            throw new Error('FAIL: vertex-coord setup failed');

        var texCoords = new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]);
        var texBuffer = createBuffer(texCoords);
        var location = gl.getAttribLocation(program, 'aTex');
        gl.enableVertexAttribArray(location);
        gl.vertexAttribPointer(location, 2, gl.FLOAT, false, 0, 0);

        if (gl.getError() != gl.NONE)
            throw new Error('FAIL: tex-coord setup setup failed');

        gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
        return canvas;
    };

    CFile.prototype._pixelsToCanvas = function(pixels, width, height)
    {
        if (!this.isUse3d)
        {
            return this._pixelsToCanvas2d(pixels, width, height);
        }

        try
        {
            return this._pixelsToCanvas3d(pixels, width, height);
        }
        catch (err)
        {
            this.isUse3d = false;
            if (this.cacheManager)
                this.cacheManager.clear();
            return this._pixelsToCanvas(pixels, width, height);
        }
    };

 	window["AscViewer"] = window["AscViewer"] || {};
    window["AscViewer"].IFile = CFile;

    window["AscViewer"].createFile = function(buffer)
    {
        var data = new Uint8Array(buffer);
        var file = null;
        if (data.length > 7 &&
            0x41 == data[0] && 0x54 == data[1] && 0x26 == data[2] && 0x54 == data[3] &&
            0x46 == data[4] && 0x4f == data[5] && 0x52 == data[6] && 0x4d == data[7])
        {
            file = new window["AscViewer"].DjVuFile();
        }

        if (!file)
        {
            var maxCheck = Math.min(100, data.length - 5);
            var pdfCheck = [
                "%".charCodeAt(0),
                "P".charCodeAt(0),
                "D".charCodeAt(0),
                "F".charCodeAt(0),
                "-".charCodeAt(0)
            ];
            var isPdf = false;
            for (var i = 0; i < maxCheck; i++)
            {
                if (data[i + 0] == pdfCheck[0] &&
                    data[i + 1] == pdfCheck[1] &&
                    data[i + 2] == pdfCheck[2] &&
                    data[i + 3] == pdfCheck[3] &&
                    data[i + 4] == pdfCheck[4])
                {
                    isPdf = true;
                    break;
                }
            }

            if (isPdf)
            {
                file = new window["AscViewer"].PdfFile();
                file.type = 0;
            }
        }

        if (!file)
        {
            file = new window["AscViewer"].XpsFile();
        }

		if (!file)
        {
            file = new window["AscViewer"].PdfFile();
            file.type = 1;
        }

        file.loadFromData(data);
        file.cacheManager = new window.CCacheManager();
        return file;
    };

})(window, undefined);
<|endoftext|>


<commit_before>'use strict';

var trace = function(){
  for(var i = 0; i < arguments.length; i++){
    console.log(arguments[i]);
  }
};

var App = App || {
    url: 'http://localhost:3000'
};

App.getMovies = function(){
  $.ajax({
    url: App.url + '/movies',
    type: 'GET'
  }).done(function(data){
    App.renderMovies(data);
  }).fail(function(jqXHR, textStatus, errorThrown){
    trace(jqXHR, textStatus, errorThrown);
  });
};

// App.indexMovies = function(movies){
//   trace(movies)
//   movies.forEach(App.renderMovie);
// };

App.filterMpaa = function(mpaaRate, e){
  if(e.preventDefault) e.preventDefault();
  //filter visible text
}

App.renderMovies = function(movies){
  for (var j = 0; j < movies.length; j++){
    $('.movie-list').append('
' + '

' + movies[j].title + '

'+ '
'+ "MPAA Rating: " + movies[j].mpaa_rating + '

' + "Release Date: " + movies[j].release_date + '

' + "Gross: " + movies[j].gross + '

')
  }
};

App.filterMovies = function(){
  var $filterDate = $('#filter-date');
  var $filterMpaa = $('#filter-mpaa');

  $filterDate.on('change',function(e){
    if(e.preventDefault) e.preventDefault();
  //  console.log($filterDate.val());
    App.filterByDate($filterDate.val());
  });

  $filterMpaa.on('change',function(e){
    if(e.preventDefault) e.preventDefault();
    App.filterByMpaa($filterMpaa.val());
  //  console.log("Made it in filter mpaa");
  });
};

App.filterByDate = function(selectDate){
  var $releaseDates = $(".release-date");
  var $movieText = $(".movie-text");
  for(var i = 0; i<$releaseDates.length; i++){
    if($releaseDates[i].id === selectDate || selectDate==='0'){
      $($movieText[i]).parent().show();
    }else{
      $($movieText[i]).parent().hide();
    }
  };
};

App.filterByMpaa = function(selectMpaa){
  var $mpaaRating = $(".mpaa");
  var $movieText = $(".movie-text");
  for(var i = 0; i<$mpaaRating.length; i++){
    if($mpaaRating[i].id === selectMpaa || selectMpaa==='0'){
      $($movieText[i]).parent().show();
    }else{
      $($movieText[i]).parent().hide();
    }
  };
};
// App.renderMovie = function(currentVal,index,array){
//   trace(currentVal, index, array);
//   for (var i = 0; i < 4; i++) {
//     $('.movie-list').append('
');
//         $('.row').append('
' + '
' + currentVal.title + '
' + '
' + currentVal.description + '
' + '
Number of reviews: ' + currentVal.reviews.length + '
' + '
');
//     $('.movie-list').append('
');
//   };

// };

$(document).ready(function(){
  // $('#movie-search').on('change', function(event){
  //   $('#sub-search').append('<select name="sub-category"><option value="">Select sub-category</option></select>');
  console.log("We're in the document ready.");
 // });
  App.getMovies();

  App.filterMovies();

  // $('#movie-list').on('')
  // $('#movie-search').on('change', function(event){
  //   $('#sub-search').append('<select name="sub-category">');
  //   $('#sub-search').append('<option value="">Select sub-category</option>');
  //   $('#sub-search').append('</select>');
  // });
});

<commit_msg>Add both date and mpaa filter.<commit_after>'use strict';

var trace = function(){
  for(var i = 0; i < arguments.length; i++){
    console.log(arguments[i]);
  }
};

var App = App || {
    url: 'http://localhost:3000'
};

App.getMovies = function(){
  $.ajax({
    url: App.url + '/movies',
    type: 'GET'
  }).done(function(data){
    App.renderMovies(data);
  }).fail(function(jqXHR, textStatus, errorThrown){
    trace(jqXHR, textStatus, errorThrown);
  });
};

App.renderMovies = function(movies){
  for (var j = 0; j < movies.length; j++){
    $('.movie-list').append('
' + '

' + movies[j].title + '

'+ '
'+ "MPAA Rating: " + movies[j].mpaa_rating + '

' + "Release Date: " + movies[j].release_date + '

' + "Gross: " + movies[j].gross + '

')
  }
};

App.filterMovies = function(){
  var $filterDate = $('#filter-date');
  var $filterMpaa = $('#filter-mpaa');
  var $filterForm = $('#filter-form');

  $filterForm.on('change',function(e){
    if(e.preventDefault) e.preventDefault();
    var releaseDate = $filterDate.val();
    var mpaa = $filterMpaa.val();
  //  console.log($filterDate.val());
    // App.filterByDate($filterDate.val());
    // App.filterByMpaa($filterMpaa.val());
  //  debugger;
    if (releaseDate==='0' && mpaa !=='0'){
      App.filterByOnlyMpaa(mpaa);
    }else if(mpaa==='0' && releaseDate !=='0'){
      App.filterByOnlyDate(releaseDate);
    }else{
      App.filterByDateMpaa(releaseDate, mpaa);
    };
  });

  // $filterMpaa.on('change',function(e){
  //   if(e.preventDefault) e.preventDefault();
  //   App.filterByMpaa($filterMpaa.val());
  // //  console.log("Made it in filter mpaa");
  // });
};

App.filterByDateMpaa = function(selectDate, selectMpaa){
  var $releaseDates = $(".release-date");
  var $mpaaRating = $(".mpaa");
  var $movieText = $(".movie-text");
//  debugger;
  for(var i = 0; i<$movieText.length; i++){
    if(selectDate === selectMpaa){
      $($movieText[i]).parent().show();
    } else if ($releaseDates[i].id === selectDate && $mpaaRating[i].id === selectMpaa){
      $($movieText[i]).parent().show();
    }else{
      $($movieText[i]).parent().hide();
    };
  }
};

App.filterByOnlyDate = function(selectDate){
  var $releaseDates = $(".release-date");
  var $movieText = $(".movie-text");
  for(var i = 0; i<$releaseDates.length; i++){
    if($releaseDates[i].id === selectDate){
      $($movieText[i]).parent().show();
    }else{
      $($movieText[i]).parent().hide();
    }
  };
};

App.filterByOnlyMpaa = function(selectMpaa){
  var $mpaaRating = $(".mpaa");
  var $movieText = $(".movie-text");
  for(var i = 0; i<$mpaaRating.length; i++){
    if($mpaaRating[i].id === selectMpaa){
      $($movieText[i]).parent().show();
    }else{
      $($movieText[i]).parent().hide();
    }
  };
};
// App.renderMovie = function(currentVal,index,array){
//   trace(currentVal, index, array);
//   for (var i = 0; i < 4; i++) {
//     $('.movie-list').append('
');
//         $('.row').append('
' + '
' + currentVal.title + '
' + '
' + currentVal.description + '
' + '
Number of reviews: ' + currentVal.reviews.length + '
' + '
');
//     $('.movie-list').append('
');
//   };

// };

$(document).ready(function(){
  // $('#movie-search').on('change', function(event){
  //   $('#sub-search').append('<select name="sub-category"><option value="">Select sub-category</option></select>');
  console.log("We're in the document ready.");
 // });
  App.getMovies();

  App.filterMovies();

  // $('#movie-list').on('')
  // $('#movie-search').on('change', function(event){
  //   $('#sub-search').append('<select name="sub-category">');
  //   $('#sub-search').append('<option value="">Select sub-category</option>');
  //   $('#sub-search').append('</select>');
  // });
});

<|endoftext|>


<commit_before>ace.define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"], function(require, exports, module) {
"use strict";

var lang = require("../lib/lang");
exports.$detectIndentation = function(lines, fallback) {
    var stats = [];
    var changes = [];
    var tabIndents = 0;
    var prevSpaces = 0;
    var max = Math.min(lines.length, 1000);
    for (var i = 0; i < max; i++) {
        var line = lines[i];
        if (!/^\s*[^*+\-\s]/.test(line))
            continue;

        if (line[0] == "\t") {
            tabIndents++;
            prevSpaces = -Number.MAX_VALUE;
        } else {
            var spaces = line.match(/^ */)[0].length;
            if (spaces && line[spaces] != "\t") {
                var diff = spaces - prevSpaces;
                if (diff > 0 && !(prevSpaces%diff) && !(spaces%diff))
                    changes[diff] = (changes[diff] || 0) + 1;

                stats[spaces] = (stats[spaces] || 0) + 1;
            }
            prevSpaces = spaces;
        }
        while (i < max && line[line.length - 1] == "\\")
            line = lines[i++];
    }

    function getScore(indent) {
        var score = 0;
        for (var i = indent; i < stats.length; i += indent)
            score += stats[i] || 0;
        return score;
    }

    var changesTotal = changes.reduce(function(a,b){return a+b}, 0);

    var first = {score: 0, length: 0};
    var spaceIndents = 0;
    for (var i = 1; i < 12; i++) {
        var score = getScore(i);
        if (i == 1) {
            spaceIndents = score;
            score = stats[1] ? 0.9 : 0.8;
            if (!stats.length)
                score = 0;
        } else
            score /= spaceIndents;

        if (changes[i])
            score += changes[i] / changesTotal;

        if (score > first.score)
            first = {score: score, length: i};
    }

    if (first.score && first.score > 1.4)
        var tabLength = first.length;

    if (tabIndents > spaceIndents + 1) {
        if (tabLength == 1 || spaceIndents < tabIndents / 4 || first.score < 1.8)
            tabLength = undefined;
        return {ch: "\t", length: tabLength};
    }
    if (spaceIndents > tabIndents + 1)
        return {ch: " ", length: tabLength};
};

exports.detectIndentation = function(session) {
    var lines = session.getLines(0, 1000);
    var indent = exports.$detectIndentation(lines) || {};

    if (indent.ch)
        session.setUseSoftTabs(indent.ch == " ");

    if (indent.length)
        session.setTabSize(indent.length);
    return indent;
};

exports.trimTrailingSpace = function(session, trimEmpty) {
    var doc = session.getDocument();
    var lines = doc.getAllLines();

    var min = trimEmpty ? -1 : 0;

    for (var i = 0, l=lines.length; i < l; i++) {
        var line = lines[i];
        var index = line.search(/\s+$/);

        if (index > min)
            doc.removeInLine(i, index, line.length);
    }
};

exports.convertIndentation = function(session, ch, len) {
    var oldCh = session.getTabString()[0];
    var oldLen = session.getTabSize();
    if (!len) len = oldLen;
    if (!ch) ch = oldCh;

    var tab = ch == "\t" ? ch: lang.stringRepeat(ch, len);

    var doc = session.doc;
    var lines = doc.getAllLines();

    var cache = {};
    var spaceCache = {};
    for (var i = 0, l=lines.length; i < l; i++) {
        var line = lines[i];
        var match = line.match(/^\s*/)[0];
        if (match) {
            var w = session.$getStringScreenWidth(match)[0];
            var tabCount = Math.floor(w/oldLen);
            var reminder = w%oldLen;
            var toInsert = cache[tabCount] || (cache[tabCount] = lang.stringRepeat(tab, tabCount));
            toInsert += spaceCache[reminder] || (spaceCache[reminder] = lang.stringRepeat(" ", reminder));

            if (toInsert != match) {
                doc.removeInLine(i, 0, match.length);
                doc.insertInLine({row: i, column: 0}, toInsert);
            }
        }
    }
    session.setTabSize(len);
    session.setUseSoftTabs(ch == " ");
};

exports.$parseStringArg = function(text) {
    var indent = {};
    if (/t/.test(text))
        indent.ch = "\t";
    else if (/s/.test(text))
        indent.ch = " ";
    var m = text.match(/\d+/);
    if (m)
        indent.length = parseInt(m[0], 10);
    return indent;
};

exports.$parseArg = function(arg) {
    if (!arg)
        return {};
    if (typeof arg == "string")
        return exports.$parseStringArg(arg);
    if (typeof arg.text == "string")
        return exports.$parseStringArg(arg.text);
    return arg;
};

exports.commands = [{
    name: "detectIndentation",
    exec: function(editor) {
        exports.detectIndentation(editor.session);
    }
}, {
    name: "trimTrailingSpace",
    exec: function(editor) {
        exports.trimTrailingSpace(editor.session);
    }
}, {
    name: "convertIndentation",
    exec: function(editor, arg) {
        var indent = exports.$parseArg(arg);
        exports.convertIndentation(editor.session, indent.ch, indent.length);
    }
}, {
    name: "setIndentation",
    exec: function(editor, arg) {
        var indent = exports.$parseArg(arg);
        indent.length && editor.session.setTabSize(indent.length);
        indent.ch && editor.session.setUseSoftTabs(indent.ch == " ");
    }
}];

});
                (function() {
                    ace.require(["ace/ext/whitespace"], function() {});
                })();
            <commit_msg>Update public/libs/bower_components/ace-builds/src-noconflict/ext-whitespace.js<commit_after><|endoftext|>


<commit_before>// ==========================================================================
// Application JavaScript for IMTD?
// ==========================================================================

//
// Imports
// --------------------------------------------------------------------------
import React from 'react';
import ReactDOM from 'react-dom';

//
// Classes
// --------------------------------------------------------------------------
class TrainInfo extends React.Component {
  constructor(props) {
    super(props);
    this.loading = false;
    this.formatDate = this.formatDate.bind(this);
  }
  componentWillMount() {

  }

  componentDidMount() {

  }

  formatDate(date) {
    let d = '';

    if (date.getHours() > 12) {
      d += date.getHours() - 12 + ':';
    }
    else {
      d += date.getHours().toString() + ':';
    }

    if (date.getMinutes() < 10) {
      d += '0' + date.getMinutes().toString() + ':';
    }
    else {
      d += date.getMinutes().toString() + ':';
    }

    if (date.getSeconds() < 10) {
      d += '0' + date.getSeconds().toString();
    }
    else {
      d += date.getSeconds().toString();
    }

    d += (date.getHours() > 12 ? ' PM' : ' AM');

    return d;
  }

  render() {
    let trains = this.props.data.trains;
    let retrieveTime = this.formatDate(new Date());

    const trainLines = trains.map((train) =>

          {train.name}
          {train.status === "Delayed" &&

              <button type='button' className='delay-info-expand' title='Click to expand and get more information about this delay' onClick={this.toggleDelayInfo}>{train.status} - {train.name}</button>

          }
          {train.status !== "Delayed" &&

                {train.status}

          }

        {train.status === "Delayed" &&
          <TrainDelayRow delays={train.details} />
        }

    );
    return (

Train status information

            <TrainInfoHeader />
            {trainLines}

              Last refreshed: {retrieveTime}

            <Button />

        <SiteInfo />

    )
  }
}

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

          Train Line
          Status

    )
  }
}

class TrainDelayRow extends React.Component {
  render() {
    let delays = this.props.delays;
    let trainLineDelays = delays.map((delay) =>

        {delay.delayMsg !== undefined &&

            More information

        }
        {delay.delayMsg === undefined &&

            {delay.delayDirection}
            {delay.delayedTrain}
            {delay.delayLength}
            Train is {delay.delayStatus.toLowerCase()}

        }

    );
    return (

          {trainLineDelays}

    );
  }
}

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

How does this work?

          This application uses the official GO Transit website to get its data. Whatever the GO
          Transit website shows for train delays is what this site will show.

So why use this over GO Transit?

          Fair question. The short answer is: impact to your data plan; the longer one is: after the initial
          load of this page, it will cost your data plan ~1.3KB to refresh and get the most up-to-date data.
          Even the first time you load this page costs less data than the GO Transit website.

Coming Soon

            Improved Accessibility:
            Better code to support screen readers, as well as interactions and design that better
            accommodate everyone who may use this application.

            Metadata Tagging:
            Information that will show when searching for train delays using Google. Similar to the
            visuals and info you see in Google search results without clicking on a result.

            Manual Refresh:
            Click or touch the Refresh button to get the latest train delays--no more page refreshing.

Want to Help?

          Please open an issue or pull request on the official GitHub repo.

    );
  }
}

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleResponse = this.handleResponse.bind(this);
    this.toggleDelayInfo = this.toggleDelayInfo.bind(this);
  }

  toggleDelayInfo(event) {
    event.preventDefault();

    if (event.target.parentElement.parentElement.nextSibling.classList.contains('delay-info--show')) {
      event.target.parentElement.parentElement.nextSibling.classList.remove('delay-info--show')
    }
    else {
      event.target.parentElement.parentElement.nextSibling.classList.add('delay-info--show');
    }
  }

  handleRefresh() {
    // Spin the loader

    var oReq = new XMLHttpRequest();

    oReq.addEventListener("load", this.handleResponse);
    oReq.addEventListener("error", this.handleResponse);
    oReq.addEventListener("timeout", this.handleResponse);

    oReq.open("GET", "/fetch");
    oReq.send();
  }

  handleResponse(res) {
    var data = JSON.parse(res.target.response);
    if (res.target.status === 200) {
      this.renderData(data);
    }
  }

  renderData(data) {
    ReactDOM.render(<TrainInfo data={data} />, document.getElementById('train-info'));
  }

  render() {
    return (
      <button type='button' onClick={this.handleRefresh}>
        <svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enableBackground="new 0 0 100 100" xmlSpace="preserve" className="icon icon--refresh">
          <g display="none">
            <polygon display="inline" points="85.982,15.043 14.018,15.043 41.006,42.031 41.006,84.957 58.996,72.963 58.996,42.031"/>
          </g>
          <g display="none">
            <path display="inline" d="M76.592,85.935l-11.32-17.052l7.006-6.496V15.922c0-1.024-0.832-1.856-1.859-1.856H29.314   c-1.027,0-1.861,0.832-1.861,1.856v46.465l7.17,6.644L23.408,85.935h6.404l8.775-13.227l0.07,0.064h22.414l0.238-0.221   l8.875,13.383H76.592z M62.004,64.233c-2.355,0-4.266-1.907-4.266-4.27c0-2.356,1.91-4.266,4.266-4.266   c2.357,0,4.27,1.909,4.27,4.266C66.273,62.326,64.361,64.233,62.004,64.233z M43.463,17.634h12.805v4.406H43.463V17.634z    M33.859,26.169h32.012V45.38H33.859V26.169z M38.525,64.233c-2.357,0-4.268-1.907-4.268-4.27c0-2.356,1.91-4.266,4.268-4.266   c2.359,0,4.271,1.909,4.271,4.266C42.797,62.326,40.885,64.233,38.525,64.233z"/>
          </g>
          <g>
            <path className="refresh-icon-top" d="M77.845,26.948c-6.625-7.896-16.55-12.932-27.689-12.932c-19.975,0-36.138,16.107-36.138,35.984h14.395   c0-11.961,9.765-21.691,21.786-21.691c7.191,0,13.567,3.501,17.538,8.867l-8.464,8.088l26.71-0.012V18.667L77.845,26.948z"/>
            <path className="refresh-icon-bottom" d="M49.799,71.687c-7.193,0-13.565-3.5-17.539-8.867l8.464-8.086l-26.706,0.012V81.33l8.134-8.281   c6.625,7.896,16.551,12.935,27.69,12.935c19.978,0,36.141-16.11,36.141-35.986H71.584C71.584,61.956,61.819,71.687,49.799,71.687z"/>
          </g>
          <g display="none">
            <polygon display="inline" points="32.01,14.02 67.99,50.002 32.01,85.98"/>
          </g>
        </svg>
        Refresh
      </button>
    )
  }
}

//
// Main
// --------------------------------------------------------------------------
document.addEventListener('DOMContentLoaded', init);

function init() {
  var trainInfo = document.querySelector('.train-info');
  var refreshBtn = document.querySelector('.train-info__actions button');

  trainInfo.addEventListener('click', function(e) {
    if (e.target.classList.contains('delay-info-expand')) {
      handleDelayInfoClick.call(this, e);
    }
    else {
      return true;
    }
  });
  refreshBtn.addEventListener('click', function(e) {
    handleDataFetch(e);
  });

  function handleDelayInfoClick(event) {
    event.preventDefault();

    // Set button's state to expanded
    var toggleState = event.target.attributes['aria-expanded'].value === 'true' ? 'false' : 'true';
    event.target.setAttribute('aria-expanded', toggleState);

    if (event.target.parentElement.parentElement.nextSibling.classList.contains('delay-info--show')) {
      event.target.parentElement.parentElement.nextSibling.classList.remove('delay-info--show')
    }
    else {
      event.target.parentElement.parentElement.nextSibling.classList.add('delay-info--show');
    }

    this.removeEventListener('click', handleDelayInfoClick);
  };

  function handleDataFetch(event) {
    event.preventDefault();
    handleRefresh();
  };

  function handleRefresh() {
    var oReq = new XMLHttpRequest();

    oReq.addEventListener("load", handleResponse);
    oReq.addEventListener("error", handleResponse);
    oReq.addEventListener("timeout", handleResponse);

    oReq.open("GET", "/fetch");
    oReq.send();
  };

  function handleResponse(res) {
    var data = JSON.parse(res.target.response);
    if (res.target.status === 200) {
      renderData(data);
    }
  };

  function renderData(data) {
    ReactDOM.render(<TrainInfo data={data} />, document.getElementById('train-info'));
  };
}
<commit_msg>Fix delay info toggle not working after React refresh 🐛<commit_after>// ==========================================================================
// Application JavaScript for IMTD?
// ==========================================================================

//
// Imports
// --------------------------------------------------------------------------
import React from 'react';
import ReactDOM from 'react-dom';

//
// Classes
// --------------------------------------------------------------------------
class TrainInfo extends React.Component {
  constructor(props) {
    super(props);
    this.loading = false;
    this.formatDate = this.formatDate.bind(this);
    this.toggleDelayInfo = this.toggleDelayInfo.bind(this);
  }
  componentWillMount() {

  }

  componentDidMount() {

  }

  toggleDelayInfo(event) {
    event.preventDefault();

    if (event.target.parentElement.parentElement.nextSibling.classList.contains('delay-info--show')) {
      event.target.parentElement.parentElement.nextSibling.classList.remove('delay-info--show')
    }
    else {
      event.target.parentElement.parentElement.nextSibling.classList.add('delay-info--show');
    }
  }

  formatDate(date) {
    let d = '';

    if (date.getHours() > 12) {
      d += date.getHours() - 12 + ':';
    }
    else {
      d += date.getHours().toString() + ':';
    }

    if (date.getMinutes() < 10) {
      d += '0' + date.getMinutes().toString() + ':';
    }
    else {
      d += date.getMinutes().toString() + ':';
    }

    if (date.getSeconds() < 10) {
      d += '0' + date.getSeconds().toString();
    }
    else {
      d += date.getSeconds().toString();
    }

    d += (date.getHours() > 12 ? ' PM' : ' AM');

    return d;
  }

  render() {
    let trains = this.props.data.trains;
    let retrieveTime = this.formatDate(new Date());

    const trainLines = trains.map((train) =>

          {train.name}
          {train.status === "Delayed" &&

              <button type='button' className='delay-info-expand' title='Click to expand and get more information about this delay' onClick={this.toggleDelayInfo}>{train.status} - {train.name}</button>

          }
          {train.status !== "Delayed" &&

                {train.status}

          }

        {train.status === "Delayed" &&
          <TrainDelayRow delays={train.details} />
        }

    );
    return (

Train status information

            <TrainInfoHeader />
            {trainLines}

              Last refreshed: {retrieveTime}

            <Button />

        <SiteInfo />

    )
  }
}

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

          Train Line
          Status

    )
  }
}

class TrainDelayRow extends React.Component {
  render() {
    let delays = this.props.delays;
    let trainLineDelays = delays.map((delay) =>

        {delay.delayMsg !== undefined &&

            More information

        }
        {delay.delayMsg === undefined &&

            {delay.delayDirection}
            {delay.delayedTrain}
            {delay.delayLength}
            Train is {delay.delayStatus.toLowerCase()}

        }

    );
    return (

          {trainLineDelays}

    );
  }
}

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

How does this work?

          This application uses the official GO Transit website to get its data. Whatever the GO
          Transit website shows for train delays is what this site will show.

So why use this over GO Transit?

          Fair question. The short answer is: impact to your data plan; the longer one is: after the initial
          load of this page, it will cost your data plan ~1.3KB to refresh and get the most up-to-date data.
          Even the first time you load this page costs less data than the GO Transit website.

Coming Soon

            Improved Accessibility:
            Better code to support screen readers, as well as interactions and design that better
            accommodate everyone who may use this application.

            Metadata Tagging:
            Information that will show when searching for train delays using Google. Similar to the
            visuals and info you see in Google search results without clicking on a result.

            Manual Refresh:
            Click or touch the Refresh button to get the latest train delays--no more page refreshing.

Want to Help?

          Please open an issue or pull request on the official GitHub repo.

    );
  }
}

class Button extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false
    }
    this.handleRefresh = this.handleRefresh.bind(this);
    this.handleResponse = this.handleResponse.bind(this);
    this.toggleDelayInfo = this.toggleDelayInfo.bind(this);
  }

  toggleDelayInfo(event) {
    event.preventDefault();

    if (event.target.parentElement.parentElement.nextSibling.classList.contains('delay-info--show')) {
      event.target.parentElement.parentElement.nextSibling.classList.remove('delay-info--show')
    }
    else {
      event.target.parentElement.parentElement.nextSibling.classList.add('delay-info--show');
    }
  }

  handleRefresh() {
    // Spin the loader

    var oReq = new XMLHttpRequest();

    oReq.addEventListener("load", this.handleResponse);
    oReq.addEventListener("error", this.handleResponse);
    oReq.addEventListener("timeout", this.handleResponse);

    oReq.open("GET", "/fetch");
    oReq.send();
  }

  handleResponse(res) {
    var data = JSON.parse(res.target.response);
    if (res.target.status === 200) {
      this.renderData(data);
    }
  }

  renderData(data) {
    ReactDOM.render(<TrainInfo data={data} />, document.getElementById('train-info'));
  }

  render() {
    return (
      <button type='button' onClick={this.handleRefresh}>
        <svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" version="1.1" x="0px" y="0px" viewBox="0 0 100 100" enableBackground="new 0 0 100 100" xmlSpace="preserve" className="icon icon--refresh">
          <g display="none">
            <polygon display="inline" points="85.982,15.043 14.018,15.043 41.006,42.031 41.006,84.957 58.996,72.963 58.996,42.031"/>
          </g>
          <g display="none">
            <path display="inline" d="M76.592,85.935l-11.32-17.052l7.006-6.496V15.922c0-1.024-0.832-1.856-1.859-1.856H29.314   c-1.027,0-1.861,0.832-1.861,1.856v46.465l7.17,6.644L23.408,85.935h6.404l8.775-13.227l0.07,0.064h22.414l0.238-0.221   l8.875,13.383H76.592z M62.004,64.233c-2.355,0-4.266-1.907-4.266-4.27c0-2.356,1.91-4.266,4.266-4.266   c2.357,0,4.27,1.909,4.27,4.266C66.273,62.326,64.361,64.233,62.004,64.233z M43.463,17.634h12.805v4.406H43.463V17.634z    M33.859,26.169h32.012V45.38H33.859V26.169z M38.525,64.233c-2.357,0-4.268-1.907-4.268-4.27c0-2.356,1.91-4.266,4.268-4.266   c2.359,0,4.271,1.909,4.271,4.266C42.797,62.326,40.885,64.233,38.525,64.233z"/>
          </g>
          <g>
            <path className="refresh-icon-top" d="M77.845,26.948c-6.625-7.896-16.55-12.932-27.689-12.932c-19.975,0-36.138,16.107-36.138,35.984h14.395   c0-11.961,9.765-21.691,21.786-21.691c7.191,0,13.567,3.501,17.538,8.867l-8.464,8.088l26.71-0.012V18.667L77.845,26.948z"/>
            <path className="refresh-icon-bottom" d="M49.799,71.687c-7.193,0-13.565-3.5-17.539-8.867l8.464-8.086l-26.706,0.012V81.33l8.134-8.281   c6.625,7.896,16.551,12.935,27.69,12.935c19.978,0,36.141-16.11,36.141-35.986H71.584C71.584,61.956,61.819,71.687,49.799,71.687z"/>
          </g>
          <g display="none">
            <polygon display="inline" points="32.01,14.02 67.99,50.002 32.01,85.98"/>
          </g>
        </svg>
        Refresh
      </button>
    )
  }
}

//
// Main
// --------------------------------------------------------------------------
document.addEventListener('DOMContentLoaded', init);

function init() {
  var trainInfo = document.querySelector('.train-info');
  var refreshBtn = document.querySelector('.train-info__actions button');

  trainInfo.addEventListener('click', function(e) {
    if (e.target.classList.contains('delay-info-expand')) {
      handleDelayInfoClick.call(this, e);
    }
    else {
      return true;
    }
  });
  refreshBtn.addEventListener('click', function(e) {
    handleDataFetch(e);
  });

  function handleDelayInfoClick(event) {
    event.preventDefault();

    // Set button's state to expanded
    var toggleState = event.target.attributes['aria-expanded'].value === 'true' ? 'false' : 'true';
    event.target.setAttribute('aria-expanded', toggleState);

    if (event.target.parentElement.parentElement.nextSibling.classList.contains('delay-info--show')) {
      event.target.parentElement.parentElement.nextSibling.classList.remove('delay-info--show')
    }
    else {
      event.target.parentElement.parentElement.nextSibling.classList.add('delay-info--show');
    }

    this.removeEventListener('click', handleDelayInfoClick);
  };

  function handleDataFetch(event) {
    event.preventDefault();
    handleRefresh();
  };

  function handleRefresh() {
    var oReq = new XMLHttpRequest();

    oReq.addEventListener("load", handleResponse);
    oReq.addEventListener("error", handleResponse);
    oReq.addEventListener("timeout", handleResponse);

    oReq.open("GET", "/fetch");
    oReq.send();
  };

  function handleResponse(res) {
    var data = JSON.parse(res.target.response);
    if (res.target.status === 200) {
      renderData(data);
    }
  };

  function renderData(data) {
    ReactDOM.render(<TrainInfo data={data} />, document.getElementById('train-info'));
  };
}
<|endoftext|>


<commit_before>ace.define("ace/snippets/cobol",["require","exports","module"], function(require, exports, module) {
"use strict";

exports.snippetText =undefined;
exports.scope = "cobol";

});
<commit_msg>Update public/libs/bower_components/ace-builds/src-noconflict/snippets/cobol.js<commit_after><|endoftext|>


<commit_before>'use strict';

var _ = require('underscore');

module.exports.map = function(object, dictionary) {

  var obj = {};
  if(!_.isEmpty(object) && !_.isEmpty(dictionary)) {
    Object.keys(dictionary).forEach(function(key) {
      if(object.hasOwnProperty(key)) {
        var renamedKey = dictionary[key];
        obj[renamedKey] = object[key];
      }
    });
  }
  return obj;
};
<commit_msg>improved the mapper to support mapping collections<commit_after>'use strict';

var _ = require('underscore');
var mapObject = function(object, dictionary) {

  var obj = {};
  if(!_.isEmpty(object) && !_.isEmpty(dictionary)) {
    Object.keys(dictionary).forEach(function(key) {
      if(object.hasOwnProperty(key)) {
        var renamedKey = dictionary[key];
        obj[renamedKey] = object[key];
      }
    });
  }
  return obj;
};

module.exports.map = mapObject;

module.exports.mapCollection = function(collection, dictionary) {
  return _.map(collection, function(object) {
    return mapObject(object, dictionary);
  });
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { propType } from 'graphql-anywhere';
import styled from 'styled-components';
import { Link } from 'react-router-dom';

import profileMetadataInfoFragment from 'react/components/ProfileMetadata/components/ProfileMetadataInfo/fragments/profileMetadataInfo';

import Box from 'react/components/UI/Box';
import Pocket from 'react/components/UI/Pocket';
import { Expandable } from 'react/components/UI/ExpandableSet';

import WithLoginStatus from 'react/hocs/WithLoginStatus';

const BlockLink = styled(Link)`
  display: inline-block;
`;

const Buttons = styled(Box).attrs({
  my: 6,
  neutralMarginsY: true,
})`
  a {
    display: block;
  }
`;

class ProfileMetadataInfo extends Component {
  static propTypes = {
    identifiable: propType(profileMetadataInfoFragment).isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
  }

  render() {
    const { identifiable, isLoggedIn } = this.props;

    const showButtons = (isLoggedIn && (
      identifiable.counts.followers > 0 ||
      identifiable.counts.following > 1 ||
      identifiable.counts.groups > 0)
    );

    return (
      <Pocket
        title={{
          User: 'Info',
          Group: 'Group Info',
        }[identifiable.__typename]}
      >
        <Expandable>

        </Expandable>

        {identifiable.__typename === 'Group' &&
          <Box my={6} neutralMarginsY>
            {'Admin — '}

            <BlockLink to={identifiable.user.href}>
              {identifiable.user.name}
            </BlockLink>
          </Box>
        }

        {showButtons &&
          <Buttons>
            {identifiable.counts.followers > 0 &&
              <BlockLink to={`${identifiable.href}/followers`}>
                Followers
              </BlockLink>
            }

            {/* Subtract 1 to ignore the default Are.na follow */}
            {(identifiable.counts.following - 1) > 0 &&
              <BlockLink to={`${identifiable.href}/following`}>
                Following
              </BlockLink>
            }

            {identifiable.counts.groups > 0 &&
              // <BlockLink to={`${identifiable.href}/groups`}>
              //   Groups
              // </BlockLink>

            }
          </Buttons>
        }
      </Pocket>
    );
  }
}

export default WithLoginStatus(ProfileMetadataInfo);
<commit_msg>Admin > Group started by<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { propType } from 'graphql-anywhere';
import styled from 'styled-components';
import { Link } from 'react-router-dom';

import profileMetadataInfoFragment from 'react/components/ProfileMetadata/components/ProfileMetadataInfo/fragments/profileMetadataInfo';

import Box from 'react/components/UI/Box';
import Pocket from 'react/components/UI/Pocket';
import { Expandable } from 'react/components/UI/ExpandableSet';

import WithLoginStatus from 'react/hocs/WithLoginStatus';

const BlockLink = styled(Link)`
  display: inline-block;
`;

const Buttons = styled(Box).attrs({
  my: 6,
  neutralMarginsY: true,
})`
  a {
    display: block;
  }
`;

class ProfileMetadataInfo extends Component {
  static propTypes = {
    identifiable: propType(profileMetadataInfoFragment).isRequired,
    isLoggedIn: PropTypes.bool.isRequired,
  }

  render() {
    const { identifiable, isLoggedIn } = this.props;

    const showButtons = (isLoggedIn && (
      identifiable.counts.followers > 0 ||
      identifiable.counts.following > 1 ||
      identifiable.counts.groups > 0)
    );

    return (
      <Pocket
        title={{
          User: 'Info',
          Group: 'Group Info',
        }[identifiable.__typename]}
      >
        <Expandable>

        </Expandable>

        {identifiable.__typename === 'Group' &&
          <Box my={6} neutralMarginsY>
            {'Group started by '}

            <BlockLink to={identifiable.user.href}>
              {identifiable.user.name}
            </BlockLink>
          </Box>
        }

        {showButtons &&
          <Buttons>
            {identifiable.counts.followers > 0 &&
              <BlockLink to={`${identifiable.href}/followers`}>
                Followers
              </BlockLink>
            }

            {/* Subtract 1 to ignore the default Are.na follow */}
            {(identifiable.counts.following - 1) > 0 &&
              <BlockLink to={`${identifiable.href}/following`}>
                Following
              </BlockLink>
            }

            {identifiable.counts.groups > 0 &&
              // <BlockLink to={`${identifiable.href}/groups`}>
              //   Groups
              // </BlockLink>

            }
          </Buttons>
        }
      </Pocket>
    );
  }
}

export default WithLoginStatus(ProfileMetadataInfo);
<|endoftext|>


<commit_before>/* global fluid, jqUnit */

(function () {

    "use strict";

    fluid.defaults("gpii.tests.visualizerTestsBase", {
        gradeNames: ["fluid.test.testEnvironment"],
        components: {
            visualizerTester: {
                type: "gpii.tests.visualizerTester"
            }
        }
    });

    fluid.defaults("gpii.tests.testVisualizerBase", {
        gradeNames: ["gpii.nexusSensorVisualizerBase"],
        components: {
            sensor: {
                type: "fluid.modelComponent",
                options: {
                    model: {
                        sensorValue: 50,
                        sensorMax: 100,
                        sensorMin: 0,
                        description: "A fake sensor"
                    }
                }
            },
            visualizer: {
                createOnEvent: "{testVisualizerBase}.events.onCreate"
                // Must be specified
                // container: ""
            }
        }
    });

    fluid.defaults("gpii.tests.realTimeVisualizerTests", {
        gradeNames: ["gpii.tests.visualizerTestsBase"],
        components: {
            visualizerTester: {
                type: "gpii.tests.realTimeVisualizerTester"
            },
            sensorVisualizer: {
                type: "gpii.tests.testRealTimeVisualizer",
                createOnEvent: "{visualizerTester}.events.onTestCaseStart"
            }
        }
    });

    fluid.defaults("gpii.tests.testRealTimeVisualizer", {
        gradeNames: ["gpii.nexusSensorVisualizer.realTimeScale", "gpii.tests.testVisualizerBase"],
        components: {
            visualizer: {
                container: "#visualizer-realTimeScale"
            }
        }
    });

    gpii.tests.generateVisualizerTestSequence = function(testSpec) {
        var sequence = [];

        fluid.each(testSpec.sequence, function (sequenceItem) {
            var applier = {
                func: "{sensorVisualizer}.sensor.applier.change",
                args: ["sensorValue", sequenceItem.sensorValue]
            };

            var listener = {
                event: "{sensorVisualizer}.visualizer.events.onUpdateCompleted",
                listener: "gpii.tests.verifyIndicator",
                args: ["{sensorVisualizer}.visualizer.dom.sensorValueIndicator", testSpec.checkAttribute, sequenceItem.attributeValue]
            };

            sequence.push(applier, listener);
        });
        return sequence;
    };

    gpii.tests.realTimeVisualizerTestSequence = {
            checkAttribute: "height",
            // Left: sensor value change (num)
            // Right: expected corresponding change to
            // indicator attribute (string)
            sequence: [
                {
                    sensorValue: 50,
                    attributeValue: "230"
                },
                {
                    sensorValue: 75,
                    attributeValue: "345"
                },
                {
                    sensorValue: 25,
                    attributeValue: "115"
                },
                {
                    sensorValue: 100,
                    attributeValue: "460"
                }
            ]
    };

    fluid.defaults("gpii.tests.realTimeVisualizerTester", {
        gradeNames: ["fluid.test.testCaseHolder"],
        modules: [{
            name: "Test real-time visualizer",
            tests: [{
                name: "Test indicator response to sensor model changes",
                expect: 4,
                sequence: gpii.tests.generateVisualizerTestSequence(gpii.tests.realTimeVisualizerTestSequence)
            }]
        }]
    });

    fluid.defaults("gpii.tests.circularPercentageScaleVisualizerTests", {
        gradeNames: ["gpii.tests.visualizerTestsBase"],
        components: {
            visualizerTester: {
                type: "gpii.tests.circularPercentageScaleVisualizerTester"
            },
            sensorVisualizer: {
                type: "gpii.tests.testCircularPercentageScaleVisualizer",
                createOnEvent: "{visualizerTester}.events.onTestCaseStart"
            }
        }
    });

    fluid.defaults("gpii.tests.testCircularPercentageScaleVisualizer", {
        gradeNames: ["gpii.nexusSensorVisualizer.circleRadius", "gpii.tests.testVisualizerBase"],
        components: {
            visualizer: {
                container: "#visualizer-circularPercentageScale"
            }
        }
    });

    gpii.tests.circularPercentageScaleVisualizerTestSequence = {
            checkAttribute: "r",
            sequence: [
                {
                    sensorValue: 50,
                    attributeValue: "50"
                },
                {
                    sensorValue: 25,
                    attributeValue: "25"
                },
                {
                    sensorValue: 75,
                    attributeValue: "75"
                },
                {
                    sensorValue: 100,
                    attributeValue: "100"
                }
            ]
    };

    fluid.defaults("gpii.tests.circularPercentageScaleVisualizerTester", {
        gradeNames: ["fluid.test.testCaseHolder"],
        modules: [{
            name: "Test circular percentage scale visualizer",
            tests: [{
                name: "Test indicator response to sensor model changes",
                expect: 4,
                sequence: gpii.tests.generateVisualizerTestSequence(gpii.tests.circularPercentageScaleVisualizerTestSequence)
            }]
        }]
    });

    fluid.defaults("gpii.tests.horizontalBarPercentageScaleVisualizerTests", {
        gradeNames: ["gpii.tests.visualizerTestsBase"],
        components: {
            visualizerTester: {
                type: "gpii.tests.horizontalBarPercentageScaleVisualizerTester"
            },
            sensorVisualizer: {
                type: "gpii.tests.testHorizontalBarPercentageScaleVisualizer",
                createOnEvent: "{visualizerTester}.events.onTestCaseStart"
            }
        }
    });

    fluid.defaults("gpii.tests.testHorizontalBarPercentageScaleVisualizer", {
        gradeNames: ["gpii.nexusSensorVisualizer.horizontalBar", "gpii.tests.testVisualizerBase"],
        components: {
            visualizer: {
                container: "#visualizer-horizontalBarPercentageScale"
            }
        }
    });

    gpii.tests.horizontalBarPercentageScaleVisualizerTestSequence = {
            checkAttribute: "width",
            sequence: [
                {
                    sensorValue: 50,
                    attributeValue: "100"
                },
                {
                    sensorValue: 25,
                    attributeValue: "50"
                },
                {
                    sensorValue: 75,
                    attributeValue: "150"
                },
                {
                    sensorValue: 100,
                    attributeValue: "200"
                }
            ]
    };

    fluid.defaults("gpii.tests.horizontalBarPercentageScaleVisualizerTester", {
        gradeNames: ["fluid.test.testCaseHolder"],
        modules: [{
            name: "Test horizontal bar percentage scale visualizer",
            tests: [{
                name: "Test indicator response to sensor model changes",
                expect: 4,
                sequence: gpii.tests.generateVisualizerTestSequence(gpii.tests.horizontalBarPercentageScaleVisualizerTestSequence)
            }]
        }]
    });

    gpii.tests.verifyIndicator = function (indicator, checkAttribute, expectedValue) {
        var message = fluid.stringTemplate("Attribute '%checkAttribute' is expected value of %expectedValue", {checkAttribute: checkAttribute, expectedValue: expectedValue});
        jqUnit.assertEquals(message, expectedValue, indicator.attr(checkAttribute));
    };

    gpii.tests.realTimeVisualizerTests();
    gpii.tests.circularPercentageScaleVisualizerTests();
    gpii.tests.horizontalBarPercentageScaleVisualizerTests();

}());
<commit_msg>GPII-2189: refurther test refactoring.<commit_after>/* global fluid, jqUnit */

(function () {

    "use strict";

    fluid.defaults("gpii.tests.visualizerTestsBase", {
        gradeNames: ["fluid.test.testEnvironment"],
        components: {
            visualizerTester: {
                type: "gpii.tests.visualizerTester"
            },
            sensorVisualizer: {
                createOnEvent: "{visualizerTester}.events.onTestCaseStart",
                options: {
                    gradeNames: ["gpii.tests.testVisualizerBase"]
                }
            }
        }
    });

    fluid.defaults("gpii.tests.testVisualizerBase", {
        gradeNames: ["gpii.nexusSensorVisualizerBase"],
        components: {
            sensor: {
                type: "fluid.modelComponent",
                options: {
                    model: {
                        sensorValue: 50,
                        sensorMax: 100,
                        sensorMin: 0,
                        description: "A fake sensor"
                    }
                }
            },
            visualizer: {
                createOnEvent: "{testVisualizerBase}.events.onCreate"
                // Must be specified
                // container: ""
            }
        }
    });

    gpii.tests.generateVisualizerTestSequence = function(testSpec) {
        var sequence = [];

        fluid.each(testSpec.sequence, function (sequenceItem) {
            var applier = {
                func: "{sensorVisualizer}.sensor.applier.change",
                args: ["sensorValue", sequenceItem.sensorValue]
            };

            var listener = {
                event: "{sensorVisualizer}.visualizer.events.onUpdateCompleted",
                listener: "gpii.tests.verifyIndicator",
                args: ["{sensorVisualizer}.visualizer.dom.sensorValueIndicator", testSpec.checkAttribute, sequenceItem.attributeValue]
            };

            sequence.push(applier, listener);
        });
        return sequence;
    };

    fluid.defaults("gpii.tests.realTimeVisualizerTests", {
        gradeNames: ["gpii.tests.visualizerTestsBase"],
        components: {
            visualizerTester: {
                type: "gpii.tests.realTimeVisualizerTester"
            },
            sensorVisualizer: {
                type: "gpii.nexusSensorVisualizer.realTimeScale",
                options: {
                    components: {
                        visualizer: {
                            container: "#visualizer-realTimeScale"
                        }
                    }
                }
            }
        }
    });

    gpii.tests.realTimeVisualizerTestSequence = {
            checkAttribute: "height",
            // Left: sensor value change (num)
            // Right: expected corresponding change to
            // indicator attribute (string)
            sequence: [
                {
                    sensorValue: 50,
                    attributeValue: "230"
                },
                {
                    sensorValue: 75,
                    attributeValue: "345"
                },
                {
                    sensorValue: 25,
                    attributeValue: "115"
                },
                {
                    sensorValue: 100,
                    attributeValue: "460"
                }
            ]
    };

    fluid.defaults("gpii.tests.realTimeVisualizerTester", {
        gradeNames: ["fluid.test.testCaseHolder"],
        modules: [{
            name: "Test real-time visualizer",
            tests: [{
                name: "Test indicator response to sensor model changes",
                expect: 4,
                sequence: gpii.tests.generateVisualizerTestSequence(gpii.tests.realTimeVisualizerTestSequence)
            }]
        }]
    });

    fluid.defaults("gpii.tests.circularPercentageScaleVisualizerTests", {
        gradeNames: ["gpii.tests.visualizerTestsBase"],
        components: {
            visualizerTester: {
                type: "gpii.tests.circularPercentageScaleVisualizerTester"
            },
            sensorVisualizer: {
                type: "gpii.nexusSensorVisualizer.circleRadius",
                options: {
                    components: {
                        visualizer: {
                            container: "#visualizer-circularPercentageScale"
                        }
                    }
                }
            }
        }
    });

    gpii.tests.circularPercentageScaleVisualizerTestSequence = {
            checkAttribute: "r",
            sequence: [
                {
                    sensorValue: 50,
                    attributeValue: "50"
                },
                {
                    sensorValue: 25,
                    attributeValue: "25"
                },
                {
                    sensorValue: 75,
                    attributeValue: "75"
                },
                {
                    sensorValue: 100,
                    attributeValue: "100"
                }
            ]
    };

    fluid.defaults("gpii.tests.circularPercentageScaleVisualizerTester", {
        gradeNames: ["fluid.test.testCaseHolder"],
        modules: [{
            name: "Test circular percentage scale visualizer",
            tests: [{
                name: "Test indicator response to sensor model changes",
                expect: 4,
                sequence: gpii.tests.generateVisualizerTestSequence(gpii.tests.circularPercentageScaleVisualizerTestSequence)
            }]
        }]
    });

    fluid.defaults("gpii.tests.horizontalBarPercentageScaleVisualizerTests", {
        gradeNames: ["gpii.tests.visualizerTestsBase"],
        components: {
            visualizerTester: {
                type: "gpii.tests.horizontalBarPercentageScaleVisualizerTester"
            },
            sensorVisualizer: {
                type: "gpii.nexusSensorVisualizer.horizontalBar",
                options: {
                    components: {
                        visualizer: {
                            container: "#visualizer-horizontalBarPercentageScale"
                        }
                    }
                }
            }
        }
    });

    gpii.tests.horizontalBarPercentageScaleVisualizerTestSequence = {
            checkAttribute: "width",
            sequence: [
                {
                    sensorValue: 50,
                    attributeValue: "100"
                },
                {
                    sensorValue: 25,
                    attributeValue: "50"
                },
                {
                    sensorValue: 75,
                    attributeValue: "150"
                },
                {
                    sensorValue: 100,
                    attributeValue: "200"
                }
            ]
    };

    fluid.defaults("gpii.tests.horizontalBarPercentageScaleVisualizerTester", {
        gradeNames: ["fluid.test.testCaseHolder"],
        modules: [{
            name: "Test horizontal bar percentage scale visualizer",
            tests: [{
                name: "Test indicator response to sensor model changes",
                expect: 4,
                sequence: gpii.tests.generateVisualizerTestSequence(gpii.tests.horizontalBarPercentageScaleVisualizerTestSequence)
            }]
        }]
    });

    gpii.tests.verifyIndicator = function (indicator, checkAttribute, expectedValue) {
        var message = fluid.stringTemplate("Attribute '%checkAttribute' is expected value of %expectedValue", {checkAttribute: checkAttribute, expectedValue: expectedValue});
        jqUnit.assertEquals(message, expectedValue, indicator.attr(checkAttribute));
    };

    gpii.tests.realTimeVisualizerTests();
    gpii.tests.circularPercentageScaleVisualizerTests();
    gpii.tests.horizontalBarPercentageScaleVisualizerTests();

}());
<|endoftext|>