<commit_before>
/**************
	GLOBALS
**************/

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var TO_RADIANS = Math.PI/180;

var imageObj = new Image();
imageObj.src = 'assets/plane.png';

var bullets = [];

/****************
	GAME TICK
****************/

gameTick.run(tick);

function tick(elapsed){

	// Location/Velocity/AI
	aircraft.move(elapsed);

	// Drawings
	clearCanvas();
	draw();

}

// This is my aircraft, there are many like it but this one is mine
var aircraft = {
	name: "TF-DESTROYER",
	x: 300, // Horizontal position
	y: 200, // Vertical position
	velX: 0, // Horizontal velocity
	velY: 0, // Vertical velocity

	power: 17, // Max engine output
	drag: 0.4, // Drag coefficient
	lift: 0.8, // Lift coefficient
	direction: 0, // 360° direction

	engineOn: false, // booleans that control movement
	turnCW: false, // Is turning clockwise
	turnCCW: false, // Is turning counter clockwise

	draw: function(){
		drawRotatedImage(imageObj, this.x, this.y, this.direction, 0.25);
	},
	move: function(elapsed){

		var gravity = {
			earth:9.81,
			mars:3.711,
			moon:1.622
		};

		// Gravity
		this.velY += gravity.earth * elapsed;

		// Drag coefficient
		this.velX = bringToZero(this.velX, (Math.pow(this.velX, 2) * this.drag * elapsed));
		this.velY = bringToZero(this.velY, (Math.pow(this.velY, 2) * this.drag * elapsed));

		// Aircraft lift - simple variation, not accurate
		this.velY -= Math.abs(this.velX * this.lift * elapsed);

		// Change direction
		if (this.turnCW) {
			this.direction += 360 * elapsed * 0.4;
		};
		if (this.turnCCW) {
			this.direction -= 360 * elapsed * 0.4;
		};
		//console.log(this.direction);

		// Add engine velocity
		if (this.engineOn) {
			var angle = this.direction % 360;

			var x = Math.cos(angle * TO_RADIANS);
			var y = Math.sin(angle * TO_RADIANS);

			this.velX += this.power * x * elapsed;
			this.velY += this.power * y * elapsed;
		};

		// Bounding box - Got to find a better bounding box
		if (this.x >= canvas.width) {
			this.x = 0;
		};
		if (this.x < 0) {
			this.x = canvas.width;
		};

		// Aircraft top/bottom borders
		if (this.y < 0) {
			this.velY += Math.pow(this.y, 2) * elapsed;
		};
		if (this.y + (this.velY * elapsed) >= canvas.height) {
			if (this.velY < 0.5) {
				this.velY = 0;
			}
			else{
				this.velY = -this.velY * 0.5;
			};
		};

		this.y = Math.min(this.y + this.velY, canvas.height);
		this.x = Math.min(this.x + this.velX, canvas.width);
	},
	keyHandler: function(key, state){
		switch(key){
			case 'w':
				this.engineOn = state;
			break;
			case 'a':
				this.turnCCW = state;
			break;
			case 'd':
				this.turnCW = state;
			break;
		}
	}
};

// This is my aircraft, there are many like it but this one is mine
function bullet_constructor(){
	x: 300; // Horizontal position
	y: 200; // Vertical position
	velX: 0; // Horizontal velocity
	velY: 0; // Vertical velocity
	power: 80; // Max engine output
	drag: 0.0125; // Drag coefficient
	direction: 0; // 360° direction

	draw = function(){
		drawRotatedImage(imageObj, this.x, this.y, this.direction, 0.5);
	};
	move = function(elapsed){

		this.radius = 5;

		// Drag coefficient
		this.velX = bringToZero(this.velX, (Math.pow(this.velX, 2) * this.drag * elapsed));
		this.velY = bringToZero(this.velY, (Math.pow(this.velY, 2) * this.drag * elapsed));

		// Aircraft lift - simple variation, not accurate
		this.velY -= this.velX * this.lift * elapsed;

		// Change direction
		if (this.turnCW) {
			this.direction += 360 * elapsed * 0.5;
		};
		if (this.turnCCW) {
			this.direction -= 360 * elapsed * 0.5;
		};
		//console.log(this.direction);

		// Add engine velocity
		if (this.engineOn) {
			var angle = this.direction % 360;

			var x = Math.cos(angle * TO_RADIANS);
			var y = Math.sin(angle * TO_RADIANS);

			this.velX += this.power * x * elapsed;
			this.velY += this.power * y * elapsed;
		};

		// Bounding box - Got to find a better bounding box
		if (this.x >= canvas.width) {
			this.x = 0;
		};
		if (this.x < 0) {
			this.x = canvas.width;
		};
		if (this.y >= canvas.height-100) {
			this.y = canvas.height-101;
			this.velY = -this.velY * 0.75;
		};

		this.y = Math.min(this.y + this.velY, canvas.height);
		this.x = Math.min(this.x + this.velX, canvas.width);
	};
};

/***********************
	HELPER FUNCTIONS
***********************/

function drawRotatedImage(image, x, y, angle, scale){
    // save the current co-ordinate system
    // before we screw with it
    ctx.save();

    // move to the middle of where we want to draw our image
    ctx.translate(x, y);

    // rotate around that point, converting our
    // angle from degrees to radians
    ctx.rotate(angle * TO_RADIANS);

    // draw it up and to the left by half the width
    // and height of the image
    ctx.drawImage(image, -(image.width/2) * scale, -(image.height/2) * scale, image.width * scale, image.height * scale);

    // and restore the co-ords to how they were when we began
    ctx.restore();
}

// Altering the math object to add a function that brings a number closer to zero by some delta
function bringToZero(number, delta) {
	if (number > 0) {
		if (number > delta) {
			return number - delta;
		}
		else{
			return 0;
		}
	}
	else if (number < 0) {
		if (number < -delta) {
			return number + delta;
		}
		else{
			return 0;
		}
	}
	else{
		return 0;
	};
};

/***********************
		CONTROLS
***********************/

// Aircraft
Mousetrap.bind({
    'a': function() { aircraft.keyHandler('a', true); },
    'd': function() { aircraft.keyHandler('d', true); },
    'w': function() { aircraft.keyHandler('w', true); }
}, 'keydown');

Mousetrap.bind({
    'a': function() { aircraft.keyHandler('a', false); },
    'd': function() { aircraft.keyHandler('d', false); },
    'w': function() { aircraft.keyHandler('w', false); }
}, 'keyup');

/***********************
	AIRCRAFT UPDATES
***********************/

/***********************
	RENDERING ENGINE
***********************/

function draw(){
	aircraft.draw();
}

function clearCanvas(){
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	ctx.beginPath();
}<commit_msg>aircraft dymanics fix<commit_after>
/**************
	GLOBALS
**************/

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var TO_RADIANS = Math.PI/180;

var imageObj = new Image();
imageObj.src = 'assets/plane.png';

var bullets = [];

/****************
	GAME TICK
****************/

gameTick.run(tick);

function tick(elapsed){

	// Location/Velocity/AI
	aircraft.move(elapsed);

	// Drawings
	clearCanvas();
	draw();

}

// This is my aircraft, there are many like it but this one is mine
var aircraft = {
	name: "TF-DESTROYER",
	x: 300, // Horizontal position
	y: 200, // Vertical position
	velX: 0, // Horizontal velocity
	velY: 0, // Vertical velocity

	power: 9, // Max engine output
	drag: 0.4, // Drag coefficient
	lift: 1.5, // Lift coefficient
	direction: 0, // 360° direction

	engineOn: false, // booleans that control movement
	turnCW: false, // Is turning clockwise
	turnCCW: false, // Is turning counter clockwise

	draw: function(){
		drawRotatedImage(imageObj, this.x, this.y, this.direction, 0.5);
	},
	move: function(elapsed){

		var gravity = {
			earth:9.81,
			mars:3.711,
			moon:1.622
		};

		// Gravity
		this.velY += gravity.earth * elapsed;

		// Drag coefficient
		this.velX = bringToZero(this.velX, (Math.pow(this.velX, 2) * this.drag * elapsed));
		this.velY = bringToZero(this.velY, (Math.pow(this.velY, 2) * this.drag * elapsed));

		// Aircraft lift - simple variation, not accurate
		this.velY -= Math.abs(this.velX * this.lift * elapsed);

		// Change direction
		if (this.turnCW) {
			this.direction += 360 * elapsed * 0.4;
		};
		if (this.turnCCW) {
			this.direction -= 360 * elapsed * 0.4;
		};
		//console.log(this.direction);

		// Add engine velocity
		if (this.engineOn) {
			var angle = this.direction % 360;

			var x = Math.cos(angle * TO_RADIANS);
			var y = Math.sin(angle * TO_RADIANS);

			this.velX += this.power * x * elapsed;
			this.velY += this.power * y * elapsed;
		};

		// Bounding box - Got to find a better bounding box
		if (this.x >= canvas.width) {
			this.x = 0;
		};
		if (this.x < 0) {
			this.x = canvas.width;
		};

		// Aircraft top/bottom borders
		if (this.y < 0) {
			this.velY += Math.pow(this.y, 2) * elapsed;
		};
		if (this.y + (this.velY * elapsed) >= canvas.height) {
			if (this.velY < 0.5) {
				this.velY = 0;
			}
			else{
				this.velY = -this.velY * 0.5;
			};
		};

		this.y = Math.min(this.y + this.velY, canvas.height);
		this.x = Math.min(this.x + this.velX, canvas.width);
	},
	keyHandler: function(key, state){
		switch(key){
			case 'w':
				this.engineOn = state;
			break;
			case 'a':
				this.turnCCW = state;
			break;
			case 'd':
				this.turnCW = state;
			break;
		}
	}
};

// This is my aircraft, there are many like it but this one is mine
function bullet_constructor(){
	x: 300; // Horizontal position
	y: 200; // Vertical position
	velX: 0; // Horizontal velocity
	velY: 0; // Vertical velocity
	power: 80; // Max engine output
	drag: 0.0125; // Drag coefficient
	direction: 0; // 360° direction

	draw = function(){
		drawRotatedImage(imageObj, this.x, this.y, this.direction, 0.5);
	};
	move = function(elapsed){

		this.radius = 5;

		// Drag coefficient
		this.velX = bringToZero(this.velX, (Math.pow(this.velX, 2) * this.drag * elapsed));
		this.velY = bringToZero(this.velY, (Math.pow(this.velY, 2) * this.drag * elapsed));

		// Aircraft lift - simple variation, not accurate
		this.velY -= this.velX * this.lift * elapsed;

		// Change direction
		if (this.turnCW) {
			this.direction += 360 * elapsed * 0.5;
		};
		if (this.turnCCW) {
			this.direction -= 360 * elapsed * 0.5;
		};
		//console.log(this.direction);

		// Add engine velocity
		if (this.engineOn) {
			var angle = this.direction % 360;

			var x = Math.cos(angle * TO_RADIANS);
			var y = Math.sin(angle * TO_RADIANS);

			this.velX += this.power * x * elapsed;
			this.velY += this.power * y * elapsed;
		};

		// Bounding box - Got to find a better bounding box
		if (this.x >= canvas.width) {
			this.x = 0;
		};
		if (this.x < 0) {
			this.x = canvas.width;
		};
		if (this.y >= canvas.height-100) {
			this.y = canvas.height-101;
			this.velY = -this.velY * 0.75;
		};

		this.y = Math.min(this.y + this.velY, canvas.height);
		this.x = Math.min(this.x + this.velX, canvas.width);
	};
};

/***********************
	HELPER FUNCTIONS
***********************/

function drawRotatedImage(image, x, y, angle, scale){
    // save the current co-ordinate system
    // before we screw with it
    ctx.save();

    // move to the middle of where we want to draw our image
    ctx.translate(x, y);

    // rotate around that point, converting our
    // angle from degrees to radians
    ctx.rotate(angle * TO_RADIANS);

    // draw it up and to the left by half the width
    // and height of the image
    ctx.drawImage(image, -(image.width/2) * scale, -(image.height/2) * scale, image.width * scale, image.height * scale);

    // and restore the co-ords to how they were when we began
    ctx.restore();
}

// Altering the math object to add a function that brings a number closer to zero by some delta
function bringToZero(number, delta) {
	if (number > 0) {
		if (number > delta) {
			return number - delta;
		}
		else{
			return 0;
		}
	}
	else if (number < 0) {
		if (number < -delta) {
			return number + delta;
		}
		else{
			return 0;
		}
	}
	else{
		return 0;
	};
};

/***********************
		CONTROLS
***********************/

// Aircraft
Mousetrap.bind({
    'a': function() { aircraft.keyHandler('a', true); },
    'd': function() { aircraft.keyHandler('d', true); },
    'w': function() { aircraft.keyHandler('w', true); }
}, 'keydown');

Mousetrap.bind({
    'a': function() { aircraft.keyHandler('a', false); },
    'd': function() { aircraft.keyHandler('d', false); },
    'w': function() { aircraft.keyHandler('w', false); }
}, 'keyup');

/***********************
	AIRCRAFT UPDATES
***********************/

/***********************
	RENDERING ENGINE
***********************/

function draw(){
	aircraft.draw();
}

function clearCanvas(){
	ctx.clearRect(0, 0, canvas.width, canvas.height);
	ctx.beginPath();
}<|endoftext|>


<commit_before>module.exports = {
  todo1: {
    name: 'Finish variables',
    desc: 'Use past sass projects for inspo.',
    cat: 'design',
    link: '',
    complete: false,
  },
  todo2: {
    name: 'React Router Transitions',
    desc: 'Animate page transitioning in and out',
    cat: 'design',
    link: '',
    complete: false,
  },
  todo3: {
    name: 'Animate Active Link',
    desc: 'Arrows going in and out on click',
    cat: 'design',
    link: '',
    complete: false,
  },
  todo4: {
    name: 'Modernizr integration',
    desc: 'Make sure it looks the same on most browsers',
    cat: 'component',
    link: '',
    complete: false,
  },
  todo5: {
    name: 'Flexbox',
    desc: 'Use flexbox for internal element layout',
    cat: 'design',
    link: '',
    complete: false,
  },
  todo6: {
    name: 'CSS Grid layout',
    desc: 'Use grid for main layout',
    cat: 'design',
    link: '',
    complete: false,
  },
  todo7: {
    name: 'Tagline powerline',
    desc: 'Set up powerline-like arrows and colors for the tagline',
    cat: 'design',
    link: '',
    complete: false,
  },
  todo8: {
    name: 'Firebase Database',
    desc: 'Get database working for projects, skills, and todos',
    cat: 'backend',
    link: '',
    complete: false,
  },
};
<commit_msg>Better prop naming<commit_after>module.exports = {
  'todo-1': {
    name: 'Finish variables',
    desc: 'Use past sass projects for inspo.',
    category: 'design',
    link: '',
    complete: false,
  },
  'todo-2': {
    name: 'React Router Transitions',
    desc: 'Animate page transitioning in and out',
    category: 'design',
    link: '',
    complete: false,
  },
  'todo-3': {
    name: 'Animate Active Link',
    desc: 'Arrows going in and out on click',
    category: 'design',
    link: '',
    complete: false,
  },
  'todo-4': {
    name: 'Modernizr integration',
    desc: 'Make sure it looks the same on most browsers',
    category: 'component',
    link: '',
    complete: false,
  },
  'todo-5': {
    name: 'Flexbox',
    desc: 'Use flexbox for internal element layout',
    category: 'design',
    link: '',
    complete: false,
  },
  'todo-6': {
    name: 'CSS Grid layout',
    desc: 'Use grid for main layout',
    category: 'design',
    link: '',
    complete: false,
  },
  'todo-7': {
    name: 'Tagline powerline',
    desc: 'Set up powerline-like arrows and colors for the tagline',
    category: 'design',
    link: '',
    complete: false,
  },
  'todo-8': {
    name: 'Firebase Database',
    desc: 'Get database working for projects, skills, and todo',
    category: 'backend',
    link: '',
    complete: false,
  },
};
<|endoftext|>


<commit_before>class Stats extends Phaser.State {

	create() {
		this.totalScore = this.game.state.states['Main'].totalScore;
		this.enemyScore = this.game.state.states['Main'].enemiesPassed;
		this.coinScore = this.game.state.states['Main'].coinCounter;

    this.game.stage.backgroundColor = '#DFF4FF';

		let statsHeader = "STATS";
    let continuePhrase = "Tap to Continue";
    // let saved = "";
    // let score = function(){adds everything}
    this.statsHeaderText = this.game.add.text(650, 50, statsHeader, { font: "250px Revalia", textalign: "center"});
		this.continueText = this.game.add.text(820, 300, continuePhrase, { font: "50px Arial", textalign: "center"});
    this.savedText = this.game.add.text(820,300, saved, { font: "50px Arial", textalign: "center"});

		this.enemyScore = this.game.add.text(1000, 600, ("Enemies dodged: " + this.enemyScore), { font: "60px Arial", fill: "#fffff"});
		this.coinScore = this.game.add.text(1000, 700, ("Coins collected: " + this.coinScore), { font: "60px Arial", fill: "#fffff"});

		this.playerScore = this.game.add.text(1000, 800, ("Total Score: " + this.totalScore), { font: "60px Arial", fill: "#fffff"});
		this.sendButton = this.game.add.button(1000, 900, 'send', this.sendScore, this);

	}

	sendScore() {
		// this.playerName = prompt("Please enter your name", "Player");
		// STILL IN PROCESS
	}

  update() {
    if(this.game.input.activePointer.justPressed()) {
      $.ajax({
        // need to edit url accordingly
        url: "http://localhost:3000/scores",
        type: "post",
        dataType: "json",
        data: {
          username: "test",
          score: this.totalScore,
        },
        // success: () => {
        //   this.saved = "Saved Successfully!";
        // }
      })
      this.game.state.start('End');
    }

  }
}

export default Stats;
<commit_msg>edit ajax request in sendScore callback function<commit_after>class Stats extends Phaser.State {

	create() {
		this.totalScore = this.game.state.states['Main'].totalScore;
		this.enemyScore = this.game.state.states['Main'].enemiesPassed;
		this.coinScore = this.game.state.states['Main'].coinCounter;

    this.game.stage.backgroundColor = '#DFF4FF';

		let statsHeader = "STATS";
    let continuePhrase = "Tap to Continue";
    // let saved = "";
    // let score = function(){adds everything}
    this.statsHeaderText = this.game.add.text(650, 50, statsHeader, { font: "250px Revalia", textalign: "center"});
		this.continueText = this.game.add.text(820, 300, continuePhrase, { font: "50px Arial", textalign: "center"});
    // this.savedText = this.game.add.text(820,300, saved, { font: "50px Arial", textalign: "center"});

		this.enemyScore = this.game.add.text(1000, 600, ("Enemies dodged: " + this.enemyScore), { font: "60px Arial", fill: "#fffff"});
		this.coinScore = this.game.add.text(1000, 700, ("Coins collected: " + this.coinScore), { font: "60px Arial", fill: "#fffff"});

		this.playerScore = this.game.add.text(1000, 800, ("Total Score: " + this.totalScore), { font: "60px Arial", fill: "#fffff"});
		this.sendButton = this.game.add.button(1000, 900, 'send', this.sendScore, this);

	}

	sendScore() {
    $.ajax({
      // need to edit url accordingly
      url: "http://localhost:3000/scores",
      type: "post",
      dataType: "json",
      data: {
        username: "test",
        score: this.totalScore,
      },
      })
	}

  update() {
    if(this.game.input.activePointer.justPressed()) {
      this.game.state.start('End');
    }

  }
}

export default Stats;
<|endoftext|>


<commit_before>function linkClickedFunction(event) {
    event.preventDefault();
    target = this.href;
    $.History.go(target);
}

$.History.bind(function (state) {
    $('.sidebar-container-right').remove();
    $('#cluetip').remove();
    $('#cluetip-waitimage').remove();

    if (state == '' || state.match('/index.html$') == '/index.html') {
        $('#contentBox').html('
Loading...
').load('index.html' + ' #fileList', function() {
            $('#fileList .fileLink').click(linkClickedFunction);
        });
    } else {
        // Go to specific review
        $('#contentBox').empty().load(state + ' #review', initReview);
    }
});

$(function() {
    $("#treeToggle").click().toggle(function() {
        $("#tree").animate({width: "hide", opacity: "hide"}, "slow");
        $("#treeToggle").css('background-image', "url('img/treeToggle-collapsed.png')");
    }, function() {
        $("#tree").animate({width: "show", opacity: "show"}, "slow");
        $("#treeToggle").css('background-image', "url('img/treeToggle-extended.png')");
    });

    $("#tree").bind("loaded.jstree", function(event, data) {
        $("#tree").animate({width: "show", opacity: "show"}, "slow");
    }).jstree({
        "plugins" : ["html_data", "themes"]
    });

    $(".treeDir").click(function() {
        $("#tree").jstree("toggle_node", this);
    });

    // When the user clicks on a leaf item in the tree (representing a file)
    // or an item in the fileList, want to hide the filelist/the currently
    // shown review and display the correct review.
    $(".fileLink").click(linkClickedFunction);
});

<commit_msg>Encode URLs so that special characters don't break requests.<commit_after>function linkClickedFunction(event) {
    event.preventDefault();
    target = this.href;
    $.History.go(target);
}

$.History.bind(function (state) {
    $('.sidebar-container-right').remove();
    $('#cluetip').remove();
    $('#cluetip-waitimage').remove();

    if (state == '' || state.match('/index.html$') == '/index.html') {
        $('#contentBox').html('
Loading...
').load('index.html' + ' #fileList', function() {
            $('#fileList .fileLink').click(linkClickedFunction);
        });
    } else {
        // Go to specific review
        $('#contentBox').empty().load(encodeURI(state) + ' #review', initReview);
    }
});

$(function() {
    $("#treeToggle").click().toggle(function() {
        $("#tree").animate({width: "hide", opacity: "hide"}, "slow");
        $("#treeToggle").css('background-image', "url('img/treeToggle-collapsed.png')");
    }, function() {
        $("#tree").animate({width: "show", opacity: "show"}, "slow");
        $("#treeToggle").css('background-image', "url('img/treeToggle-extended.png')");
    });

    $("#tree").bind("loaded.jstree", function(event, data) {
        $("#tree").animate({width: "show", opacity: "show"}, "slow");
    }).jstree({
        "plugins" : ["html_data", "themes"]
    });

    $(".treeDir").click(function() {
        $("#tree").jstree("toggle_node", this);
    });

    // When the user clicks on a leaf item in the tree (representing a file)
    // or an item in the fileList, want to hide the filelist/the currently
    // shown review and display the correct review.
    $(".fileLink").click(linkClickedFunction);
});

<|endoftext|>


<commit_before>// Vex Flow Notation
// Author Larry Kuhns 2011
// Implements barlines (single, double, repeat, end)
//
// Requires vex.js.

/**
 * @constructor
 */
Vex.Flow.Barline = (function() {
  function Barline(type, x) {
    if (arguments.length > 0) this.init(type, x);
  }

  Barline.type = {
    SINGLE: 1,
    DOUBLE: 2,
    END: 3,
    REPEAT_BEGIN: 4,
    REPEAT_END: 5,
    REPEAT_BOTH: 6,
    NONE: 7
  };

  var THICKNESS = Vex.Flow.STAVE_LINE_THICKNESS;

  Vex.Inherit(Barline, Vex.Flow.StaveModifier, {
    init: function(type, x) {
      Barline.superclass.init.call(this);
      this.barline = type;
      this.x = x;    // Left most x for the stave
    },

    getCategory: function() { return "barlines"; },
    setX: function(x) { this.x = x; return this; },

    // Draw barlines
    draw: function(stave, x_shift) {
      x_shift = typeof x_shift !== 'number' ? 0 : x_shift;

      switch (this.barline) {
        case Barline.type.SINGLE:
          this.drawVerticalBar(stave, this.x, false);
          break;
        case Barline.type.DOUBLE:
          this.drawVerticalBar(stave, this.x, true);
          break;
        case Barline.type.END:
          this.drawVerticalEndBar(stave, this.x);
          break;
        case Barline.type.REPEAT_BEGIN:
          // If the barline is shifted over (in front of clef/time/key)
          // Draw vertical bar at the beginning.
          if (x_shift > 0) {
            this.drawVerticalBar(stave, this.x);
          }
          this.drawRepeatBar(stave, this.x + x_shift, true);
          break;
        case Barline.type.REPEAT_END:
          this.drawRepeatBar(stave, this.x, false);
          break;
        case Barline.type.REPEAT_BOTH:
          this.drawRepeatBar(stave, this.x, false);
          this.drawRepeatBar(stave, this.x, true);
          break;
        default:
          // Default is NONE, so nothing to draw
          break;
      }
    },

    drawVerticalBar: function(stave, x, double_bar) {
      if (!stave.context) throw new Vex.RERR("NoCanvasContext",
          "Can't draw stave without canvas context.");
      var top_line = stave.getYForLine(0);
      var bottom_line = stave.getYForLine(stave.options.num_lines - 1) + (THICKNESS / 2);
      if (double_bar)
        stave.context.fillRect(x - 3, top_line, 1, bottom_line - top_line + 1);
      stave.context.fillRect(x, top_line, 1, bottom_line - top_line + 1);
    },

    drawVerticalEndBar: function(stave, x) {
      if (!stave.context) throw new Vex.RERR("NoCanvasContext",
          "Can't draw stave without canvas context.");

      var top_line = stave.getYForLine(0);
      var bottom_line = stave.getYForLine(stave.options.num_lines - 1) + (THICKNESS / 2);
      stave.context.fillRect(x - 5, top_line, 1, bottom_line - top_line + 1);
      stave.context.fillRect(x - 2, top_line, 3, bottom_line - top_line + 1);
    },

    drawRepeatBar: function(stave, x, begin) {
      if (!stave.context) throw new Vex.RERR("NoCanvasContext",
          "Can't draw stave without canvas context.");

      var top_line = stave.getYForLine(0);
      var bottom_line = stave.getYForLine(stave.options.num_lines - 1) + (THICKNESS / 2);
      var x_shift = 3;

      if (!begin) {
        x_shift = -5;
      }

      stave.context.fillRect(x + x_shift, top_line, 1, bottom_line - top_line + 1);
      stave.context.fillRect(x - 2, top_line, 3, bottom_line - top_line + 1);

      var dot_radius = 2;

      // Shift dots left or right
      if (begin) {
        x_shift += 4;
      } else {
        x_shift -= 4;
      }

      var dot_x = (x + x_shift) + (dot_radius / 2);

      // calculate the y offset based on number of stave lines
      var y_offset = (stave.options.num_lines -1) *
        stave.options.spacing_between_lines_px;
      y_offset = (y_offset / 2) -
                 (stave.options.spacing_between_lines_px / 2);
      var dot_y = top_line + y_offset + (dot_radius / 2);

      // draw the top repeat dot
      stave.context.beginPath();
      stave.context.arc(dot_x, dot_y, dot_radius, 0, Math.PI * 2, false);
      stave.context.fill();

      //draw the bottom repeat dot
      dot_y += stave.options.spacing_between_lines_px;
      stave.context.beginPath();
      stave.context.arc(dot_x, dot_y, dot_radius, 0, Math.PI * 2, false);
      stave.context.fill();
    }
  });

  return Barline;
}());
<commit_msg>changed barline length calculation<commit_after>// Vex Flow Notation
// Author Larry Kuhns 2011
// Implements barlines (single, double, repeat, end)
//
// Requires vex.js.

/**
 * @constructor
 */
Vex.Flow.Barline = (function() {
  function Barline(type, x) {
    if (arguments.length > 0) this.init(type, x);
  }

  Barline.type = {
    SINGLE: 1,
    DOUBLE: 2,
    END: 3,
    REPEAT_BEGIN: 4,
    REPEAT_END: 5,
    REPEAT_BOTH: 6,
    NONE: 7
  };

  var THICKNESS = Vex.Flow.STAVE_LINE_THICKNESS;

  Vex.Inherit(Barline, Vex.Flow.StaveModifier, {
    init: function(type, x) {
      Barline.superclass.init.call(this);
      this.barline = type;
      this.x = x;    // Left most x for the stave
    },

    getCategory: function() { return "barlines"; },
    setX: function(x) { this.x = x; return this; },

    // Draw barlines
    draw: function(stave, x_shift) {
      x_shift = typeof x_shift !== 'number' ? 0 : x_shift;

      switch (this.barline) {
        case Barline.type.SINGLE:
          this.drawVerticalBar(stave, this.x, false);
          break;
        case Barline.type.DOUBLE:
          this.drawVerticalBar(stave, this.x, true);
          break;
        case Barline.type.END:
          this.drawVerticalEndBar(stave, this.x);
          break;
        case Barline.type.REPEAT_BEGIN:
          // If the barline is shifted over (in front of clef/time/key)
          // Draw vertical bar at the beginning.
          if (x_shift > 0) {
            this.drawVerticalBar(stave, this.x);
          }
          this.drawRepeatBar(stave, this.x + x_shift, true);
          break;
        case Barline.type.REPEAT_END:
          this.drawRepeatBar(stave, this.x, false);
          break;
        case Barline.type.REPEAT_BOTH:
          this.drawRepeatBar(stave, this.x, false);
          this.drawRepeatBar(stave, this.x, true);
          break;
        default:
          // Default is NONE, so nothing to draw
          break;
      }
    },

    drawVerticalBar: function(stave, x, double_bar) {
      if (!stave.context) throw new Vex.RERR("NoCanvasContext",
          "Can't draw stave without canvas context.");
      var topY = stave.getYForLine(0);
      var botY = stave.getYForLine(stave.getNumLines() - 1) + THICKNESS;
      if (double_bar)
        stave.context.fillRect(x - 3, topY, 1, botY - topY);
      stave.context.fillRect(x, topY, 1, botY - topY);
    },

    drawVerticalEndBar: function(stave, x) {
      if (!stave.context) throw new Vex.RERR("NoCanvasContext",
          "Can't draw stave without canvas context.");

      var topY = stave.getYForLine(0);
      var botY = stave.getYForLine(stave.getNumLines() - 1) + THICKNESS;
      stave.context.fillRect(x - 5, topY, 1, botY - topY);
      stave.context.fillRect(x - 2, topY, 3, botY - topY);
    },

    drawRepeatBar: function(stave, x, begin) {
      if (!stave.context) throw new Vex.RERR("NoCanvasContext",
          "Can't draw stave without canvas context.");

      var topY = stave.getYForLine(0);
      var botY = stave.getYForLine(stave.getNumLines() - 1) + THICKNESS;
      var x_shift = 3;

      if (!begin) {
        x_shift = -5;
      }

      stave.context.fillRect(x + x_shift, topY, 1, botY - topY);
      stave.context.fillRect(x - 2, topY, 3, botY - topY);

      var dot_radius = 2;

      // Shift dots left or right
      if (begin) {
        x_shift += 4;
      } else {
        x_shift -= 4;
      }

      var dot_x = (x + x_shift) + (dot_radius / 2);

      // calculate the y offset based on number of stave lines
      var y_offset = (stave.getNumLines() - 1) *
        stave.getSpacingBetweenLines();
      y_offset = (y_offset / 2) -
                 (stave.getSpacingBetweenLines() / 2);
      var dot_y = topY + y_offset + (dot_radius / 2);

      // draw the top repeat dot
      stave.context.beginPath();
      stave.context.arc(dot_x, dot_y, dot_radius, 0, Math.PI * 2, false);
      stave.context.fill();

      //draw the bottom repeat dot
      dot_y += stave.getSpacingBetweenLines();
      stave.context.beginPath();
      stave.context.arc(dot_x, dot_y, dot_radius, 0, Math.PI * 2, false);
      stave.context.fill();
    }
  });

  return Barline;
}());
<|endoftext|>


<commit_before>var pause = undefined;
var play = undefined;
var audio = undefined;
var tapesound = undefined;
// var staticsound = undefined;

function endstatic()
{
document.body.style.backgroundImage = "none";
document.body.style.backgroundColor = "black";

//staticsound.pause();
}

function startmusic()
{
audio.play();
}

function startsound()
{
tapesound.play();
}

function onplay(e)
{
var curvebox = document.getElementById("curvebox");
var rude = document.getElementById("rude");
var spun = document.getElementById("spun");
curvebox.classList.add("getmeinofhere");
rude.classList.add("getmeoutofhere");
rude.style.display = null;
setTimeout(startmusic, 5000);
setTimeout(endstatic, 2000);
setTimeout(startsound, 1000);
}

function reset()
{
audio.currentTime = 0;
audio.pause();

tapesound.currentTime = 0;
tapesound.pause();

 // staticsound.play();

var string = "/img/tiled static.gif";
document.body.style.backgroundImage = "url('" + string + "')";
document.body.style.backgroundColor = "white";
}

window.onload = function()
{
var button = document.getElementById("OHGODWORK");
button.onclick = onplay;

console.log("load successed");
tapesound = document.createElement("audio");
tapesound.src = "/tapefeed.mp3";
tapesound.pause();

audio = document.createElement("audio");
audio.src = " https://oman.imjake.me/LawBreaker.mp3 ";
audio.pause();
audio.addEventListener('ended',function(){
	reset();
	},false);
}
<commit_msg>Update gdpr.js<commit_after>var pause = undefined;
var play = undefined;
var audio = undefined;
var tapesound = undefined;
// var staticsound = undefined;

function endstatic()
{
document.body.style.backgroundImage = "none";
document.body.style.backgroundColor = "white";

//staticsound.pause();
}

function startmusic()
{
audio.play();
}

function startsound()
{
tapesound.play();
rude.style.display = "none";
curvebox.style.display = "none";
spun.style.display = null;
}

function onplay(e)
{
var curvebox = document.getElementById("curvebox");
var rude = document.getElementById("rude");
var spun = document.getElementById("spun");
curvebox.classList.add("getmeinofhere");
rude.classList.add("getmeoutofhere");
rude.style.display = null;
setTimeout(startmusic, 5000);
setTimeout(endstatic, 2000);
}

function reset()
{
audio.currentTime = 0;
audio.pause();

tapesound.currentTime = 0;
tapesound.pause();

 // staticsound.play();

var string = "/img/tiled static.gif";
document.body.style.backgroundImage = "url('" + string + "')";
document.body.style.backgroundColor = "white";
}

window.onload = function()
{
var button = document.getElementById("OHGODWORK");
button.onclick = onplay;

console.log("load successed");
tapesound = document.createElement("audio");
tapesound.src = "/tapefeed.mp3";
tapesound.pause();

audio = document.createElement("audio");
audio.src = " https://oman.imjake.me/LawBreaker.mp3 ";
audio.pause();
audio.addEventListener('ended',function(){
	reset();
	},false);
}
<|endoftext|>


<commit_before>const email = require(__dirname + '/lib/chron_email.js');
const Plan = require(__dirname + '/models/plan.js');
const handlebars = require('handlebars');
const readFile = require('fs-readfile-promise');
const errorHandler = require(__dirname + '/lib/errorHandler.js');
const mongoose = require('mongoose');

function check(cb) {
  mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost/plan_db', (err) => {
    if (err) return errorHandler(err);
    var now = new Date();
    Plan.find( { 'reminderDate': { $lt: now } }, (err, remindArray) => {
      if (err) return console.log(err);
      var body;
      var template;
      readFile(__dirname + '/view/mail_template.html').then((buffer) => {
        template = handlebars.compile(buffer.toString());
        remindArray.forEach((value) => {
          body = template(value);
          var mailConfig = {
            from: 'info@preparedfordisaster.org',
            to: value.email,
            subject: 'Your Emergency Disaster Plan as of: ' + now,
            html: body
          };
          email.sendMail(mailConfig, (err, info) => {
            if (err) return console.log(err);
            process.stdout.write('Message sent: ' + info.response + '\n');
          });
          value.reminderDate.setDate(value.reminderDate.getDate() + value.reminderFrequency);
          Plan.update({ _id: value._id }, value, (err) => {
            if (err) return console.log(err);
            console.log('updated successfully');
          });
        });
        var timerCounter = 0;
        var timer = setInterval(() => {
          Plan.find( { 'reminderDate': { $lt: now } }, (err, checkArray) => {
            if (err) console.log(err);
            console.log(checkArray);
            timerCounter++;
            if ( checkArray.length === 0 || timerCounter === 30) {
              mongoose.disconnect(() => {
                clearInterval(timer);
                var callback = cb || function() {};
                // for testing purposes only
                callback();
              });
            }
          });
        }, 1000);
      });
    });
  });
}
module.exports = exports = check;
<commit_msg>email timeouts<commit_after>const email = require(__dirname + '/lib/chron_email.js');
const Plan = require(__dirname + '/models/plan.js');
const handlebars = require('handlebars');
const readFile = require('fs-readfile-promise');
const errorHandler = require(__dirname + '/lib/errorHandler.js');
const mongoose = require('mongoose');

function check(cb) {
  mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost/plan_db', (err, done) => {
    if (err) return errorHandler(err);
    var now = new Date();
    Plan.find( { 'reminderDate': { $lt: now } }, (err, remindArray) => {
      if (err) return console.log(err);
      var body;
      var template;
      readFile(__dirname + '/view/mail_template.html').then((buffer) => {
        template = handlebars.compile(buffer.toString());
        remindArray.forEach((value) => {
          body = template(value);
          var mailConfig = {
            from: 'info@preparedfordisaster.org',
            to: value.email,
            subject: 'Your Emergency Disaster Plan as of: ' + now,
            html: body
          };
          email.sendMail(mailConfig, (err, info) => {
            if (err) return console.log(err);
            process.stdout.write('Message sent: ' + info.response + '\n');
          });
          value.reminderDate.setDate(value.reminderDate.getDate() + value.reminderFrequency);
          Plan.update({ _id: value._id }, value, (err) => {
            if (err) return console.log(err);
            console.log('updated successfully');
          });
        });
        var timerCounter = 0;
        var timer = setInterval(() => {
          Plan.find( { 'reminderDate': { $lt: now } }, (err, checkArray) => {
            if (err) console.log(err);
            console.log(checkArray.length);
            timerCounter++;
            if ( checkArray.length === 0 || timerCounter === 5) {
              mongoose.disconnect(done);
              clearInterval(timer);
              var callback = cb || function() {};
              // for testing purposes only
              callback();
            }
          });
        }, 1000);
      });
    });
  });
}
module.exports = exports = check;
<|endoftext|>


<commit_before>'use strict';

import uuid from '../utils/uuid';
import VueResource from 'vue-resource';
import Vuex from 'vuex';
import Vue from 'vue';

import {
  ADD_TASK,
  DELETE_TASK,
  TOGGLE_COMPLETED,
  REPLACE_TASKS
} from './MutationTypes';

Vue.use(VueResource);
Vue.use(Vuex);

const Store = new Vuex.Store({
  state: {
    tasks: [
      { id: uuid(), description: 'Task 1', completed: false },
      { id: uuid(), description: 'Task 2', completed: false },
      { id: uuid(), description: 'Task 3', completed: true }
    ]
  },

  mutations: {
    /**
     * Add a new task to the local store
     */
    [ADD_TASK]: function(state, payload) {
      state.tasks.push({
        id: uuid(),
        description: payload.description,
        completed: payload.completed
      });
    },

    /**
     * Delete a task from the local store by index
     */
    [DELETE_TASK]: function(state, payload) {
      state.tasks.splice(payload.index, 1);
    },

    /**
     * Toggle the completed state of a specific task
     */
    [TOGGLE_COMPLETED]: function(state, payload) {
      let task = state.tasks.find(item => item.id == payload.id);
      task.completed = ! task.completed;
    },

    /**
     * Replace all tasks within the store
     */
    [REPLACE_TASKS]: function(state, payload) {
      state.tasks = payload.tasks;
    }
  },

  actions: {
    /**
     * Fetcyh tasks from end point
     */
    fetchTasks: function({ commit }) {
      Vue.http.get('/api/tasks')
        .then(response => {
          commit(REPLACE_TASKS, response.body);
        }, error => {
          console.log(error);
        });
    },

    /**
     * Persist tasks to server via end point
     */
    saveTasks: function({ state }) {
      Vue.http.put('/api/tasks', state.tasks)
        .then(() => {
          alert('Task list saved!');
        }, error => {
          console.log(error);
        });
    }
  }
});

export default Store;
<commit_msg>Comment out test data in store<commit_after>'use strict';

import uuid from '../utils/uuid';
import VueResource from 'vue-resource';
import Vuex from 'vuex';
import Vue from 'vue';

import {
  ADD_TASK,
  DELETE_TASK,
  TOGGLE_COMPLETED,
  REPLACE_TASKS
} from './MutationTypes';

Vue.use(VueResource);
Vue.use(Vuex);

const Store = new Vuex.Store({
  state: {
    tasks: [
      // { id: uuid(), description: 'Task 1', completed: false },
      // { id: uuid(), description: 'Task 2', completed: false },
      // { id: uuid(), description: 'Task 3', completed: true }
    ]
  },

  mutations: {
    /**
     * Add a new task to the local store
     */
    [ADD_TASK]: function(state, payload) {
      state.tasks.push({
        id: uuid(),
        description: payload.description,
        completed: payload.completed
      });
    },

    /**
     * Delete a task from the local store by index
     */
    [DELETE_TASK]: function(state, payload) {
      state.tasks.splice(payload.index, 1);
    },

    /**
     * Toggle the completed state of a specific task
     */
    [TOGGLE_COMPLETED]: function(state, payload) {
      let task = state.tasks.find(item => item.id == payload.id);
      task.completed = ! task.completed;
    },

    /**
     * Replace all tasks within the store
     */
    [REPLACE_TASKS]: function(state, payload) {
      state.tasks = payload.tasks;
    }
  },

  actions: {
    /**
     * Fetcyh tasks from end point
     */
    fetchTasks: function({ commit }) {
      Vue.http.get('/api/tasks')
        .then(response => {
          commit(REPLACE_TASKS, response.body);
        }, error => {
          console.log(error);
        });
    },

    /**
     * Persist tasks to server via end point
     */
    saveTasks: function({ state }) {
      Vue.http.put('/api/tasks', state.tasks)
        .then(() => {
          alert('Task list saved!');
        }, error => {
          console.log(error);
        });
    }
  }
});

export default Store;
<|endoftext|>


<commit_before>// Disable eslint do not modify native methods
/* eslint-disable no-extend-native */

String.prototype.hasVowels = function hasVowels() {
  // Returns true if a vowel exists in the input string. Returns false otherwise.
  const vowels = new RegExp('[aeiou]', 'i');
  return vowels.test(this);
};

String.prototype.toUpper = function toUpper() {
  /* Replace all lowercase letters in the input string with their uppercase
  * analogs by converting each letter's ASCII value to decimal then back to
  * ASCII
  */
  const upper = new RegExp('[a-z]', 'g');
  return this.replace(upper, function transform(letter) {
    return String.fromCharCode(letter.charCodeAt(0) - 32);
  });
};

String.prototype.toLower = function toLower() {
  const lower = new RegExp('[A-Z]', 'g');
  return this.replace(lower, function transform(letter) {
    return String.fromCharCode(letter.charCodeAt(0) + 32);
  });
};

String.prototype.ucFirst = function ucFirst() {
  /* Convert the first character of the input string to uppercase then concatenate
  * the rest of the string with the uppercase character
  */
  return this.length ? this[0].toUpper() + this.slice(1) : '';
};

String.prototype.isQuestion = function isQuestion() {
  // Returns true if the last letter of the input string a question mark. False otherwise
  const questionable = new RegExp(/\?$/);
  return questionable.test(this);
};

String.prototype.words = function words() {
  /* Returns an array of the words in the input string
  * The expression evaluates to true for a word with a letter as it's first character
  */
  const beginningVoid = /^\w/;
  return beginningVoid.test(this) ? this.trim().split(' ') : [];
};

String.prototype.wordCount = function wordCount() {
  return this.words().length;
};

String.prototype.cleanWords = function words() {
  /* Filter out any non word characters at the beginning and end of the input string.
  * Split the new string at any non word character excluding the apostrophe.
  * and return an array of words.
  * i.e. Don't split at (A-Z,a-z,0-9 or ')
  */
  const parsedString = this.trim().replace(new RegExp(/^\W|\W$/g), '');
  return parsedString.split(new RegExp(new RegExp(/[^A-Za-z0-9_']+/g)));
};

String.prototype.toCurrency = function toCurrency() {
  /* (/d) -> Matches digits from 0-9 and remembers the particular digit match
  * (/d)(?=(\d{3})+\.) -> Lookahead - Only matches a digit if it is followed by
  * three or other digits and if the entire string is a float.
  * Upon encountering match, insert a comma character
  */
  const currency = new RegExp(/(\d)(?=(\d{3})+\.)/g);
  return (parseFloat(this).toFixed(2).replace(currency, '$1,'));
};

String.prototype.fromCurrency = function fromCurrency() {
  // Converts a string representation of a currency to a number
  return Number(this.replace(/,/, ''));
};

String.prototype.isEven = function isEven() {
  // Returns true if the input string is an even number. Returns false otherwise.
  const even = new RegExp('d*[02468]$', 'g');
  return this == '0' ? false : even.test(parseInt(this, 10));
};

String.prototype.toTitle = function toTitle() {
  /* Returns the input string in titlecase
   * Matches any word character multiple times at a word boundary
   */
  return this.replace(/\b\w+/g, function transform(string) {
    return string.charAt(0).toUpper() + string.substr(1).toLower();
  });
};

String.prototype.toCamel = function toCamel() {
  // Returns the input string in camelcase
  const camel = new RegExp(/(?:^\w|[A-Z]|\b\w)/g);
  return this.replace(camel, function transform(letter, index) {
    return index === 0 ? letter.toLower() : letter.toUpper();
  }).replace(/\s+/g, '');
};

String.prototype.toToggle = function toToggle() {
  // Returns the input string in togglecase beginning with a lowercase letter
  const toggled = new RegExp(/\w+/g);
  let counter = 0;
  let toggledString = '';

  for (const letter of this) {
    if (letter.match(toggled)) {
      toggledString = toggledString.concat(counter % 2 === 0 ? letter.toLower() :
      letter.toUpper());
      counter++;
    } else {
      toggledString = toggledString.concat(letter);
    }
  }
  return toggledString;
};
<commit_msg>Refactor isEven method<commit_after>// Disable eslint do not modify native methods
/* eslint-disable no-extend-native */

String.prototype.hasVowels = function hasVowels() {
  // Returns true if a vowel exists in the input string. Returns false otherwise.
  const vowels = new RegExp('[aeiou]', 'i');
  return vowels.test(this);
};

String.prototype.toUpper = function toUpper() {
  /* Replace all lowercase letters in the input string with their uppercase
  * analogs by converting each letter's ASCII value to decimal then back to
  * ASCII
  */
  const upper = new RegExp('[a-z]', 'g');
  return this.replace(upper, function transform(letter) {
    return String.fromCharCode(letter.charCodeAt(0) - 32);
  });
};

String.prototype.toLower = function toLower() {
  const lower = new RegExp('[A-Z]', 'g');
  return this.replace(lower, function transform(letter) {
    return String.fromCharCode(letter.charCodeAt(0) + 32);
  });
};

String.prototype.ucFirst = function ucFirst() {
  /* Convert the first character of the input string to uppercase then concatenate
  * the rest of the string with the uppercase character
  */
  return this.length ? this[0].toUpper() + this.slice(1) : '';
};

String.prototype.isQuestion = function isQuestion() {
  // Returns true if the last letter of the input string a question mark. False otherwise
  const questionable = new RegExp(/\?$/);
  return questionable.test(this);
};

String.prototype.words = function words() {
  /* Returns an array of the words in the input string
  * The expression evaluates to true for a word with a letter as it's first character
  */
  const beginningVoid = /^\w/;
  return beginningVoid.test(this) ? this.trim().split(' ') : [];
};

String.prototype.wordCount = function wordCount() {
  return this.words().length;
};

String.prototype.cleanWords = function words() {
  /* Filter out any non word characters at the beginning and end of the input string.
  * Split the new string at any non word character excluding the apostrophe.
  * and return an array of words.
  * i.e. Don't split at (A-Z,a-z,0-9 or ')
  */
  const parsedString = this.trim().replace(new RegExp(/^\W|\W$/g), '');
  return parsedString.split(new RegExp(new RegExp(/[^A-Za-z0-9_']+/g)));
};

String.prototype.toCurrency = function toCurrency() {
  /* (/d) -> Matches digits from 0-9 and remembers the particular digit match
  * (/d)(?=(\d{3})+\.) -> Lookahead - Only matches a digit if it is followed by
  * three or other digits and if the entire string is a float.
  * Upon encountering match, insert a comma character
  */
  const currency = new RegExp(/(\d)(?=(\d{3})+\.)/g);
  return (parseFloat(this).toFixed(2).replace(currency, '$1,'));
};

String.prototype.fromCurrency = function fromCurrency() {
  // Converts a string representation of a currency to a number
  return Number(this.replace(/,/, ''));
};

String.prototype.isEven = function isEven() {
  // Returns true if the input string is an even number. Returns false otherwise.
  const even = new RegExp('d*[02468]$', 'g');
  return even.test(parseInt(this, 10));
};

String.prototype.toTitle = function toTitle() {
  /* Returns the input string in titlecase
   * Matches any word character multiple times at a word boundary
   */
  return this.replace(/\b\w+/g, function transform(string) {
    return string.charAt(0).toUpper() + string.substr(1).toLower();
  });
};

String.prototype.toCamel = function toCamel() {
  // Returns the input string in camelcase
  const camel = new RegExp(/(?:^\w|[A-Z]|\b\w)/g);
  return this.replace(camel, function transform(letter, index) {
    return index === 0 ? letter.toLower() : letter.toUpper();
  }).replace(/\s+/g, '');
};

String.prototype.toToggle = function toToggle() {
  // Returns the input string in togglecase beginning with a lowercase letter
  const toggled = new RegExp(/\w+/g);
  let counter = 0;
  let toggledString = '';

  for (const letter of this) {
    if (letter.match(toggled)) {
      toggledString = toggledString.concat(counter % 2 === 0 ? letter.toLower() :
      letter.toUpper());
      counter++;
    } else {
      toggledString = toggledString.concat(letter);
    }
  }
  return toggledString;
};
<|endoftext|>


<commit_before>// Copyright 2009, 2010, 2011 Chris Forno
//
// This file is part of Vocabulink.
//
// Vocabulink is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Vocabulink is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Vocabulink. If not, see <http://www.gnu.org/licenses/>.

(function ($) {

V.annotateLink = function (link) {
  link.children('.foreign, .familiar, .dest').each(function () {
    var word = $(this);
    var caption = $('' + word.attr('title') + '');
    // We have to calculate these before we add content to them and screw up
    // the dimensions.
    var width = word.outerWidth();
    if (word.hasClass('foreign') || word.hasClass('familiar')) {
      var y = word.outerHeight() + 4;
    } else {
      var y = word.height() + 8;
    }
    caption.appendTo(word);
    var x = (width - caption.width()) / 2;
    caption.css({'position': 'absolute', 'left': x, 'top': y});
  });
}

function linkNumber() {
  return window.location.pathname.split('/').pop();
}

function collapseStory(q, h, mh) {
  q.addClass('collapsed').css('height', mh);
  var readMore = $('
read more...
');
  readMore.find('a').click(function () {
    var readLess = $('read less...');
    readLess.click(function () {
      q.animate({'height': mh}, 750, function () {
        readMore.remove();
        collapseStory(q, h, mh);
      });
    });
    q.animate({'height': h}, 750, function () {
      q.removeClass('collapsed');
      readMore.find('a').replaceWith(readLess);
    });
  });
  q.after(readMore);
}

function showNewStory() {
  var newStory =
    $('
'
      + '
'
        + '<form method="post" action="/link/' + linkNumber() + '/stories">'
          + '
'
            + '<textarea name="story" required placeholder="Add your own story here."></textarea>'
          + '
'
        + '</form>'
      + '
'
    + '
');
  newStory.appendTo('#linkword-stories');
  newStory.find('textarea').one('focus', function () {
    $(this).animate({'height': '10em'}, 250, function () {
      $(this).markItUp(mySettings);
      $(this).select().focus();
      $(this).parents('form').append(
        '
'
        + '<input type="submit" class="save light" value="Save Story"></input>'
        + '<button class="cancel">cancel</button>'
        + '

'
      + '
');
      newStory.find('.cancel').click(function () {
        newStory.remove();
        showNewStory();
      });
    });
  });
  $('form', newStory).minform();
}

$(function () {
  V.annotateLink($('h1.link:visible'));

  $('#pronounce').click(function () {
    $(this).find('audio')[0].play();
  });

  $('.linkword-story blockquote').each(function () {
    if ($(this).height() > 140) {
      collapseStory($(this), $(this).height(), 140);
    }
  });

  if (V.loggedIn()) {
    showNewStory();
    $('.linkword-story').each(function () {
      if ($(this).find('.username').text() === V.memberName()) {
        var sig = $(this).find('.signature');
        var editButton = $('<button class="light">Edit</button>');
        editButton.click(function () {
          var story = $(this).parents('.linkword-story');
          var storyNumber = parseInt(story.parent().find('a:first').attr('id'), 10);
          story.mask('Loading...');
          var body = $.ajax({ 'type': 'GET'
                            , 'url': '/link/story/' + storyNumber
                            , 'success': function (data) {
                              story.unmask();
                              story.hide();
                              var form = $(
                                '<form class="linkword-story" method="post" action="/link/story/' + storyNumber + '">'
                                + '
'
                                  + '<textarea name="story" required>' + data + '</textarea>'
                                + '
'
                                + '
'
                                  + '<input type="submit" value="Save" class="light">'
                                  + '<button class="cancel">cancel</button>'
                                + '
'
                              + '</form>').insertAfter(story).minform();
                              form.find('textarea').css('height', '10em').markItUp(mySettings);
                              form.find('.cancel').click(function () {
                                form.remove();
                                story.show();
                              });
                            }
                            , 'error': function () {
                              story.unmask();
                              alert('Error retrieving story.');
                            }
                           });
        });
        sig.prepend(editButton);
      }
    });
  }

  // "add to review"
  $('#link-op-review.enabled').click(function () {
    var op = $(this);
    op.mask("Adding...");
    var linkNum = window.location.pathname.split('/').pop();
    $.postJSON('/review/' + linkNum + '/add', null, function (successful, data) {
      op.unmask();
      op.removeClass("enabled").addClass("disabled");
      if (successful) {
        op.text("now reviewing");
      } else {
        op.addClass("failed");
        op.text("Failed!");
      }
    });
  });

  // "delete link"
  $('#link-op-delete.enabled').click(function () {
    var op = $(this);
    op.mask('Deleting...');
    $.ajax({'type': 'DELETE'
           ,'url': '/link/' + linkNumber()
           ,'success': function () {
             op.text('Deleted.');
           }
           ,'error': function () {
             op.addClass('failed');
             op.text('Failed!');
           }
          });
  });
});

})(jQuery);<commit_msg>Fixing JS error on non-linkword links.<commit_after>// Copyright 2009, 2010, 2011 Chris Forno
//
// This file is part of Vocabulink.
//
// Vocabulink is free software: you can redistribute it and/or modify it under
// the terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Vocabulink is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Vocabulink. If not, see <http://www.gnu.org/licenses/>.

(function ($) {

V.annotateLink = function (link) {
  link.children('.foreign, .familiar, .dest').each(function () {
    var word = $(this);
    var caption = $('' + word.attr('title') + '');
    // We have to calculate these before we add content to them and screw up
    // the dimensions.
    var width = word.outerWidth();
    if (word.hasClass('foreign') || word.hasClass('familiar')) {
      var y = word.outerHeight() + 4;
    } else {
      var y = word.height() + 8;
    }
    caption.appendTo(word);
    var x = (width - caption.width()) / 2;
    caption.css({'position': 'absolute', 'left': x, 'top': y});
  });
}

function linkNumber() {
  return window.location.pathname.split('/').pop();
}

function collapseStory(q, h, mh) {
  q.addClass('collapsed').css('height', mh);
  var readMore = $('
read more...
');
  readMore.find('a').click(function () {
    var readLess = $('read less...');
    readLess.click(function () {
      q.animate({'height': mh}, 750, function () {
        readMore.remove();
        collapseStory(q, h, mh);
      });
    });
    q.animate({'height': h}, 750, function () {
      q.removeClass('collapsed');
      readMore.find('a').replaceWith(readLess);
    });
  });
  q.after(readMore);
}

function showNewStory() {
  var newStory =
    $('
'
      + '
'
        + '<form method="post" action="/link/' + linkNumber() + '/stories">'
          + '
'
            + '<textarea name="story" required placeholder="Add your own story here."></textarea>'
          + '
'
        + '</form>'
      + '
'
    + '
');
  newStory.appendTo('#linkword-stories');
  newStory.find('textarea').one('focus', function () {
    $(this).animate({'height': '10em'}, 250, function () {
      $(this).markItUp(mySettings);
      $(this).select().focus();
      $(this).parents('form').append(
        '
'
        + '<input type="submit" class="save light" value="Save Story"></input>'
        + '<button class="cancel">cancel</button>'
        + '

'
      + '
');
      newStory.find('.cancel').click(function () {
        newStory.remove();
        showNewStory();
      });
    });
  });
  $('form', newStory).minform();
}

$(function () {
  V.annotateLink($('h1.link:visible'));

  $('#pronounce').click(function () {
    $(this).find('audio')[0].play();
  });

  $('.linkword-story blockquote').each(function () {
    if ($(this).height() > 140) {
      collapseStory($(this), $(this).height(), 140);
    }
  });

  if (V.loggedIn() && $('#linkword-stories').length) {
    showNewStory();
    $('.linkword-story').each(function () {
      if ($(this).find('.username').text() === V.memberName()) {
        var sig = $(this).find('.signature');
        var editButton = $('<button class="light">Edit</button>');
        editButton.click(function () {
          var story = $(this).parents('.linkword-story');
          var storyNumber = parseInt(story.parent().find('a:first').attr('id'), 10);
          story.mask('Loading...');
          var body = $.ajax({ 'type': 'GET'
                            , 'url': '/link/story/' + storyNumber
                            , 'success': function (data) {
                              story.unmask();
                              story.hide();
                              var form = $(
                                '<form class="linkword-story" method="post" action="/link/story/' + storyNumber + '">'
                                + '
'
                                  + '<textarea name="story" required>' + data + '</textarea>'
                                + '
'
                                + '
'
                                  + '<input type="submit" value="Save" class="light">'
                                  + '<button class="cancel">cancel</button>'
                                + '
'
                              + '</form>').insertAfter(story).minform();
                              form.find('textarea').css('height', '10em').markItUp(mySettings);
                              form.find('.cancel').click(function () {
                                form.remove();
                                story.show();
                              });
                            }
                            , 'error': function () {
                              story.unmask();
                              alert('Error retrieving story.');
                            }
                           });
        });
        sig.prepend(editButton);
      }
    });
  }

  // "add to review"
  $('#link-op-review.enabled').click(function () {
    var op = $(this);
    op.mask("Adding...");
    var linkNum = window.location.pathname.split('/').pop();
    $.postJSON('/review/' + linkNum + '/add', null, function (successful, data) {
      op.unmask();
      op.removeClass("enabled").addClass("disabled");
      if (successful) {
        op.text("now reviewing");
      } else {
        op.addClass("failed");
        op.text("Failed!");
      }
    });
  });

  // "delete link"
  $('#link-op-delete.enabled').click(function () {
    var op = $(this);
    op.mask('Deleting...');
    $.ajax({'type': 'DELETE'
           ,'url': '/link/' + linkNumber()
           ,'success': function () {
             op.text('Deleted.');
           }
           ,'error': function () {
             op.addClass('failed');
             op.text('Failed!');
           }
          });
  });
});

})(jQuery);<|endoftext|>


<commit_before>
/*
 * Customization options available -
 *
 * tala pattern = || , , , , | , , | , , ||
 * aksharas per line = 8
 * aksharas = aksharas per line
 * line spacing = 22
 * para spacing = 22
 * notation font size = 13
 * notation small font size = 11
 * notation font = serif
 * text font = serif
 * stretch = 1.0
 * stretch space = 1.0
 * margin top = 22
 * margin left = 10
 * line extension top = 0
 * line extension bottom = 5
 *
 */
function RenderSVG(window, section, paragraphs, style) {

    var keyTalaPattern = '$tala pattern';
    var keyAksharasPerLine = '$aksharas per line';
    var keyAksharas = '$aksharas';
    var keyLineSpacing = '$line spacing';
    var keyParaSpacing = '$para spacing';
    var keyNotationFontSize = '$notation font size';
    var keyNotationSmallFontSize = '$notation small font size';
    var keyNotationFont = '$notation font';
    var keyTextFont = '$text font';
    var keyStretch = '$stretch';
    var keyStretchSpace = '$stretch space';
    var keyMarginTop = '$margin top';
    var keyMarginLeft = '$margin left';
    var keyLineExtensionTop = '$line extension top';
    var keyLineExtensionBottom = '$line extension bottom';

    var talaCache = {};
    var cursor = {x: 0, y: 0, xmax: 0, ymax: 0};
    var pendingLines = {};

    loadStyleDefaults(style);

    section.hidden = true;
    cursor.y = style[keyMarginTop];
    cursor.x = style[keyMarginLeft];

    processTalaPatterns(paragraphs);

    var div = window.document.createElement('div');
    var svg = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    div.insertBefore(svg, null);

    paragraphs.forEach(typesetPara);

    svg.setAttribute('width', cursor.xmax);
    svg.setAttribute('height', cursor.ymax);

    section.parentElement.insertBefore(div, section);

    function extendLine(ix, x, fromY, toY) {
        var l = pendingLines[ix];
        if (!l) {
            l = pendingLines[ix] = {x: x, fromY: fromY, toY: toY};
        }

        l.toY = toY;
    }

    function flushLines() {
        var ix, l;
        for (ix in pendingLines) {
            if (pendingLines.hasOwnProperty(ix)) {
                l = pendingLines[ix];
                svgelem(svg, 'line', {
                    x1: l.x,
                    y1: l.fromY,
                    x2: l.x,
                    y2: l.toY,
                    'stroke-width': 2,
                    stroke: 'black'
                });
            }
        }
        pendingLines = {};
    }

    function typesetPara(para, i) {
        if (para.lines) {
            para.lines.forEach(function (line) { typesetLine(para, line); });
            flushLines();
            if (i + 1 < paragraphs.length) {
                nextLine(keyParaSpacing);
            }
        }
    }

    function typesetLine(para, line) {
        switch (line.type) {
            case 'text':
                flushLines();
                typesetText(para, line);
                break;
            case 'svarasthana':
                typesetSvarasthana(para, line);
                break;
            case 'lyrics':
                typesetLyrics(para, line);
                break;
            default:
                throw new Error('Unknown line type ' + line.type);
        }
    }

    function typesetText(para, line) {
        svgelem(svg, 'text', {x: cursor.x, y: cursor.y, style: ('font-family: ' + style[keyTextFont] + ';') + 'font-size: 12pt;'}, line.tokens.join(' '));
        nextLine();
        cursor.y += style[keyLineExtensionTop] + style[keyLineExtensionBottom];
    }

    function typesetSvarasthana(para, line) {
        typesetTimedText(para, line);
    }

    function getSubSvaras(word) {
        return word.match(/([SrRgGmMPdDnNS][\+\-]*)|[,_]/g) || [];
    }

    function typesetTimedText(para, line, additionalTextStyle) {
        var tala = para.properties[keyTalaPattern];
        var akshIx = 0, instrIx = 0, tokIx = 0, instr;

        // Skip aksharas until start
        while (akshIx < para.tala_interval.from) {
            if (tala.instructions[instrIx].tick) {
                akshIx++;
            }
            instrIx++;
        }

        // Skip all spaces
        while (instrIx < tala.instructions.length && tala.instructions[instrIx].space) {
            ++instrIx;
        }

        var givenAksharas = +(para.properties[keyAksharas] || para.properties[keyAksharasPerLine]);
        var startAkshIx = akshIx;
        var startInstrIx = instrIx;
        var subdivs = line.tokens.length / givenAksharas;
        var textStyle = ('font-family:' + style[keyNotationFont] + ';') + ('font-size:' + (subdivs > 2 ? style[keyNotationSmallFontSize] : style[keyNotationFontSize]) + 'pt;') + (additionalTextStyle || '');
        var textStyleSmall = ('font-family:' + style[keyNotationFont] + ';') + ('font-size:' + style[keyNotationSmallFontSize] + 'pt;') + (additionalTextStyle || '');
        var subDivIx = 0;
        var stretch = (+para.properties[keyStretch]) * style[keyStretch];
        var stretchSpace = stretch * ((+para.properties[keyStretchSpace]) || style[keyStretchSpace]);
        var subsvaras, props, dx;
        var isSvarasthana = line.type === 'svarasthana';

        REQUIRE(subdivs % 1.0 < 0.00001, "Invalid subdivision");
        subdivs = Math.floor(subdivs);
        props = {x: cursor.x, y: cursor.y, style: textStyle};

        var renderSubsvara = function (s) {
            svgelem(svg, 'text', props, show(s));
            props.x += dx / subsvaras.length;
        };

        while (akshIx < para.tala_interval.to) {
            instr = tala.instructions[instrIx];
            if (instr.tick) {
                dx = instr.tick * stretch / subdivs;
                props.x = cursor.x;
                props.y = cursor.y;
                props.style = textStyle;
                if (isSvarasthana) {
                    subsvaras = getSubSvaras(line.tokens[tokIx]);
                    if (subsvaras.length > 2) {
                        props.style = textStyleSmall;
                    }
                    subsvaras.forEach(renderSubsvara);
                } else {
                    svgelem(svg, 'text', props, show(line.tokens[tokIx]));
                }
                cursor.x += dx;
                ++subDivIx;
                ++tokIx;
                if (subDivIx >= subdivs) {
                    subDivIx = 0;
                    ++akshIx;
                    ++instrIx;
                } else {
                    continue;
                }
            }

            // Consume other non-tick instructions up to the next tick.
            while (instrIx < tala.instructions.length && (instr = tala.instructions[instrIx], !instr.tick)) {
                if (instr.space) {
                    if (instr.scale) {
                        cursor.x += instr.space * stretchSpace;
                    } else {
                        cursor.x += instr.space;
                    }
                } else if (instr.line) {
                    if (instr.draw) {
                        extendLine(instrIx,
                                cursor.x,
                                cursor.y - style[keyLineSpacing] - style[keyLineExtensionTop],
                                cursor.y + style[keyLineExtensionBottom]);
                    }
                    cursor.x += instr.line;
                }
                instr = tala.instructions[++instrIx];
            }
        }

        nextLine();
    }

    function typesetLyrics(para, line) {
        typesetTimedText(para, line, 'font-style: italic;');
    }

    function nextLine(spacingKey) {
        cursor.y += style[spacingKey || keyLineSpacing];
        cursor.ymax = Math.max(cursor.y, cursor.ymax);
        cursor.xmax = Math.max(cursor.x + 40, cursor.xmax);
        cursor.x = style[keyMarginLeft];
    }

    // Augment each "paragraph" with information about
    // where in the tala cycle it begins and where it
    // ends.
    //
    // Adds "tala_interval" property, which is an object
    // of the form {from: m, to:n}, where the aksharas
    // included are k >= m & k < n.
    function processTalaPatterns(paragraphs) {
        var fromAkshara = 0, toAkshara = 0, aksharas = 0, aksharasInTala = 0, aksharasPerLine = 0;

        var i, N, para, tala, aksh;

        for (i = 0, N = paragraphs.length; i < N; ++i) {

            para = paragraphs[i];
            tala = para.properties[keyTalaPattern];

            aksharasInTala = countAksharasInTala(tala);
            aksharasPerLine = +(para.properties[keyAksharasPerLine]);
            aksharas = +(para.properties[keyAksharas] || para.properties[keyAksharasPerLine]);

            toAkshara += aksharas;

            // Repeat the tala pattern enough times to cover the given notation line.
            aksh = aksharasInTala;
            while (toAkshara > aksh) {
                para.properties[keyTalaPattern] += tala;
                aksh += aksharasInTala;
            }

            // On repetition, you may find patterns such as '||||' in the tala.
            // This we normalize to '||' - i.e. the maximum number of times a vertical
            // bar may be repeated is 2.
            tala = para.properties[keyTalaPattern] = compileTala(para.properties[keyTalaPattern].replace(/\|\|+/g, '||'));

            var paraAksharas = +(para.properties[keyAksharas] || para.properties[keyAksharasPerLine]);

            // Adjust notation lines whose akshara count is smaller than
            // the given aksharas per line. We do this by stretching the
            // line by an integer factor.
            para.lines.forEach(function (line) {
                if (line.type !== 'text') {
                    if (line.tokens.length < paraAksharas) {
                        ASSERT(aksh % line.tokens.length === 0);
                        var i, j, M, N, newTokens = [];
                        M = aksh / line.tokens.length;
                        for (i = 0, N = line.tokens.length; i < N; ++i) {
                            newTokens.push(line.tokens[i]);
                            for (j = 1; j < M; ++j) {
                                newTokens.push('_');
                            }
                        }
                        line.tokens = newTokens;
                    }
                }
            });

            para.tala_interval = {
                from: fromAkshara,
                to: toAkshara
            };

            // Modulo tala cycle.
            fromAkshara = toAkshara;
            while (fromAkshara >= aksharasInTala) {
                fromAkshara -= aksharasInTala;
                toAkshara -= aksharasInTala;
            }
        }

        return paragraphs;
    }

    function compileTala(talaPattern) {
        var talaKey = '$' + talaPattern;

        if (talaKey in talaCache) {
            return talaCache[talaKey];
        }

        var i, N, c, instrs = [], nearLine;
        for (i = 0, N = talaPattern.length; i < N; ++i) {
            c = talaPattern.charAt(i);
            nearLine = (i + 1 < N && talaPattern.charAt(i+1) === '|') || (i > 0 && talaPattern.charAt(i-1) === '|');
            switch (c) {
                case '|' :
                    if (nearLine) {
                        instrs.push({line: 5, draw: true});
                    } else {
                        instrs.push({line: 10, draw: true});
                    }
                    break;
                case ' ':
                    if (nearLine) {
                        instrs.push({space: 15, scale: false});
                    } else {
                        instrs.push({space: 30, scale: true});
                    }
                    break;
                case ',':
                    instrs.push({tick: 40});
                    break;
                case '_':
                    instrs.push({line: 10, draw: false});
                    break;
                default:
                    throw new Error('Unknown pattern character [' + c + '] in tala - "' + talaPattern + '"');
            }
        }

        return (talaCache[talaKey] = {
            pattern: talaPattern,
            aksharas: countAksharasInTala(talaPattern),
            instructions: instrs
        });
    }

    function countAksharasInTala(talaPattern) {
        var commas = talaPattern.match(/,/g);
        return (commas && commas.length) || 0;
    }

    function show(text) {
        var hisa = "Ṡ";
        var losa = "Ṣ";

        if (text === '_') {
            return "";
        }

        if (text.length === 2 && text[1] === '+') {
            return text[0] + hisa[1];
        }

        if (text.length === 2 && text[1] === '-') {
            return text[0] + losa[1];
        }

        return text;
    }

    function svgelem(elem, n, attrs, content) {
        var tag = window.document.createElementNS('http://www.w3.org/2000/svg', n);
        if (attrs) {
            Object.keys(attrs).forEach(function (k) {
                if (attrs[k]) {
                    tag.setAttribute(k, attrs[k]);
                }
            });
        }
        if (content) {
            tag.textContent = content;
        }
        elem.appendChild(tag);
        return tag;
    }

    function loadStyleDefaults(style) {
        style[keyLineSpacing] = (+style[keyLineSpacing]) || 22;
        style[keyParaSpacing] = (+style[keyParaSpacing]) || style[keyLineSpacing];
        style[keyNotationFontSize] = (+style[keyNotationFontSize]) || 13;
        style[keyNotationSmallFontSize] = (+style[keyNotationSmallFontSize]) || (style[keyNotationFontSize] - 2);
        style[keyNotationFont] = (style[keyNotationFont] || 'serif');
        style[keyTextFont] = (style[keyTextFont] || 'serif');
        style[keyStretch] = (+style[keyStretch]) || 1.0;
        style[keyStretchSpace] = (+style[keyStretchSpace]) || 1.0;
        style[keyMarginTop] = (+style[keyMarginTop]) || style[keyLineSpacing];
        style[keyMarginLeft] = (+style[keyMarginLeft]) || 10;
        style[keyLineExtensionTop] = (+style[keyLineExtensionTop]) || 0;
        style[keyLineExtensionBottom] = (+style[keyLineExtensionBottom]) || 5;
    }

    return null;
}
<commit_msg>Changed default notation font to sans-serif which looks nicer.<commit_after>
/*
 * Customization options available -
 *
 * tala pattern = || , , , , | , , | , , ||
 * aksharas per line = 8
 * aksharas = aksharas per line
 * line spacing = 22
 * para spacing = 22
 * notation font size = 13
 * notation small font size = 11
 * notation font = serif
 * text font = serif
 * stretch = 1.0
 * stretch space = 1.0
 * margin top = 22
 * margin left = 10
 * line extension top = 0
 * line extension bottom = 5
 *
 */
function RenderSVG(window, section, paragraphs, style) {

    var keyTalaPattern = '$tala pattern';
    var keyAksharasPerLine = '$aksharas per line';
    var keyAksharas = '$aksharas';
    var keyLineSpacing = '$line spacing';
    var keyParaSpacing = '$para spacing';
    var keyNotationFontSize = '$notation font size';
    var keyNotationSmallFontSize = '$notation small font size';
    var keyNotationFont = '$notation font';
    var keyTextFont = '$text font';
    var keyStretch = '$stretch';
    var keyStretchSpace = '$stretch space';
    var keyMarginTop = '$margin top';
    var keyMarginLeft = '$margin left';
    var keyLineExtensionTop = '$line extension top';
    var keyLineExtensionBottom = '$line extension bottom';

    var talaCache = {};
    var cursor = {x: 0, y: 0, xmax: 0, ymax: 0};
    var pendingLines = {};

    loadStyleDefaults(style);

    section.hidden = true;
    cursor.y = style[keyMarginTop];
    cursor.x = style[keyMarginLeft];

    processTalaPatterns(paragraphs);

    var div = window.document.createElement('div');
    var svg = window.document.createElementNS('http://www.w3.org/2000/svg', 'svg');
    div.insertBefore(svg, null);

    paragraphs.forEach(typesetPara);

    svg.setAttribute('width', cursor.xmax);
    svg.setAttribute('height', cursor.ymax);

    section.parentElement.insertBefore(div, section);

    function extendLine(ix, x, fromY, toY) {
        var l = pendingLines[ix];
        if (!l) {
            l = pendingLines[ix] = {x: x, fromY: fromY, toY: toY};
        }

        l.toY = toY;
    }

    function flushLines() {
        var ix, l;
        for (ix in pendingLines) {
            if (pendingLines.hasOwnProperty(ix)) {
                l = pendingLines[ix];
                svgelem(svg, 'line', {
                    x1: l.x,
                    y1: l.fromY,
                    x2: l.x,
                    y2: l.toY,
                    'stroke-width': 2,
                    stroke: 'black'
                });
            }
        }
        pendingLines = {};
    }

    function typesetPara(para, i) {
        if (para.lines) {
            para.lines.forEach(function (line) { typesetLine(para, line); });
            flushLines();
            if (i + 1 < paragraphs.length) {
                nextLine(keyParaSpacing);
            }
        }
    }

    function typesetLine(para, line) {
        switch (line.type) {
            case 'text':
                flushLines();
                typesetText(para, line);
                break;
            case 'svarasthana':
                typesetSvarasthana(para, line);
                break;
            case 'lyrics':
                typesetLyrics(para, line);
                break;
            default:
                throw new Error('Unknown line type ' + line.type);
        }
    }

    function typesetText(para, line) {
        svgelem(svg, 'text', {x: cursor.x, y: cursor.y, style: ('font-family: ' + style[keyTextFont] + ';') + 'font-size: 12pt;'}, line.tokens.join(' '));
        nextLine();
        cursor.y += style[keyLineExtensionTop] + style[keyLineExtensionBottom];
    }

    function typesetSvarasthana(para, line) {
        typesetTimedText(para, line);
    }

    function getSubSvaras(word) {
        return word.match(/([SrRgGmMPdDnNS][\+\-]*)|[,_]/g) || [];
    }

    function typesetTimedText(para, line, additionalTextStyle) {
        var tala = para.properties[keyTalaPattern];
        var akshIx = 0, instrIx = 0, tokIx = 0, instr;

        // Skip aksharas until start
        while (akshIx < para.tala_interval.from) {
            if (tala.instructions[instrIx].tick) {
                akshIx++;
            }
            instrIx++;
        }

        // Skip all spaces
        while (instrIx < tala.instructions.length && tala.instructions[instrIx].space) {
            ++instrIx;
        }

        var givenAksharas = +(para.properties[keyAksharas] || para.properties[keyAksharasPerLine]);
        var startAkshIx = akshIx;
        var startInstrIx = instrIx;
        var subdivs = line.tokens.length / givenAksharas;
        var textStyle = ('font-family:' + style[keyNotationFont] + ';') + ('font-size:' + (subdivs > 2 ? style[keyNotationSmallFontSize] : style[keyNotationFontSize]) + 'pt;') + (additionalTextStyle || '');
        var textStyleSmall = ('font-family:' + style[keyNotationFont] + ';') + ('font-size:' + style[keyNotationSmallFontSize] + 'pt;') + (additionalTextStyle || '');
        var subDivIx = 0;
        var stretch = (+para.properties[keyStretch]) * style[keyStretch];
        var stretchSpace = stretch * ((+para.properties[keyStretchSpace]) || style[keyStretchSpace]);
        var subsvaras, props, dx;
        var isSvarasthana = line.type === 'svarasthana';

        REQUIRE(subdivs % 1.0 < 0.00001, "Invalid subdivision");
        subdivs = Math.floor(subdivs);
        props = {x: cursor.x, y: cursor.y, style: textStyle};

        var renderSubsvara = function (s) {
            svgelem(svg, 'text', props, show(s));
            props.x += dx / subsvaras.length;
        };

        while (akshIx < para.tala_interval.to) {
            instr = tala.instructions[instrIx];
            if (instr.tick) {
                dx = instr.tick * stretch / subdivs;
                props.x = cursor.x;
                props.y = cursor.y;
                props.style = textStyle;
                if (isSvarasthana) {
                    subsvaras = getSubSvaras(line.tokens[tokIx]);
                    if (subsvaras.length > 2) {
                        props.style = textStyleSmall;
                    }
                    subsvaras.forEach(renderSubsvara);
                } else {
                    svgelem(svg, 'text', props, show(line.tokens[tokIx]));
                }
                cursor.x += dx;
                ++subDivIx;
                ++tokIx;
                if (subDivIx >= subdivs) {
                    subDivIx = 0;
                    ++akshIx;
                    ++instrIx;
                } else {
                    continue;
                }
            }

            // Consume other non-tick instructions up to the next tick.
            while (instrIx < tala.instructions.length && (instr = tala.instructions[instrIx], !instr.tick)) {
                if (instr.space) {
                    if (instr.scale) {
                        cursor.x += instr.space * stretchSpace;
                    } else {
                        cursor.x += instr.space;
                    }
                } else if (instr.line) {
                    if (instr.draw) {
                        extendLine(instrIx,
                                cursor.x,
                                cursor.y - style[keyLineSpacing] - style[keyLineExtensionTop],
                                cursor.y + style[keyLineExtensionBottom]);
                    }
                    cursor.x += instr.line;
                }
                instr = tala.instructions[++instrIx];
            }
        }

        nextLine();
    }

    function typesetLyrics(para, line) {
        typesetTimedText(para, line, 'font-style: italic;');
    }

    function nextLine(spacingKey) {
        cursor.y += style[spacingKey || keyLineSpacing];
        cursor.ymax = Math.max(cursor.y, cursor.ymax);
        cursor.xmax = Math.max(cursor.x + 40, cursor.xmax);
        cursor.x = style[keyMarginLeft];
    }

    // Augment each "paragraph" with information about
    // where in the tala cycle it begins and where it
    // ends.
    //
    // Adds "tala_interval" property, which is an object
    // of the form {from: m, to:n}, where the aksharas
    // included are k >= m & k < n.
    function processTalaPatterns(paragraphs) {
        var fromAkshara = 0, toAkshara = 0, aksharas = 0, aksharasInTala = 0, aksharasPerLine = 0;

        var i, N, para, tala, aksh;

        for (i = 0, N = paragraphs.length; i < N; ++i) {

            para = paragraphs[i];
            tala = para.properties[keyTalaPattern];

            aksharasInTala = countAksharasInTala(tala);
            aksharasPerLine = +(para.properties[keyAksharasPerLine]);
            aksharas = +(para.properties[keyAksharas] || para.properties[keyAksharasPerLine]);

            toAkshara += aksharas;

            // Repeat the tala pattern enough times to cover the given notation line.
            aksh = aksharasInTala;
            while (toAkshara > aksh) {
                para.properties[keyTalaPattern] += tala;
                aksh += aksharasInTala;
            }

            // On repetition, you may find patterns such as '||||' in the tala.
            // This we normalize to '||' - i.e. the maximum number of times a vertical
            // bar may be repeated is 2.
            tala = para.properties[keyTalaPattern] = compileTala(para.properties[keyTalaPattern].replace(/\|\|+/g, '||'));

            var paraAksharas = +(para.properties[keyAksharas] || para.properties[keyAksharasPerLine]);

            // Adjust notation lines whose akshara count is smaller than
            // the given aksharas per line. We do this by stretching the
            // line by an integer factor.
            para.lines.forEach(function (line) {
                if (line.type !== 'text') {
                    if (line.tokens.length < paraAksharas) {
                        ASSERT(aksh % line.tokens.length === 0);
                        var i, j, M, N, newTokens = [];
                        M = aksh / line.tokens.length;
                        for (i = 0, N = line.tokens.length; i < N; ++i) {
                            newTokens.push(line.tokens[i]);
                            for (j = 1; j < M; ++j) {
                                newTokens.push('_');
                            }
                        }
                        line.tokens = newTokens;
                    }
                }
            });

            para.tala_interval = {
                from: fromAkshara,
                to: toAkshara
            };

            // Modulo tala cycle.
            fromAkshara = toAkshara;
            while (fromAkshara >= aksharasInTala) {
                fromAkshara -= aksharasInTala;
                toAkshara -= aksharasInTala;
            }
        }

        return paragraphs;
    }

    function compileTala(talaPattern) {
        var talaKey = '$' + talaPattern;

        if (talaKey in talaCache) {
            return talaCache[talaKey];
        }

        var i, N, c, instrs = [], nearLine;
        for (i = 0, N = talaPattern.length; i < N; ++i) {
            c = talaPattern.charAt(i);
            nearLine = (i + 1 < N && talaPattern.charAt(i+1) === '|') || (i > 0 && talaPattern.charAt(i-1) === '|');
            switch (c) {
                case '|' :
                    if (nearLine) {
                        instrs.push({line: 5, draw: true});
                    } else {
                        instrs.push({line: 10, draw: true});
                    }
                    break;
                case ' ':
                    if (nearLine) {
                        instrs.push({space: 15, scale: false});
                    } else {
                        instrs.push({space: 30, scale: true});
                    }
                    break;
                case ',':
                    instrs.push({tick: 40});
                    break;
                case '_':
                    instrs.push({line: 10, draw: false});
                    break;
                default:
                    throw new Error('Unknown pattern character [' + c + '] in tala - "' + talaPattern + '"');
            }
        }

        return (talaCache[talaKey] = {
            pattern: talaPattern,
            aksharas: countAksharasInTala(talaPattern),
            instructions: instrs
        });
    }

    function countAksharasInTala(talaPattern) {
        var commas = talaPattern.match(/,/g);
        return (commas && commas.length) || 0;
    }

    function show(text) {
        var hisa = "Ṡ";
        var losa = "Ṣ";

        if (text === '_') {
            return "";
        }

        if (text.length === 2 && text[1] === '+') {
            return text[0] + hisa[1];
        }

        if (text.length === 2 && text[1] === '-') {
            return text[0] + losa[1];
        }

        return text;
    }

    function svgelem(elem, n, attrs, content) {
        var tag = window.document.createElementNS('http://www.w3.org/2000/svg', n);
        if (attrs) {
            Object.keys(attrs).forEach(function (k) {
                if (attrs[k]) {
                    tag.setAttribute(k, attrs[k]);
                }
            });
        }
        if (content) {
            tag.textContent = content;
        }
        elem.appendChild(tag);
        return tag;
    }

    function loadStyleDefaults(style) {
        style[keyLineSpacing] = (+style[keyLineSpacing]) || 22;
        style[keyParaSpacing] = (+style[keyParaSpacing]) || style[keyLineSpacing];
        style[keyNotationFontSize] = (+style[keyNotationFontSize]) || 13;
        style[keyNotationSmallFontSize] = (+style[keyNotationSmallFontSize]) || (style[keyNotationFontSize] - 2);
        style[keyNotationFont] = (style[keyNotationFont] || 'sans-serif');
        style[keyTextFont] = (style[keyTextFont] || 'serif');
        style[keyStretch] = (+style[keyStretch]) || 1.0;
        style[keyStretchSpace] = (+style[keyStretchSpace]) || 1.0;
        style[keyMarginTop] = (+style[keyMarginTop]) || style[keyLineSpacing];
        style[keyMarginLeft] = (+style[keyMarginLeft]) || 10;
        style[keyLineExtensionTop] = (+style[keyLineExtensionTop]) || 0;
        style[keyLineExtensionBottom] = (+style[keyLineExtensionBottom]) || 5;
    }

    return null;
}
<|endoftext|>


<commit_before>var g8v={
	'objList': [],
	'module': {},
	'bgLayer': 0,
	'windowOption': [
		function(){
			return $.tag('span',{
				'className': 'vw_close',
				'textContent': 'X'
			});
		},
		function(obj){
			return $.tag('span',{
				'textContent': '標',
				'addEventListener': ['click',function(e){
					var newtitle=prompt('請輸入新標題',obj.title);
					if(newtitle===null) return;
					obj.title=newtitle;
					e.target.parentNode.parentNode.getElementsByClassName('vw_bar')[0].textContent=newtitle;
					g8v.updateShareUrl();
				}]
			});
		},
		function(){
			return $.tag('span',{
				'className': 'vw_opacity',
				'textContent': '透'
			});
		}
	],
	'loadModule': function(module,onload){
		if(onload) $().$add('script',{'src': 'module/'+module+'.js'}).addEventListener('load',onload);
		else $().$add('script',{'src': 'module/'+module+'.js'});
	},
	'createWindow': function(obj,title,content,option){
		var windowObj=$().$add('div',{
			'className': 'window'
		});
		var titleObj=windowObj.$add('div',{'className': 'vw_bar'}).$add(document.createTextNode(title));
		windowObj.$add(
			g8v.windowOption.reduceRight(
				function(r,f){
					return r.$add(f(obj),null,true);
				},
				$.tag('div',{
					'className': 'vw_option'
				})
			)
			,null,true
		).$add(content);
		var vw=new VirtualWindow(
			windowObj,
			obj.width,
			obj.height,
			obj.posX,
			obj.posY
		);
		vw.on('move',function(){
			obj.posX=this.posX;
			obj.posY=this.posY;
			g8v.updateShareUrl();
		});
		vw.on('resize',function(){
			obj.width=this.width;
			obj.height=this.height;
			g8v.updateShareUrl();
		});
		vw.on('close',function(){
			this.objList.splice(this.objList.indexOf(obj));
			g8v.updateShareUrl();
		}.bind(this));
		return vw;
	},
	'createObj': function(module,args,title,width,height,posX,posY){
		var data={
			'module': module,
			'args': args
		};
		if(title && width && height && posX!=undefined && posY!=undefined){
			data.title=title
			data.width=width;
			data.height=height;
			data.posX=posX;
			data.posY=posY;
		}
		this.objList.push(data);
		return data;
	},
	'updateShareUrl': function(){
		$('seting_url').value=location.origin+location.pathname+'#'+this.objList.reduce(function(r,v){
			return r+
				(r.length? '&':'')+v.module+'='+v.args.reduce(function(r,v){
					return r+(r.length? '|':'')+encodeURIComponent(v);
				},'')+
				(
					(v.title && v.width && v.height && v.posX!=undefined && v.posY!=undefined)?
					'|'+encodeURIComponent(v.title)+'|'+v.width+'|'+v.height+'|'+v.posX+'|'+v.posY:''
				);
		},'');
	}
};
addEventListener('load',function(){
	/* Module ConfigWindow */
	(function(){
		var configVW=$('setting_window');
		var configVWObj=new VirtualWindow(configVW,0,0,350).close();
		var addItemBefore=configVW.childNodes[4];
		$('setting').addEventListener('click',function(){
			configVWObj.open();
			if(configVW.scrollWidth)
				configVWObj.resize(
					Math.ceil(configVW.scrollWidth/10)*10+10,
					Math.ceil(configVW.scrollHeight/10)*10+10
				);
			configVWObj.toTop();
		});
		g8v.module.config={
			'window': configVWObj,
			'addItem': function(htmlObj){
				if(configVW.scrollWidth)
					configVWObj.resize(
						Math.ceil(configVW.scrollWidth/10)*10+10,
						Math.ceil(configVW.scrollHeight/10)*10+10
					);
				return configVW.$add(htmlObj,addItemBefore);
			}
		};
	})();
	$('seting_url').addEventListener('click',function(){this.select();});

	/* Load Module*/
	var loadStep=new taskStep();
	['video','chat','iframe','sourceList','bg','bigScreen'].forEach(function(module){
		this.loadModule(module,loadStep.spawnCallback());
	},g8v);

	/* Load data */
	loadStep.callback(function(){
		location.hash.length>1 && location.hash.substring(1,location.hash.length).split('&').reduce(function(r,v){
			var s=v.indexOf('=');
			r.push({
				'module': v.substring(0,s),
				'args': v.substring(s+1,v.length).split('|').reduce(function(r,v){
					r.push(decodeURIComponent(v));
					return r;
				},[])
			});
			return r;
		},[]).forEach(function(data){
			console.log('[load]module=%s,args=%s',data.module,data.args.toString())
			if(this.module[data.module])
				this.module[data.module].load.apply(this.module[data.module],data.args);
			else
				console.error('[load]module %s 不存在',data.module)
		},g8v);
	});
});<commit_msg>不更動參數順序以兼容舊格式<commit_after>var g8v={
	'objList': [],
	'module': {},
	'bgLayer': 0,
	'windowOption': [
		function(){
			return $.tag('span',{
				'className': 'vw_close',
				'textContent': 'X'
			});
		},
		function(obj){
			return $.tag('span',{
				'textContent': '標',
				'addEventListener': ['click',function(e){
					var newtitle=prompt('請輸入新標題',obj.title);
					if(newtitle===null) return;
					obj.title=newtitle;
					e.target.parentNode.parentNode.getElementsByClassName('vw_bar')[0].textContent=newtitle;
					g8v.updateShareUrl();
				}]
			});
		},
		function(){
			return $.tag('span',{
				'className': 'vw_opacity',
				'textContent': '透'
			});
		}
	],
	'loadModule': function(module,onload){
		if(onload) $().$add('script',{'src': 'module/'+module+'.js'}).addEventListener('load',onload);
		else $().$add('script',{'src': 'module/'+module+'.js'});
	},
	'createWindow': function(obj,title,content,option){
		var windowObj=$().$add('div',{
			'className': 'window'
		});
		var titleObj=windowObj.$add('div',{'className': 'vw_bar'}).$add(document.createTextNode(title));
		windowObj.$add(
			g8v.windowOption.reduceRight(
				function(r,f){
					return r.$add(f(obj),null,true);
				},
				$.tag('div',{
					'className': 'vw_option'
				})
			)
			,null,true
		).$add(content);
		var vw=new VirtualWindow(
			windowObj,
			obj.posX,
			obj.posY,
			obj.width,
			obj.height
		);
		vw.on('move',function(){
			obj.posX=this.posX;
			obj.posY=this.posY;
			g8v.updateShareUrl();
		});
		vw.on('resize',function(){
			obj.width=this.width;
			obj.height=this.height;
			g8v.updateShareUrl();
		});
		vw.on('close',function(){
			this.objList.splice(this.objList.indexOf(obj));
			g8v.updateShareUrl();
		}.bind(this));
		return vw;
	},
	'createObj': function(module,args,title,posX,posY,width,height){
		var data={
			'module': module,
			'args': args
		};
		if(title && width && height && posX!=undefined && posY!=undefined){
			data.title=title
			data.width=width;
			data.height=height;
			data.posX=posX;
			data.posY=posY;
		}
		this.objList.push(data);
		return data;
	},
	'updateShareUrl': function(){
		$('seting_url').value=location.origin+location.pathname+'#'+this.objList.reduce(function(r,v){
			return r+
				(r.length? '&':'')+v.module+'='+v.args.reduce(function(r,v){
					return r+(r.length? '|':'')+encodeURIComponent(v);
				},'')+
				(
					(v.title && v.width && v.height && v.posX!=undefined && v.posY!=undefined)?
					'|'+encodeURIComponent(v.title)+'|'+v.posX+'|'+v.posY+'|'+v.width+'|'+v.height:''
				);
		},'');
	}
};
addEventListener('load',function(){
	/* Module ConfigWindow */
	(function(){
		var configVW=$('setting_window');
		var configVWObj=new VirtualWindow(configVW,0,0,350).close();
		var addItemBefore=configVW.childNodes[4];
		$('setting').addEventListener('click',function(){
			configVWObj.open();
			if(configVW.scrollWidth)
				configVWObj.resize(
					Math.ceil(configVW.scrollWidth/10)*10+10,
					Math.ceil(configVW.scrollHeight/10)*10+10
				);
			configVWObj.toTop();
		});
		g8v.module.config={
			'window': configVWObj,
			'addItem': function(htmlObj){
				if(configVW.scrollWidth)
					configVWObj.resize(
						Math.ceil(configVW.scrollWidth/10)*10+10,
						Math.ceil(configVW.scrollHeight/10)*10+10
					);
				return configVW.$add(htmlObj,addItemBefore);
			}
		};
	})();
	$('seting_url').addEventListener('click',function(){this.select();});

	/* Load Module*/
	var loadStep=new taskStep();
	['video','chat','iframe','sourceList','bg','bigScreen'].forEach(function(module){
		this.loadModule(module,loadStep.spawnCallback());
	},g8v);

	/* Load data */
	loadStep.callback(function(){
		location.hash.length>1 && location.hash.substring(1,location.hash.length).split('&').reduce(function(r,v){
			var s=v.indexOf('=');
			r.push({
				'module': v.substring(0,s),
				'args': v.substring(s+1,v.length).split('|').reduce(function(r,v){
					r.push(decodeURIComponent(v));
					return r;
				},[])
			});
			return r;
		},[]).forEach(function(data){
			console.log('[load]module=%s,args=%s',data.module,data.args.toString())
			if(this.module[data.module])
				this.module[data.module].load.apply(this.module[data.module],data.args);
			else
				console.error('[load]module %s 不存在',data.module)
		},g8v);
	});
});<|endoftext|>