<commit_before>var program;

var N = 20 ;  // The number of cubes will be (2N+1)^3

var xAxis = 0;
var yAxis = 1;
var zAxis = 2;

var axis = 0;
var theta = [ 0, 0, 0 ];
var paused = 0;
var depthTest = 1;
var eyePosition = [ 0, 0, 2 ];

// event handlers for mouse input (borrowed from "Learning WebGL" lesson 11)
var mouseDown = false;
var lastMouseX = null;
var lastMouseY = null;

var moonRotationMatrix = mat4();

function handleMouseDown(event) {
	mouseDown = true;
	lastMouseX = event.clientX;
	lastMouseY = event.clientY;
}

function handleMouseUp(event) {
	mouseDown = false;
}

function handleMouseMove(event) {
	if (!mouseDown) return;

    var newX = event.clientX;
    var newY = event.clientY;
    var deltaX = newX - lastMouseX;
    var newRotationMatrix = rotate(deltaX/10, 0, 1, 0);

    var deltaY = newY - lastMouseY;
    newRotationMatrix = mult(rotate(deltaY/10, 1, 0, 0), newRotationMatrix);

    moonRotationMatrix = mult(newRotationMatrix, moonRotationMatrix);

    lastMouseX = newX
    lastMouseY = newY;
}

// event handlers for button clicks
function rotateX() {
	paused = 0;
    axis = xAxis;
	theta[yAxis] = 0;
    theta[zAxis] = 0;
};
function rotateY() {
	paused = 0;
	axis = yAxis;
	theta[xAxis] = 192.0;
    theta[zAxis] = 640.0;
};

// ModelView and Projection matrices
var modelingLoc, viewingLoc, projectionLoc, lightMatrixLoc;
var modeling, viewing, projection;

var volumeLoc;

var numVertices  = 36;

var pointsArray = [];
var colorsArray = [];
var normalsArray = [];
var texCoordsArray = [];

var texture;

var texCoord = [
    vec2(0, 2),
    vec2(0, 0),
    vec2(1, 0),
    vec2(1, 2)
];

var vertices = [
	vec4( -0.5, -0.5,  0.5, 1 ),
	vec4( -0.5,  0.5,  0.5, 1 ),
	vec4(  0.5,  0.5,  0.5, 1 ),
	vec4(  0.5, -0.5,  0.5, 1 ),
	vec4( -0.5, -0.5, -0.5, 1 ),
	vec4( -0.5,  0.5, -0.5, 1 ),
	vec4(  0.5,  0.5, -0.5, 1 ),
	vec4(  0.5, -0.5, -0.5, 1 )
];

// Using off-white cube for testing
var vertexColors = [
	vec4( 0.80, 0.86, 0.22, 1.0 ),
	vec4( 0.13, 0.59, 0.95, 1.0 ),
	vec4( 0.13, 0.59, 0.95, 1.0 ),
	vec4( 0.80, 0.86, 0.22, 1.0 ),
	vec4( 0.61, 0.15, 0.69, 1.0 ),
	vec4( 1.00, 0.92, 0.23, 1.0 ),
	vec4( 1.00, 0.92, 0.23, 1.0 ),
	vec4( 0.61, 0.15, 0.69, 1.0 )
];

var lightPosition = vec4( 0.0, 100.0, 200.0, 1.0 );

var materialAmbient = vec4( 0.25, 0.25, 0.25, 1.0 );
var materialDiffuse = vec4( 0.8, 0.8, 0.8, 1.0);
var materialSpecular = vec4( 10.0, 0.0, 0.0, 1.0 );
var materialShininess = 12.0;

function configureTexture( image ) {
    texture = gl.createTexture();
    gl.bindTexture( gl.TEXTURE_2D, texture );
    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
    gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image );
    gl.generateMipmap( gl.TEXTURE_2D );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR );
    gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );

    gl.uniform1i(gl.getUniformLocation(program, "texture"), 0);
}

function quad(a, b, c, d) {

     var t1 = subtract(vertices[b], vertices[a]);
     var t2 = subtract(vertices[c], vertices[b]);
     var normal = cross(t1, t2);  // cross returns vec3
     var normal = vec4(normal);
     normal = normalize(normal);

	pointsArray.push(vertices[a]);
	colorsArray.push(vertexColors[a]);
	normalsArray.push(normal);
	texCoordsArray.push(texCoord[0]);

	pointsArray.push(vertices[b]);
	colorsArray.push(vertexColors[b]);
	normalsArray.push(normal);
	texCoordsArray.push(texCoord[1]);

	pointsArray.push(vertices[c]);
	colorsArray.push(vertexColors[c]);
	normalsArray.push(normal);
	texCoordsArray.push(texCoord[2]);

	pointsArray.push(vertices[a]);
	colorsArray.push(vertexColors[a]);
	normalsArray.push(normal);
	texCoordsArray.push(texCoord[0]);

	pointsArray.push(vertices[c]);
	colorsArray.push(vertexColors[c]);
	normalsArray.push(normal);
	texCoordsArray.push(texCoord[2]);

	pointsArray.push(vertices[d]);
	colorsArray.push(vertexColors[d]);
	normalsArray.push(normal);
	texCoordsArray.push(texCoord[3]);
}

function colorCube()
{
    quad( 1, 0, 3, 2 );
    quad( 2, 3, 7, 6 );
    quad( 3, 0, 4, 7 );
    quad( 6, 5, 1, 2 );
    quad( 4, 5, 6, 7 );
    quad( 5, 4, 0, 1 );
}

var analyser;
var frequencyData = new Uint8Array();

window.onload = function init()
{
    var canvas = document.getElementById( "gl-canvas" );

    gl = WebGLUtils.setupWebGL( canvas );
    if ( !gl ) alert( "WebGL isn't available" );

 //=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
 // Experimenting with HTML5 audio

  var context = new AudioContext();
  var audio = document.getElementById('myAudio');
  var audioSrc = context.createMediaElementSource(audio);
  var sourceJs = context.createScriptProcessor(2048); // createJavaScriptNode() deprecated.

  analyser = context.createAnalyser();

  // we could configure the analyser: e.g. analyser.fftSize (for further infos read the spec)
    analyser.smoothingTimeConstant = 0.6;
	analyser.fftSize = 512;

  // we have to connect the MediaElementSource with the analyser
	audioSrc.connect(analyser);
	analyser.connect(sourceJs);
	sourceJs.buffer = audioSrc.buffer;
	sourceJs.connect(context.destination);
	audioSrc.connect(context.destination);

 	sourceJs.onaudioprocess = function(e) {
		// frequencyBinCount tells you how many values you'll receive from the analyser
		frequencyData = new Uint8Array(analyser.frequencyBinCount);
		analyser.getByteFrequencyData(frequencyData);
	};

  //audio.play();
//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

	//
    //  Configure WebGL
    //
    gl.viewport( 0, 0, canvas.width, canvas.height );
    gl.clearColor( 0.93, 0.93, 0.93, 1.0 );

    //  Load shaders and initialize attribute buffers

    program = initShaders( gl, "vertex-shader", "fragment-shader" );
    gl.useProgram( program );

	// Generate pointsArray[], colorsArray[] and normalsArray[] from vertices[] and vertexColors[].
	// We don't use indices and ELEMENT_ARRAY_BUFFER (as in previous example)
	// because we need to assign different face normals to shared vertices.
	colorCube();

    // vertex array attribute buffer

    var vBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );

    var vPosition = gl.getAttribLocation( program, "vPosition" );
    gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vPosition );

    // color array atrribute buffer

    var cBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );

    var vColor = gl.getAttribLocation( program, "vColor" );
    gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vColor );

    // normal array atrribute buffer

    var nBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, nBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(normalsArray), gl.STATIC_DRAW );

    var vNormal = gl.getAttribLocation( program, "vNormal" );
    gl.vertexAttribPointer( vNormal, 4, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vNormal );

    // texture-coordinate array atrribute buffer
	/*
    var tBuffer = gl.createBuffer();
    gl.bindBuffer( gl.ARRAY_BUFFER, tBuffer );
    gl.bufferData( gl.ARRAY_BUFFER, flatten(texCoordsArray), gl.STATIC_DRAW );

    var vTexCoord = gl.getAttribLocation( program, "vTexCoord" );
    gl.vertexAttribPointer( vTexCoord, 2, gl.FLOAT, false, 0, 0 );
    gl.enableVertexAttribArray( vTexCoord );
*/
    //
    // Initialize a texture
    //
    //var image = new Image();
    //image.onload = function() {
    //	configureTexture( image );
    //}
    //image.src = "bump.jpg";

	// uniform variables in shaders
    modelingLoc   = gl.getUniformLocation(program, "modelingMatrix");
    viewingLoc    = gl.getUniformLocation(program, "viewingMatrix");
    projectionLoc = gl.getUniformLocation(program, "projectionMatrix");
    lightMatrixLoc= gl.getUniformLocation(program, "lightMatrix");

	volumeLoc = gl.getUniformLocation(program, "volume");

    gl.uniform4fv( gl.getUniformLocation(program, "lightPosition"),
       flatten(lightPosition) );
    gl.uniform4fv( gl.getUniformLocation(program, "materialAmbient"),
       flatten(materialAmbient));
    gl.uniform4fv( gl.getUniformLocation(program, "materialDiffuse"),
       flatten(materialDiffuse) );
    gl.uniform4fv( gl.getUniformLocation(program, "materialSpecular"),
       flatten(materialSpecular) );
    gl.uniform1f( gl.getUniformLocation(program, "shininess"), materialShininess);

    //event listeners for buttons
    document.getElementById( "xButton" ).onclick = rotateX;
    document.getElementById( "yButton" ).onclick = rotateY;
    document.getElementById( "pButton" ).onclick = function() {paused=!paused;};

	// event handlers for mouse input (borrowed from "Learning WebGL" lesson 11)
	canvas.onmousedown = handleMouseDown;
    document.onmouseup = handleMouseUp;
    document.onmousemove = handleMouseMove;

    render();
};

function render() {
	modeling = mult(rotate(theta[xAxis], 1, 0, 0),
	                mult(rotate(theta[yAxis], 0, 1, 0),rotate(theta[zAxis], 0, 0, 1)));

	viewing = lookAt(eyePosition, [0,0,0], [0,1,0]);

	projection = perspective(45, 1.0, 1.0, 3.0);

    gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );

    if (! paused) theta[axis] += 2.0;
	depthTest?
		gl.enable(gl.DEPTH_TEST) :
		gl.disable(gl.DEPTH_TEST);

    gl.uniformMatrix4fv( viewingLoc,    0, flatten(viewing) );
	gl.uniformMatrix4fv( projectionLoc, 0, flatten(projection) );
	gl.uniformMatrix4fv( lightMatrixLoc,0, flatten(moonRotationMatrix) );

	// update data in frequencyData
    analyser.getByteFrequencyData(frequencyData);

	var N2 = 2*N+1;
	var step = 1.5/N2;
	var size = step * 0.3;

	for (i=-N; i<=N; i++) {
		// render frame based on values in frequencyData
		gl.uniform1f( volumeLoc, frequencyData[Math.floor(256/N2)*(i+N)] /275 * N + N*3/4 );

		for (j=-0; j<=0; j++)
			for (k=-0; k<=0; k++) {
//				var cloned = mult(mult(translate(step*i, step*j, step*k), scale(0.12, 0.12, 0.12)), modeling);
				var cloned = mult(modeling, mult(translate(step*i, step*j, step*k), scale(size, size, size)));
				cloned = mult(cloned , rotate(180/N*(i+N),1,0,0));
				gl.uniformMatrix4fv( modelingLoc, 0, flatten(cloned) );
				gl.drawArrays( gl.TRIANGLES, 0, numVertices );
			}
	}

    requestAnimFrame( render );
}
<commit_msg>Use IIFE to get rid of lots of global variables<commit_after>(function() {
	var program;

	var N = 20 ;  // The number of cubes will be (2N+1)^3

	var xAxis = 0;
	var yAxis = 1;
	var zAxis = 2;

	var axis = 0;
	var theta = [ 0, 0, 0 ];
	var paused = 0;
	var depthTest = 1;
	var eyePosition = [ 0, 0, 2 ];

	// event handlers for mouse input (borrowed from "Learning WebGL" lesson 11)
	var mouseDown = false;
	var lastMouseX = null;
	var lastMouseY = null;

	var moonRotationMatrix = mat4();

	function handleMouseDown(event) {
		mouseDown = true;
		lastMouseX = event.clientX;
		lastMouseY = event.clientY;
	}

	function handleMouseUp(event) {
		mouseDown = false;
	}

	function handleMouseMove(event) {
		if (!mouseDown) return;

		var newX = event.clientX;
		var newY = event.clientY;
		var deltaX = newX - lastMouseX;
		var newRotationMatrix = rotate(deltaX/10, 0, 1, 0);

		var deltaY = newY - lastMouseY;
		newRotationMatrix = mult(rotate(deltaY/10, 1, 0, 0), newRotationMatrix);

		moonRotationMatrix = mult(newRotationMatrix, moonRotationMatrix);

		lastMouseX = newX
		lastMouseY = newY;
	}

	// event handlers for button clicks
	function rotateX() {
		paused = 0;
		axis = xAxis;
		theta[yAxis] = 0;
		theta[zAxis] = 0;
	};
	function rotateY() {
		paused = 0;
		axis = yAxis;
		theta[xAxis] = 192.0;
		theta[zAxis] = 640.0;
	};

	// ModelView and Projection matrices
	var modelingLoc, viewingLoc, projectionLoc, lightMatrixLoc;
	var modeling, viewing, projection;

	var volumeLoc;

	var numVertices  = 36;

	var pointsArray = [];
	var colorsArray = [];
	var normalsArray = [];
	var texCoordsArray = [];

	var texture;

	var texCoord = [
		vec2(0, 2),
		vec2(0, 0),
		vec2(1, 0),
		vec2(1, 2)
	];

	var vertices = [
		vec4( -0.5, -0.5,  0.5, 1 ),
		vec4( -0.5,  0.5,  0.5, 1 ),
		vec4(  0.5,  0.5,  0.5, 1 ),
		vec4(  0.5, -0.5,  0.5, 1 ),
		vec4( -0.5, -0.5, -0.5, 1 ),
		vec4( -0.5,  0.5, -0.5, 1 ),
		vec4(  0.5,  0.5, -0.5, 1 ),
		vec4(  0.5, -0.5, -0.5, 1 )
	];

	// COLOR of EACH VERTEX of DNA
	var vertexColors = [
		vec4( 0.95, 0.26, 0.21, 1.0 ),	// RED
		vec4( 0.13, 0.59, 0.95, 1.0 ),	// BLUE
		vec4( 0.13, 0.59, 0.95, 1.0 ),	// BLUE
		vec4( 0.95, 0.26, 0.21, 1.0 ),	// RED
		vec4( 0.61, 0.15, 0.69, 1.0 ),	// PURPLE
		vec4( 1.00, 0.92, 0.23, 1.0 ),	// YELLOW
		vec4( 1.00, 0.92, 0.23, 1.0 ),	// YELLOW
		vec4( 0.61, 0.15, 0.69, 1.0 )	// PURPLE
	];

	var lightPosition = vec4( 0.0, 100.0, 200.0, 1.0 );

	var materialAmbient = vec4( 0.25, 0.25, 0.25, 1.0 );
	var materialDiffuse = vec4( 0.8, 0.8, 0.8, 1.0);
	var materialSpecular = vec4( 10.0, 0.0, 0.0, 1.0 );
	var materialShininess = 12.0;

	function configureTexture( image ) {
		texture = gl.createTexture();
		gl.bindTexture( gl.TEXTURE_2D, texture );
		gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
		gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image );
		gl.generateMipmap( gl.TEXTURE_2D );
		gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR );
		gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST );

		gl.uniform1i(gl.getUniformLocation(program, "texture"), 0);
	}

	function quad(a, b, c, d) {

		var t1 = subtract(vertices[b], vertices[a]);
		var t2 = subtract(vertices[c], vertices[b]);
		var normal = cross(t1, t2);  // cross returns vec3
		var normal = vec4(normal);
		normal = normalize(normal);

		pointsArray.push(vertices[a]);
		colorsArray.push(vertexColors[a]);
		normalsArray.push(normal);
		texCoordsArray.push(texCoord[0]);

		pointsArray.push(vertices[b]);
		colorsArray.push(vertexColors[b]);
		normalsArray.push(normal);
		texCoordsArray.push(texCoord[1]);

		pointsArray.push(vertices[c]);
		colorsArray.push(vertexColors[c]);
		normalsArray.push(normal);
		texCoordsArray.push(texCoord[2]);

		pointsArray.push(vertices[a]);
		colorsArray.push(vertexColors[a]);
		normalsArray.push(normal);
		texCoordsArray.push(texCoord[0]);

		pointsArray.push(vertices[c]);
		colorsArray.push(vertexColors[c]);
		normalsArray.push(normal);
		texCoordsArray.push(texCoord[2]);

		pointsArray.push(vertices[d]);
		colorsArray.push(vertexColors[d]);
		normalsArray.push(normal);
		texCoordsArray.push(texCoord[3]);
	}

	function colorCube()
	{
		quad( 1, 0, 3, 2 );
		quad( 2, 3, 7, 6 );
		quad( 3, 0, 4, 7 );
		quad( 6, 5, 1, 2 );
		quad( 4, 5, 6, 7 );
		quad( 5, 4, 0, 1 );
	}

	var analyser;
	var frequencyData = new Uint8Array();

	window.onload = function init()
	{
		var canvas = document.getElementById( "gl-canvas" );

		gl = WebGLUtils.setupWebGL( canvas );
		if ( !gl ) alert( "WebGL isn't available" );

		//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
		// Experimenting with HTML5 audio

		var context = new AudioContext();
		var audio = document.getElementById('myAudio');
		var audioSrc = context.createMediaElementSource(audio);
		var sourceJs = context.createScriptProcessor(2048); // createJavaScriptNode() deprecated.

		analyser = context.createAnalyser();

		// we could configure the analyser: e.g. analyser.fftSize (for further infos read the spec)
		analyser.smoothingTimeConstant = 0.6;
		analyser.fftSize = 512;

		// we have to connect the MediaElementSource with the analyser
		audioSrc.connect(analyser);
		analyser.connect(sourceJs);
		sourceJs.buffer = audioSrc.buffer;
		sourceJs.connect(context.destination);
		audioSrc.connect(context.destination);

		sourceJs.onaudioprocess = function(e) {
			// frequencyBinCount tells you how many values you'll receive from the analyser
			frequencyData = new Uint8Array(analyser.frequencyBinCount);
			analyser.getByteFrequencyData(frequencyData);
		};

		//audio.play();
		//=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

		//
		//  Configure WebGL
		//
		gl.viewport( 0, 0, canvas.width, canvas.height );
		gl.clearColor( 0.93, 0.93, 0.93, 1.0 );					// BACKGROUND COLOR

		//  Load shaders and initialize attribute buffers

		program = initShaders( gl, "vertex-shader", "fragment-shader" );
		gl.useProgram( program );

		// Generate pointsArray[], colorsArray[] and normalsArray[] from vertices[] and vertexColors[].
		// We don't use indices and ELEMENT_ARRAY_BUFFER (as in previous example)
		// because we need to assign different face normals to shared vertices.
		colorCube();

		// vertex array attribute buffer

		var vBuffer = gl.createBuffer();
		gl.bindBuffer( gl.ARRAY_BUFFER, vBuffer );
		gl.bufferData( gl.ARRAY_BUFFER, flatten(pointsArray), gl.STATIC_DRAW );

		var vPosition = gl.getAttribLocation( program, "vPosition" );
		gl.vertexAttribPointer( vPosition, 4, gl.FLOAT, false, 0, 0 );
		gl.enableVertexAttribArray( vPosition );

		// color array atrribute buffer

		var cBuffer = gl.createBuffer();
		gl.bindBuffer( gl.ARRAY_BUFFER, cBuffer );
		gl.bufferData( gl.ARRAY_BUFFER, flatten(colorsArray), gl.STATIC_DRAW );

		var vColor = gl.getAttribLocation( program, "vColor" );
		gl.vertexAttribPointer( vColor, 4, gl.FLOAT, false, 0, 0 );
		gl.enableVertexAttribArray( vColor );

		// normal array atrribute buffer

		var nBuffer = gl.createBuffer();
		gl.bindBuffer( gl.ARRAY_BUFFER, nBuffer );
		gl.bufferData( gl.ARRAY_BUFFER, flatten(normalsArray), gl.STATIC_DRAW );

		var vNormal = gl.getAttribLocation( program, "vNormal" );
		gl.vertexAttribPointer( vNormal, 4, gl.FLOAT, false, 0, 0 );
		gl.enableVertexAttribArray( vNormal );

		modelingLoc   = gl.getUniformLocation(program, "modelingMatrix");
		viewingLoc    = gl.getUniformLocation(program, "viewingMatrix");
		projectionLoc = gl.getUniformLocation(program, "projectionMatrix");
		lightMatrixLoc= gl.getUniformLocation(program, "lightMatrix");

		volumeLoc = gl.getUniformLocation(program, "volume");

		gl.uniform4fv( gl.getUniformLocation(program, "lightPosition"),
		   flatten(lightPosition) );
		gl.uniform4fv( gl.getUniformLocation(program, "materialAmbient"),
		   flatten(materialAmbient));
		gl.uniform4fv( gl.getUniformLocation(program, "materialDiffuse"),
		   flatten(materialDiffuse) );
		gl.uniform4fv( gl.getUniformLocation(program, "materialSpecular"),
		   flatten(materialSpecular) );
		gl.uniform1f( gl.getUniformLocation(program, "shininess"), materialShininess);

		//event listeners for buttons
		document.getElementById( "xButton" ).onclick = rotateX;
		document.getElementById( "yButton" ).onclick = rotateY;
		document.getElementById( "pButton" ).onclick = function() {paused=!paused;};

		// event handlers for mouse input (borrowed from "Learning WebGL" lesson 11)
		canvas.onmousedown = handleMouseDown;
		document.onmouseup = handleMouseUp;
		document.onmousemove = handleMouseMove;

		render();
	};

	function render() {
		modeling = mult(rotate(theta[xAxis], 1, 0, 0), mult(rotate(theta[yAxis], 0, 1, 0),rotate(theta[zAxis], 0, 0, 1)));

		viewing = lookAt(eyePosition, [0,0,0], [0,1,0]);

		projection = perspective(45, 1.0, 1.0, 3.0);

		gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );

		if (! paused) theta[axis] += 2.0;
		depthTest?
			gl.enable(gl.DEPTH_TEST) :
			gl.disable(gl.DEPTH_TEST);

		gl.uniformMatrix4fv( viewingLoc,    0, flatten(viewing) );
		gl.uniformMatrix4fv( projectionLoc, 0, flatten(projection) );
		gl.uniformMatrix4fv( lightMatrixLoc,0, flatten(moonRotationMatrix) );

		// update data in frequencyData
		analyser.getByteFrequencyData(frequencyData);

		var N2 = 2*N+1;
		var step = 1.5/N2;
		var size = step * 0.3;

		for (i=-N; i<=N; i++) {
			// render frame based on values in frequencyData
			gl.uniform1f( volumeLoc, frequencyData[Math.floor(256/N2)*(i+N)] /275 * N + N*3/4 );

			for (j=-0; j<=0; j++)
				for (k=-0; k<=0; k++) {
	//				var cloned = mult(mult(translate(step*i, step*j, step*k), scale(0.12, 0.12, 0.12)), modeling);
					var cloned = mult(modeling, mult(translate(step*i, step*j, step*k), scale(size, size, size)));
					cloned = mult(cloned , rotate(180/N*(i+N),1,0,0));
					gl.uniformMatrix4fv( modelingLoc, 0, flatten(cloned) );
					gl.drawArrays( gl.TRIANGLES, 0, numVertices );
				}
		}

		requestAnimFrame( render );
	}
})();
<|endoftext|>


<commit_before>// doT.js
// 2011, Laura Doktorova, https://github.com/olado/doT
// Licensed under the MIT license.

(function() {
	"use strict";

	var doT = {
		version: '1.0.1',
		templateSettings: {
			evaluate:    /\{\{([\s\S]+?(\}?)+)\}\}/g,
			interpolate: /\{\{=([\s\S]+?)\}\}/g,
			encode:      /\{\{!([\s\S]+?)\}\}/g,
			use:         /\{\{#([\s\S]+?)\}\}/g,
			useParams:   /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
			define:      /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
			defineParams:/^\s*([\w$]+):([\s\S]+)/,
			conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
			iterate:     /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
			varname:	'it',
			strip:		true,
			append:		true,
			selfcontained: false
		},
		template: undefined, //fn, compile template
		compile:  undefined  //fn, for express
	}, global;

	if (typeof module !== 'undefined' && module.exports) {
		module.exports = doT;
	} else if (typeof define === 'function' && define.amd) {
		define(function(){return doT;});
	} else {
		global = (function(){ return this || (0,eval)('this'); }());
		global.doT = doT;
	}

	function encodeHTMLSource() {
		var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' },
			matchHTML = /&(?!#?\w+;)|<|>|"|'|\//g;
		return function() {
			return this ? this.replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : this;
		};
	}
	String.prototype.encodeHTML = encodeHTMLSource();

	var startend = {
		append: { start: "'+(",      end: ")+'",      endencode: "||'').toString().encodeHTML()+'" },
		split:  { start: "';out+=(", end: ");out+='", endencode: "||'').toString().encodeHTML();out+='"}
	}, skip = /$^/;

	function resolveDefs(c, block, def) {
		return ((typeof block === 'string') ? block : block.toString())
		.replace(c.define || skip, function(m, code, assign, value) {
			if (code.indexOf('def.') === 0) {
				code = code.substring(4);
			}
			if (!(code in def)) {
				if (assign === ':') {
					if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
						def[code] = {arg: param, text: v};
					});
					if (!(code in def)) def[code]= value;
				} else {
					new Function("def", "def['"+code+"']=" + value)(def);
				}
			}
			return '';
		})
		.replace(c.use || skip, function(m, code) {
			if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
				if (def[d] && def[d].arg && param) {
					var rw = (d+":"+param).replace(/'|\\/g, '_');
					def.__exp = def.__exp || {};
					def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
					return s + "def.__exp['"+rw+"']";
				}
			});
			var v = new Function("def", "return " + code)(def);
			return v ? resolveDefs(c, v, def) : v;
		});
	}

	function unescape(code) {
		return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, ' ');
	}

	doT.template = function(tmpl, c, def) {
		c = c || doT.templateSettings;
		var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
			str  = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;

		str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g,' ')
					.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,''): str)
			.replace(/'|\\/g, '\\$&')
			.replace(c.interpolate || skip, function(m, code) {
				return cse.start + unescape(code) + cse.end;
			})
			.replace(c.encode || skip, function(m, code) {
				needhtmlencode = true;
				return cse.start + unescape(code) + cse.endencode;
			})
			.replace(c.conditional || skip, function(m, elsecase, code) {
				return elsecase ?
					(code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
					(code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
			})
			.replace(c.iterate || skip, function(m, iterate, vname, iname) {
				if (!iterate) return "';} } out+='";
				sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
				return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
					+vname+"=arr"+sid+"["+indv+"+=1];out+='";
			})
			.replace(c.evaluate || skip, function(m, code) {
				return "';" + unescape(code) + "out+='";
			})
			+ "';return out;")
			.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r')
			.replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, '')
			.replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+=');

		if (needhtmlencode && c.selfcontained) {
			str = "String.prototype.encodeHTML=(" + encodeHTMLSource.toString() + "());" + str;
		}
		try {
			return new Function(c.varname, str);
		} catch (e) {
			if (typeof console !== 'undefined') console.log("Could not create a template function: " + str);
			throw e;
		}
	};

	doT.compile = function(tmpl, def) {
		return doT.template(tmpl, null, def);
	};
}());
<commit_msg>modify startend.startencode and startend.endencode (doT.js:48) modify doT.js:101 to avoid global prototype pollution.<commit_after>// doT.js
// 2011, Laura Doktorova, https://github.com/olado/doT
// Licensed under the MIT license.

(function() {
	"use strict";

	var doT = {
		version: '1.0.1',
		templateSettings: {
			evaluate:    /\{\{([\s\S]+?(\}?)+)\}\}/g,
			interpolate: /\{\{=([\s\S]+?)\}\}/g,
			encode:      /\{\{!([\s\S]+?)\}\}/g,
			use:         /\{\{#([\s\S]+?)\}\}/g,
			useParams:   /(^|[^\w$])def(?:\.|\[[\'\"])([\w$\.]+)(?:[\'\"]\])?\s*\:\s*([\w$\.]+|\"[^\"]+\"|\'[^\']+\'|\{[^\}]+\})/g,
			define:      /\{\{##\s*([\w\.$]+)\s*(\:|=)([\s\S]+?)#\}\}/g,
			defineParams:/^\s*([\w$]+):([\s\S]+)/,
			conditional: /\{\{\?(\?)?\s*([\s\S]*?)\s*\}\}/g,
			iterate:     /\{\{~\s*(?:\}\}|([\s\S]+?)\s*\:\s*([\w$]+)\s*(?:\:\s*([\w$]+))?\s*\}\})/g,
			varname:	'it',
			strip:		true,
			append:		true,
			selfcontained: false
		},
		template: undefined, //fn, compile template
		compile:  undefined  //fn, for express
	}, global;

	if (typeof module !== 'undefined' && module.exports) {
		module.exports = doT;
	} else if (typeof define === 'function' && define.amd) {
		define(function(){return doT;});
	} else {
		global = (function(){ return this || (0,eval)('this'); }());
		global.doT = doT;
	}

	function encodeHTMLSource() {
		var encodeHTMLRules = { "&": "&", "<": "<", ">": ">", '"': '"', "'": ''', "/": '/' },
			matchHTML = /&(?!#?\w+;)|<|>|"|'|\//g;
		return function() {
			return this ? this.replace(matchHTML, function(m) {return encodeHTMLRules[m] || m;}) : this;
		};
	}
	String.prototype.encodeHTML = encodeHTMLSource();

	var startend = {
		append: { start: "'+(",      end: ")+'",      startencode:"'+encodeHTML(",      endencode: ")+'" },
		split:  { start: "';out+=(", end: ");out+='", startencode:"';out+=encodeHTML(", endencode: ");out+='"}
	}, skip = /$^/;

	function resolveDefs(c, block, def) {
		return ((typeof block === 'string') ? block : block.toString())
		.replace(c.define || skip, function(m, code, assign, value) {
			if (code.indexOf('def.') === 0) {
				code = code.substring(4);
			}
			if (!(code in def)) {
				if (assign === ':') {
					if (c.defineParams) value.replace(c.defineParams, function(m, param, v) {
						def[code] = {arg: param, text: v};
					});
					if (!(code in def)) def[code]= value;
				} else {
					new Function("def", "def['"+code+"']=" + value)(def);
				}
			}
			return '';
		})
		.replace(c.use || skip, function(m, code) {
			if (c.useParams) code = code.replace(c.useParams, function(m, s, d, param) {
				if (def[d] && def[d].arg && param) {
					var rw = (d+":"+param).replace(/'|\\/g, '_');
					def.__exp = def.__exp || {};
					def.__exp[rw] = def[d].text.replace(new RegExp("(^|[^\\w$])" + def[d].arg + "([^\\w$])", "g"), "$1" + param + "$2");
					return s + "def.__exp['"+rw+"']";
				}
			});
			var v = new Function("def", "return " + code)(def);
			return v ? resolveDefs(c, v, def) : v;
		});
	}

	function unescape(code) {
		return code.replace(/\\('|\\)/g, "$1").replace(/[\r\t\n]/g, ' ');
	}

	doT.template = function(tmpl, c, def) {
		c = c || doT.templateSettings;
		var cse = c.append ? startend.append : startend.split, needhtmlencode, sid = 0, indv,
			str  = (c.use || c.define) ? resolveDefs(c, tmpl, def || {}) : tmpl;

		str = ("var out='" + (c.strip ? str.replace(/(^|\r|\n)\t* +| +\t*(\r|\n|$)/g,' ')
					.replace(/\r|\n|\t|\/\*[\s\S]*?\*\//g,''): str)
			.replace(/'|\\/g, '\\$&')
			.replace(c.interpolate || skip, function(m, code) {
				return cse.start + unescape(code) + cse.end;
			})
			.replace(c.encode || skip, function(m, code) {
				needhtmlencode = true;
				return cse.startencode + unescape(code) + cse.endencode;
			})
			.replace(c.conditional || skip, function(m, elsecase, code) {
				return elsecase ?
					(code ? "';}else if(" + unescape(code) + "){out+='" : "';}else{out+='") :
					(code ? "';if(" + unescape(code) + "){out+='" : "';}out+='");
			})
			.replace(c.iterate || skip, function(m, iterate, vname, iname) {
				if (!iterate) return "';} } out+='";
				sid+=1; indv=iname || "i"+sid; iterate=unescape(iterate);
				return "';var arr"+sid+"="+iterate+";if(arr"+sid+"){var "+vname+","+indv+"=-1,l"+sid+"=arr"+sid+".length-1;while("+indv+"<l"+sid+"){"
					+vname+"=arr"+sid+"["+indv+"+=1];out+='";
			})
			.replace(c.evaluate || skip, function(m, code) {
				return "';" + unescape(code) + "out+='";
			})
			+ "';return out;")
			.replace(/\n/g, '\\n').replace(/\t/g, '\\t').replace(/\r/g, '\\r')
			.replace(/(\s|;|\}|^|\{)out\+='';/g, '$1').replace(/\+''/g, '')
			.replace(/(\s|;|\}|^|\{)out\+=''\+/g,'$1out+=');

		if (needhtmlencode && c.selfcontained) {
			str = "String.prototype.encodeHTML=(" + encodeHTMLSource.toString() + "());" + str;
		}
		try {
			return new Function(c.varname, str);
		} catch (e) {
			if (typeof console !== 'undefined') console.log("Could not create a template function: " + str);
			throw e;
		}
	};

	doT.compile = function(tmpl, def) {
		return doT.template(tmpl, null, def);
	};
}());
<|endoftext|>


<commit_before>var fs = require('fs-extra');
var winston = require('winston');

exports.update = function (commitInfo, sourceFolder, callback) {
    var name = commitInfo.repository.name;
    var branch = commitInfo.ref.split('/').pop() === 'master' ? 'master' : 'dev';
    // TODO: 用环境变量
    var docFolder = require('path').join('/', 'var', 'www', 'doc', name, branch);
    if (!fs.existsSync(docFolder)) {
        winston.log('Document site folder "' + docFolder + '" does not exit, create it');
        try {
            fs.mkdirpSync(docFolder);
            winston.log('Create dir "' + docFolder + '"');
        }
        catch (err) {
            callback(err);
        }
    }

    winston.info('Remove old documents');
    fs.remove(
        docFolder,
        function (err) {
            if (err) {
                return callback(err);
            }

            winston.info('Move new documents to site folder "' + docFolder + '"');
            fs.rename(sourceFolder, docFolder, function (err) {
                if (err) {
                    console.error('Failed to move document to site folder: ' + err);
                    console.log('Remove generated documents due to failure');
                    return fs.remove(sourceFolder, callback);
                }

                callback(err);
            });
        }
    );
};
<commit_msg>修改生成路径<commit_after>var fs = require('fs-extra');
var winston = require('winston');

exports.update = function (commitInfo, sourceFolder, callback) {
    var name = commitInfo.repository.name;
    var branch = commitInfo.ref.split('/').pop() === 'master' ? 'stable' : 'dev';
    // TODO: 用环境变量
    var docFolder = require('path').join('/', 'var', 'www', 'doc', name, branch);
    if (!fs.existsSync(docFolder)) {
        winston.log('Document site folder "' + docFolder + '" does not exit, create it');
        try {
            fs.mkdirpSync(docFolder);
            winston.log('Create dir "' + docFolder + '"');
        }
        catch (err) {
            callback(err);
        }
    }

    winston.info('Remove old documents');
    fs.remove(
        docFolder,
        function (err) {
            if (err) {
                return callback(err);
            }

            winston.info('Move new documents to site folder "' + docFolder + '"');
            fs.rename(sourceFolder, docFolder, function (err) {
                if (err) {
                    console.error('Failed to move document to site folder: ' + err);
                    console.log('Remove generated documents due to failure');
                    return fs.remove(sourceFolder, callback);
                }

                callback(err);
            });
        }
    );
};
<|endoftext|>


<commit_before>/* ex: set tabstop=2 softtabstop=2 shiftwidth=2 : */
/*jshint unused:false, boss:true */
/*global DOMTokenList:true, features:true */

/**
 * @description
 * shorthand for getElementById
 * @param el
 */
function ___(el) {
  return document.getElementById(el);
}

/**
 * @name elementHasClass
 * @function
 *
 * @description
 *
 * @param element
 * @param _className
 */
function elementHasClass(el, _className) {
  // has to do this check first because if _className is not present
  // and el is absence as well, it should not return true
  if (!el) {
    throw new Error("elementHasClass failed becase element is undefined");
  }
  if (!_className) {
    return true;
  }
  if (!el.className) {
    return false;
  }

  // so that we do not have to make special case for the 1st / last item
  return (new RegExp("\\b" + _className + "\\b").test(el.className));
}

/**
 * @name elementCanBeDescribedAs
 * @function
 *
 * @description
 *
 * support 4 selectors:
 * 1.  #id
 * 2.  .className
 * 3.  tagName
 * 4.  tagName.className
 *
 * @param el
 * @param selector
 */
function elementFitsDescription(el, selector) {
  if (!selector) {
    return false;
  }
  if (!el) {
    return false;
  }

  var _tagName, _className, pos;

  switch (selector.charAt(0)) {
  case "#" :
    if ("#" + el.id === selector) {
      return el;
    }
    break;
  case "." :
    // so we do not have to consider whether the className is the first or the last
    if (elementHasClass(el, selector.substring(1))) {
      return el;
    }
    break;
  default :
    pos = selector.indexOf(".");
    // tagName.className
    // now we know that "." will not be the leading character
    if (~pos) {
      _tagName = selector;
      _className = _tagName.splice(0, pos).substring(1);
      if ((el.tagName.toLowerCase() === _tagName) && elementHasClass(el, _className)) {
        return el;
      }
    }
    // tagName
    else {
      // apparently `#' will not be at 0
      if (selector.indexOf("#") > 0) {
        throw new Error(selector + "not supported, use #id instead.");
      }
      else {
        if (el.tagName.toLowerCase() === selector) {
          return el;
        }
      }
    }
    // end of default branch
  }
  return null;
}

/**
 * @name manipulateClass
 * @function
 *
 * @description
 * order of execution:
 * remove then add
 *
 * @param el
 * @param option
 * parameters:
 * {
 *    add   : STRING/ARRAY (must be unique)
 *    remove: STRING/ARRAY (must be unique)
 * }
 */
function manipulateClass(el, option) {
  if (!el || !option || typeof option !== "object") {
    return;
  }

  var toAdd = [], toRemove = [];
  if (option.add) {
    if (typeof option.add === "string") {
      toAdd = option.add.split(/\s+/).unique();
    }
    else if (typeof option.add === "array") {
      toAdd = option.add;
    }
  }
  if (option.remove) {
    if (typeof option.remove === "string") {
      toRemove = option.remove.split(/\s+/).unique();
    }
    if (typeof option.remove === "array") {
      toRemove = option.remove;
    }
  }

  // Firefox has a bug in classList
  // https://bugzilla.mozilla.org/show_bug.cgi?id=826973
  if ("classList" in document.body && "DOMTokenList" in window && !features.firefox) {
    if (toRemove.length) {
      DOMTokenList.prototype.remove.apply(el.classList, toRemove);
    }
    if (toAdd.length) {
      DOMTokenList.prototype.add.apply(el.classList, toAdd);
    }
    return;
  }

  var  _classNameArray, _className = el.className;

  if (!_className) {
    if (option.add) {
      el.className = option.add;
      return;
    }
    // nothing else to do
    return;
  }

  // FIXME: use classList as much as possible
  _classNameArray = _className.split(/\s+/).unique();

  if (option.remove) {
    _classNameArray = _classNameArray.diff(toRemove);
  }
  if (option.add) {
    // in case there is duplicate
    var classToAdd = option.add.split(" ");

    // remove duplicates and join two arraries
    [].push.apply(_classNameArray, toAdd.diff(_classNameArray));
  }
  el.className = _classNameArray.join(" ");
  _classNameArray = null;
  _className = null;
  toAdd = null;
  toRemove = null;
  return;
}

/**
 * @name toggleElement
 * @function
 *
 * @description
 * @param el
 * @param state
 */
function toggleElement(el, state) {
  if (!___(el)) {
    return;
  }
  return ___(el).style.display = state ? state : "none";
}
<commit_msg>fixed Firefox and Opera classList Issue<commit_after>/* ex: set tabstop=2 softtabstop=2 shiftwidth=2 : */
/*jshint unused:false, boss:true */
/*global DOMTokenList:true, features:true */

/**
 * @description
 * shorthand for getElementById
 * @param el
 */
function ___(el) {
  return document.getElementById(el);
}

/**
 * @name elementHasClass
 * @function
 *
 * @description
 *
 * @param element
 * @param _className
 */
function elementHasClass(el, _className) {
  // has to do this check first because if _className is not present
  // and el is absence as well, it should not return true
  if (!el) {
    throw new Error("elementHasClass failed becase element is undefined");
  }
  if (!_className) {
    return true;
  }

  if ("classList" in document.body && "DOMTokenList") {
    return el.classList.contains(_className);
  }

  if (!el.className) {
    return false;
  }
  // so that we do not have to make special case for the 1st / last item
  return (new RegExp("\\b" + _className + "\\b").test(el.className));
}

/**
 * @name elementCanBeDescribedAs
 * @function
 *
 * @description
 *
 * support 4 selectors:
 * 1.  #id
 * 2.  .className
 * 3.  tagName
 * 4.  tagName.className
 *
 * @param el
 * @param selector
 */
function elementFitsDescription(el, selector) {
  if (!selector) {
    return false;
  }
  if (!el) {
    return false;
  }

  var _tagName, _className, pos;

  switch (selector.charAt(0)) {
  case "#" :
    if ("#" + el.id === selector) {
      return el;
    }
    break;
  case "." :
    // so we do not have to consider whether the className is the first or the last
    if (elementHasClass(el, selector.substring(1))) {
      return el;
    }
    break;
  default :
    pos = selector.indexOf(".");
    // tagName.className
    // now we know that "." will not be the leading character
    if (~pos) {
      _tagName = selector;
      _className = _tagName.splice(0, pos).substring(1);
      if ((el.tagName.toLowerCase() === _tagName) && elementHasClass(el, _className)) {
        return el;
      }
    }
    // tagName
    else {
      // apparently `#' will not be at 0
      if (selector.indexOf("#") > 0) {
        throw new Error(selector + "not supported, use #id instead.");
      }
      else {
        if (el.tagName.toLowerCase() === selector) {
          return el;
        }
      }
    }
    // end of default branch
  }
  return null;
}

/**
 * @name manipulateClass
 * @function
 *
 * @description
 * order of execution:
 * remove then add
 *
 * @param el
 * @param option
 * parameters:
 * {
 *    add   : STRING/ARRAY (must be unique)
 *    remove: STRING/ARRAY (must be unique)
 * }
 */
function manipulateClass(el, option) {
  if (!el || !option || typeof option !== "object") {
    return;
  }

  var toAdd = [], toRemove = [];
  if (option.add) {
    if (typeof option.add === "string") {
      toAdd = option.add.split(/\s+/).unique();
    }
    else if (typeof option.add === "array") {
      toAdd = option.add;
    }
  }
  if (option.remove) {
    if (typeof option.remove === "string") {
      toRemove = option.remove.split(/\s+/).unique();
    }
    if (typeof option.remove === "array") {
      toRemove = option.remove;
    }
  }

  // Firefox and Opera has a bug in classList (or should I say feature?)
  // https://bugzilla.mozilla.org/show_bug.cgi?id=826973
  // so we cannot use DOMTokenList.prototype.remove.apply(el.classList, toRemove);
  if ("classList" in document.body && Array.prototype.hasOwnProperty("map")) {
    toRemove.map(function(item) {el.classList.remove(item);});
    toAdd.map(function(item) {el.classList.add(item);});
    return;
  }

  var  _classNameArray, _className = el.className;

  if (!_className) {
    if (option.add) {
      el.className = option.add;
      return;
    }
    // nothing else to do
    return;
  }

  // FIXME: use classList as much as possible
  _classNameArray = _className.split(/\s+/).unique();

  if (option.remove) {
    _classNameArray = _classNameArray.diff(toRemove);
  }
  if (option.add) {
    // in case there is duplicate
    var classToAdd = option.add.split(" ");

    // remove duplicates and join two arraries
    [].push.apply(_classNameArray, toAdd.diff(_classNameArray));
  }
  el.className = _classNameArray.join(" ");
  _classNameArray = null;
  _className = null;
  toAdd = null;
  toRemove = null;
  return;
}

/**
 * @name toggleElement
 * @function
 *
 * @description
 * @param el
 * @param state
 */
function toggleElement(el, state) {
  if (!___(el)) {
    return;
  }
  return ___(el).style.display = state ? state : "none";
}
<|endoftext|>


<commit_before>function view_artifact_ajax_call(asa_token_content, editor){
    var ind_init = asa_token_content.indexOf(":");
    var sub = asa_token_content.substr(ind_init+1, asa_token_content.length);
    var ind_end = sub.indexOf(" ");
    var id = sub.substr(0, ind_end);

    createASAFormDialogFromUrl('View Adaptive Artifact', baseurl+"/artifact/"+id+"?action=view",
        {
            "Edit": function() {
                $(this).dialog("close");
                createASAFormDialogFromUrl('Artifact', baseurl+"/artifact/"+id+"?action=edit",
                    {
                        "Save   ": function() {
                            submitASAFormDialog(
                                $(this),
                                {
                                    success: function(data){
                                        var statesLength = editor.session.bgTokenizer.states.length;
                                        editor.session.bgTokenizer.fireUpdateEvent(0,statesLength);
                                        editor.session.bgTokenizer.start(0);
                                    },
                                    error: function(data){
                                        console.log("Ajax call failed!");
                                    }
                                }
                            )},
                        "Close": function() { $(this).dialog("close"); }
                    }
                ).dialog('open');
            },
            "Close": function() { $(this).dialog("close"); } }
    ).dialog('open');
}

function link_to_existing_artifact_ajax_call(click_callback, value){
    createASAFormDialogFromUrl('Select Adaptive Artifact',  baseurl+"/search/by_filter?",
        [
            {
                id:'button-choose',
                text:'Choose',
                click: function(){
                    click_callback();
                    $(this).dialog("close");
                }
            },
            {
                id:'button-cancel',
                text:'Cancel',
                click: function() { $(this).dialog("close"); }
            }
        ],
        {
            open: function(){
                $("#button-choose").button("disable");

                var selectionUpdated = function(selected){
                    var content_div = $(".artifacts #asa #dialog-content");
                    var asa_div = $(".artifacts #asa");
                    var close_button = $("#button-choose");
                    if (selected.length==0){
                        close_button.button("disabled");
                        content_div.html("").hide();
                        asa_div.addClass('invisible');
                        return;
                    }
                    selected.prop('checked', true);
                    close_button.button("enable");
                    Requests.getArtifactHtml(selected.val(), function(data){
                        content_div.html(data).show();
                        asa_div.removeClass('invisible');
                    });
                };
                $('table.listing tbody tr').click(function() {
                    selectionUpdated($(this).find('td input[type=radio]'));
                });

                var clearRows = function(){
                    $(".artifacts table.listing tbody tr:not(.prototype)").remove();
                };
                var addResultRow = function(id, spec_name, title){
                    var copy = $(".artifacts table.listing tr.prototype").clone(true);
                    copy.removeClass('prototype');
                    copy.find("input[type^='radio']").attr("value", id);
                    copy.find("td")[1].innerText = spec_name;
                    copy.find("td")[2].innerText = title;
                    $(".artifacts table.listing tbody").append(copy);
                };
                var addMessageRow = function(text){
                    var messageRow = $('
' + text + '
');
                    $(".artifacts table.listing tbody").append(messageRow);
                };
                var timer;
                var delayedUpdateResults = function(){
                    clearTimeout(timer);
                    timer = setTimeout(function(){
                        var spec = $('.filter #spec').val();
                        var attr_name = $('.filter #attribute').val();
                        var attr_value = $('.filter #value').val();
                        var attribute = {};
                        attribute[attr_name] = [attr_value];
                        Requests.searchArtifacts(spec, attribute, function(data){
                            clearRows();
                            if(data.length==0){
                                addMessageRow('No results found');
                            }
                            for(var i=0;i<data.length;i++)
                                addResultRow(data[i].id, data[i].spec, data[i].title);
                            selectionUpdated($('form#artifact-select input[name=selected]:checked'));
                        })
                    }, 1000)
                };
                $(".filter #spec").on('input',function(){delayedUpdateResults();});
                $(".filter #attribute").on('input',function(){delayedUpdateResults();});
                $(".filter #value")
                    .on('input',function(){delayedUpdateResults();})
                    .val(value)
                    .focus();
                delayedUpdateResults();
                $('.asa-dialog').parent().css('top', Math.max($('.asa-dialog').parent().position().top-100, 0) + 'px');
            }
        }
    ).dialog('open');
}

var setupEditor = function() {
    // Hide trac's textarea and show a contenteditable div in its place
    var textarea = $('#text');
    textarea.hide().before('
');

    var editor = ace.edit("editor");
    //Get Ace Keyboard Handler and remove Find Events
    var khandler = editor.getKeyboardHandler();
    for(var key in khandler.commmandKeyBinding) {
        for(var prop in khandler.commmandKeyBinding[key]) {
            if(khandler.commmandKeyBinding[key].hasOwnProperty(prop))
                var control = khandler.commmandKeyBinding[key][prop].bindKey.win;
                var SupressingList = ["Ctrl-Shift-R", "Ctrl-R","Ctrl-F"];
                if(SupressingList.indexOf(control) != -1 )
                    khandler.commmandKeyBinding[key][prop] = null;
        }
    }
    editor.setKeyboardHandler(khandler);

    editor.setTheme("ace/theme/trac_wiki");
    editor.getSession().setUseWrapMode(true);
    editor.setHighlightActiveLine(false);
    editor.setShowPrintMargin(false);
    editor.renderer.setShowGutter(false);

    editor.getSession().setValue(textarea.val());
    editor.getSession().on('change', function(){
      textarea.val(editor.getSession().getValue());
    });

    // Initially a copy of trac/htdocs/js/resizer.js
    // Allow resizing <textarea> elements through a drag bar
    var setupEditorResizing = function(editor, editordiv) {
        var offset = null;

        function beginDrag(e) {
            offset = editordiv.height() - e.pageY;
            editordiv.blur();
            $(document).mousemove(dragging).mouseup(endDrag);
            return false;
        }

        function dragging(e) {
            editordiv.height(Math.max(32, offset + e.pageY) + 'px');
            editor.resize();
            return false;
        }

        function endDrag(e) {
          editordiv.focus();
          $(document).unbind('mousemove', dragging).unbind('mouseup', endDrag);
        }

        var grip = $('.trac-grip').mousedown(beginDrag)[0];
        if (grip != undefined){
            editordiv.wrap('

')
                .parent().append(grip);
            grip.style.marginLeft = (this.offsetLeft - grip.offsetLeft) + 'px';
            grip.style.marginRight = (grip.offsetWidth - this.offsetWidth) +'px';
        }
    };
    setupEditorResizing(editor, $('#editor'));

    // Originally copied from trac/wiki/templates/wiki_edit.html
    // Rewires the event of checking the "Adjust edit area height" box
    $("#editrows").change(function() {
        $('#editor').height(this.options[this.selectedIndex].value * $("div.ace_gutter-layer").find(".ace_gutter-cell:first").height())
        editor.renderer.onResize(true);
    });

    return editor;
};

var setupToolbar = function(editor){
    var wrapSelection = function(prefix, sufix){
        var value = editor.getCopyText();
        editor.insert(prefix + value + sufix);
        editor.focus();
    };

    // Rewire the event handlers of the toolbat buttons to work with the div instead of the textarea
    $("#strong").click(function() {
        wrapSelection("'''", "'''");
    });

    $("#heading").click(function() {
        wrapSelection("\n== ", " ==\n");
    });

    $("#em").click(function() {
        wrapSelection("''", "''");
    });

    $("#link").click(function() {
        wrapSelection("[", "]");
    });

    $("#code").click(function() {
        wrapSelection("\n{{{\n", "\n}}}\n");
    });

    $("#hr").click(function() {
        wrapSelection("\n----\n", "");
    });

    $("#np").click(function() {
        wrapSelection("\n\n", "");
    });

    $("#br").click(function() {
        wrapSelection("[[BR]]\n", "");
    });

    $("#img").click(function() {
        wrapSelection("[[Image(", ")]]");
    });

    // Add custom buttons to the toolbar
    var toolbar = $('.wikitoolbar');

    toolbar.after('

');
    var asa_toolbar = $('#asa_toolbar');
    asa_toolbar.append('');
    asa_toolbar.append('');

    // Events for the custom toolbar buttons
    $("#asa_create_button").click(function() {
        editor.focus();
        if(!editor.getSelection().isEmpty()){
            createASAFormDialogFromUrl('Create Adaptive Artifact',  baseurl+"/artifact?action=new",
                { "Create": function() {
                    submitASAFormDialog(
                        $(this),
                        {
                            success: function(data){
                                wrapSelection("[asa:"+data[0].resource_id+" ", "]");
                                var statesLength = editor.session.bgTokenizer.states.length;
                                /*var i=0;
                                 while ( i  < statesLength){
                                 editor.session.bgTokenizer.states[i] = null;
                                 i++;
                                 }*/
                                editor.session.bgTokenizer.fireUpdateEvent(0,statesLength);
                                editor.session.bgTokenizer.start(0);
                            },
                            error: function(data){
                                console.log("Ajax call failed!");
                            }
                        }
                    )}
                },
                {
                    open: function(){
                        addValue(this, "Name", editor.getCopyText());
                    }
                }
            ).dialog('open');
        }
    });

    $("#asa_link_button").click(function() {
        if(!editor.getSelection().isEmpty()){
            link_to_existing_artifact_ajax_call(function() {
                var artifact_id = $('form#artifact-select input[name=selected]:checked').val();
                wrapSelection("[asa:"+artifact_id+" ", "]");
            }, "")
        }
    });

};

var setupTokenizer = function(editor){
    var Tokenizer = require("ace/tokenizer").Tokenizer;
     // words in database
    var goodWords = Object.create(null);
    // words checked to not be in database. this can be omitted if it is ok to check for same words several times
    var words = Object.create(null);

    // cache for words pending resolution
    var pending = [];

    var tokenizer = new Tokenizer({
        "start": [
            {token : "asa_artifact", regex : ".\[asa:[0-9]+\\s+[\\s\\w]+\]"},
            {token : function(val){
                val = val.toLowerCase();
                if (goodWords[val])
                    return "keyword";
                if (words[val])
                    return "just-a-word";
                if (pending.indexOf(val) == -1)
                    pending.push(val);
                return "unknown";
            }, regex : "\\w+"},
            {token : "text", regex : "[^\\w]+"}

        ]
    });

    var queryTimeout = null;
    var dirtySessions = [];
    var attachToSession = function(session) {
        var self = session.bgTokenizer;
        self.rehighlight = function() {
            var states = this.states;
            var lines = this.lines;
            for (var i = states.length; i--;){
                if (states[i] || !lines[i])
                    continue;
                states[i] = "start";
                lines[i].forEach(function(t){
                    var term = t.value.toLowerCase();
                    if (goodWords[term])
                        t.type = "keyword";
                    else if (words[term])
                        t.type = "just-a-word";
                });
            }
            // this can be smarter and update only changed lines
            this.fireUpdateEvent(0, states.length);
        };
        self.$tokenizeRow = function(row) {
            // tokenize
            var line = this.doc.getLine(row);
            var data = this.tokenizer.getLineTokens(line, "start").tokens;
            // if we found new words schedule server query
            if (pending.length && !queryTimeout)
                queryTimeout = setTimeout(queryServer, 700);
            if (dirtySessions.indexOf(this) == -1)
                dirtySessions.push(this);
            // set state to null to indicate that it needs updating
            this.states[row] = null;

            return this.lines[row] = data;
        };
        self.setTokenizer(tokenizer);
    };

    var queryServer = function() {
        queryTimeout = null;
        Requests.searchArtifacts(undefined, {'': pending}, function(serverWords){
            // update goodWords and words based on serverWords
            goodWords = Object.create(null);
            for(var i=0;i<serverWords.length; i++){
                goodWords[serverWords[i].term.toLowerCase()] = true;
            }
            //goodWords = serverWords;
            words = Object.create(null);
            // then
            dirtySessions.forEach(function(x){
                x.rehighlight();
            });
            dirtySessions = [];
            // some code to reset queryTimeout
            // shedule again if there are more words in pending
            // etc...
            pending = [];
        })
    };

    /// use this instead of setMode
    attachToSession(editor.session);
};

var setupBalloons = function(editor){
    var balloon;
    editor.on('mousemove', function(e) {
        var canvasPos = editor.renderer.scroller.getBoundingClientRect();
        // Originally adapted from the code of screenToTextCoordinates()
        // Accounts for whitespace columns on the end of lines.
        var position = {
            row:e.getDocumentPosition().row ,
            column: Math.round((e.clientX + editor.renderer.scrollLeft - canvasPos.left - editor.renderer.$padding) / editor.renderer.characterWidth)};
        var session = editor.session;

        //Testes para ajustar posicionamento do balao
        //console.log("Janela: "+ editor.offsetLeft+ "   "+editor.offsetTop);
        //console.log(position.row+"      " +position.column ) ;
        //var range = editor.session.getAWordRange(position.row, position.column);
        //console.log(range.start);
        //console.log(range.toScreenRange(editor.session).start);
        //range.end.column-position.column

        // If the user clicked on a fold, then expand it.
        var token = session.getTokenAt(position.row, position.column, 1);
        if (token){

            var editordiv = $('#editor');
            var tooltip_content;
            if (token.type == 'keyword' || token.type == 'asa_artifact') {
               /* console.log("Aqui: ");
                console.log(session.getTabSize());

                console.log("Old");
                console.log(e.clientX);*/

                balloon = editordiv.showBalloon(
                    {
                        position: "top left",
                        offsetX: e.clientX - canvasPos.left ,
                        offsetY: canvasPos.top - e.clientY + 10,
                        tipSize: 10,
                        delay: 500,
                        minLifetime: 500,
                        showDuration: 1000,
                        hideDuration: 200,
                        showAnimation: function(d) { this.fadeIn(d); },
                        contents: function(){
                            var content = $('');
                            if (token.type == 'asa_artifact'){
                                content.attr("id", "asa_view_button_tooltip");
                                content.attr("title", "View Adaptive Artifact");
                                content.click(function(){ view_artifact_ajax_call(token.value, editor)});
                            }else if (token.type == 'keyword'){
                                content.attr("id", "asa_link_button_tooltip");
                                content.attr("title", "Link to existing Adaptive Artifact");
                                content.click(function(){
                                    link_to_existing_artifact_ajax_call(function() {
                                        var artifact_id = $('form#artifact-select input[name=selected]:checked').val();
                                        editor.session.insert({row: position.row, column: token.start + token.value.length}, "]");
                                        editor.session.insert({row: position.row, column: token.start}, "[asa:"+artifact_id+" ");
                                        editor.focus();
                                    }, token.value)
                                });
                            }
                            return content;
                        }
                    }
                ).data("balloon");

                if(balloon) {
                    balloon.mouseleave(function(e) {
                        editordiv.hideBalloon();
                    }).mouseenter(function(e) {
                        editordiv.showBalloon();
                    });
                }

            }else{
                balloon && editordiv.hideBalloon();
            }
            e.stop();
        }
    });
};

$(document).ready(function(){
    var editor = setupEditor();
    setupToolbar(editor);
    setupTokenizer(editor);
    setupBalloons(editor);
});<commit_msg>Improved UI message<commit_after>function view_artifact_ajax_call(asa_token_content, editor){
    var ind_init = asa_token_content.indexOf(":");
    var sub = asa_token_content.substr(ind_init+1, asa_token_content.length);
    var ind_end = sub.indexOf(" ");
    var id = sub.substr(0, ind_end);

    createASAFormDialogFromUrl('View Adaptive Artifact', baseurl+"/artifact/"+id+"?action=view",
        {
            "Edit": function() {
                $(this).dialog("close");
                createASAFormDialogFromUrl('Artifact', baseurl+"/artifact/"+id+"?action=edit",
                    {
                        "Save   ": function() {
                            submitASAFormDialog(
                                $(this),
                                {
                                    success: function(data){
                                        var statesLength = editor.session.bgTokenizer.states.length;
                                        editor.session.bgTokenizer.fireUpdateEvent(0,statesLength);
                                        editor.session.bgTokenizer.start(0);
                                    },
                                    error: function(data){
                                        console.log("Ajax call failed!");
                                    }
                                }
                            )},
                        "Close": function() { $(this).dialog("close"); }
                    }
                ).dialog('open');
            },
            "Close": function() { $(this).dialog("close"); } }
    ).dialog('open');
}

function link_to_existing_artifact_ajax_call(click_callback, value){
    createASAFormDialogFromUrl('Select Adaptive Artifact',  baseurl+"/search/by_filter?",
        [
            {
                id:'button-choose',
                text:'Choose',
                click: function(){
                    click_callback();
                    $(this).dialog("close");
                }
            },
            {
                id:'button-cancel',
                text:'Cancel',
                click: function() { $(this).dialog("close"); }
            }
        ],
        {
            open: function(){
                $("#button-choose").button("disable");

                var selectionUpdated = function(selected){
                    var content_div = $(".artifacts #asa #dialog-content");
                    var asa_div = $(".artifacts #asa");
                    var close_button = $("#button-choose");
                    if (selected.length==0){
                        close_button.button("disabled");
                        content_div.html("").hide();
                        asa_div.addClass('invisible');
                        return;
                    }
                    selected.prop('checked', true);
                    close_button.button("enable");
                    Requests.getArtifactHtml(selected.val(), function(data){
                        content_div.html(data).show();
                        asa_div.removeClass('invisible');
                    });
                };
                $('table.listing tbody tr').click(function() {
                    selectionUpdated($(this).find('td input[type=radio]'));
                });

                var clearRows = function(){
                    $(".artifacts table.listing tbody tr:not(.prototype)").remove();
                };
                var addResultRow = function(id, spec_name, title){
                    var copy = $(".artifacts table.listing tr.prototype").clone(true);
                    copy.removeClass('prototype');
                    copy.find("input[type^='radio']").attr("value", id);
                    copy.find("td")[1].innerText = spec_name;
                    copy.find("td")[2].innerText = title;
                    $(".artifacts table.listing tbody").append(copy);
                };
                var addMessageRow = function(text){
                    var messageRow = $('
' + text + '
');
                    $(".artifacts table.listing tbody").append(messageRow);
                };
                var timer;
                var delayedUpdateResults = function(){
                    clearTimeout(timer);
                    timer = setTimeout(function(){
                        var spec = $('.filter #spec').val();
                        var attr_name = $('.filter #attribute').val();
                        var attr_value = $('.filter #value').val();
                        var attribute = {};
                        attribute[attr_name] = [attr_value];
                        Requests.searchArtifacts(spec, attribute, function(data){
                            clearRows();
                            if(data.length==0){
                                addMessageRow('No Adaptive Artifacts found');
                            }
                            for(var i=0;i<data.length;i++)
                                addResultRow(data[i].id, data[i].spec, data[i].title);
                            selectionUpdated($('form#artifact-select input[name=selected]:checked'));
                        })
                    }, 1000)
                };
                $(".filter #spec").on('input',function(){delayedUpdateResults();});
                $(".filter #attribute").on('input',function(){delayedUpdateResults();});
                $(".filter #value")
                    .on('input',function(){delayedUpdateResults();})
                    .val(value)
                    .focus();
                delayedUpdateResults();
                $('.asa-dialog').parent().css('top', Math.max($('.asa-dialog').parent().position().top-100, 0) + 'px');
            }
        }
    ).dialog('open');
}

var setupEditor = function() {
    // Hide trac's textarea and show a contenteditable div in its place
    var textarea = $('#text');
    textarea.hide().before('
');

    var editor = ace.edit("editor");
    //Get Ace Keyboard Handler and remove Find Events
    var khandler = editor.getKeyboardHandler();
    for(var key in khandler.commmandKeyBinding) {
        for(var prop in khandler.commmandKeyBinding[key]) {
            if(khandler.commmandKeyBinding[key].hasOwnProperty(prop))
                var control = khandler.commmandKeyBinding[key][prop].bindKey.win;
                var SupressingList = ["Ctrl-Shift-R", "Ctrl-R","Ctrl-F"];
                if(SupressingList.indexOf(control) != -1 )
                    khandler.commmandKeyBinding[key][prop] = null;
        }
    }
    editor.setKeyboardHandler(khandler);

    editor.setTheme("ace/theme/trac_wiki");
    editor.getSession().setUseWrapMode(true);
    editor.setHighlightActiveLine(false);
    editor.setShowPrintMargin(false);
    editor.renderer.setShowGutter(false);

    editor.getSession().setValue(textarea.val());
    editor.getSession().on('change', function(){
      textarea.val(editor.getSession().getValue());
    });

    // Initially a copy of trac/htdocs/js/resizer.js
    // Allow resizing <textarea> elements through a drag bar
    var setupEditorResizing = function(editor, editordiv) {
        var offset = null;

        function beginDrag(e) {
            offset = editordiv.height() - e.pageY;
            editordiv.blur();
            $(document).mousemove(dragging).mouseup(endDrag);
            return false;
        }

        function dragging(e) {
            editordiv.height(Math.max(32, offset + e.pageY) + 'px');
            editor.resize();
            return false;
        }

        function endDrag(e) {
          editordiv.focus();
          $(document).unbind('mousemove', dragging).unbind('mouseup', endDrag);
        }

        var grip = $('.trac-grip').mousedown(beginDrag)[0];
        if (grip != undefined){
            editordiv.wrap('

')
                .parent().append(grip);
            grip.style.marginLeft = (this.offsetLeft - grip.offsetLeft) + 'px';
            grip.style.marginRight = (grip.offsetWidth - this.offsetWidth) +'px';
        }
    };
    setupEditorResizing(editor, $('#editor'));

    // Originally copied from trac/wiki/templates/wiki_edit.html
    // Rewires the event of checking the "Adjust edit area height" box
    $("#editrows").change(function() {
        $('#editor').height(this.options[this.selectedIndex].value * $("div.ace_gutter-layer").find(".ace_gutter-cell:first").height())
        editor.renderer.onResize(true);
    });

    return editor;
};

var setupToolbar = function(editor){
    var wrapSelection = function(prefix, sufix){
        var value = editor.getCopyText();
        editor.insert(prefix + value + sufix);
        editor.focus();
    };

    // Rewire the event handlers of the toolbat buttons to work with the div instead of the textarea
    $("#strong").click(function() {
        wrapSelection("'''", "'''");
    });

    $("#heading").click(function() {
        wrapSelection("\n== ", " ==\n");
    });

    $("#em").click(function() {
        wrapSelection("''", "''");
    });

    $("#link").click(function() {
        wrapSelection("[", "]");
    });

    $("#code").click(function() {
        wrapSelection("\n{{{\n", "\n}}}\n");
    });

    $("#hr").click(function() {
        wrapSelection("\n----\n", "");
    });

    $("#np").click(function() {
        wrapSelection("\n\n", "");
    });

    $("#br").click(function() {
        wrapSelection("[[BR]]\n", "");
    });

    $("#img").click(function() {
        wrapSelection("[[Image(", ")]]");
    });

    // Add custom buttons to the toolbar
    var toolbar = $('.wikitoolbar');

    toolbar.after('

');
    var asa_toolbar = $('#asa_toolbar');
    asa_toolbar.append('');
    asa_toolbar.append('');

    // Events for the custom toolbar buttons
    $("#asa_create_button").click(function() {
        editor.focus();
        if(!editor.getSelection().isEmpty()){
            createASAFormDialogFromUrl('Create Adaptive Artifact',  baseurl+"/artifact?action=new",
                { "Create": function() {
                    submitASAFormDialog(
                        $(this),
                        {
                            success: function(data){
                                wrapSelection("[asa:"+data[0].resource_id+" ", "]");
                                var statesLength = editor.session.bgTokenizer.states.length;
                                /*var i=0;
                                 while ( i  < statesLength){
                                 editor.session.bgTokenizer.states[i] = null;
                                 i++;
                                 }*/
                                editor.session.bgTokenizer.fireUpdateEvent(0,statesLength);
                                editor.session.bgTokenizer.start(0);
                            },
                            error: function(data){
                                console.log("Ajax call failed!");
                            }
                        }
                    )}
                },
                {
                    open: function(){
                        addValue(this, "Name", editor.getCopyText());
                    }
                }
            ).dialog('open');
        }
    });

    $("#asa_link_button").click(function() {
        if(!editor.getSelection().isEmpty()){
            link_to_existing_artifact_ajax_call(function() {
                var artifact_id = $('form#artifact-select input[name=selected]:checked').val();
                wrapSelection("[asa:"+artifact_id+" ", "]");
            }, "")
        }
    });

};

var setupTokenizer = function(editor){
    var Tokenizer = require("ace/tokenizer").Tokenizer;
     // words in database
    var goodWords = Object.create(null);
    // words checked to not be in database. this can be omitted if it is ok to check for same words several times
    var words = Object.create(null);

    // cache for words pending resolution
    var pending = [];

    var tokenizer = new Tokenizer({
        "start": [
            {token : "asa_artifact", regex : ".\[asa:[0-9]+\\s+[\\s\\w]+\]"},
            {token : function(val){
                val = val.toLowerCase();
                if (goodWords[val])
                    return "keyword";
                if (words[val])
                    return "just-a-word";
                if (pending.indexOf(val) == -1)
                    pending.push(val);
                return "unknown";
            }, regex : "\\w+"},
            {token : "text", regex : "[^\\w]+"}

        ]
    });

    var queryTimeout = null;
    var dirtySessions = [];
    var attachToSession = function(session) {
        var self = session.bgTokenizer;
        self.rehighlight = function() {
            var states = this.states;
            var lines = this.lines;
            for (var i = states.length; i--;){
                if (states[i] || !lines[i])
                    continue;
                states[i] = "start";
                lines[i].forEach(function(t){
                    var term = t.value.toLowerCase();
                    if (goodWords[term])
                        t.type = "keyword";
                    else if (words[term])
                        t.type = "just-a-word";
                });
            }
            // this can be smarter and update only changed lines
            this.fireUpdateEvent(0, states.length);
        };
        self.$tokenizeRow = function(row) {
            // tokenize
            var line = this.doc.getLine(row);
            var data = this.tokenizer.getLineTokens(line, "start").tokens;
            // if we found new words schedule server query
            if (pending.length && !queryTimeout)
                queryTimeout = setTimeout(queryServer, 700);
            if (dirtySessions.indexOf(this) == -1)
                dirtySessions.push(this);
            // set state to null to indicate that it needs updating
            this.states[row] = null;

            return this.lines[row] = data;
        };
        self.setTokenizer(tokenizer);
    };

    var queryServer = function() {
        queryTimeout = null;
        Requests.searchArtifacts(undefined, {'': pending}, function(serverWords){
            // update goodWords and words based on serverWords
            goodWords = Object.create(null);
            for(var i=0;i<serverWords.length; i++){
                goodWords[serverWords[i].term.toLowerCase()] = true;
            }
            //goodWords = serverWords;
            words = Object.create(null);
            // then
            dirtySessions.forEach(function(x){
                x.rehighlight();
            });
            dirtySessions = [];
            // some code to reset queryTimeout
            // shedule again if there are more words in pending
            // etc...
            pending = [];
        })
    };

    /// use this instead of setMode
    attachToSession(editor.session);
};

var setupBalloons = function(editor){
    var balloon;
    editor.on('mousemove', function(e) {
        var canvasPos = editor.renderer.scroller.getBoundingClientRect();
        // Originally adapted from the code of screenToTextCoordinates()
        // Accounts for whitespace columns on the end of lines.
        var position = {
            row:e.getDocumentPosition().row ,
            column: Math.round((e.clientX + editor.renderer.scrollLeft - canvasPos.left - editor.renderer.$padding) / editor.renderer.characterWidth)};
        var session = editor.session;

        //Testes para ajustar posicionamento do balao
        //console.log("Janela: "+ editor.offsetLeft+ "   "+editor.offsetTop);
        //console.log(position.row+"      " +position.column ) ;
        //var range = editor.session.getAWordRange(position.row, position.column);
        //console.log(range.start);
        //console.log(range.toScreenRange(editor.session).start);
        //range.end.column-position.column

        // If the user clicked on a fold, then expand it.
        var token = session.getTokenAt(position.row, position.column, 1);
        if (token){

            var editordiv = $('#editor');
            var tooltip_content;
            if (token.type == 'keyword' || token.type == 'asa_artifact') {
               /* console.log("Aqui: ");
                console.log(session.getTabSize());

                console.log("Old");
                console.log(e.clientX);*/

                balloon = editordiv.showBalloon(
                    {
                        position: "top left",
                        offsetX: e.clientX - canvasPos.left ,
                        offsetY: canvasPos.top - e.clientY + 10,
                        tipSize: 10,
                        delay: 500,
                        minLifetime: 500,
                        showDuration: 1000,
                        hideDuration: 200,
                        showAnimation: function(d) { this.fadeIn(d); },
                        contents: function(){
                            var content = $('');
                            if (token.type == 'asa_artifact'){
                                content.attr("id", "asa_view_button_tooltip");
                                content.attr("title", "View Adaptive Artifact");
                                content.click(function(){ view_artifact_ajax_call(token.value, editor)});
                            }else if (token.type == 'keyword'){
                                content.attr("id", "asa_link_button_tooltip");
                                content.attr("title", "Link to existing Adaptive Artifact");
                                content.click(function(){
                                    link_to_existing_artifact_ajax_call(function() {
                                        var artifact_id = $('form#artifact-select input[name=selected]:checked').val();
                                        editor.session.insert({row: position.row, column: token.start + token.value.length}, "]");
                                        editor.session.insert({row: position.row, column: token.start}, "[asa:"+artifact_id+" ");
                                        editor.focus();
                                    }, token.value)
                                });
                            }
                            return content;
                        }
                    }
                ).data("balloon");

                if(balloon) {
                    balloon.mouseleave(function(e) {
                        editordiv.hideBalloon();
                    }).mouseenter(function(e) {
                        editordiv.showBalloon();
                    });
                }

            }else{
                balloon && editordiv.hideBalloon();
            }
            e.stop();
        }
    });
};

$(document).ready(function(){
    var editor = setupEditor();
    setupToolbar(editor);
    setupTokenizer(editor);
    setupBalloons(editor);
});<|endoftext|>


<commit_before>Mayjs.dsl = Mayjs.$run(function(Mayjs) {
    var util = Mayjs.util;

    var dsl = {
        $obj: function(a) {
            var o = new this.Base();
            Mayjs.util.mix(a, o);
            return o;
        },

        $meta: function(obj, name) {
            return Mayjs.meta.get(obj, name);
        }
    };

    Object.keys(util).forEach(function(name) {
        if(name != "parseParamNames")
            dsl["$" + name] = util[name];
    });

    Object.keys(Mayjs).forEach(function(name) {
        if(/^\$/.test(name)){
            dsl[name] = Mayjs[name];
        }
    });

    return dsl;
}, Mayjs);<commit_msg>updated: def这个方法也不加入Mayjs.dsl<commit_after>Mayjs.dsl = Mayjs.$run(function(Mayjs) {
    var util = Mayjs.util;

    var dsl = {
        $obj: function(a) {
            var o = new this.Base();
            Mayjs.util.mix(a, o);
            return o;
        },

        $meta: function(obj, name) {
            return Mayjs.meta.get(obj, name);
        }
    };

    var utilExcludes = ["parseParamNames", "def"];
    Object.keys(util).forEach(function(name) {
        if(utilExcludes.indexOf(name) == -1)
            dsl["$" + name] = util[name];
    });

    Object.keys(Mayjs).forEach(function(name) {
        if(/^\$/.test(name)){
            dsl[name] = Mayjs[name];
        }
    });

    return dsl;
}, Mayjs);

Mayjs.DSL = Mayjs.$dsl(Mayjs.dsl);<|endoftext|>


<commit_before>var fs = require('fs'),
	path = require('path'),
	wrench = require('wrench'),
	logger = require('../../logger'),
	CONST = require('../../common/constants'),
	_ = require('../../lib/alloy/underscore');

var paths, platform;

function Orphanage(_paths, _platform) {
	platform = _platform;
	paths = _.clone(_paths);
}

function extension(file, newExt) {
	return file.replace(/[^\.]+$/, newExt);
}

function remove(folder, types, exceptions) {
	var runtimePath = path.join(paths.resourcesAlloy, folder);
	types = _.isString(types) ? [types] : types;
	exceptions = exceptions || [];

	// skip if the target runtime folder doesn't exist
	if (!fs.existsSync(runtimePath)) {
		return;
	}

	_.each(wrench.readdirSyncRecursive(runtimePath), function(file) {
		var runtimeFullpath = path.join(runtimePath, file);
		var stat = fs.statSync(runtimeFullpath);
		var found = false;
		var checks = [];
		var i;

		// skip exceptions
		for (i = 0; i < exceptions.length; i++) {
			if (_.contains([exceptions[i], path.join(platform, exceptions[i])], file)) {
				return;
			}
		}

		// is this is a file or directory?
		if (stat.isDirectory()) {
			_.each(types, function(type) {
				checks.push(
					path.join(paths.app, CONST.DIR[type], file),
					path.join(paths.app, CONST.DIR[type], platform, file)
				);
			});
		} else {
			_.each(types, function(type) {
				checks.push(
					path.join(paths.app, CONST.DIR[type],
						extension(file, CONST.FILE_EXT[type])),
					path.join(paths.app, CONST.DIR[type], platform,
						extension(file, CONST.FILE_EXT[type]))
				);
			});
		}

		console.log(checks);

		// If we find the corresponding app folder file(s), skip this file
		for (i = 0; i < checks.length; i++) {
			if (fs.existsSync(checks[i])) {
				found = true;
				return;
			}
		}

		if (!found) {
			console.log('ORPHAN: ' + runtimeFullpath);
			// delete, might be folder or file
		}
	});
}

Orphanage.prototype.remove = function(opts) {
	opts = opts || {};
	this.removeControllers();
	this.removeStyles();
	this.removeModels();
};

Orphanage.prototype.removeControllers = function() {
	remove(CONST.DIR.CONTROLLER, ['CONTROLLER','VIEW'], ['BaseController.js']);
};

Orphanage.prototype.removeModels = function() {
	remove(CONST.DIR.MODEL, 'MODEL');
};

Orphanage.prototype.removeStyles = function() {
	remove(CONST.DIR.STYLE, ['CONTROLLER','VIEW']);
};

// Orphanage.prototype.removeWidgets = function() {
// 	remove(CONST.DIR.WIDGET, 'WIDGET');
// };

module.exports = Orphanage;<commit_msg>major updates to handle themes, widgets (and dependencies), and platform specifics<commit_after>var fs = require('fs'),
	path = require('path'),
	wrench = require('wrench'),
	platforms = require('../../../platforms/index'),
	logger = require('../../logger'),
	CONST = require('../../common/constants'),
	U = require('../../utils'),
	_ = require('../../lib/alloy/underscore');

var ALLOY_ROOT = path.join(__dirname, '..', '..');

var dirs, platform, titaniumFolder, theme;
var widgets = {};

function Orphanage(projectDir, _platform, opts) {
	opts = opts || {};
	platform = _platform;
	titaniumFolder = platforms[platform].titaniumFolder;
	theme = opts.theme;

	// gather directories to be used throughout Orphanage
	var resourcesDir = path.join(projectDir, CONST.RESOURCES_DIR);
	dirs = {
		app: path.join(projectDir, CONST.ALLOY_DIR),
		resources: path.join(projectDir, CONST.RESOURCES_DIR),
		runtime: path.join(resourcesDir, CONST.ALLOY_RUNTIME_DIR)
	};

	// get widgets in use
	_.each(U.getWidgetDirectories(dirs.app) || [], function(dir) {
		widgets[fs.basename(dir)] = dir;
	});
}
module.exports = Orphanage;

Orphanage.prototype.clean = function() {
	var that = this;

	// Clean the base app folder
	this.removeAll();

	// Clean out each widget
	var widgets = path.join(dirs.runtime, CONST.DIR.WIDGET);
	if (fs.existsSync(widgets)) {
		_.each(fs.readdirSync(widgets), function(file) {
			that.removeAll({ widgetId: file });
		});
	}

	// assets must be cleaned up last
	logger.debug('Removing orphaned assets and libs...');
	this.removeAssets();
};

Orphanage.prototype.removeAll = function(opts) {
	opts = opts || {};

	logger.debug('Removing orphaned controllers...');
	this.removeControllers(opts);

	logger.debug('Removing orphaned models...');
	this.removeModels(opts);

	logger.debug('Removing orphaned styles...');
	this.removeStyles(opts);
};

Orphanage.prototype.removeControllers = function(opts) {
	opts = _.clone(opts || {});
	remove(_.extend(opts, {
		folder: CONST.DIR.CONTROLLER,
		types: ['CONTROLLER','VIEW'],
		exceptions: ['BaseController.js']
	}));
};

Orphanage.prototype.removeModels = function(opts) {
	opts = _.clone(opts || {});
	remove(_.extend(opts, {
		folder: CONST.DIR.MODEL,
		types: 'MODEL'
	}));
};

Orphanage.prototype.removeStyles = function(opts) {
	opts = _.clone(opts || {});
	remove(_.extend(opts, {
		folder: CONST.DIR.STYLE,
		types: ['CONTROLLER','VIEW']
	}));
};

Orphanage.prototype.removeAssets = function() {
	var locations = [
		path.join(dirs.app, CONST.DIR.ASSETS),
		path.join(dirs.app, CONST.DIR.ASSETS, platforms[platform].titaniumFolder),
		path.join(dirs.app, CONST.DIR.LIB),
		path.join(dirs.app, CONST.DIR.VENDOR)
	];

	// add theme locations, if necessary
	if (theme) {
		locations.push(
			path.join(dirs.app, CONST.DIR.THEME, theme, CONST.DIR.ASSETS),
			path.join(dirs.app, CONST.DIR.THEME, theme, CONST.DIR.ASSETS, platform)
		);
	}

	// files to skip
	var exceptions = [
		'app.js',
		'alloy.js',
		'alloy',
		'alloy/*'
	];

	// check the current platform as well
	_.each(_.clone(exceptions), function(ex) {
		exceptions.push(path.join(platforms[platform].titaniumFolder, ex));
	});

	// don't worry about cleaning platforms that aren't the current target
	_.each(_.without(_.pluck(platforms, 'titaniumFolder'), platforms[platform].titaniumFolder),
		function(tf) {
			exceptions.unshift(tf + '*');
		}
	);

	remove({
		runtimePath: dirs.resources,
		locations: locations,
		exceptions: exceptions
	});
};

// private function
function extension(file, newExt) {
	return file.replace(/[^\.]+$/, newExt);
}

function getChecks(file, fullpath, opts) {
	opts = opts || {};
	var isDir = fs.statSync(fullpath).isDirectory();
	var checks = [];

	// Check all the app folder file types
	if (opts.types) {
		_.each(opts.types, function(type) {
			var dir = CONST.DIR[type];

			// use type-specific extension if it's not a directory
			if (!isDir) {
				file = extension(file, CONST.FILE_EXT[type]);
			}

			// use widget path, if it's a widget
			if (opts.widgetId) {
				dir = path.join(CONST.DIR.WIDGET, opts.widgetId, dir);
			}

			// create the file checks
			checks.push(
				path.join(dirs.app, dir, file),
				path.join(dirs.app, dir, platform, file)
			);
		});

	// use explicit full location paths
	} else if (opts.locations) {
		// Is it a widget file?
		for (var i = 0; i < widgets.length; i++) {
			var widgetId = fs.basename(widgets[i]);
			var parts = file.split(/[\\\/]/);

			// strip off the platform if present
			if (parts[0] === platforms[platform]) { parts.shift(); }

			// is this a widget asset?
			if (_.contains(parts, widgetId)) {
				var wDir = widgets[widgetId];
				var wFile = _.without(parts, widgetId).join('/');
				checks.push(
					path.join(wDir, CONST.DIR.ASSETS, wFile),
					path.join(wDir, CONST.DIR.ASSETS, platform, wFile),
					path.join(wDir, CONST.DIR.LIB, wFile),
					path.join(wDir, CONST.DIR.VENDOR, wFile)
				);
				return checks;
			}
		}

		// No widget? Just use the given locations.
		_.each(opts.locations, function(loc) {
			checks.push(path.join(loc, file));
		});
	}

	return checks;
}

function isException(file, exceptions) {
	var ex, exs = [];
	exceptions = exceptions || [];

	for (var i = 0; i < exceptions.length; i++) {
		ex = exceptions[i];
		exs.push(ex);

		// handle folder wildcards
		if (ex.charAt(ex.length-1) === '*') {
			for (var j = 0; j < exs.length; j++) {
				var newEx = exs[i].substr(0, exs[i].length-2);

				// see if the file starts with the wildcard
				if (file.length >= newEx.length && file.substr(0, newEx.length) === newEx) {
					return true;
				}
			}

		// straight up comparison if there's no wildcards
		} else if (_.contains(exs, file)) {
			return true;
		}
	}

	return false;
}

function remove(opts) {
	opts = opts || {};
	var folder = opts.folder;
	var exceptions = opts.exceptions || [];
	var types = _.isString(opts.types) ? [opts.types] : opts.types;
	var locations = _.isString(opts.locations) ? [opts.locations] : opts.locations;
	var runtimePath = opts.runtimePath;

	// Set the base runtime search path
	if (!runtimePath) {
		if (!folder) {
			logger.die([
				'You must specify either "runtimePath" or "folder" when calling Orphanage.remove()',
				new Error().stack
			]);
		} else {
			if (opts.widgetId) {
				runtimePath = path.join(dirs.runtime, CONST.DIR.WIDGET, opts.widgetId, folder);
			} else {
				runtimePath = path.join(dirs.runtime, folder);
			}
		}
	}

	// skip if the target runtime folder doesn't exist
	if (!fs.existsSync(runtimePath)) {
		return;
	}

	// Let's see if we need to delete any orphan files...
	_.each(wrench.readdirSyncRecursive(runtimePath), function(file) {
		var runtimeFullpath = path.join(runtimePath, file);
		var found = false;
		var checks, i;

		// skip exceptions
		if (!opts.widgetId && isException(file, exceptions)) {
			return;
		}

		// Get a list of app folder locations to check for a match against the runtime file
		checks = getChecks(file, runtimeFullpath, _.extend({ widgetId: opts.widgetId },
			types ? { types: types } : { locations: locations }));

		// If we find the corresponding app folder file(s), skip this file
		for (i = 0; i < checks.length; i++) {
			if (fs.existsSync(checks[i])) {
				found = true;
				return;
			}
		}

		if (!found) {
			console.log('ORPHAN: ' + runtimeFullpath);
			// delete, might be folder or file
		}
	});
}
<|endoftext|>