<commit_before>// exports.handler = function(event, context) { eventHandler(event, context) };

function eventHandler(event, context) {
  try {
    if (event.request.type === 'LaunchRequest') {
      welcome(function callback(speechletResponse) {
        context.succeed(buildResponse(event.session.attributes, speechletResponse));
      });
    } else if (event.request.type === 'IntentRequest') {
      intentHandler(event.request, function callback(speechletResponse) {
        context.succeed(buildResponse(event.session.attributes, speechletResponse));
      });
    }
  } catch (e) {
    context.fail('Exception: ' + e);
  }
}

function welcome(callback) {
  this.game = new Game(3);
  callback(buildSpeechResponse('welcome to tic tac toe. to play the game select a cell by row and column. for example say top left or bottom middle. you can ask for help if you need more information, or say stop to exit.', 'select a cell by row and column. for example say top left or middle right or bottom middle.', false));
}

function support(callback) {
  callback(buildSpeechResponse('tic tac toe is usually played with a pencil and paper. two players take turns marking the cells in a three by three grid. the first player to place three of their marks in a horizontal, vertical, or diagonal line wins. to play the game with alexa select a cell by row and then column. for example you can say middle right or bottom middle. which cell would you like to select?', 'select a cell by row and column. for example say top left or middle right or bottom middle', false));
}

function goodbye(callback) {
  callback(buildSpeechResponse('goodbye', '', true));
}

function intentHandler(intentRequest, callback) {
  var intentName = intentRequest.intent.name;
  if (intentName === 'AMAZON.HelpIntent') {
    support(callback);
  } else if (intentName === 'AMAZON.StopIntent') {
    goodbye(callback);
  } else if (intentName === 'PlayIntent') {
    this.game.playerPlay(intentRequest.intent.slots.row.value, intentRequest.intent.slots.column.value, callback);
  } else {
    throw 'Invalid intent';
  }
}

function Game(boardSize) {
  this._boardSize = boardSize;
  this._board = new Board(boardSize);
  this._player = new Player();
  this._robot = new Robot();
}

Game.prototype.board = function() {
  return this._board;
};

Game.prototype.playerPlay = function(row, column, callback) {
  var rows = {'top': 0, 'middle': 1, 'bottom': 2};
  var columns = {'left': 0, 'middle': 1, 'right': 2};
  if(this._board.grid()[rows[row]][columns[column]] !== '') {
    callback(buildSpeechResponse('that cell is already taken', 'select another cell', 'false'));
  } else {
    this._board.take(rows[row], columns[column], this._player.symbol());
    this.playerPlayOutcomes(row, column, callback);
  }
};

Game.prototype.playerPlayOutcomes = function(row, column, callback) {
  if(this._board.hasWon(this._player.symbol())) {
    callback(buildSpeechResponse('you played ' + row + ' ' + column + '. you won.', '', 'true'));
  } else if(this._board.isFull()) {
    callback(buildSpeechResponse('you played ' + row + ' ' + column + '. there are no cells left. the game is a draw.', '', 'true'));
  } else {
    this.robotPlay(row, column, callback);
  }
};

Game.prototype.robotPlay = function(playerRow, playerColumn, callback) {
  var robotRow = this._robot.choice(this._boardSize);
  var robotColumn = this._robot.choice(this._boardSize);
  if(this._board.grid()[robotRow][robotColumn] !== '') {
    this.robotPlay(playerRow, playerColumn, callback);
  } else {
    this._board.take(robotRow, robotColumn, this._robot.symbol());
    this.robotPlayOutcomes(playerRow, playerColumn, robotRow, robotColumn, callback);
  }
};

Game.prototype.robotPlayOutcomes = function(playerRow, playerColumn, robotRow, robotColumn, callback) {
  var rows = ['top', 'middle', 'bottom'];
  var columns = ['left', 'middle', 'right'];
  if(this._board.hasWon(this._robot.symbol())) {
    callback(buildSpeechResponse('you played ' + playerRow + ' ' + playerColumn + '. the computer played ' + rows[robotRow] + ' ' + columns[robotColumn] + '. the computer won.', '', 'true'));
  } else {
    callback(buildSpeechResponse('you played ' + playerRow + ' ' + playerColumn + '. the computer played ' + rows[robotRow] + ' ' + columns[robotColumn], 'select another cell by row and column', 'false'));
  }
};

function Board(size) {
  this._grid = [];
  for(i = 0; i < size; i++) {
    this._grid.push(makeRow(size));
  }
  this._size = size;
}

function makeRow(length) {
    var row = [];
    for(j = 0; j < length; j++) {
      row.push('');
    }
    return row;
  }

Board.prototype.grid = function() {
  return this._grid;
};

Board.prototype.take = function(row, column, symbol) {
  if(this._grid[row][column] !== '') {
    throw('that cell is already taken');
  }
  this._grid[row][column] = symbol;
};

Board.prototype.hasWon = function(symbol) {
  return this.anyRowWin(symbol) || this.anyColumnWin(symbol, this.grid()) || this.anyDiagonalWin(symbol, this.grid());
};

Board.prototype.anyRowWin = function(symbol) {
  return this.grid().some(function checkRow(row) {
    return row.every(function checkCell(cell) {
      return cell === symbol;
    });
  });
};

Board.prototype.anyColumnWin = function(symbol, grid) {
  return this.dimensions().some(function checkColumn(column) {
    return grid.every(function checkRow(row) {
      return row[column] === symbol;
    });
  });
};

Board.prototype.anyDiagonalWin = function(symbol, grid) {
  return this.dimensions().every(function checkCell(cell) {
    return grid[cell][cell] === symbol || grid[cell][(grid.length-1)-cell] === symbol ;
  });
};

Board.prototype.dimensions = function() {
  var dimensions = [];
  for(k = 0; k < this._size; k++) {
    dimensions.push(k);
  }
  return dimensions;
};

Board.prototype.isFull = function() {
  return this.grid().every(function checkRow(row) {
    return row.every(function checkCell(cell) {
      return cell !== '';
    });
  });
};

function Player() {
}

Player.prototype.symbol = function() {
  return 'x';
};

function Robot() {
}

Robot.prototype.symbol = function() {
  return 'o';
};

Robot.prototype.choice = function(size) {
  return Math.floor(Math.random() * size);
};

function buildSpeechResponse(output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output
        },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildResponse(sessionAttributes, speechletResponse) {
    return {
        version: '1.0',
        sessionAttributes: sessionAttributes,
        response: speechletResponse
    };
}
<commit_msg>rename speechResponse variable<commit_after>// exports.handler = function(event, context) { eventHandler(event, context) };

function eventHandler(event, context) {
  try {
    if (event.request.type === 'LaunchRequest') {
      welcome(function callback(speechResponse) {
        context.succeed(buildResponse(event.session.attributes, speechResponse));
      });
    } else if (event.request.type === 'IntentRequest') {
      intentHandler(event.request, function callback(speechResponse) {
        context.succeed(buildResponse(event.session.attributes, speechResponse));
      });
    }
  } catch (e) {
    context.fail('Exception: ' + e);
  }
}

function welcome(callback) {
  this.game = new Game(3);
  callback(buildSpeechResponse('welcome to tic tac toe. to play the game select a cell by row and column. for example say top left or bottom middle. you can ask for help if you need more information, or say stop to exit.', 'select a cell by row and column. for example say top left or middle right or bottom middle.', false));
}

function support(callback) {
  callback(buildSpeechResponse('tic tac toe is usually played with a pencil and paper. two players take turns marking the cells in a three by three grid. the first player to place three of their marks in a horizontal, vertical, or diagonal line wins. to play the game with alexa select a cell by row and then column. for example you can say middle right or bottom middle. which cell would you like to select?', 'select a cell by row and column. for example say top left or middle right or bottom middle', false));
}

function goodbye(callback) {
  callback(buildSpeechResponse('goodbye', '', true));
}

function intentHandler(intentRequest, callback) {
  var intentName = intentRequest.intent.name;
  if (intentName === 'AMAZON.HelpIntent') {
    support(callback);
  } else if (intentName === 'AMAZON.StopIntent') {
    goodbye(callback);
  } else if (intentName === 'PlayIntent') {
    this.game.playerPlay(intentRequest.intent.slots.row.value, intentRequest.intent.slots.column.value, callback);
  } else {
    throw 'Invalid intent';
  }
}

function Game(boardSize) {
  this._boardSize = boardSize;
  this._board = new Board(boardSize);
  this._player = new Player();
  this._robot = new Robot();
}

Game.prototype.board = function() {
  return this._board;
};

Game.prototype.playerPlay = function(row, column, callback) {
  var rows = {'top': 0, 'middle': 1, 'bottom': 2};
  var columns = {'left': 0, 'middle': 1, 'right': 2};
  if(this._board.grid()[rows[row]][columns[column]] !== '') {
    callback(buildSpeechResponse('that cell is already taken', 'select another cell', 'false'));
  } else {
    this._board.take(rows[row], columns[column], this._player.symbol());
    this.playerPlayOutcomes(row, column, callback);
  }
};

Game.prototype.playerPlayOutcomes = function(row, column, callback) {
  if(this._board.hasWon(this._player.symbol())) {
    callback(buildSpeechResponse('you played ' + row + ' ' + column + '. you won.', '', 'true'));
  } else if(this._board.isFull()) {
    callback(buildSpeechResponse('you played ' + row + ' ' + column + '. there are no cells left. the game is a draw.', '', 'true'));
  } else {
    this.robotPlay(row, column, callback);
  }
};

Game.prototype.robotPlay = function(playerRow, playerColumn, callback) {
  var robotRow = this._robot.choice(this._boardSize);
  var robotColumn = this._robot.choice(this._boardSize);
  if(this._board.grid()[robotRow][robotColumn] !== '') {
    this.robotPlay(playerRow, playerColumn, callback);
  } else {
    this._board.take(robotRow, robotColumn, this._robot.symbol());
    this.robotPlayOutcomes(playerRow, playerColumn, robotRow, robotColumn, callback);
  }
};

Game.prototype.robotPlayOutcomes = function(playerRow, playerColumn, robotRow, robotColumn, callback) {
  var rows = ['top', 'middle', 'bottom'];
  var columns = ['left', 'middle', 'right'];
  if(this._board.hasWon(this._robot.symbol())) {
    callback(buildSpeechResponse('you played ' + playerRow + ' ' + playerColumn + '. the computer played ' + rows[robotRow] + ' ' + columns[robotColumn] + '. the computer won.', '', 'true'));
  } else {
    callback(buildSpeechResponse('you played ' + playerRow + ' ' + playerColumn + '. the computer played ' + rows[robotRow] + ' ' + columns[robotColumn], 'select another cell by row and column', 'false'));
  }
};

function Board(size) {
  this._grid = [];
  for(i = 0; i < size; i++) {
    this._grid.push(makeRow(size));
  }
  this._size = size;
}

function makeRow(length) {
    var row = [];
    for(j = 0; j < length; j++) {
      row.push('');
    }
    return row;
  }

Board.prototype.grid = function() {
  return this._grid;
};

Board.prototype.take = function(row, column, symbol) {
  if(this._grid[row][column] !== '') {
    throw('that cell is already taken');
  }
  this._grid[row][column] = symbol;
};

Board.prototype.hasWon = function(symbol) {
  return this.anyRowWin(symbol) || this.anyColumnWin(symbol, this.grid()) || this.anyDiagonalWin(symbol, this.grid());
};

Board.prototype.anyRowWin = function(symbol) {
  return this.grid().some(function checkRow(row) {
    return row.every(function checkCell(cell) {
      return cell === symbol;
    });
  });
};

Board.prototype.anyColumnWin = function(symbol, grid) {
  return this.dimensions().some(function checkColumn(column) {
    return grid.every(function checkRow(row) {
      return row[column] === symbol;
    });
  });
};

Board.prototype.anyDiagonalWin = function(symbol, grid) {
  return this.dimensions().every(function checkCell(cell) {
    return grid[cell][cell] === symbol || grid[cell][(grid.length-1)-cell] === symbol ;
  });
};

Board.prototype.dimensions = function() {
  var dimensions = [];
  for(k = 0; k < this._size; k++) {
    dimensions.push(k);
  }
  return dimensions;
};

Board.prototype.isFull = function() {
  return this.grid().every(function checkRow(row) {
    return row.every(function checkCell(cell) {
      return cell !== '';
    });
  });
};

function Player() {
}

Player.prototype.symbol = function() {
  return 'x';
};

function Robot() {
}

Robot.prototype.symbol = function() {
  return 'o';
};

Robot.prototype.choice = function(size) {
  return Math.floor(Math.random() * size);
};

function buildSpeechResponse(output, repromptText, shouldEndSession) {
    return {
        outputSpeech: {
            type: 'PlainText',
            text: output
        },
        reprompt: {
            outputSpeech: {
                type: 'PlainText',
                text: repromptText
            }
        },
        shouldEndSession: shouldEndSession
    };
}

function buildResponse(sessionAttributes, speechResponse) {
    return {
        version: '1.0',
        sessionAttributes: sessionAttributes,
        response: speechResponse
    };
}
<|endoftext|>


<commit_before>import {Cookie} from './cookie';

export function configure(aurelia) {
    aurelia.singleton(Cookie, new Cookie());
}

export {Cookie};
<commit_msg>fix(all): properly register plugin singleton class<commit_after>import {Cookie} from './cookie';

export function configure(aurelia) {
    aurelia.container.registerSingleton(Cookie, new Cookie());
}

export {Cookie};
<|endoftext|>


<commit_before>var log = require('./log');
var Tone = require('tone');

var PitchEffect = require('./effects/PitchEffect');
var PanEffect = require('./effects/PanEffect');

var RoboticEffect = require('./effects/RoboticEffect');
var FuzzEffect = require('./effects/FuzzEffect');
var EchoEffect = require('./effects/EchoEffect');
var ReverbEffect = require('./effects/ReverbEffect');

var SoundPlayer = require('./SoundPlayer');
var ADPCMSoundDecoder = require('./ADPCMSoundDecoder');
var InstrumentPlayer = require('./InstrumentPlayer');
var DrumPlayer = require('./DrumPlayer');

/**
 * @fileOverview Scratch Audio is divided into a single AudioEngine,
 * that handles global functionality, and AudioPlayers, belonging to individual sprites and clones.
 */

/**
 * There is a single instance of the AudioEngine. It handles global audio properties and effects,
 * loads all the audio buffers for sounds belonging to sprites, and creates a single instrument player
 * and a drum player, used by all play note and play drum blocks.
 * @constructor
 */
function AudioEngine () {

    // create the global audio effects
    this.roboticEffect = new RoboticEffect();
    this.fuzzEffect = new FuzzEffect();
    this.echoEffect = new EchoEffect();
    this.reverbEffect = new ReverbEffect();

    // chain the global effects to the output
    this.input = new Tone.Gain();
    this.input.chain (
        this.roboticEffect, this.fuzzEffect, this.echoEffect, this.reverbEffect,
        Tone.Master
    );

    // global tempo in bpm (beats per minute)
    this.currentTempo = 60;

    // instrument player for play note blocks
    this.instrumentPlayer = new InstrumentPlayer(this.input);
    this.numInstruments = this.instrumentPlayer.instrumentNames.length;

    // drum player for play drum blocks
    this.drumPlayer = new DrumPlayer(this.input);
    this.numDrums = this.drumPlayer.drumSounds.length;

    // a map of md5s to audio buffers, holding sounds for all sprites
    this.audioBuffers = {};
}

/**
 * Decode a sound, decompressing it into audio samples.
 * Store a reference to it the sound in the audioBuffers dictionary, indexed by md5
 * @param  {Object} sound - an object containing audio data and metadata for a sound
 */
AudioEngine.prototype.decodeSound = function (sound) {

    var storedContext = this;

    // if the format string is empty, assume the sound is a wav file and use the native decoder
    if (sound.format === '') {
        Tone.context.decodeAudioData(sound.data.buffer).then(
            function (decodedAudio) {
                storedContext.audioBuffers[sound.md5] = new Tone.Buffer(decodedAudio);
            },
            function (error) {
                log.warn('audio data could not be decoded', error);
            }
        );
    }

    // if the format is adpcm, we use a custom decoder
    if (sound.format === 'adpcm') {
        var loader = new ADPCMSoundDecoder();
        loader.decode(sound.data.buffer).then(
            function (decodedAudio) {
                storedContext.audioBuffers[sound.md5] = new Tone.Buffer(decodedAudio);
            },
            function (error) {
                log.warn('adpcm audio data could not be decoded', error);
            }
        );
    }
};

/**
 * Play a note for a duration on an instrument with a volume
 * @param  {number} note - a MIDI note number
 * @param  {number} beats - a duration in beats
 * @param  {number} inst - an instrument number (0-indexed)
 * @param  {number} vol - a volume level (0-100%)
 * @return {Promise} a Promise that resolves after the duration has elapsed
 */
AudioEngine.prototype.playNoteForBeatsWithInstAndVol = function (note, beats, inst, vol) {
    var sec = this.beatsToSec(beats);
    this.instrumentPlayer.playNoteForSecWithInstAndVol(note, sec, inst, vol);
    return this.waitForBeats(beats);
};

/**
 * Convert a number of beats to a number of seconds, using the current tempo
 * @param  {number} beats
 * @return {number} seconds
 */
AudioEngine.prototype.beatsToSec = function (beats) {
    return (60 / this.currentTempo) * beats;
};

/**
 * Wait for some number of beats
 * @param  {number} beats
 * @return {Promise} a Promise that resolves after the duration has elapsed
 */
AudioEngine.prototype.waitForBeats = function (beats) {
    var storedContext = this;
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve();
        }, storedContext.beatsToSec(beats) * 1000);
    });
};

/**
 * Set the global tempo in bpm (beats per minute)
 * @param {number} value - the new tempo to set
 */
AudioEngine.prototype.setTempo = function (value) {
    this.currentTempo = value;
};

/**
 * Change the tempo by some number of bpm (beats per minute)
 * @param  {number} value - the number of bpm to change the tempo by
 */
AudioEngine.prototype.changeTempo = function (value) {
    this.setTempo(this.currentTempo  + value);
};

/**
 * Names of the audio effects.
 * @readonly
 * @enum {string}
 */
AudioEngine.prototype.EFFECT_NAMES = {
    pitch: 'pitch',
    pan: 'pan',
    echo: 'echo',
    reverb: 'reverb',
    fuzz: 'fuzz',
    robot: 'robot'
};

/**
 * Create an AudioPlayer. Each sprite or clone has an AudioPlayer.
 * It includes a reference to the AudioEngine so it can use global
 * functionality such as playing notes.
 * @return {AudioPlayer}
 */
AudioEngine.prototype.createPlayer = function () {
    return new AudioPlayer(this);
};

/**
 * Each sprite or clone has an audio player
 * the audio player handles sound playback, volume, and the sprite-specific audio effects:
 * pitch and pan
 * @param {AudioEngine}
 * @constructor
 */
function AudioPlayer (audioEngine) {

    this.audioEngine = audioEngine;

    // effects setup
    this.pitchEffect = new PitchEffect();
    this.panEffect = new PanEffect();

    // the effects are chained to an effects node for this player, then to the main audio engine
    // audio is sent from each soundplayer, through the effects in order, then to the global effects
    // note that the pitch effect works differently - it sets the playback rate for each soundplayer
    this.effectsNode = new Tone.Gain();
    this.effectsNode.chain(this.panEffect, this.audioEngine.input);

    // reset effects to their default parameters
    this.clearEffects();

    // sound players that are currently playing, indexed by the sound's md5
    this.activeSoundPlayers = {};
}

/**
 * Play a sound
 * @param  {string} md5 - the md5 id of a sound file
 * @return {Promise} a Promise that resolves when the sound finishes playing
 */
AudioPlayer.prototype.playSound = function (md5) {
    // if this sound is not in the audio engine, return
    if (!this.audioEngine.audioBuffers[md5]) {
        return;
    }

    // if this sprite or clone is already playing this sound, stop it first
    if (this.activeSoundPlayers[md5]) {
        this.activeSoundPlayers[md5].stop();
    }

    // create a new soundplayer to play the sound
    var player = new SoundPlayer();
    player.setBuffer(this.audioEngine.audioBuffers[md5]);
    player.connect(this.effectsNode);
    this.pitchEffect.updatePlayer(player);
    player.start();

    // add it to the list of active sound players
    this.activeSoundPlayers[md5] = player;

    // remove sounds that are not playing from the active sound players array
    for (var id in this.activeSoundPlayers) {
        if (this.activeSoundPlayers.hasOwnProperty(id)) {
            if (!this.activeSoundPlayers[id].isPlaying) {
                delete this.activeSoundPlayers[id];
            }
        }
    }

    return player.finished();
};

/**
 * Play a drum sound. The AudioEngine contains the DrumPlayer, but the AudioPlayer
 * calls this function so that it can pass a reference to its own effects node.
 * @param  {number} drum - a drum number (0-indexed)
 * @param  {number} beats - a duration in beats
 * @return {Promise} a Promise that resolves after the duration has elapsed
 */
AudioPlayer.prototype.playDrumForBeats = function (drum, beats) {
    this.audioEngine.drumPlayer.play(drum, this.effectsNode);
    return this.audioEngine.waitForBeats(beats);
};

/**
 * Stop all sounds, notes and drums that are playing
 */
AudioPlayer.prototype.stopAllSounds = function () {
    // stop all active sound players
    for (var md5 in this.activeSoundPlayers) {
        this.activeSoundPlayers[md5].stop();
    }

    // stop all instruments
    this.audioEngine.instrumentPlayer.stopAll();

    // stop drum notes
    this.audioEngine.drumPlayer.stopAll();
};

/**
 * Set an audio effect to a value
 * @param {string} effect - the name of the effect
 * @param {number} value - the value to set the effect to
 */
AudioPlayer.prototype.setEffect = function (effect, value) {
    switch (effect) {
    case this.audioEngine.EFFECT_NAMES.pitch:
        this.pitchEffect.set(value, this.activeSoundPlayers);
        break;
    case this.audioEngine.EFFECT_NAMES.pan:
        this.panEffect.set(value);
        break;
    case this.audioEngine.EFFECT_NAMES.echo:
        this.audioEngine.echoEffect.set(value);
        break;
    case this.audioEngine.EFFECT_NAMES.reverb:
        this.audioEngine.reverbEffect.set(value);
        break;
    case this.audioEngine.EFFECT_NAMES.fuzz:
        this.audioEngine.fuzzEffect.set(value);
        break;
    case this.audioEngine.EFFECT_NAMES.robot:
        this.audioEngine.roboticEffect.set(value);
        break;
    }
};

/**
 * Clear all audio effects
 */
AudioPlayer.prototype.clearEffects = function () {
    this.panEffect.set(0);
    this.pitchEffect.set(0, this.activeSoundPlayers);
    this.effectsNode.gain.value = 1;

    this.audioEngine.echoEffect.set(0);
    this.audioEngine.reverbEffect.set(0);
    this.audioEngine.fuzzEffect.set(0);
    this.audioEngine.roboticEffect.set(0);
};

/**
 * Set the volume for sounds played by this AudioPlayer
 * @param {number} value - the volume in range 0-100
 */
AudioPlayer.prototype.setVolume = function (value) {
    this.effectsNode.gain.value = value / 100;
};

module.exports = AudioEngine;

<commit_msg>Tidy up sound decoding<commit_after>var log = require('./log');
var Tone = require('tone');

var PitchEffect = require('./effects/PitchEffect');
var PanEffect = require('./effects/PanEffect');

var RoboticEffect = require('./effects/RoboticEffect');
var FuzzEffect = require('./effects/FuzzEffect');
var EchoEffect = require('./effects/EchoEffect');
var ReverbEffect = require('./effects/ReverbEffect');

var SoundPlayer = require('./SoundPlayer');
var ADPCMSoundDecoder = require('./ADPCMSoundDecoder');
var InstrumentPlayer = require('./InstrumentPlayer');
var DrumPlayer = require('./DrumPlayer');

/**
 * @fileOverview Scratch Audio is divided into a single AudioEngine,
 * that handles global functionality, and AudioPlayers, belonging to individual sprites and clones.
 */

/**
 * There is a single instance of the AudioEngine. It handles global audio properties and effects,
 * loads all the audio buffers for sounds belonging to sprites, and creates a single instrument player
 * and a drum player, used by all play note and play drum blocks.
 * @constructor
 */
function AudioEngine () {

    // create the global audio effects
    this.roboticEffect = new RoboticEffect();
    this.fuzzEffect = new FuzzEffect();
    this.echoEffect = new EchoEffect();
    this.reverbEffect = new ReverbEffect();

    // chain the global effects to the output
    this.input = new Tone.Gain();
    this.input.chain (
        this.roboticEffect, this.fuzzEffect, this.echoEffect, this.reverbEffect,
        Tone.Master
    );

    // global tempo in bpm (beats per minute)
    this.currentTempo = 60;

    // instrument player for play note blocks
    this.instrumentPlayer = new InstrumentPlayer(this.input);
    this.numInstruments = this.instrumentPlayer.instrumentNames.length;

    // drum player for play drum blocks
    this.drumPlayer = new DrumPlayer(this.input);
    this.numDrums = this.drumPlayer.drumSounds.length;

    // a map of md5s to audio buffers, holding sounds for all sprites
    this.audioBuffers = {};
}

/**
 * Decode a sound, decompressing it into audio samples.
 * Store a reference to it the sound in the audioBuffers dictionary, indexed by md5
 * @param  {Object} sound - an object containing audio data and metadata for a sound
 */
AudioEngine.prototype.decodeSound = function (sound) {

    var loaderPromise = null;

    switch (sound.format) {
    case '':
        loaderPromise = Tone.context.decodeAudioData(sound.data.buffer);
        break;
    case 'adpcm':
        loaderPromise = (new ADPCMSoundDecoder()).decode(sound.data.buffer);
        break;
    default:
        return log.warn('unknown sound format', sound.format);
    }

    var storedContext = this;

    loaderPromise.then(
        function (decodedAudio) {
            storedContext.audioBuffers[sound.md5] = new Tone.Buffer(decodedAudio);
        },
        function (error) {
            log.warn('audio data could not be decoded', error);
        }
    );
};

/**
 * Play a note for a duration on an instrument with a volume
 * @param  {number} note - a MIDI note number
 * @param  {number} beats - a duration in beats
 * @param  {number} inst - an instrument number (0-indexed)
 * @param  {number} vol - a volume level (0-100%)
 * @return {Promise} a Promise that resolves after the duration has elapsed
 */
AudioEngine.prototype.playNoteForBeatsWithInstAndVol = function (note, beats, inst, vol) {
    var sec = this.beatsToSec(beats);
    this.instrumentPlayer.playNoteForSecWithInstAndVol(note, sec, inst, vol);
    return this.waitForBeats(beats);
};

/**
 * Convert a number of beats to a number of seconds, using the current tempo
 * @param  {number} beats
 * @return {number} seconds
 */
AudioEngine.prototype.beatsToSec = function (beats) {
    return (60 / this.currentTempo) * beats;
};

/**
 * Wait for some number of beats
 * @param  {number} beats
 * @return {Promise} a Promise that resolves after the duration has elapsed
 */
AudioEngine.prototype.waitForBeats = function (beats) {
    var storedContext = this;
    return new Promise(function (resolve) {
        setTimeout(function () {
            resolve();
        }, storedContext.beatsToSec(beats) * 1000);
    });
};

/**
 * Set the global tempo in bpm (beats per minute)
 * @param {number} value - the new tempo to set
 */
AudioEngine.prototype.setTempo = function (value) {
    this.currentTempo = value;
};

/**
 * Change the tempo by some number of bpm (beats per minute)
 * @param  {number} value - the number of bpm to change the tempo by
 */
AudioEngine.prototype.changeTempo = function (value) {
    this.setTempo(this.currentTempo  + value);
};

/**
 * Names of the audio effects.
 * @readonly
 * @enum {string}
 */
AudioEngine.prototype.EFFECT_NAMES = {
    pitch: 'pitch',
    pan: 'pan',
    echo: 'echo',
    reverb: 'reverb',
    fuzz: 'fuzz',
    robot: 'robot'
};

/**
 * Create an AudioPlayer. Each sprite or clone has an AudioPlayer.
 * It includes a reference to the AudioEngine so it can use global
 * functionality such as playing notes.
 * @return {AudioPlayer}
 */
AudioEngine.prototype.createPlayer = function () {
    return new AudioPlayer(this);
};

/**
 * Each sprite or clone has an audio player
 * the audio player handles sound playback, volume, and the sprite-specific audio effects:
 * pitch and pan
 * @param {AudioEngine}
 * @constructor
 */
function AudioPlayer (audioEngine) {

    this.audioEngine = audioEngine;

    // effects setup
    this.pitchEffect = new PitchEffect();
    this.panEffect = new PanEffect();

    // the effects are chained to an effects node for this player, then to the main audio engine
    // audio is sent from each soundplayer, through the effects in order, then to the global effects
    // note that the pitch effect works differently - it sets the playback rate for each soundplayer
    this.effectsNode = new Tone.Gain();
    this.effectsNode.chain(this.panEffect, this.audioEngine.input);

    // reset effects to their default parameters
    this.clearEffects();

    // sound players that are currently playing, indexed by the sound's md5
    this.activeSoundPlayers = {};
}

/**
 * Play a sound
 * @param  {string} md5 - the md5 id of a sound file
 * @return {Promise} a Promise that resolves when the sound finishes playing
 */
AudioPlayer.prototype.playSound = function (md5) {
    // if this sound is not in the audio engine, return
    if (!this.audioEngine.audioBuffers[md5]) {
        return;
    }

    // if this sprite or clone is already playing this sound, stop it first
    if (this.activeSoundPlayers[md5]) {
        this.activeSoundPlayers[md5].stop();
    }

    // create a new soundplayer to play the sound
    var player = new SoundPlayer();
    player.setBuffer(this.audioEngine.audioBuffers[md5]);
    player.connect(this.effectsNode);
    this.pitchEffect.updatePlayer(player);
    player.start();

    // add it to the list of active sound players
    this.activeSoundPlayers[md5] = player;

    // remove sounds that are not playing from the active sound players array
    for (var id in this.activeSoundPlayers) {
        if (this.activeSoundPlayers.hasOwnProperty(id)) {
            if (!this.activeSoundPlayers[id].isPlaying) {
                delete this.activeSoundPlayers[id];
            }
        }
    }

    return player.finished();
};

/**
 * Play a drum sound. The AudioEngine contains the DrumPlayer, but the AudioPlayer
 * calls this function so that it can pass a reference to its own effects node.
 * @param  {number} drum - a drum number (0-indexed)
 * @param  {number} beats - a duration in beats
 * @return {Promise} a Promise that resolves after the duration has elapsed
 */
AudioPlayer.prototype.playDrumForBeats = function (drum, beats) {
    this.audioEngine.drumPlayer.play(drum, this.effectsNode);
    return this.audioEngine.waitForBeats(beats);
};

/**
 * Stop all sounds, notes and drums that are playing
 */
AudioPlayer.prototype.stopAllSounds = function () {
    // stop all active sound players
    for (var md5 in this.activeSoundPlayers) {
        this.activeSoundPlayers[md5].stop();
    }

    // stop all instruments
    this.audioEngine.instrumentPlayer.stopAll();

    // stop drum notes
    this.audioEngine.drumPlayer.stopAll();
};

/**
 * Set an audio effect to a value
 * @param {string} effect - the name of the effect
 * @param {number} value - the value to set the effect to
 */
AudioPlayer.prototype.setEffect = function (effect, value) {
    switch (effect) {
    case this.audioEngine.EFFECT_NAMES.pitch:
        this.pitchEffect.set(value, this.activeSoundPlayers);
        break;
    case this.audioEngine.EFFECT_NAMES.pan:
        this.panEffect.set(value);
        break;
    case this.audioEngine.EFFECT_NAMES.echo:
        this.audioEngine.echoEffect.set(value);
        break;
    case this.audioEngine.EFFECT_NAMES.reverb:
        this.audioEngine.reverbEffect.set(value);
        break;
    case this.audioEngine.EFFECT_NAMES.fuzz:
        this.audioEngine.fuzzEffect.set(value);
        break;
    case this.audioEngine.EFFECT_NAMES.robot:
        this.audioEngine.roboticEffect.set(value);
        break;
    }
};

/**
 * Clear all audio effects
 */
AudioPlayer.prototype.clearEffects = function () {
    this.panEffect.set(0);
    this.pitchEffect.set(0, this.activeSoundPlayers);
    this.effectsNode.gain.value = 1;

    this.audioEngine.echoEffect.set(0);
    this.audioEngine.reverbEffect.set(0);
    this.audioEngine.fuzzEffect.set(0);
    this.audioEngine.roboticEffect.set(0);
};

/**
 * Set the volume for sounds played by this AudioPlayer
 * @param {number} value - the volume in range 0-100
 */
AudioPlayer.prototype.setVolume = function (value) {
    this.effectsNode.gain.value = value / 100;
};

module.exports = AudioEngine;

<|endoftext|>


<commit_before>require("regenerator-runtime/runtime")
require("coffeescript/register")
require("@babel/register")({
  extensions: [".ts", ".js", ".tsx", ".jsx"],
  plugins: ["babel-plugin-dynamic-import-node"],
})

global.Promise = require("bluebird")

const artsyXapp = require("artsy-xapp")
const cache = require("./lib/cache")
const express = require("express")
const setup = require("./lib/setup").default
const app = (module.exports = express())

const {
  APP_URL,
  API_URL,
  CLIENT_ID,
  CLIENT_SECRET,
  NODE_ENV,
  PORT,
  PROFILE_MEMORY,
} = process.env

if (PROFILE_MEMORY) require(".src/lib/memory_profiler")()

// Add all of the middleware and global setup
setup(app)

// Connect to Redis
cache.setup(() => {
  // if we can't get an xapp token, just exit and let the whole system try
  // again - this prevents a sustained broken state when gravity returns a
  // 502 during force startup.
  artsyXapp.on("error", err => {
    error(`
Could not start Force because it could not set up the xapp token, this is likely
due to \`API_URL\`, \`CLIENT_ID\` and \`CLIENT_SECRET\` not being set, but
also could be gravity being down.`)
    error(err)
    process.exit()
  })
  // Get an xapp token
  artsyXapp.init({ url: API_URL, id: CLIENT_ID, secret: CLIENT_SECRET }, () => {
    // Start the server
    if (module === require.main) {
      const message =
        NODE_ENV === "development"
          ? `\n\n  [Force] Booting on port ${PORT}... \n`
          : `\n\n  [Force] Started on ${APP_URL}. \n`

      app.listen(PORT, "0.0.0.0", () => console.log(message))
    }
  })
})
<commit_msg>set server.keepAliveTimeout via env var<commit_after>require("regenerator-runtime/runtime")
require("coffeescript/register")
require("@babel/register")({
  extensions: [".ts", ".js", ".tsx", ".jsx"],
  plugins: ["babel-plugin-dynamic-import-node"],
})

global.Promise = require("bluebird")

const artsyXapp = require("artsy-xapp")
const cache = require("./lib/cache")
const express = require("express")
const setup = require("./lib/setup").default
const app = (module.exports = express())

const {
  APP_URL,
  API_URL,
  CLIENT_ID,
  CLIENT_SECRET,
  NODE_ENV,
  PORT,
  KEEPALIVE_TIMEOUT,
  PROFILE_MEMORY,
} = process.env

if (PROFILE_MEMORY) require(".src/lib/memory_profiler")()

// Add all of the middleware and global setup
setup(app)

// Connect to Redis
cache.setup(() => {
  // if we can't get an xapp token, just exit and let the whole system try
  // again - this prevents a sustained broken state when gravity returns a
  // 502 during force startup.
  artsyXapp.on("error", err => {
    error(`
Could not start Force because it could not set up the xapp token, this is likely
due to \`API_URL\`, \`CLIENT_ID\` and \`CLIENT_SECRET\` not being set, but
also could be gravity being down.`)
    error(err)
    process.exit()
  })
  // Get an xapp token
  artsyXapp.init({ url: API_URL, id: CLIENT_ID, secret: CLIENT_SECRET }, () => {
    // Start the server
    if (module === require.main) {
      const message =
        NODE_ENV === "development"
          ? `\n\n  [Force] Booting on port ${PORT}... \n`
          : `\n\n  [Force] Started on ${APP_URL}. \n`

      const server = app.listen(PORT, "0.0.0.0", () => console.log(message))
      if (KEEPALIVE_TIMEOUT) {
        console.log("Setting keepAliveTimeout to " + KEEPALIVE_TIMEOUT + " ms")
        server.keepAliveTimeout = Number(KEEPALIVE_TIMEOUT)
      }
    }
  })
})
<|endoftext|>


<commit_before>import StyleProvider from './provider'
import { createRenderer } from 'fela'

export { createRenderer, StyleProvider }
export * from './components'
<commit_msg>simplify re-exports<commit_after>export { default as StyleProvider } from './provider'
export { createRenderer } from 'fela'
export * from './components'
<|endoftext|>


<commit_before>const http = require('http')
const path = require('path')
const fs = require('fs')
const net = require('net')

const express = require('express')
const ejs = require('ejs')
const app = express()
const server = http.createServer(app)
const io = require('socket.io')(server)
const spawn = require('child_process').spawn
const NODE_PORT = 3333

const args = [
  'autovideosrc',
  'horizontal-speed=1',
  'is-live=true',
  '!',
  'videoconvert',
  '!',
  'vp8enc',
  'cpu-used=16',
  'deadline=1',
  'keyframe-max-dist=10',
  '!',
  'queue',
  'leaky=1',
  '!',
  'm.',
  'webmmux',
  'name=m',
  'streamable=true',
  '!',
  'queue',
  'leaky=1',
  '!',
  'tcpserversink',
  'host=127.0.0.1',
  'port=9001',
  'sync-method=2'
]
const gstreamer = spawn('gst-launch-1.0', args, { stdio: 'inherit' })

gstreamer.on('exit', code => {
  if (code !== null) {
    console.log(`GStreamer error, exit code ${code}`)
  }
  process.exit()
})

app.set('view engine', 'ejs')
app.get('/', (req, res) => res.render('index'))

let connections = 0
let streamStarted = false

io.on('connection', socket => {
  console.log('connection made to socket server')

  connections++

  socket.on('disconnect', () => {
    connections--
  })

  if (connections > 0 && !streamStarted) {
    const gs_socket = net.connect(9001, () => {
      streamStarted = true
      gs_socket.on('close', error => {
        console.log(`gs socket closed =>>>`, error)
        streamStarted = false
        // res.end()
      })
      gs_socket.on('data', data => {
        io.sockets.emit('liveStream', data)
      })
    })

    gs_socket.on('error', error => {
      console.log(`gs-error =>>>`, error)
    })
  }
})

// app.get('/webm', (req, res) => {
//   const date = new Date()

//   res.writeHead(200, {
//     Date: date.toUTCString(),
//     Connection: 'close',
//     'Cache-Control': 'private',
//     'Content-Type': 'video/webm',
//     Server: 'CustomStreamer/0.0.1'
//   })

// })

server.listen(NODE_PORT, () => {
  console.log(`Application running on port: ${NODE_PORT}`)
})
<commit_msg>attempt<commit_after>const http = require('http')
const path = require('path')
const fs = require('fs')
const net = require('net')

const express = require('express')
const ejs = require('ejs')
const app = express()
const server = http.createServer(app)
const io = require('socket.io')(server)
const spawn = require('child_process').spawn
const NODE_PORT = 3333

const args = [
  'autovideosrc',
  'horizontal-speed=1',
  'is-live=true',
  '!',
  'videoconvert',
  '!',
  'vp8enc',
  'cpu-used=16',
  'deadline=1',
  'keyframe-max-dist=10',
  '!',
  'queue',
  'leaky=1',
  '!',
  'm.',
  'webmmux',
  'name=m',
  'streamable=true',
  '!',
  'queue',
  'leaky=1',
  '!',
  'tcpserversink',
  'host=127.0.0.1',
  'port=9001',
  'sync-method=2'
]
const gstreamer = spawn('gst-launch-1.0', args, { stdio: 'inherit' })

gstreamer.on('exit', code => {
  if (code !== null) {
    console.log(`GStreamer error, exit code ${code}`)
  }
  process.exit()
})

app.set('view engine', 'ejs')
app.get('/', (req, res) => res.render('index'))

let connections = 0
let streamStarted = false

io.on('connection', socket => {
  console.log('connection made to socket server')

  connections++

  socket.on('disconnect', () => {
    connections--
  })

  if (connections > 0 && !streamStarted) {
    const gs_socket = net.connect(9001, () => {
      streamStarted = true
      gs_socket.on('close', error => {
        console.log(`gs socket closed =>>>`, error)
        streamStarted = false
        // res.end()
      })
      gs_socket.on('data', data => {
        io.sockets.emit('liveStream', data.toString())
      })
    })

    gs_socket.on('error', error => {
      console.log(`gs-error =>>>`, error)
    })
  }
})

// app.get('/webm', (req, res) => {
//   const date = new Date()

//   res.writeHead(200, {
//     Date: date.toUTCString(),
//     Connection: 'close',
//     'Cache-Control': 'private',
//     'Content-Type': 'video/webm',
//     Server: 'CustomStreamer/0.0.1'
//   })

// })

server.listen(NODE_PORT, () => {
  console.log(`Application running on port: ${NODE_PORT}`)
})
<|endoftext|>


<commit_before>import interpreter from './interpreter';
import fromNow from './from-now';
import assert from 'assert';
import {
  isString, isNumber, isBool,
  isArray, isObject, isFunction,
} from './type-utils';
import builtins from './builtins';
import TemplateError from './error';

let jsonTemplateError = (msg, template) => new TemplateError(msg + JSON.stringify(template, null, '\t'));

let interpolate = (string, context) => {
  let result = '';
  let begin = 0;
  let remaining = string;
  let offset;
  while ((offset = remaining.search(/\${/g)) !== -1) {
    let v = interpreter.parseUntilTerminator(remaining.slice(offset), 2, '}', context);
    if (isArray(v.result) || isObject(v.result)) {
      throw new TemplateError('cannot interpolate array/object: ' + string);
    }
    result += remaining.slice(0, offset) + v.result.toString();
    remaining = remaining.slice(offset + v.offset + 1);
  }
  result += remaining;
  return result;
};

// Object used to indicate deleteMarker
let deleteMarker = {};

let constructs = {};

constructs.$eval = (template, context) => {
  if (!isString(template['$eval'])) {
    throw jsonTemplateError('$eval can evaluate string expressions only\n', template);
  }
  return interpreter.parse(template['$eval'], context);
};

constructs.$fromNow = (template, context) => {
  if (!isString(template['$fromNow'])) {
    throw jsonTemplateError('$fromNow can evaluate string expressions only\n', template);
  }
  return fromNow(template['$fromNow']);
};

constructs.$if = (template, context) => {
  if (!isString(template['$if'])) {
    throw jsonTemplateError('$if can evaluate string expressions only\n', template);
  }
  if (interpreter.parse(template['$if'], context)) {
    return template.hasOwnProperty('then') ? render(template.then, context) : deleteMarker;
  }
  return template.hasOwnProperty('else') ? render(template.else, context) : deleteMarker;
};

constructs.$switch = (template, context) => {
  if (!isString(template['$switch'])) {
    throw jsonTemplateError('$switch can evaluate string expressions only\n', template);
  }
  let c = interpreter.parse(template['$switch'], context);
  return template.hasOwnProperty(c) ? render(template[c], context) : deleteMarker;
};

constructs.$json = (template, context) => {
  return JSON.stringify(render(template['$json'], context));
};

constructs.$reverse = (template, context) => {
  let value = render(template['$reverse'], context);

  if (!isArray(value) && !isArray(template['$reverse'])) {
    throw jsonTemplateError('$reverse value must evaluate to an array\n', template);
  }

  if (!isArray(value)) {
    throw jsonTemplateError('$reverse requires array as value\n', template);
  }
  return value.reverse();
};

constructs.$map = (template, context) => {
  let value = render(template['$map'], context);
  if (!isArray(value)) {
    throw jsonTemplateError('$map requires array as value\n', template);
  }

  if (Object.keys(template).length !== 2) {
    throw jsonTemplateError('$map requires cannot have more than two properties\n', template);
  }

  let eachKey = Object.keys(template).filter(k => k !== '$map')[0];
  let match = /^each\(([a-zA-Z_][a-zA-Z0-9_]*)\)$/.exec(eachKey);
  if (!match) {
    throw jsonTemplateError('$map requires each(identifier) syntax\n', template);
  }

  let x = match[1];
  let each = template[eachKey];

  return value.map(v => render(each, Object.assign({}, context, {[x]: v})))
              .filter(v => v !== deleteMarker);

};

constructs.$sort = (template, context) => {
  let value = render(template['$sort'], context);
  if (!isArray(value)) {
    throw jsonTemplateError('$sort requires array as value\n', template);
  }

  let byKey = Object.keys(template).filter(k => k !== '$sort')[0];
  let match = /^by\(([a-zA-Z_][a-zA-Z0-9_]*)\)$/.exec(byKey);
  if (!match) {
    let needBy = value.some(v => isArray(v) || isObject(v));
    if (needBy) {
      throw jsonTemplateError('$sort requires by(identifier) for sorting arrays of objects/arrays\n', template);
    }
    return value.sort();
  }

  let x = match[1];
  let by = template[byKey];
  let contextClone = Object.assign({}, context);

  return value.sort((left, right) => {
    contextClone[x] = left;
    left = interpreter.parse(by, contextClone);
    contextClone[x] = right;
    right = interpreter.parse(by, contextClone);
    if (left <= right) {
      return false;
    }
    return true;
  });
};

let render = (template, context) => {
  if (isNumber(template) || isBool(template)) {
    return template;
  }
  if (isString(template)) {
    return interpolate(template, context);
  }
  if (isArray(template)) {
    return template.map((v) => render(v, context)).filter((v) => v !== deleteMarker);
  }

  let matches = Object.keys(constructs).filter(c => template.hasOwnProperty(c));
  if (matches.length > 1) {
    throw jsonTemplateError('only one construct allowed\n', template);
  }
  if (matches.length === 1) {
    return constructs[matches[0]](template, context);
  }

  // clone object
  let result = {};
  for (let key of Object.keys(template)) {
    let value = render(template[key], context);
    if (value !== deleteMarker) {
      result[interpolate(key, context)] = value;
    }
  }
  return result;
};

export default (template, context = {}) => {
  let test = Object.keys(context).every(v => /[a-zA-Z_][a-zA-Z0-9_]*/.exec(v)[0]);
  context = Object.assign({}, builtins, context);
  assert(test, 'top level keys of context must follow /[a-zA-Z_][a-zA-Z0-9_]*/');
  let result = render(template, context);
  if (result === deleteMarker) {
    return undefined;
  }
  return result;
};
<commit_msg>Cleaning up index.js, sorting functions<commit_after>import interpreter from './interpreter';
import fromNow from './from-now';
import assert from 'assert';
import {
  isString, isNumber, isBool,
  isArray, isObject, isFunction,
} from './type-utils';
import builtins from './builtins';
import TemplateError from './error';

let jsonTemplateError = (msg, template) => new TemplateError(msg + JSON.stringify(template, null, '\t'));

let interpolate = (string, context) => {
  let result = '';
  let begin = 0;
  let remaining = string;
  let offset;
  while ((offset = remaining.search(/\${/g)) !== -1) {
    let v = interpreter.parseUntilTerminator(remaining.slice(offset), 2, '}', context);
    if (isArray(v.result) || isObject(v.result)) {
      throw new TemplateError('cannot interpolate array/object: ' + string);
    }
    result += remaining.slice(0, offset) + v.result.toString();
    remaining = remaining.slice(offset + v.offset + 1);
  }
  result += remaining;
  return result;
};

// Object used to indicate deleteMarker
let deleteMarker = {};

let constructs = {};

constructs.$eval = (template, context) => {
  if (!isString(template['$eval'])) {
    throw jsonTemplateError('$eval can evaluate string expressions only\n', template);
  }
  return interpreter.parse(template['$eval'], context);
};

constructs.$fromNow = (template, context) => {
  if (!isString(template['$fromNow'])) {
    throw jsonTemplateError('$fromNow can evaluate string expressions only\n', template);
  }
  return fromNow(template['$fromNow']);
};

constructs.$if = (template, context) => {
  if (!isString(template['$if'])) {
    throw jsonTemplateError('$if can evaluate string expressions only\n', template);
  }
  if (interpreter.parse(template['$if'], context)) {
    return template.hasOwnProperty('then') ? render(template.then, context) : deleteMarker;
  }
  return template.hasOwnProperty('else') ? render(template.else, context) : deleteMarker;
};

constructs.$json = (template, context) => {
  return JSON.stringify(render(template['$json'], context));
};

constructs.$map = (template, context) => {
  let value = render(template['$map'], context);
  if (!isArray(value)) {
    throw jsonTemplateError('$map requires array as value\n', template);
  }

  if (Object.keys(template).length !== 2) {
    throw jsonTemplateError('$map requires cannot have more than two properties\n', template);
  }

  let eachKey = Object.keys(template).filter(k => k !== '$map')[0];
  let match = /^each\(([a-zA-Z_][a-zA-Z0-9_]*)\)$/.exec(eachKey);
  if (!match) {
    throw jsonTemplateError('$map requires each(identifier) syntax\n', template);
  }

  let x = match[1];
  let each = template[eachKey];

  return value.map(v => render(each, Object.assign({}, context, {[x]: v})))
              .filter(v => v !== deleteMarker);

};

constructs.$reverse = (template, context) => {
  let value = render(template['$reverse'], context);

  if (!isArray(value) && !isArray(template['$reverse'])) {
    throw jsonTemplateError('$reverse value must evaluate to an array\n', template);
  }

  if (!isArray(value)) {
    throw jsonTemplateError('$reverse requires array as value\n', template);
  }
  return value.reverse();
};

constructs.$sort = (template, context) => {
  let value = render(template['$sort'], context);
  if (!isArray(value)) {
    throw jsonTemplateError('$sort requires array as value\n', template);
  }

  let byKey = Object.keys(template).filter(k => k !== '$sort')[0];
  let match = /^by\(([a-zA-Z_][a-zA-Z0-9_]*)\)$/.exec(byKey);
  if (!match) {
    let needBy = value.some(v => isArray(v) || isObject(v));
    if (needBy) {
      throw jsonTemplateError('$sort requires by(identifier) for sorting arrays of objects/arrays\n', template);
    }
    return value.sort();
  }

  let x = match[1];
  let by = template[byKey];
  let contextClone = Object.assign({}, context);

  return value.sort((left, right) => {
    contextClone[x] = left;
    left = interpreter.parse(by, contextClone);
    contextClone[x] = right;
    right = interpreter.parse(by, contextClone);
    if (left <= right) {
      return false;
    }
    return true;
  });
};

constructs.$switch = (template, context) => {
  if (!isString(template['$switch'])) {
    throw jsonTemplateError('$switch can evaluate string expressions only\n', template);
  }
  let c = interpreter.parse(template['$switch'], context);
  return template.hasOwnProperty(c) ? render(template[c], context) : deleteMarker;
};

let render = (template, context) => {
  if (isNumber(template) || isBool(template)) {
    return template;
  }
  if (isString(template)) {
    return interpolate(template, context);
  }
  if (isArray(template)) {
    return template.map((v) => render(v, context)).filter((v) => v !== deleteMarker);
  }

  let matches = Object.keys(constructs).filter(c => template.hasOwnProperty(c));
  if (matches.length > 1) {
    throw jsonTemplateError('only one construct allowed\n', template);
  }
  if (matches.length === 1) {
    return constructs[matches[0]](template, context);
  }

  // clone object
  let result = {};
  for (let key of Object.keys(template)) {
    let value = render(template[key], context);
    if (value !== deleteMarker) {
      result[interpolate(key, context)] = value;
    }
  }
  return result;
};

export default (template, context = {}) => {
  let test = Object.keys(context).every(v => /[a-zA-Z_][a-zA-Z0-9_]*/.exec(v)[0]);
  context = Object.assign({}, builtins, context);
  assert(test, 'top level keys of context must follow /[a-zA-Z_][a-zA-Z0-9_]*/');
  let result = render(template, context);
  if (result === deleteMarker) {
    return undefined;
  }
  return result;
};
<|endoftext|>


<commit_before>import isPlainObject from 'lodash/isPlainObject'
import { toType, getType, isFunction, validateType, isInteger, isArray, warn, noop } from './utils'
import { setDefaults } from './sensibles'

const VueTypes = {

  get any () {
    return toType('any', {
      type: null
    }, true)
  },

  get func () {
    return toType('function', {
      type: Function
    }, true).def(VueTypes.sensibleDefaults.func)
  },

  get bool () {
    return toType('boolean', {
      type: Boolean
    }, true).def(VueTypes.sensibleDefaults.bool)
  },

  get string () {
    return toType('string', {
      type: String
    }, true).def(VueTypes.sensibleDefaults.string)
  },

  get number () {
    return toType('number', {
      type: Number
    }, true).def(VueTypes.sensibleDefaults.number)
  },

  get array () {
    return toType('array', {
      type: Array
    }, true).def(VueTypes.sensibleDefaults.array)
  },

  get object () {
    return toType('object', {
      type: Object
    }, true).def(VueTypes.sensibleDefaults.object)
  },

  get integer () {
    return toType('integer', {
      type: Number,
      validator (value) {
        return isInteger(value)
      }
    }).def(VueTypes.sensibleDefaults.integer)
  },

  get symbol () {
    return toType('symbol', {
      type: null,
      validator (value) {
        return typeof value === 'symbol'
      }
    }, true)
  },

  extend (props = {}) {
    const { name, validate = false, getter = false, ...type } = props
    let descriptor
    if (getter) {
      descriptor = {
        get () {
          return toType(name, type, validate)
        },
        enumerable: true,
        configurable: false
      }
    } else {
      const { validator } = type
      descriptor = {
        value (...args) {
          if (validator) {
            type.validator = validator.bind(this, ...args)
          }
          return toType(name, type, validate)
        },
        writable: false,
        enumerable: true,
        configurable: false
      }
    }

    return Object.defineProperty(this, name, descriptor)
  },

  custom (validatorFn, warnMsg = 'custom validation failed') {
    if (typeof validatorFn !== 'function') {
      throw new TypeError('[VueTypes error]: You must provide a function as argument')
    }

    return toType(validatorFn.name || '<<anonymous function>>', {
      validator (value) {
        const valid = validatorFn(value)
        if (!valid) warn(`${this._vueTypes_name} - ${warnMsg}`)
        return valid
      }
    })
  },

  oneOf (arr) {
    if (!isArray(arr)) {
      throw new TypeError('[VueTypes error]: You must provide an array as argument')
    }
    const msg = `oneOf - value should be one of "${arr.join('", "')}"`
    const allowedTypes = arr.reduce((ret, v) => {
      if (v !== null && v !== undefined) {
        ret.indexOf(v.constructor) === -1 && ret.push(v.constructor)
      }
      return ret
    }, [])

    return toType('oneOf', {
      type: allowedTypes.length > 0 ? allowedTypes : null,
      validator (value) {
        const valid = arr.indexOf(value) !== -1
        if (!valid) warn(msg)
        return valid
      }
    })
  },

  instanceOf (instanceConstructor) {
    return toType('instanceOf', {
      type: instanceConstructor
    })
  },

  oneOfType (arr) {
    if (!isArray(arr)) {
      throw new TypeError('[VueTypes error]: You must provide an array as argument')
    }

    let hasCustomValidators = false

    const nativeChecks = arr.reduce((ret, type, i) => {
      if (isPlainObject(type)) {
        if (type._vueTypes_name === 'oneOf') {
          return ret.concat(type.type || [])
        }
        if (type.type && !isFunction(type.validator)) {
          if (isArray(type.type)) return ret.concat(type.type)
          ret.push(type.type)
        } else if (isFunction(type.validator)) {
          hasCustomValidators = true
        }
        return ret
      }
      ret.push(type)
      return ret
    }, [])

    if (!hasCustomValidators) {
      // we got just native objects (ie: Array, Object)
      // delegate to Vue native prop check
      return toType('oneOfType', {
        type: nativeChecks
      })
    }

    const typesStr = arr.map((type) => {
      if (type && isArray(type.type)) {
        return type.type.map(getType)
      }
      return getType(type)
    }).reduce((ret, type) => ret.concat(isArray(type) ? type : [type]), []).join('", "')

    return this.custom(function oneOfType (value) {
      const valid = arr.some((type) => {
        if (type._vueTypes_name === 'oneOf') {
          return type.type ? validateType(type.type, value, true) : true
        }
        return validateType(type, value, true)
      })
      if (!valid) warn(`oneOfType - value type should be one of "${typesStr}"`)
      return valid
    })
  },

  arrayOf (type) {
    return toType('arrayOf', {
      type: Array,
      validator (values) {
        const valid = values.every((value) => validateType(type, value))
        if (!valid) warn(`arrayOf - value must be an array of "${getType(type)}"`)
        return valid
      }
    })
  },

  objectOf (type) {
    return toType('objectOf', {
      type: Object,
      validator (obj) {
        const valid = Object.keys(obj).every((key) => validateType(type, obj[key]))
        if (!valid) warn(`objectOf - value must be an object of "${getType(type)}"`)
        return valid
      }
    })
  },

  shape (obj) {
    const keys = Object.keys(obj)
    const requiredKeys = keys.filter((key) => obj[key] && obj[key].required === true)

    const type = toType('shape', {
      type: Object,
      validator (value) {
        if (!isPlainObject(value)) {
          return false
        }
        const valueKeys = Object.keys(value)

        // check for required keys (if any)
        if (requiredKeys.length > 0 && requiredKeys.some((req) => valueKeys.indexOf(req) === -1)) {
          warn(`shape - at least one of required properties "${requiredKeys.join('", "')}" is not present`)
          return false
        }

        return valueKeys.every((key) => {
          if (keys.indexOf(key) === -1) {
            if (this._vueTypes_isLoose === true) return true
            warn(`shape - object is missing "${key}" property`)
            return false
          }
          const type = obj[key]
          return validateType(type, value[key])
        })
      }
    })

    Object.defineProperty(type, '_vueTypes_isLoose', {
      enumerable: false,
      writable: true,
      value: false
    })

    Object.defineProperty(type, 'loose', {
      get () {
        this._vueTypes_isLoose = true
        return this
      },
      enumerable: false
    })

    return type
  }

}

setDefaults(VueTypes)

VueTypes.utils = {
  validate (value, type) {
    return validateType(type, value, true)
  },
  toType
}

export default VueTypes
<commit_msg>cleanup unused import<commit_after>import isPlainObject from 'lodash/isPlainObject'
import { toType, getType, isFunction, validateType, isInteger, isArray, warn } from './utils'
import { setDefaults } from './sensibles'

const VueTypes = {

  get any () {
    return toType('any', {
      type: null
    }, true)
  },

  get func () {
    return toType('function', {
      type: Function
    }, true).def(VueTypes.sensibleDefaults.func)
  },

  get bool () {
    return toType('boolean', {
      type: Boolean
    }, true).def(VueTypes.sensibleDefaults.bool)
  },

  get string () {
    return toType('string', {
      type: String
    }, true).def(VueTypes.sensibleDefaults.string)
  },

  get number () {
    return toType('number', {
      type: Number
    }, true).def(VueTypes.sensibleDefaults.number)
  },

  get array () {
    return toType('array', {
      type: Array
    }, true).def(VueTypes.sensibleDefaults.array)
  },

  get object () {
    return toType('object', {
      type: Object
    }, true).def(VueTypes.sensibleDefaults.object)
  },

  get integer () {
    return toType('integer', {
      type: Number,
      validator (value) {
        return isInteger(value)
      }
    }).def(VueTypes.sensibleDefaults.integer)
  },

  get symbol () {
    return toType('symbol', {
      type: null,
      validator (value) {
        return typeof value === 'symbol'
      }
    }, true)
  },

  extend (props = {}) {
    const { name, validate = false, getter = false, ...type } = props
    let descriptor
    if (getter) {
      descriptor = {
        get () {
          return toType(name, type, validate)
        },
        enumerable: true,
        configurable: false
      }
    } else {
      const { validator } = type
      descriptor = {
        value (...args) {
          if (validator) {
            type.validator = validator.bind(this, ...args)
          }
          return toType(name, type, validate)
        },
        writable: false,
        enumerable: true,
        configurable: false
      }
    }

    return Object.defineProperty(this, name, descriptor)
  },

  custom (validatorFn, warnMsg = 'custom validation failed') {
    if (typeof validatorFn !== 'function') {
      throw new TypeError('[VueTypes error]: You must provide a function as argument')
    }

    return toType(validatorFn.name || '<<anonymous function>>', {
      validator (value) {
        const valid = validatorFn(value)
        if (!valid) warn(`${this._vueTypes_name} - ${warnMsg}`)
        return valid
      }
    })
  },

  oneOf (arr) {
    if (!isArray(arr)) {
      throw new TypeError('[VueTypes error]: You must provide an array as argument')
    }
    const msg = `oneOf - value should be one of "${arr.join('", "')}"`
    const allowedTypes = arr.reduce((ret, v) => {
      if (v !== null && v !== undefined) {
        ret.indexOf(v.constructor) === -1 && ret.push(v.constructor)
      }
      return ret
    }, [])

    return toType('oneOf', {
      type: allowedTypes.length > 0 ? allowedTypes : null,
      validator (value) {
        const valid = arr.indexOf(value) !== -1
        if (!valid) warn(msg)
        return valid
      }
    })
  },

  instanceOf (instanceConstructor) {
    return toType('instanceOf', {
      type: instanceConstructor
    })
  },

  oneOfType (arr) {
    if (!isArray(arr)) {
      throw new TypeError('[VueTypes error]: You must provide an array as argument')
    }

    let hasCustomValidators = false

    const nativeChecks = arr.reduce((ret, type, i) => {
      if (isPlainObject(type)) {
        if (type._vueTypes_name === 'oneOf') {
          return ret.concat(type.type || [])
        }
        if (type.type && !isFunction(type.validator)) {
          if (isArray(type.type)) return ret.concat(type.type)
          ret.push(type.type)
        } else if (isFunction(type.validator)) {
          hasCustomValidators = true
        }
        return ret
      }
      ret.push(type)
      return ret
    }, [])

    if (!hasCustomValidators) {
      // we got just native objects (ie: Array, Object)
      // delegate to Vue native prop check
      return toType('oneOfType', {
        type: nativeChecks
      })
    }

    const typesStr = arr.map((type) => {
      if (type && isArray(type.type)) {
        return type.type.map(getType)
      }
      return getType(type)
    }).reduce((ret, type) => ret.concat(isArray(type) ? type : [type]), []).join('", "')

    return this.custom(function oneOfType (value) {
      const valid = arr.some((type) => {
        if (type._vueTypes_name === 'oneOf') {
          return type.type ? validateType(type.type, value, true) : true
        }
        return validateType(type, value, true)
      })
      if (!valid) warn(`oneOfType - value type should be one of "${typesStr}"`)
      return valid
    })
  },

  arrayOf (type) {
    return toType('arrayOf', {
      type: Array,
      validator (values) {
        const valid = values.every((value) => validateType(type, value))
        if (!valid) warn(`arrayOf - value must be an array of "${getType(type)}"`)
        return valid
      }
    })
  },

  objectOf (type) {
    return toType('objectOf', {
      type: Object,
      validator (obj) {
        const valid = Object.keys(obj).every((key) => validateType(type, obj[key]))
        if (!valid) warn(`objectOf - value must be an object of "${getType(type)}"`)
        return valid
      }
    })
  },

  shape (obj) {
    const keys = Object.keys(obj)
    const requiredKeys = keys.filter((key) => obj[key] && obj[key].required === true)

    const type = toType('shape', {
      type: Object,
      validator (value) {
        if (!isPlainObject(value)) {
          return false
        }
        const valueKeys = Object.keys(value)

        // check for required keys (if any)
        if (requiredKeys.length > 0 && requiredKeys.some((req) => valueKeys.indexOf(req) === -1)) {
          warn(`shape - at least one of required properties "${requiredKeys.join('", "')}" is not present`)
          return false
        }

        return valueKeys.every((key) => {
          if (keys.indexOf(key) === -1) {
            if (this._vueTypes_isLoose === true) return true
            warn(`shape - object is missing "${key}" property`)
            return false
          }
          const type = obj[key]
          return validateType(type, value[key])
        })
      }
    })

    Object.defineProperty(type, '_vueTypes_isLoose', {
      enumerable: false,
      writable: true,
      value: false
    })

    Object.defineProperty(type, 'loose', {
      get () {
        this._vueTypes_isLoose = true
        return this
      },
      enumerable: false
    })

    return type
  }

}

setDefaults(VueTypes)

VueTypes.utils = {
  validate (value, type) {
    return validateType(type, value, true)
  },
  toType
}

export default VueTypes
<|endoftext|>


<commit_before>/*
function htmlEncode(value) {
	return value.toString()
		.replace(/&/g,'&').replace(/"/g,'"').replace(/'/g,''')
		.replace(/</g,'<').replace(/>/g,'>')
	; // https://github.com/emn178/js-htmlencode/blob/master/src/htmlencode.js
}
*/

/*
var OptionsSection=function(){
	this.added=[];
};
OptionsSection.prototype.add=function(name,type){
	function getDefaultValue() {
		if (Array.isArray(type)) {
			return
		} else if (type=='bool') {
			return false;
		} else if (type=='color') {
			return {
				r: 1.0,
				g: 1.0,
				b: 1.0,
			};
		}
	}
	this.added.push({
		name: name,
		type: type,
		value: getDefaultValue(),
	});
};

var Options=function(){
	//this.fixed= // TODO stuff like language
	this.code=new OptionsSection();
	this.code.add('clearBackground','bool');
	this.code.add('draw',['triangle','gasket']);
	this.code.add('rotate','bool');
	this.inputs=new OptionsSection(); // TODO recreate based on this.code
	this.inputs.add('fragmentColor','color');
};
*/

function generateCode(options) {
	function indent(level,lines) {
		return lines.map(function(line){
			return Array(level+1).join("	")+line;
		});
	}
	function render() {
		return [].concat(options.clearBackground?[
			"gl.clear(gl.COLOR_BUFFER_BIT);",
		]:[],options.rotate?[
			"gl.uniform1f(rotationAngleLoc,(time-startTime)*360/5000);",
		]:[],[
			"gl.drawArrays(gl.TRIANGLES,0,nVertices);",
		]);
	}
	function colorComponentValue(intName) {
		return options[intName].toFixed(3);
	}
	function colorValue(name) {
		return colorComponentValue(name+'.value.r')+","+
		       colorComponentValue(name+'.value.g')+","+
		       colorComponentValue(name+'.value.b');
	}
	function colorInput(name) {
		return [].concat.apply([],
			['red','green','blue'].map(function(component){
				var c=component.charAt(0);
				var C=c.toUpperCase();
				var intName=name+'.value.'+c;
				var extName='my'+name.charAt(0).toUpperCase()+name.slice(1)+C;
				return [
					"
",
					"	Fragment color: "+component+"",
					"	0% <input id='"+extName+"' type='range' min='0' max='1' step='0.001' value='"+colorComponentValue(intName)+"' /> 100%",
					"
",
				];
			})
		);
	}
	return [].concat([
		"<!DOCTYPE html>",
		"",
		"",
		"<meta charset='utf-8' />",
		"<title>Generated code</title>",
	],options['fragmentColor.input']?[
		"",
	]:[],[
		"",
		"",
		"",
		"",
		"
",
		"	<canvas id='myCanvas' width='512' height='512'></canvas>",
		"
",
	],options['fragmentColor.input']?colorInput('fragmentColor'):[],[
		"",
		"",
		"",
	]).join("\n");
}

function getHtmlDataUri(html) {
	// with base64: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
	//return "data:text/html;charset=utf-8;base64,"+window.btoa(unescape(encodeURIComponent(str)));
	// without base64: https://en.wikipedia.org/wiki/Data_URI_scheme
	return 'data:text/html;charset=utf-8,'+encodeURIComponent(html);
}

$(function(){
	$('.webgl-starter').each(function(){
		var container=$(this);
		var options={
			clearBackground: false,
			draw: 'triangle',
			rotate: false,
			// inputs
			'fragmentColor.value.r': 1.0,
			'fragmentColor.value.g': 0.0,
			'fragmentColor.value.b': 0.0,
			'fragmentColor.input': false,
		};
		var code;
		function updateCode() {
			code.text(generateCode(options));
			hljs.highlightBlock(code[0]);
		}
		container.empty().append(
			$("
").append(
				$("").text(" Clear background").prepend( // TODO fix misleading option name - background is clear (transparent) by default
					$("<input type='checkbox'>").change(function(){
						options.clearBackground=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").text("Draw ").append(
					$("<select><option>triangle</option><option>gasket</option></select>").change(function(){
						options.draw=this.value;
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").text(" Animated rotation").prepend(
					$("<input type='checkbox'>").change(function(){
						options.rotate=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").append("Fragment color: red 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='1'>").change(function(){ // TODO ie fix
						options['fragmentColor.value.r']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").append("Fragment color: green 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='0'>").change(function(){ // TODO ie fix
						options['fragmentColor.value.g']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").append("Fragment color: blue 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='0'>").change(function(){ // TODO ie fix
						options['fragmentColor.value.b']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").text(" Provide fragment color inputs to users").prepend(
					$("<input type='checkbox'>").change(function(){
						options['fragmentColor.input']=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(code=$("").text(generateCode(options)))
		).append(
			$("
").append(
				$("<button type='button'>Run in new window</button>").click(function(){
					window.open(getHtmlDataUri(code.text()),"generatedCode");
				})
			).append(
				" running in new window doesn't work in Internet Explorer"
			)
		);
		hljs.highlightBlock(code[0]);
	});
});
<commit_msg>user color input works for animated rotation<commit_after>/*
function htmlEncode(value) {
	return value.toString()
		.replace(/&/g,'&').replace(/"/g,'"').replace(/'/g,''')
		.replace(/</g,'<').replace(/>/g,'>')
	; // https://github.com/emn178/js-htmlencode/blob/master/src/htmlencode.js
}
*/

/*
var OptionsSection=function(){
	this.added=[];
};
OptionsSection.prototype.add=function(name,type){
	function getDefaultValue() {
		if (Array.isArray(type)) {
			return
		} else if (type=='bool') {
			return false;
		} else if (type=='color') {
			return {
				r: 1.0,
				g: 1.0,
				b: 1.0,
			};
		}
	}
	this.added.push({
		name: name,
		type: type,
		value: getDefaultValue(),
	});
};

var Options=function(){
	//this.fixed= // TODO stuff like language
	this.code=new OptionsSection();
	this.code.add('clearBackground','bool');
	this.code.add('draw',['triangle','gasket']);
	this.code.add('rotate','bool');
	this.inputs=new OptionsSection(); // TODO recreate based on this.code
	this.inputs.add('fragmentColor','color');
};
*/

function generateCode(options) {
	function indent(level,lines) {
		return lines.map(function(line){
			return Array(level+1).join("	")+line;
		});
	}
	function render() {
		return [].concat(options.clearBackground?[
			"gl.clear(gl.COLOR_BUFFER_BIT);",
		]:[],options.rotate?[
			"gl.uniform1f(rotationAngleLoc,(time-startTime)*360/5000);",
		]:[],[
			"gl.drawArrays(gl.TRIANGLES,0,nVertices);",
		]);
	}
	function colorComponentValue(intName) {
		return options[intName].toFixed(3);
	}
	function colorValue(name) {
		return colorComponentValue(name+'.value.r')+","+
		       colorComponentValue(name+'.value.g')+","+
		       colorComponentValue(name+'.value.b');
	}
	function colorInput(name) {
		return [].concat.apply([],
			['red','green','blue'].map(function(component){
				var c=component.charAt(0);
				var C=c.toUpperCase();
				var intName=name+'.value.'+c;
				var extName='my'+name.charAt(0).toUpperCase()+name.slice(1)+C;
				return [
					"
",
					"	Fragment color: "+component+"",
					"	0% <input id='"+extName+"' type='range' min='0' max='1' step='0.001' value='"+colorComponentValue(intName)+"' /> 100%",
					"
",
				];
			})
		);
	}
	return [].concat([
		"<!DOCTYPE html>",
		"",
		"",
		"<meta charset='utf-8' />",
		"<title>Generated code</title>",
	],options['fragmentColor.input']?[
		"",
	]:[],[
		"",
		"",
		"",
		"",
		"
",
		"	<canvas id='myCanvas' width='512' height='512'></canvas>",
		"
",
	],options['fragmentColor.input']?colorInput('fragmentColor'):[],[
		"",
		"",
		"",
	]).join("\n");
}

function getHtmlDataUri(html) {
	// with base64: https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/btoa
	//return "data:text/html;charset=utf-8;base64,"+window.btoa(unescape(encodeURIComponent(str)));
	// without base64: https://en.wikipedia.org/wiki/Data_URI_scheme
	return 'data:text/html;charset=utf-8,'+encodeURIComponent(html);
}

$(function(){
	$('.webgl-starter').each(function(){
		var container=$(this);
		var options={
			clearBackground: false,
			draw: 'triangle',
			rotate: false,
			// inputs
			'fragmentColor.value.r': 1.0,
			'fragmentColor.value.g': 0.0,
			'fragmentColor.value.b': 0.0,
			'fragmentColor.input': false,
		};
		var code;
		function updateCode() {
			code.text(generateCode(options));
			hljs.highlightBlock(code[0]);
		}
		container.empty().append(
			$("
").append(
				$("").text(" Clear background").prepend( // TODO fix misleading option name - background is clear (transparent) by default
					$("<input type='checkbox'>").change(function(){
						options.clearBackground=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").text("Draw ").append(
					$("<select><option>triangle</option><option>gasket</option></select>").change(function(){
						options.draw=this.value;
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").text(" Animated rotation").prepend(
					$("<input type='checkbox'>").change(function(){
						options.rotate=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(
				$("").append("Fragment color: red 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='1'>").change(function(){
						options['fragmentColor.value.r']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").append("Fragment color: green 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='0'>").change(function(){
						options['fragmentColor.value.g']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").append("Fragment color: blue 0% ").append(
					$("<input type='range' min='0' max='1' step='0.001' value='0'>").change(function(){
						options['fragmentColor.value.b']=parseFloat(this.value);
						updateCode();
					})
				).append(" 100%")
			)
		).append(
			$("
").append(
				$("").text(" Provide fragment color inputs to users").prepend(
					$("<input type='checkbox'>").change(function(){
						options['fragmentColor.input']=$(this).prop('checked');
						updateCode();
					})
				)
			)
		).append(
			$("
").append(code=$("").text(generateCode(options)))
		).append(
			$("
").append(
				$("<button type='button'>Run in new window</button>").click(function(){
					window.open(getHtmlDataUri(code.text()),"generatedCode");
				})
			).append(
				" running in new window doesn't work in Internet Explorer"
			)
		);
		hljs.highlightBlock(code[0]);
	});
});
<|endoftext|>


<commit_before>(function (w) {
  'use strict';

  /**
   * Constructor function for the blob reader.
   *
   * @public
   * @constructor
   * @param {Blob} blob The blob object, which should be read
   */
  function BlobReader(blob) {
    if (!(this instanceof BlobReader)) {
      return new BlobReader(blob);
    }
    this.blob = blob;
    this.position = 0;
    this.queue = [];
    this._pendingTask = false;
  }

  BlobReader.ARRAY_BUFFER = 'ArrayBuffer';
  BlobReader.BINARY_STRING = 'BinaryString';
  BlobReader.TEXT = 'Text';
  BlobReader.DATA_URL = 'DataURL';

  BlobReader.prototype._invokeNext = function () {
    var current = this.queue.shift();
    if (!current) {
      return;
    }
    if (this.position + current.count > this.blob.size) {
      throw new Error('Limit reached. Trying to read ' +
          (this.position + current.count) + ' bytes out of ' +
          this.blob.size + '.');
    }
    var reader = new FileReader();
    this._pendingTask = true;
    reader.onload = function (e) {
      var data = e.target.result;
      this._pendingTask = false;
      current.cb(data);
      this._invokeNext();
    }.bind(this);
    reader.onerror = function () {
      throw new Error('Error while reading the blob');
    };
    if (!current.type) {
      current.type = BlobReader.BINARY_STRING;
    }
    reader['readAs' + current.type](
        this.blob.slice(this.position, this.position + current.count)
    );
    this.position += current.count;
  };

  /**
   * Read definite amount of bytes by the blob
   *
   * @public
   * @param {Number} count The count of bytes, which should be read
   * @param {Function} cb The callback, which should be
   *  invoked once the bytes are read
   * @return {BlobReader} Returns `this`
   */
  BlobReader.prototype.read = function (count, type, cb) {
    if (typeof count === 'string') {
      cb = type;
      count = undefined;
      type = count;
    }
    if (count === undefined) {
      count = this.blob.size - this.position;
    }
    if (typeof count === 'function') {
      cb = count;
      type = undefined;
      count = this.blob.size - this.position;
    }
    if (typeof type === 'function') {
      cb = type;
      type = undefined;
    }
    this.queue.push({
      count: count,
      cb: cb,
      type: type
    });
    if (!this._pendingTask) {
      this._invokeNext();
    }
    return this;
  };

  /**
   * Read defined amount of bytes as text
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object instance
   */
  BlobReader.prototype.readText = function (count, cb) {
    return this.read(count, BlobReader.TEXT, cb);
  };

  /**
   * Read defined amount of bytes as array buffer
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object instance
   */
  BlobReader.prototype.readArrayBuffer = function (count, cb) {
    return this.read(count, BlobReader.ARRAY_BUFFER, cb);
  };

  /**
   * Read defined amount of bytes as binary string
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object instance
   */
  BlobReader.prototype.readBinaryString = function (count, cb) {
    return this.read(count, BlobReader.BINARY_STRING, cb);
  };

  /**
   * Read defined amount of bytes as data url
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object instance
   */
  BlobReader.prototype.readDataURL = function (count, cb) {
    return this.read(count, BlobReader.DATA_URL, cb);
  };

  /**
   * Read defined amount of bytes as text
   *
   * @private
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @param {Function} type Constructor function which indicates
   *  the type which should be used as wrapper of the returned data
   * @return {BlobReader} Return the target object instance
   */
  BlobReader.prototype._readWrapped = function (count, cb, type) {
    if (typeof count === 'function') {
      cb = count;
      count = undefined;
    }
    var callback = function (data) {
      data = new type(data);
      cb(data);
    };
    return this.readArrayBuffer(count, callback);
  };

  /**
   * Read defined amount of bytes as uint8 array
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object instance
   */
  BlobReader.prototype.readUint8 = function (count, cb) {
    return this._readWrapped(count, cb, Uint8Array);
  };

  /**
   * Read defined amount of bytes as uint16 array
   *
   * @public
   * @param {Number} count Number of elements to be read (count * 2 bytes)
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object instance
   */
  BlobReader.prototype.readUint16 = function (count, cb) {
    return this._readWrapped(count * 2, cb, Uint16Array);
  };

  /**
   * Read defined amount of bytes as uint32 array
   *
   * @public
   * @param {Number} count Number of elements to be read (count * 4 bytes)
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object instance
   */
  BlobReader.prototype.readUint32 = function (count, cb) {
    return this._readWrapped(count * 4, cb, Uint32Array);
  };

  w.BlobReader = BlobReader;

}(window));
<commit_msg>Add readBlob method<commit_after>/*jshint bitwise: false*/

(function (w) {
  'use strict';

  function getEndianness() {
    var a = new ArrayBuffer(4);
    var b = new Uint8Array(a);
    var c = new Uint32Array(a);
    b[0] = 0xa1;
    b[1] = 0xb2;
    b[2] = 0xc3;
    b[3] = 0xd4;
    if (c[0] === 0xd4c3b2a1) {
      return BlobReader.ENDIANNESS.LITTLE_ENDIAN;
    }
    if (c[0] === 0xa1b2c3d4) {
      return BlobReader.ENDIANNESS.BIG_ENDIAN;
    } else {
      throw new Error('Unrecognized endianness');
    }
  }
  /**
   * Constructor function for the blob reader.
   *
   * @public
   * @constructor
   * @param {Blob} blob The blob object, which should be read
   * @param {BlobReader.ENDIANNESS} dataEndianness Endianness of the
   *  expected data
   * @param {BlobReader.ENDIANNESS} endianness System endianness
   */
  function BlobReader(blob, dataEndianness, endianness) {
    if (!(this instanceof BlobReader)) {
      return new BlobReader(blob, dataEndianness, endianness);
    }
    this._blob = blob;
    this._position = 0;
    this._queue = [];
    this._currentEndianness = endianness || getEndianness();
    this._dataEndianness = dataEndianness || this._currentEndianness;
    this._pendingTask = false;
    this._currentResult = null;
  }

  BlobReader.ARRAY_BUFFER = 'ArrayBuffer';
  BlobReader.BINARY_STRING = 'BinaryString';
  BlobReader.TEXT = 'Text';
  BlobReader.DATA_URL = 'DataURL';

  BlobReader.ENDIANNESS = {
    BIG_ENDIAN: 'BIG_ENDIAN',
    LITTLE_ENDIAN: 'LITTLE_ENDIAN'
  };

  BlobReader.prototype.setDataEndianness = function (endianness) {
    this._dataEndianness = endianness;
  };

  /* jshint validthis: true */
  function invokeNext() {
    var current = this._queue.shift();
    if (!current) {
      return;
    }
    if (this._position + current.count > this._blob.size) {
      throw new Error('Limit reached. Trying to read ' +
          (this._position + current.count) + ' bytes out of ' +
          this._blob.size + '.');
    }
    var reader = new FileReader();
    this._pendingTask = true;
    reader.onload = function (e) {
      var data = e.target.result;
      this._pendingTask = false;
      current.cb(data);
      invokeNext.call(this);
    }.bind(this);
    reader.onerror = function () {
      throw new Error('Error while reading the blob');
    };
    if (!current.type) {
      current.type = BlobReader.BINARY_STRING;
    }
    reader['readAs' + current.type](
        this._blob.slice(this._position, this._position + current.count)
    );
    this._position += current.count;
  }

  /**
   * Read definite amount of bytes by the blob
   *
   * @public
   * @param {Number} count The count of bytes, which should be read
   * @param {Function} cb The callback, which should be
   *  invoked once the bytes are read
   * @return {BlobReader} Returns `this`
   */
  BlobReader.prototype.read = function (count, type, cb) {
    if (typeof count === 'string') {
      cb = type;
      count = undefined;
      type = count;
    }
    if (count === undefined) {
      count = this._blob.size - this._position;
    }
    if (typeof count === 'function') {
      cb = count;
      type = undefined;
      count = this._blob.size - this._position;
    }
    if (typeof type === 'function') {
      cb = type;
      type = undefined;
    }
    this._queue.push({
      count: count,
      cb: cb,
      type: type
    });
    if (!this._pendingTask) {
      invokeNext.call(this);
    }
    return this;
  };

  /**
   * Read defined amount of bytes as text
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object
   */
  BlobReader.prototype.readText = function (count, cb) {
    return this.read(count, BlobReader.TEXT, cb);
  };

  /**
   * Read defined amount of bytes as array buffer
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object
   */
  BlobReader.prototype.readArrayBuffer = function (count, cb) {
    return this.read(count, BlobReader.ARRAY_BUFFER, cb);
  };

  /**
   * Read defined amount of bytes as binary string
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object
   */
  BlobReader.prototype.readBinaryString = function (count, cb) {
    return this.read(count, BlobReader.BINARY_STRING, cb);
  };

  /**
   * Read defined amount of bytes as data url
   *
   * @public
   * @param {Number} count Number of bytes to be read
   * @param {Function} cb Calback to be invoked
   * @return {BlobReader} Return the target object
   */
  BlobReader.prototype.readDataURL = function (count, cb) {
    return this.read(count, BlobReader.DATA_URL, cb);
  };

  function swap(arr, cb) {
    for (var i = 0; i < arr.length; i += 1) {
      arr[i] = cb(arr[i]);
    }
    return arr;
  }

  var byteFormatter = {
    swap8: function (arr) {
      return swap(arr, function (val) {
        return val;
      });
    },
    swap16: function (arr) {
      return swap(arr, function (val) {
        return ((val & 0xFF) << 8) |
               ((val >> 8) & 0xFF);
      });
    },
    swap32: function (arr) {
      return swap(arr, function (val) {
        return ((val & 0xFF) << 24) |
               ((val & 0xFF00) << 8) |
               ((val >> 8) & 0xFF00) |
               ((val >> 24) & 0xFF);
      });
    }
  };

  /* jshint validthis: true */
  function uintReader(name, count, octets, endianness) {
    if (!this._currentResult) {
      this._currentResult = {};
    }
    count = (count || 1) * octets;
    var callback = function (data) {
      var bitsNum = 8 * octets;
      var type = window['Uint' + bitsNum + 'Array'];
      data = new type(data);
      if (this._currentEndianness !== endianness) {
        data = byteFormatter['swap' + bitsNum](data);
      }
      this._currentResult[name] = data;
    }.bind(this);
    return this.readArrayBuffer(count, callback);
  }

  /**
   * Read defined amount of bytes as uint8 array
   *
   * @public
   * @param {String} name Property name
   * @param {Number} count Number of 8 bit numbers to be read
   * @param {BlobReader.ENDIANNESS} endianness Endianness of the
   *  bytes which should be read. If differ from the system's endianness
   *  the values will be converted
   * @return {BlobReader} Return the target object
   */
  BlobReader.prototype.readUint8 = function (name, count, endianness) {
    return uintReader.call(this, name, count, 1,
           endianness || this._dataEndianness);
  };

  /**
   * Read defined amount of bytes as uint16 array
   *
   * @public
   * @param {String} name Property name
   * @param {Number} count Number of 16 bit numbers to be read
   * @param {BlobReader.ENDIANNESS} endianness Endianness of the
   *  bytes which should be read. If differ from the system's endianness
   *  the values will be converted
   * @return {BlobReader} Return the target object
   */
  BlobReader.prototype.readUint16 = function (name, count, endianness) {
    return uintReader.call(this, name, count, 2,
           endianness || this._dataEndianness);
  };

  /**
   * Read defined amount of bytes as uint32 array
   *
   * @public
   * @param {String} name Property name
   * @param {Number} count Number of 32 bit numbers to be read
   * @param {BlobReader.ENDIANNESS} endianness Endianness of the
   *  bytes which should be read. If differ from the system's endianness
   *  the values will be converted
   * @return {BlobReader} Return the target object
   */
  BlobReader.prototype.readUint32 = function (name, count, endianness) {
    return uintReader.call(this, name, count, 4,
           endianness || this._dataEndianness);
  };

  /**
   * Read a blob and push it to the result object
   *
   * @public
   * @param {String} name Property name
   * @param {Number} count Number of bytes to be sliced from the Blob
   * @return {BlobReader} Return the target object
   */
  BlobReader.prototype.readBlob = function (name, count) {
    var result = this._blob.slice(this._position, this._position + count);
    this._queue.push({
      count: count,
      cb: function () {
        this._currentResult[name] = result;
      }.bind(this)
    });
    return this;
  };

  /**
   * Gets the result object
   *
   * @public
   * @return {Object} The object resulted from the calls of readUint
   */
  BlobReader.prototype.commit = function (cb) {
    if (!this._currentResult) {
      throw new Error('Cannot commit without any reads');
    }
    var res = this._currentResult;
    var task = {
      count: 0,
      type: BlobReader.ARRAY_BUFFER,
      cb: function () {
        cb(res);
        this._currentResult = null;
      }.bind(this)
    };
    this._queue.push(task);
    return this;
  };

  w.BlobReader = BlobReader;

}(window));
<|endoftext|>


<commit_before>load('lib/cuke4jas.js');
var text,addSteps;
if(arguments[0]=='-s'){
  addSteps=true;
  text= readFile(arguments[1]);   //load the src file
}else{
  text= readFile(arguments[0]);   //load the src file
}

var jastext = cuke4jas.toJasmine(text,addSteps);
print(jastext);<commit_msg>fixed reference to lib<commit_after>load('../lib/cuke4jas.js');
var text,addSteps;
if(arguments[0]=='-s'){
  addSteps=true;
  text= readFile(arguments[1]);   //load the src file
}else{
  text= readFile(arguments[0]);   //load the src file
}

var jastext = cuke4jas.toJasmine(text,addSteps);
print(jastext);<|endoftext|>