constructor(fragmentShaderSource, uniformParameterNames) {
        let ctx = initializedWglContext();
        let precision = ctx.maximumShaderFloatPrecision;
        let vertexShader = `
            precision ${precision} float;
            precision ${precision} int;
            attribute vec2 position;
            void main() {
              gl_Position = vec4(position, 0, 1);
            }`;
        let fullFragmentShader = `
            precision ${precision} float;
            precision ${precision} int;
            ${fragmentShaderSource}`;

        const GL = WebGLRenderingContext;
        let gl = ctx.gl;
        let glVertexShader = WglCompiledShader.compileShader(gl, GL.VERTEX_SHADER, vertexShader);
        let glFragmentShader = WglCompiledShader.compileShader(gl, GL.FRAGMENT_SHADER, fullFragmentShader);

        let program = gl.createProgram();
        gl.attachShader(program, glVertexShader);
        gl.attachShader(program, glFragmentShader);
        gl.linkProgram(program);

        // Note: MDN says the result of getProgramInfoLog is always a DOMString, but a user reported an
        // error where it returned null. So now we fallback to the empty string when getting a falsy value.
        let warnings = (gl.getProgramInfoLog(program) || '').trim();
        if (warnings !== '' &&
                warnings !== '\0' && // [happened in Ubuntu with NVIDIA GK107GL]
                Config.SUPPRESSED_GLSL_WARNING_PATTERNS.every(e => !e.test(warnings))) {
            console.warn('Shader compile caused warnings', 'gl.getProgramInfoLog()', warnings);
        }

        if (gl.getProgramParameter(program, GL.LINK_STATUS) === false) {
            throw new Error(
                "Failed to link shader program." +
                "\n" +
                "\n" +
                `gl.VALIDATE_STATUS: ${gl.getProgramParameter(program, GL.VALIDATE_STATUS)}` +
                "\n" +
                `gl.getError(): ${gl.getError()}`);
        }

        gl.deleteShader(glVertexShader);
        gl.deleteShader(glFragmentShader);

        /** @type {!Map.<!string, !WebGLUniformLocation>} */
        this.uniformLocations = new Seq(uniformParameterNames).toMap(e => e, e => gl.getUniformLocation(program, e));
        /** @type {!Number} */
        this.positionAttributeLocation = gl.getAttribLocation(program, 'position');
        /** @type {!WebGLProgram} */
        this.program = program;
    }
@param {!string} fragmentShaderSource
@param {!Array.<!string>|!Iterable.<!string>} uniformParameterNames