function createProgram(gl, shaders, opt_attribs, opt_locations, opt_errorCallback) {
	    var progOptions = getProgramOptions(opt_attribs, opt_locations, opt_errorCallback);
	    var realShaders = [];
	    var newShaders = [];
	    for (var ndx = 0; ndx < shaders.length; ++ndx) {
	      var shader = shaders[ndx];
	      if (typeof shader === 'string') {
	        var elem = document.getElementById(shader);
	        var src = elem ? elem.text : shader;
	        var type = gl[defaultShaderType[ndx]];
	        if (elem && elem.type) {
	          type = getShaderTypeFromScriptType(elem.type) || type;
	        }
	        shader = loadShader(gl, src, type, progOptions.errorCallback);
	        newShaders.push(shader);
	      }
	      if (shader instanceof WebGLShader) {
	        realShaders.push(shader);
	      }
	    }

	    if (realShaders.length !== shaders.length) {
	      progOptions.errorCallback("not enough shaders for program");
	      deleteShaders(gl, newShaders);
	      return null;
	    }

	    var program = gl.createProgram();
	    realShaders.forEach(function (shader) {
	      gl.attachShader(program, shader);
	    });
	    if (progOptions.attribLocations) {
	      Object.keys(progOptions.attribLocations).forEach(function (attrib) {
	        gl.bindAttribLocation(program, progOptions.attribLocations[attrib], attrib);
	      });
	    }
	    var varyings = progOptions.transformFeedbackVaryings;
	    if (varyings) {
	      if (varyings.attribs) {
	        varyings = varyings.attribs;
	      }
	      if (!Array.isArray(varyings)) {
	        varyings = Object.keys(varyings);
	      }
	      gl.transformFeedbackVaryings(program, varyings, progOptions.transformFeedbackMode || gl.SEPARATE_ATTRIBS);
	    }
	    gl.linkProgram(program);

	    // Check the link status
	    var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
	    if (!linked) {
	      // something went wrong with the link
	      var lastError = gl.getProgramInfoLog(program);
	      progOptions.errorCallback("Error in program linking:" + lastError);

	      gl.deleteProgram(program);
	      deleteShaders(gl, newShaders);
	      return null;
	    }
	    return program;
	  }
Creates a program, attaches (and/or compiles) shaders, binds attrib locations, links the
program and calls useProgram.

NOTE: There are 4 signatures for this function

    twgl.createProgram(gl, [vs, fs], options);
    twgl.createProgram(gl, [vs, fs], opt_errFunc);
    twgl.createProgram(gl, [vs, fs], opt_attribs, opt_errFunc);
    twgl.createProgram(gl, [vs, fs], opt_attribs, opt_locations, opt_errFunc);

@param {WebGLShader[]|string[]} shaders The shaders to attach, or element ids for their source, or strings that contain their source
@param {module:twgl.ProgramOptions|string[]} [opt_attribs] Options for the program or an array of attribs names. Locations will be assigned by index if not passed in
@param {number[]} [opt_locations] The locations for the. A parallel array to opt_attribs letting you assign locations.
@param {module:twgl.ErrorCallback} [opt_errorCallback] callback for errors. By default it just prints an error to the console
       on error. If you want something else pass an callback. It's passed an error message.
@return {WebGLProgram?} the created program or null if error.
@memberOf module:twgl/programs