<commit_before>"use strict";

var app = angular.module('js120', []);

app.controller('InstrumentController', ['$scope', 'InstrumentService', function($scope, InstrumentService) {
  this.updateInstrument = function() {
    InstrumentService.updateInstrument();
  };
}]);

app.controller('PatternController', ['$scope', 'PatternService', function($scope, PatternService) {
  this.updateName = function() {
    PatternService.updateName(this.pattern.id);
  };

  this.addRow = function() {
    PatternService.addRow(this.pattern.id);
  };

  this.removeRow = function(rowIndex) {
    PatternService.removeRow(this.pattern.id, rowIndex);
  };

  this.toggleRowMute = function(rowIndex) {
    PatternService.toggleRowMute(this.pattern.id, rowIndex);
  };

  this.updateNotes = function(rowIndex, noteIndex) {
    PatternService.updateNotes(this.pattern.id, rowIndex, noteIndex);
  };
}]);

app.controller('SequencerController', ['$rootScope', '$scope', '$interval', 'InstrumentService', 'PatternService', 'SequencerService', 'TransportService', function($rootScope, $scope, $interval, InstrumentService, PatternService, SequencerService, TransportService) {
  var LEFT_ARROW = "←";
  var RIGHT_ARROW = "→";
  var timeoutId;

  $scope.expanded = true;
  $scope.expansionToggleLabel = LEFT_ARROW;
  $scope.tracks = SequencerService.tracks();
  $scope.currentStep = null;

  var buildPatternOptions = function() {
    var patternOptions = $scope.tracks.map(function(track) {
      var trackPatterns = PatternService.patternsByTrackID(track.id);
      var options = trackPatterns.map(function(pattern) {
        return { id: pattern.id, name: pattern.name, }
      });

      options.unshift({ id: -1, name: ''});

      return options;
    });

    return patternOptions;
  };

  $scope.$on('TransportService.start', function(event) {
    timeoutId = $interval(function() {
      $scope.syncCurrentStep();
    }, 15);
  });

  $scope.$on('TransportService.stop', function(event) {
    $interval.cancel(timeoutId);
    $scope.currentStep = null;
  });

  $scope.patternOptions = buildPatternOptions();
  $scope.$on('PatternService.add', function(event) {
    $scope.patternOptions = buildPatternOptions();
  });
  $scope.$on('PatternService.remove', function(event) {
    $scope.patternOptions = buildPatternOptions();
  });
  $scope.$on('PatternService.update', function(event) {
    $scope.patternOptions = buildPatternOptions();
  });

  $scope.changeSequencer = function() {
    SequencerService.changeSequencer();
  };

  $scope.toggleExpansion = function() {
    $scope.expanded = !$scope.expanded;

    if ($scope.expanded) {
      $scope.expansionToggleLabel = LEFT_ARROW;
    }
    else {
      $scope.expansionToggleLabel = RIGHT_ARROW;
    }
  };

  $scope.addTrack = function() {
    var newTrack = SequencerService.addTrack();
  };

  $scope.removeTrack = function(trackID) {
    SequencerService.removeTrack(trackID);
    $scope.patternOptions = buildPatternOptions();
  };

  $scope.toggleTrackMute = function(trackID) {
    SequencerService.toggleTrackMute(trackID);
  };

  $scope.changeTrackName = function(trackID) {
    $rootScope.$broadcast('SequencerController.trackNameChanged', { trackID: trackID, });
  }

  $scope.syncCurrentStep = function() {
    if (TransportService.currentStep() !== null) {
      $scope.currentStep = Math.floor((TransportService.currentStep() / 16) % 8) + 1;
    }
    else
    {
      $scope.currentStep = null;
    }
  };
}]);

app.controller('TrackEditorController',
               ['$scope', 'SequencerService', 'InstrumentService', 'PatternService',
               function($scope, SequencerService, InstrumentService, PatternService) {
  $scope.trackID = 1;
  $scope.selectedTab = "instrument";

  $scope.instrument = InstrumentService.instrumentByID(SequencerService.trackByID($scope.trackID).instrumentID);
  $scope.pattern = PatternService.patternsByTrackID($scope.trackID)[0];

  var buildTrackOptions = function() {
    return SequencerService.tracks().map(function(track) {
      return { id: track.id, name: track.name };
    });
  };

  $scope.trackOptions = buildTrackOptions();

  var buildPatternOptions = function() {
    return PatternService.patternsByTrackID($scope.trackID).map(function(pattern) {
      return { id: pattern.id, name: pattern.name };
    });
  };

  $scope.patternOptions = buildPatternOptions();

  $scope.$on('SequencerService.addTrack', function(event, args) {
    $scope.trackOptions = buildTrackOptions();
  });

  $scope.$on('SequencerService.removeTrack', function(event, args) {
    $scope.trackOptions = buildTrackOptions();

    if (args.trackID === $scope.trackID) {
      $scope.trackID = $scope.trackOptions[0].id;
    }
    $scope.changeSelectedTrack();
  });

  $scope.$on('SequencerController.trackNameChanged', function(event, args) {
    $scope.trackOptions = buildTrackOptions();
  });

   $scope.$on('PatternService.update', function(event, args) {
     $scope.patternOptions = buildPatternOptions();
     $scope.pattern = PatternService.patternByID($scope.pattern.id);
  });

  $scope.changeSelectedTab = function(newSelectedTab) {
    $scope.selectedTab = newSelectedTab;
  };

  $scope.changeSelectedTrack = function() {
    $scope.instrument = InstrumentService.instrumentByID(SequencerService.trackByID($scope.trackID).instrumentID);
    $scope.patternOptions = buildPatternOptions();
    $scope.pattern = PatternService.patternByID($scope.patternOptions[0].id);
  };

  $scope.changeSelectedPattern = function(patternID) {
    $scope.pattern = PatternService.patternByID(patternID);
  };

  $scope.addPattern = function() {
    var newPatternName = $scope.instrument.name + ' ' + ($scope.patternOptions.length + 1);
    var newPattern = PatternService.addPattern($scope.trackID, newPatternName);

    $scope.patternOptions = buildPatternOptions();
    $scope.pattern = newPattern;
  };

  $scope.removePattern = function(patternID) {
    var i;
    var newSelectedPatternID;

    if (patternID === $scope.pattern.id) {
      i = 0;
      while (i < this.patternOptions.length && this.patternOptions[i].id !== patternID) {
        i++;
      }

      if (i === (this.patternOptions.length - 1)) {
        newSelectedPatternID = this.patternOptions[i - 1].id;
      }
      else {
        newSelectedPatternID = this.patternOptions[i + 1].id;
      }
    }
    else {
      newSelectedPatternID = $scope.pattern.id;
    }

    SequencerService.unsetPattern(patternID);
    PatternService.removePattern(patternID);

    $scope.patternOptions = buildPatternOptions();
    if (newSelectedPatternID !== patternID) {
      $scope.changeSelectedPattern(newSelectedPatternID);
    }
  };
}]);

app.controller('TransportController', ['$scope', 'SerializationService', 'TransportService', function($scope, SerializationService, TransportService) {
  $scope.playing = false;
  $scope.amplitude = 0.8;
  $scope.tempo = 100;
  $scope.loop = true;

  TransportService.setNotes(SerializationService.serialize());
  $scope.$on('InstrumentService.update', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });
  $scope.$on('PatternService.remove', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });
  $scope.$on('PatternService.update', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });
  $scope.$on('SequencerService.removeTrack', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });
  $scope.$on('SequencerService.update', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });

  $scope.updateTempo = function() {
    TransportService.setTempo(parseInt($scope.tempo, 10));
  };

  $scope.updateAmplitude = function() {
    TransportService.setAmplitude(parseFloat($scope.amplitude));
  };

  $scope.toggle = function() {
    TransportService.toggle();
    $scope.playing = !$scope.playing;
  };

  $scope.updateLoop = function() {
    TransportService.loop = $scope.loop;
  };

  $scope.isEnabled = function() {
    return TransportService.isEnabled();
  };
}]);

app.controller('ExportController', ['$scope', 'TransportService', function($scope, TransportService) {
  var downloadEnabled = typeof document.getElementById("hidden-download-link").download !== "undefined";

  $scope.downloadFileName = "js-120";
  $scope.downloadBoxVisible = false;

  $scope.toggleDownloadBox = function() {
    if (!downloadEnabled) {
      alert("Downloading to Wave file is not supported in your browser.");
      return;
    }

    $scope.downloadBoxVisible = !$scope.downloadBoxVisible;
  };

  $scope.export = function() {
    var exportCompleteCallback = function(blob) {
      var url  = window.URL.createObjectURL(blob);

      var hiddenDownloadLink = document.getElementById("hidden-download-link");
      hiddenDownloadLink.download = $scope.downloadFileName + ".wav";
      hiddenDownloadLink.href = url;
      hiddenDownloadLink.click();

      window.URL.revokeObjectURL(blob);
    };

    TransportService.export(exportCompleteCallback);
  };
}]);
<commit_msg>Fixing new pattern name to use track name, not instrument name<commit_after>"use strict";

var app = angular.module('js120', []);

app.controller('InstrumentController', ['$scope', 'InstrumentService', function($scope, InstrumentService) {
  this.updateInstrument = function() {
    InstrumentService.updateInstrument();
  };
}]);

app.controller('PatternController', ['$scope', 'PatternService', function($scope, PatternService) {
  this.updateName = function() {
    PatternService.updateName(this.pattern.id);
  };

  this.addRow = function() {
    PatternService.addRow(this.pattern.id);
  };

  this.removeRow = function(rowIndex) {
    PatternService.removeRow(this.pattern.id, rowIndex);
  };

  this.toggleRowMute = function(rowIndex) {
    PatternService.toggleRowMute(this.pattern.id, rowIndex);
  };

  this.updateNotes = function(rowIndex, noteIndex) {
    PatternService.updateNotes(this.pattern.id, rowIndex, noteIndex);
  };
}]);

app.controller('SequencerController', ['$rootScope', '$scope', '$interval', 'InstrumentService', 'PatternService', 'SequencerService', 'TransportService', function($rootScope, $scope, $interval, InstrumentService, PatternService, SequencerService, TransportService) {
  var LEFT_ARROW = "←";
  var RIGHT_ARROW = "→";
  var timeoutId;

  $scope.expanded = true;
  $scope.expansionToggleLabel = LEFT_ARROW;
  $scope.tracks = SequencerService.tracks();
  $scope.currentStep = null;

  var buildPatternOptions = function() {
    var patternOptions = $scope.tracks.map(function(track) {
      var trackPatterns = PatternService.patternsByTrackID(track.id);
      var options = trackPatterns.map(function(pattern) {
        return { id: pattern.id, name: pattern.name, }
      });

      options.unshift({ id: -1, name: ''});

      return options;
    });

    return patternOptions;
  };

  $scope.$on('TransportService.start', function(event) {
    timeoutId = $interval(function() {
      $scope.syncCurrentStep();
    }, 15);
  });

  $scope.$on('TransportService.stop', function(event) {
    $interval.cancel(timeoutId);
    $scope.currentStep = null;
  });

  $scope.patternOptions = buildPatternOptions();
  $scope.$on('PatternService.add', function(event) {
    $scope.patternOptions = buildPatternOptions();
  });
  $scope.$on('PatternService.remove', function(event) {
    $scope.patternOptions = buildPatternOptions();
  });
  $scope.$on('PatternService.update', function(event) {
    $scope.patternOptions = buildPatternOptions();
  });

  $scope.changeSequencer = function() {
    SequencerService.changeSequencer();
  };

  $scope.toggleExpansion = function() {
    $scope.expanded = !$scope.expanded;

    if ($scope.expanded) {
      $scope.expansionToggleLabel = LEFT_ARROW;
    }
    else {
      $scope.expansionToggleLabel = RIGHT_ARROW;
    }
  };

  $scope.addTrack = function() {
    var newTrack = SequencerService.addTrack();
  };

  $scope.removeTrack = function(trackID) {
    SequencerService.removeTrack(trackID);
    $scope.patternOptions = buildPatternOptions();
  };

  $scope.toggleTrackMute = function(trackID) {
    SequencerService.toggleTrackMute(trackID);
  };

  $scope.changeTrackName = function(trackID) {
    $rootScope.$broadcast('SequencerController.trackNameChanged', { trackID: trackID, });
  }

  $scope.syncCurrentStep = function() {
    if (TransportService.currentStep() !== null) {
      $scope.currentStep = Math.floor((TransportService.currentStep() / 16) % 8) + 1;
    }
    else
    {
      $scope.currentStep = null;
    }
  };
}]);

app.controller('TrackEditorController',
               ['$scope', 'SequencerService', 'InstrumentService', 'PatternService',
               function($scope, SequencerService, InstrumentService, PatternService) {
  $scope.trackID = 1;
  $scope.selectedTab = "instrument";

  $scope.instrument = InstrumentService.instrumentByID(SequencerService.trackByID($scope.trackID).instrumentID);
  $scope.pattern = PatternService.patternsByTrackID($scope.trackID)[0];

  var buildTrackOptions = function() {
    return SequencerService.tracks().map(function(track) {
      return { id: track.id, name: track.name };
    });
  };

  $scope.trackOptions = buildTrackOptions();

  var buildPatternOptions = function() {
    return PatternService.patternsByTrackID($scope.trackID).map(function(pattern) {
      return { id: pattern.id, name: pattern.name };
    });
  };

  $scope.patternOptions = buildPatternOptions();

  $scope.$on('SequencerService.addTrack', function(event, args) {
    $scope.trackOptions = buildTrackOptions();
  });

  $scope.$on('SequencerService.removeTrack', function(event, args) {
    $scope.trackOptions = buildTrackOptions();

    if (args.trackID === $scope.trackID) {
      $scope.trackID = $scope.trackOptions[0].id;
    }
    $scope.changeSelectedTrack();
  });

  $scope.$on('SequencerController.trackNameChanged', function(event, args) {
    $scope.trackOptions = buildTrackOptions();
  });

   $scope.$on('PatternService.update', function(event, args) {
     $scope.patternOptions = buildPatternOptions();
     $scope.pattern = PatternService.patternByID($scope.pattern.id);
  });

  $scope.changeSelectedTab = function(newSelectedTab) {
    $scope.selectedTab = newSelectedTab;
  };

  $scope.changeSelectedTrack = function() {
    $scope.instrument = InstrumentService.instrumentByID(SequencerService.trackByID($scope.trackID).instrumentID);
    $scope.patternOptions = buildPatternOptions();
    $scope.pattern = PatternService.patternByID($scope.patternOptions[0].id);
  };

  $scope.changeSelectedPattern = function(patternID) {
    $scope.pattern = PatternService.patternByID(patternID);
  };

  $scope.addPattern = function() {
    var newPatternName = SequencerService.trackByID($scope.trackID).name + ' ' + ($scope.patternOptions.length + 1);
    var newPattern = PatternService.addPattern($scope.trackID, newPatternName);

    $scope.patternOptions = buildPatternOptions();
    $scope.pattern = newPattern;
  };

  $scope.removePattern = function(patternID) {
    var i;
    var newSelectedPatternID;

    if (patternID === $scope.pattern.id) {
      i = 0;
      while (i < this.patternOptions.length && this.patternOptions[i].id !== patternID) {
        i++;
      }

      if (i === (this.patternOptions.length - 1)) {
        newSelectedPatternID = this.patternOptions[i - 1].id;
      }
      else {
        newSelectedPatternID = this.patternOptions[i + 1].id;
      }
    }
    else {
      newSelectedPatternID = $scope.pattern.id;
    }

    SequencerService.unsetPattern(patternID);
    PatternService.removePattern(patternID);

    $scope.patternOptions = buildPatternOptions();
    if (newSelectedPatternID !== patternID) {
      $scope.changeSelectedPattern(newSelectedPatternID);
    }
  };
}]);

app.controller('TransportController', ['$scope', 'SerializationService', 'TransportService', function($scope, SerializationService, TransportService) {
  $scope.playing = false;
  $scope.amplitude = 0.8;
  $scope.tempo = 100;
  $scope.loop = true;

  TransportService.setNotes(SerializationService.serialize());
  $scope.$on('InstrumentService.update', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });
  $scope.$on('PatternService.remove', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });
  $scope.$on('PatternService.update', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });
  $scope.$on('SequencerService.removeTrack', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });
  $scope.$on('SequencerService.update', function(event) {
    TransportService.setNotes(SerializationService.serialize());
  });

  $scope.updateTempo = function() {
    TransportService.setTempo(parseInt($scope.tempo, 10));
  };

  $scope.updateAmplitude = function() {
    TransportService.setAmplitude(parseFloat($scope.amplitude));
  };

  $scope.toggle = function() {
    TransportService.toggle();
    $scope.playing = !$scope.playing;
  };

  $scope.updateLoop = function() {
    TransportService.loop = $scope.loop;
  };

  $scope.isEnabled = function() {
    return TransportService.isEnabled();
  };
}]);

app.controller('ExportController', ['$scope', 'TransportService', function($scope, TransportService) {
  var downloadEnabled = typeof document.getElementById("hidden-download-link").download !== "undefined";

  $scope.downloadFileName = "js-120";
  $scope.downloadBoxVisible = false;

  $scope.toggleDownloadBox = function() {
    if (!downloadEnabled) {
      alert("Downloading to Wave file is not supported in your browser.");
      return;
    }

    $scope.downloadBoxVisible = !$scope.downloadBoxVisible;
  };

  $scope.export = function() {
    var exportCompleteCallback = function(blob) {
      var url  = window.URL.createObjectURL(blob);

      var hiddenDownloadLink = document.getElementById("hidden-download-link");
      hiddenDownloadLink.download = $scope.downloadFileName + ".wav";
      hiddenDownloadLink.href = url;
      hiddenDownloadLink.click();

      window.URL.revokeObjectURL(blob);
    };

    TransportService.export(exportCompleteCallback);
  };
}]);
<|endoftext|>


<commit_before>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2016, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

import _ from 'lodash';

import * as ActionTypes from '../constants/actionTypes';

const trackMetricMap = {
  LOGIN_SUCCESS: 'Logged In',
  SETUP_DATA_STORAGE_SUCCESS: 'Created Profile',
  UPDATE_PATIENT_SUCCESS: 'Updated Profile',
  UPDATE_USER_SUCCESS: 'Updated Account',
  LOGOUT_REQUEST: 'Logged Out',
  VERIFY_CUSTODIAL_SUCCESS: 'VCA Home Verification - Verified',
};

const interpretMetricMap = {
  SIGNUP_SUCCESS: function(action) {
    let roles = _.get(action, 'payload.user.roles');
    return { eventName: `Signed Up`, properties: roles ? { roles: roles } : null };
  },
  TURN_ON_CBG_RANGE: function(action) {
    return { eventName: `Turn on ${action.payload.range}${!_.isNaN(parseInt(action.payload.range, 10)) ? encodeURIComponent('%') : ''}` };
  },
  TURN_OFF_CBG_RANGE: function(action) {
    return { eventName: `Turn off ${action.payload.range}${!_.isNaN(parseInt(action.payload.range, 10)) ? encodeURIComponent('%') : ''}` };
  }
}

export default (api) => {
  return ({ getState }) => (next) => (action) => {
    if (trackMetricMap[action.type]) {
      api.metrics.track(trackMetricMap[action.type]);
    }
    if (interpretMetricMap[action.type]) {
      let { eventName, properties } = interpretMetricMap[action.type](action)
      api.metrics.track(eventName, properties);
    }
    return next(action);
  };
}
<commit_msg>Fix eslint error<commit_after>/*
 * == BSD2 LICENSE ==
 * Copyright (c) 2016, Tidepool Project
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the associated License, which is identical to the BSD 2-Clause
 * License as published by the Open Source Initiative at opensource.org.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the License for more details.
 *
 * You should have received a copy of the License along with this program; if
 * not, you can obtain one from Tidepool Project at tidepool.org.
 * == BSD2 LICENSE ==
 */

import _ from 'lodash';

import * as ActionTypes from '../constants/actionTypes';

const trackMetricMap = {
  LOGIN_SUCCESS: 'Logged In',
  SETUP_DATA_STORAGE_SUCCESS: 'Created Profile',
  UPDATE_PATIENT_SUCCESS: 'Updated Profile',
  UPDATE_USER_SUCCESS: 'Updated Account',
  LOGOUT_REQUEST: 'Logged Out',
  VERIFY_CUSTODIAL_SUCCESS: 'VCA Home Verification - Verified',
};

const interpretMetricMap = {
  SIGNUP_SUCCESS: function(action) {
    let roles = _.get(action, 'payload.user.roles');
    return { eventName: 'Signed Up', properties: roles ? { roles: roles } : null };
  },
  TURN_ON_CBG_RANGE: function(action) {
    return { eventName: `Turn on ${action.payload.range}${!_.isNaN(parseInt(action.payload.range, 10)) ? encodeURIComponent('%') : ''}` };
  },
  TURN_OFF_CBG_RANGE: function(action) {
    return { eventName: `Turn off ${action.payload.range}${!_.isNaN(parseInt(action.payload.range, 10)) ? encodeURIComponent('%') : ''}` };
  }
}

export default (api) => {
  return ({ getState }) => (next) => (action) => {
    if (trackMetricMap[action.type]) {
      api.metrics.track(trackMetricMap[action.type]);
    }
    if (interpretMetricMap[action.type]) {
      let { eventName, properties } = interpretMetricMap[action.type](action)
      api.metrics.track(eventName, properties);
    }
    return next(action);
  };
}
<|endoftext|>


<commit_before>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var ParagraphStyle = this.ParagraphStyle = Base.extend({
	initialize: function(style) {
		Base.initialize(this, style, {
			justification: 'left'
		});
	},

	statics: {
		create: function(item) {
			var style = new CharacterStyle(CharacterStyle.dont);
			style._item = item;
			return style;
		}
	}
});
<commit_msg>Fix ParagraphStyle.create(item).<commit_after>/*
 * Paper.js
 *
 * This file is part of Paper.js, a JavaScript Vector Graphics Library,
 * based on Scriptographer.org and designed to be largely API compatible.
 * http://paperjs.org/
 * http://scriptographer.org/
 *
 * Distributed under the MIT license. See LICENSE file for details.
 *
 * Copyright (c) 2011, Juerg Lehni & Jonathan Puckey
 * http://lehni.org/ & http://jonathanpuckey.com/
 *
 * All rights reserved.
 */

var ParagraphStyle = this.ParagraphStyle = Base.extend({
	initialize: function(style) {
		Base.initialize(this, style, {
			justification: 'left'
		});
	},

	statics: {
		create: function(item) {
			var style = new ParagraphStyle(ParagraphStyle.dont);
			style._item = item;
			return style;
		}
	}
});
<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/component/LFO", "Tone/effect/FeedbackEffect", "Tone/component/Filter", "Tone/effect/StereoFeedbackEffect"],
function(Tone){

	"use strict";

	/**
	 *  @class A Phaser effect with feedback. inspiration from https://github.com/Dinahmoe/tuna/
	 *
	 *	@extends {Tone.StereoFeedbackEffect}
	 *	@constructor
	 *	@param {number|object=} rate the speed of the phasing
	 *	@param {number=} depth the depth of the effect
	 *	@param {number} baseFrequency the base frequency of the filters
	 */
	Tone.Phaser = function(){

		//set the defaults
		var options = this.optionsObject(arguments, ["rate", "depth", "baseFrequency"], Tone.Phaser.defaults);
		Tone.StereoFeedbackEffect.call(this, options);

		/**
		 *  the lfo which controls the frequency on the left side
		 *  @type {Tone.LFO}
		 *  @private
		 */
		this._lfoL = new Tone.LFO(options.rate, 0, 1);

		/**
		 *  the lfo which controls the frequency on the right side
		 *  @type {Tone.LFO}
		 *  @private
		 */
		this._lfoR = new Tone.LFO(options.rate, 0, 1);
		this._lfoR.setPhase(180);

		/**
		 *  the base modulation frequency
		 *  @type {number}
		 *  @private
		 */
		this._baseFrequency = options.baseFrequency;

		/**
		 *  the depth of the phasing
		 *  @type {number}
		 *  @private
		 */
		this._depth = options.depth;

		/**
		 *  the array of filters for the left side
		 *  @type {Array.<Tone.Filter>}
		 *  @private
		 */
		this._filtersL = this._makeFilters(options.stages, this._lfoL, options.Q);

		/**
		 *  the array of filters for the left side
		 *  @type {Array.<Tone.Filter>}
		 *  @private
		 */
		this._filtersR = this._makeFilters(options.stages, this._lfoR, options.Q);

		//connect them up
		this.effectSendL.connect(this._filtersL[0]);
		this.effectSendR.connect(this._filtersR[0]);
		this._filtersL[options.stages - 1].connect(this.effectReturnL);
		this._filtersR[options.stages - 1].connect(this.effectReturnR);
		this.effectSendL.connect(this.effectReturnL);
		this.effectSendR.connect(this.effectReturnR);
		//control the frequency with one LFO
		this._lfoL.frequency.connect(this._lfoR.frequency);
		//set the options
		this.setBaseFrequency(options.baseFrequency);
		this.setDepth(options.depth);
		this.setRate(options.rate);
		//start the lfo
		this._lfoL.start();
		this._lfoR.start();
	};

	Tone.extend(Tone.Phaser, Tone.StereoFeedbackEffect);

	/**
	 *  defaults
	 *  @static
	 *  @type {object}
	 */
	Tone.Phaser.defaults = {
		"rate" : 0.5,
		"depth" : 1,
		"stages" : 4,
		"Q" : 6,
		"baseFrequency" : 400,
		"feedback" : 0.6
	};

	/**
	 *  @param {number} stages
	 *  @returns {Array} the number of filters all connected together
	 *  @private
	 */
	Tone.Phaser.prototype._makeFilters = function(stages, connectToFreq, Q){
		var filters = new Array(stages);
		//make all the filters
		for (var i = 0; i < stages; i++){
			var filter = this.context.createBiquadFilter();
			filter.type = "allpass";
			filter.Q.value = Q;
			connectToFreq.connect(filter.frequency);
			filters[i] = filter;
		}
		this.connectSeries.apply(this, filters);
		return filters;
	};

	/**
	 *  set the depth of the chorus
	 *  @param {number} depth
	 */
	Tone.Phaser.prototype.setDepth = function(depth){
		this._depth = depth;
		var max = this._baseFrequency + this._baseFrequency * depth;
		this._lfoL.setMax(max);
		this._lfoR.setMax(max);
	};

	/**
	 *  set the base frequency of the filters
	 *  @param {number} freq
	 */
	Tone.Phaser.prototype.setBaseFrequency = function(freq){
		this._baseFrequency = freq;
		this._lfoL.setMin(freq);
		this._lfoR.setMin(freq);
		this.setDepth(this._depth);
	};

	/**
	 *  set the phaser rate
	 *  @param {number} rate in hertz
	 */
	Tone.Phaser.prototype.setRate = function(rate){
		this._lfoL.setFrequency(rate);
	};

	/**
	 *  bulk setter
	 *  @param {object} params
	 */
	Tone.Phaser.prototype.set = function(params){
		if (!this.isUndef(params.rate)) this.setRate(params.rate);
		if (!this.isUndef(params.baseFrequency)) this.setBaseFrequency(params.baseFrequency);
		if (!this.isUndef(params.depth)) this.setDepth(params.depth);
		Tone.StereoFeedbackEffect.prototype.set.call(this, params);
	};

	/**
	 *  clean up
	 */
	Tone.Phaser.prototype.dispose = function(){
		Tone.StereoFeedbackEffect.prototype.dispose.call(this);
		this._lfoL.dispose();
		this._lfoL = null;
		this._lfoR.dispose();
		this._lfoR = null;
		for (var i = 0; i < this._filtersL.length; i++){
			this._filtersL[i].disconnect();
			this._filtersL[i] = null;
		}
		this._filtersL = null;
		for (var j = 0; j < this._filtersR.length; j++){
			this._filtersR[j].disconnect();
			this._filtersR[j] = null;
		}
		this._filtersR = null;
	};

	return Tone.Phaser;
});<commit_msg>removed feedback from phaser<commit_after>define(["Tone/core/Tone", "Tone/component/LFO", "Tone/component/Filter", "Tone/effect/StereoEffect"],
function(Tone){

	"use strict";

	/**
	 *  @class A Phaser effect. inspiration from https://github.com/Dinahmoe/tuna/
	 *
	 *	@extends {Tone.StereoEffect}
	 *	@constructor
	 *	@param {number|object=} rate the speed of the phasing
	 *	@param {number=} depth the depth of the effect
	 *	@param {number} baseFrequency the base frequency of the filters
	 */
	Tone.Phaser = function(){

		//set the defaults
		var options = this.optionsObject(arguments, ["rate", "depth", "baseFrequency"], Tone.Phaser.defaults);
		Tone.StereoEffect.call(this, options);

		/**
		 *  the lfo which controls the frequency on the left side
		 *  @type {Tone.LFO}
		 *  @private
		 */
		this._lfoL = new Tone.LFO(options.rate, 0, 1);

		/**
		 *  the lfo which controls the frequency on the right side
		 *  @type {Tone.LFO}
		 *  @private
		 */
		this._lfoR = new Tone.LFO(options.rate, 0, 1);
		this._lfoR.setPhase(180);

		/**
		 *  the base modulation frequency
		 *  @type {number}
		 *  @private
		 */
		this._baseFrequency = options.baseFrequency;

		/**
		 *  the depth of the phasing
		 *  @type {number}
		 *  @private
		 */
		this._depth = options.depth;

		/**
		 *  the array of filters for the left side
		 *  @type {Array.<Tone.Filter>}
		 *  @private
		 */
		this._filtersL = this._makeFilters(options.stages, this._lfoL, options.Q);

		/**
		 *  the array of filters for the left side
		 *  @type {Array.<Tone.Filter>}
		 *  @private
		 */
		this._filtersR = this._makeFilters(options.stages, this._lfoR, options.Q);

		//connect them up
		this.effectSendL.connect(this._filtersL[0]);
		this.effectSendR.connect(this._filtersR[0]);
		this._filtersL[options.stages - 1].connect(this.effectReturnL);
		this._filtersR[options.stages - 1].connect(this.effectReturnR);
		this.effectSendL.connect(this.effectReturnL);
		this.effectSendR.connect(this.effectReturnR);
		//control the frequency with one LFO
		this._lfoL.frequency.connect(this._lfoR.frequency);
		//set the options
		this.setBaseFrequency(options.baseFrequency);
		this.setDepth(options.depth);
		this.setRate(options.rate);
		//start the lfo
		this._lfoL.start();
		this._lfoR.start();
	};

	Tone.extend(Tone.Phaser, Tone.StereoEffect);

	/**
	 *  defaults
	 *  @static
	 *  @type {object}
	 */
	Tone.Phaser.defaults = {
		"rate" : 0.5,
		"depth" : 10,
		"stages" : 4,
		"Q" : 100,
		"baseFrequency" : 400,
	};

	/**
	 *  @param {number} stages
	 *  @returns {Array} the number of filters all connected together
	 *  @private
	 */
	Tone.Phaser.prototype._makeFilters = function(stages, connectToFreq, Q){
		var filters = new Array(stages);
		//make all the filters
		for (var i = 0; i < stages; i++){
			var filter = this.context.createBiquadFilter();
			filter.type = "allpass";
			filter.Q.value = Q;
			connectToFreq.connect(filter.frequency);
			filters[i] = filter;
		}
		this.connectSeries.apply(this, filters);
		return filters;
	};

	/**
	 *  set the depth of the chorus
	 *  @param {number} depth
	 */
	Tone.Phaser.prototype.setDepth = function(depth){
		this._depth = depth;
		var max = this._baseFrequency + this._baseFrequency * depth;
		this._lfoL.setMax(max);
		this._lfoR.setMax(max);
	};

	/**
	 *  set the base frequency of the filters
	 *  @param {number} freq
	 */
	Tone.Phaser.prototype.setBaseFrequency = function(freq){
		this._baseFrequency = freq;
		this._lfoL.setMin(freq);
		this._lfoR.setMin(freq);
		this.setDepth(this._depth);
	};

	/**
	 *  set the phaser rate
	 *  @param {number} rate in hertz
	 */
	Tone.Phaser.prototype.setRate = function(rate){
		this._lfoL.setFrequency(rate);
	};

	/**
	 *  bulk setter
	 *  @param {object} params
	 */
	Tone.Phaser.prototype.set = function(params){
		if (!this.isUndef(params.rate)) this.setRate(params.rate);
		if (!this.isUndef(params.baseFrequency)) this.setBaseFrequency(params.baseFrequency);
		if (!this.isUndef(params.depth)) this.setDepth(params.depth);
		Tone.StereoEffect.prototype.set.call(this, params);
	};

	/**
	 *  clean up
	 */
	Tone.Phaser.prototype.dispose = function(){
		Tone.StereoEffect.prototype.dispose.call(this);
		this._lfoL.dispose();
		this._lfoL = null;
		this._lfoR.dispose();
		this._lfoR = null;
		for (var i = 0; i < this._filtersL.length; i++){
			this._filtersL[i].disconnect();
			this._filtersL[i] = null;
		}
		this._filtersL = null;
		for (var j = 0; j < this._filtersR.length; j++){
			this._filtersR[j].disconnect();
			this._filtersR[j] = null;
		}
		this._filtersR = null;
	};

	return Tone.Phaser;
});<|endoftext|>


<commit_before>var assert = require('assert')
var ops = require('./opcodes')
var scripts = require('./scripts')

var ECPubKey = require('./ecpubkey')
var ECSignature = require('./ecsignature')
var Script = require('./script')
var Transaction = require('./transaction')

function isCoinbase(txHash) {
  return Array.prototype.every.call(txHash, function(x) {
    return x === 0
  })
}

function extractInput(txIn) {
  var redeemScript
  var scriptSig = txIn.script
  var prevOutScript
  var prevOutType = scripts.classifyInput(scriptSig, true)
  var scriptType

  // Re-classify if scriptHash
  if (prevOutType === 'scripthash') {
    redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0])
    prevOutScript = scripts.scriptHashOutput(redeemScript.getHash())

    scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
    scriptType = scripts.classifyInput(scriptSig, true)

  } else {
    scriptType = prevOutType
  }

  // Extract hashType, pubKeys and signatures
  var hashType, parsed, pubKeys, signatures

  switch (scriptType) {
    case 'pubkeyhash': {
      parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
      hashType = parsed.hashType
      pubKeys = [ECPubKey.fromBuffer(scriptSig.chunks[1])]
      signatures = [parsed.signature]
      prevOutScript = pubKeys[0].getAddress().toOutputScript()

      break
    }

    case 'pubkey': {
      parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
      hashType = parsed.hashType
      signatures = [parsed.signature]

      if (redeemScript) {
        pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])]
      }

      break
    }

    case 'multisig': {
      signatures = scriptSig.chunks.slice(1).map(function(chunk) {
        if (chunk === ops.OP_0) return chunk

        var parsed = ECSignature.parseScriptSignature(chunk)
        hashType = parsed.hashType

        return parsed.signature
      })

      if (redeemScript) {
        pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
      }

      break
    }
  }

  return {
    hashType: hashType,
    prevOutScript: prevOutScript,
    prevOutType: prevOutType,
    pubKeys: pubKeys,
    redeemScript: redeemScript,
    scriptType: scriptType,
    signatures: signatures
  }
}

function TransactionBuilder() {
  this.prevTxMap = {}
  this.prevOutScripts = {}
  this.prevOutTypes = {}

  this.inputs = []
  this.tx = new Transaction()
}

TransactionBuilder.fromTransaction = function(transaction) {
  var txb = new TransactionBuilder()

  // Copy other transaction fields
  txb.tx.version = transaction.version
  txb.tx.locktime = transaction.locktime

  // Extract/add inputs
  transaction.ins.forEach(function(txIn) {
    txb.addInput(txIn.hash, txIn.index, txIn.sequence)
  })

  // Extract/add outputs
  transaction.outs.forEach(function(txOut) {
    txb.addOutput(txOut.script, txOut.value)
  })

  // Extract/add signatures
  txb.inputs = transaction.ins.map(function(txIn) {
    // TODO: remove me after testcase added
    assert(!isCoinbase(txIn.hash), 'coinbase inputs not supported')

    // Ignore empty scripts
    if (txIn.script.buffer.length === 0) return

    return extractInput(txIn)
  })

  return txb
}

TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOutScript) {
  var prevOutHash

  if (typeof prevTx === 'string') {
    prevOutHash = new Buffer(prevTx, 'hex')

    // TxId hex is big-endian, we want little-endian hash
    Array.prototype.reverse.call(prevOutHash)

  } else if (prevTx instanceof Transaction) {
    prevOutHash = prevTx.getHash()
    prevOutScript = prevTx.outs[index].script

  } else {
    prevOutHash = prevTx

  }

  var input = {}
  if (prevOutScript) {
    var prevOutType = scripts.classifyOutput(prevOutScript)

    // if we can, extract pubKey information
    switch (prevOutType) {
      case 'multisig':
        input.pubKeys = prevOutScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
        break

      case 'pubkey':
        input.pubKeys = prevOutScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer)
        break
    }

    if (prevOutType !== 'scripthash') {
      input.scriptType = prevOutType
    }

    input.prevOutScript = prevOutScript
    input.prevOutType = prevOutType
  }

  assert(this.inputs.every(function(input2) {
    if (input2.hashType === undefined) return true

    return input2.hashType & Transaction.SIGHASH_ANYONECANPAY
  }), 'No, this would invalidate signatures')

  var prevOut = prevOutHash.toString('hex') + ':' + index
  assert(!(prevOut in this.prevTxMap), 'Transaction is already an input')

  var vin = this.tx.addInput(prevOutHash, index, sequence)
  this.inputs[vin] = input
  this.prevTxMap[prevOut] = vin

  return vin
}

TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) {
  assert(this.inputs.every(function(input) {
    if (input.hashType === undefined) return true

    return (input.hashType & 0x1f) === Transaction.SIGHASH_SINGLE
  }), 'No, this would invalidate signatures')

  return this.tx.addOutput(scriptPubKey, value)
}

TransactionBuilder.prototype.build = function() { return this.__build(false) }
TransactionBuilder.prototype.buildIncomplete = function() { return this.__build(true) }

var canSignTypes = { 'pubkeyhash': true, 'multisig': true, 'pubkey': true }

TransactionBuilder.prototype.__build = function(allowIncomplete) {
  if (!allowIncomplete) {
    assert(this.tx.ins.length > 0, 'Transaction has no inputs')
    assert(this.tx.outs.length > 0, 'Transaction has no outputs')
  }

  var tx = this.tx.clone()

  // Create script signatures from signature meta-data
  this.inputs.forEach(function(input, index) {
    var scriptType = input.scriptType
    var scriptSig

    if (!allowIncomplete) {
      assert(!!scriptType, 'Transaction is not complete')
      assert(scriptType in canSignTypes, scriptType + ' not supported')
      assert(input.signatures, 'Transaction is missing signatures')
    }

    if (input.signatures) {
      switch (scriptType) {
        case 'pubkeyhash':
          var pkhSignature = input.signatures[0].toScriptSignature(input.hashType)
          scriptSig = scripts.pubKeyHashInput(pkhSignature, input.pubKeys[0])
          break

        case 'multisig':
          // Array.prototype.map is sparse-compatible
          var msSignatures = input.signatures.map(function(signature) {
            return signature.toScriptSignature(input.hashType)
          })

          // fill in blanks with OP_0
          for (var i = 0; i < msSignatures.length; ++i) {
            if (msSignatures[i]) continue

            msSignatures[i] = ops.OP_0
          }

          var redeemScript = allowIncomplete ? undefined : input.redeemScript
          scriptSig = scripts.multisigInput(msSignatures, redeemScript)
          break

        case 'pubkey':
          var pkSignature = input.signatures[0].toScriptSignature(input.hashType)
          scriptSig = scripts.pubKeyInput(pkSignature)
          break
      }
    }

    // did we build a scriptSig?
    if (scriptSig) {
      // wrap as scriptHash if necessary
      if (input.prevOutType === 'scripthash') {
        scriptSig = scripts.scriptHashInput(scriptSig, input.redeemScript)
      }

      tx.setInputScript(index, scriptSig)
    }
  })

  return tx
}

TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashType) {
  assert(index in this.inputs, 'No input at index: ' + index)
  hashType = hashType || Transaction.SIGHASH_ALL

  var input = this.inputs[index]

  if (input.hashType !== undefined) {
    assert.equal(input.hashType, hashType, 'Inconsistent hashType')
  }

  var initialized = input.hashType &&
                    input.prevOutScript &&
                    input.prevOutType &&
                    input.pubKeys &&
                    input.scriptType &&
                    input.signatures

  // are we already initialized?
  if (initialized) {
    // redeemScript only needed to initialize, but if provided again, enforce consistency
    if (redeemScript) {
      assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
    }

  // initialize it
  } else {
    if (redeemScript) {
      // if we have a prevOutScript, enforce scriptHash equality to the redeemScript
      if (input.prevOutScript) {
        assert.equal(input.prevOutType, 'scripthash', 'PrevOutScript must be P2SH')

        var scriptHash = input.prevOutScript.chunks[1]
        assert.deepEqual(scriptHash, redeemScript.getHash(), 'RedeemScript does not match ' + scriptHash.toString('hex'))
      }

      var scriptType = scripts.classifyOutput(redeemScript)
      assert(scriptType in canSignTypes, 'RedeemScript not supported (' + scriptType + ')')

      var pubKeys = []
      switch (scriptType) {
        case 'multisig':
          pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
          break

        case 'pubkeyhash':
          var pkh1 = redeemScript.chunks[2]
          var pkh2 = privKey.pub.getAddress().hash

          assert.deepEqual(pkh1, pkh2, 'privateKey cannot sign for this input')
          pubKeys = [privKey.pub]
          break

        case 'pubkey':
          pubKeys = redeemScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer)
          break
      }

      if (!input.prevOutScript) {
        input.prevOutScript = scripts.scriptHashOutput(redeemScript.getHash())
        input.prevOutType = 'scripthash'
      }

      input.pubKeys = pubKeys
      input.redeemScript = redeemScript
      input.scriptType = scriptType

    } else {
      assert.notEqual(input.prevOutType, 'scripthash', 'PrevOutScript is P2SH, missing redeemScript')

      // can we sign this?
      if (input.scriptType) {
        assert(input.pubKeys, input.scriptType + ' not supported')

      // we know nothin' Jon Snow, assume pubKeyHash
      } else {
        input.prevOutScript = privKey.pub.getAddress().toOutputScript()
        input.prevOutType = 'pubkeyhash'
        input.pubKeys = [privKey.pub]
        input.scriptType = input.prevOutType

      }
    }

    input.hashType = hashType
    input.signatures = input.signatures || []
  }

  // enforce in order signing of public keys
  assert(input.pubKeys.some(function(pubKey, i) {
    if (!privKey.pub.Q.equals(pubKey.Q)) return false

    assert(!input.signatures[i], 'Signature already exists')
    var signatureScript = input.redeemScript || input.prevOutScript
    var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType)
    var signature = privKey.sign(signatureHash)
    input.signatures[i] = signature

    return true
  }, this), 'privateKey cannot sign for this input')
}

module.exports = TransactionBuilder
<commit_msg>TxBuilder: hashtype only relevant to things we can sign<commit_after>var assert = require('assert')
var ops = require('./opcodes')
var scripts = require('./scripts')

var ECPubKey = require('./ecpubkey')
var ECSignature = require('./ecsignature')
var Script = require('./script')
var Transaction = require('./transaction')

function isCoinbase(txHash) {
  return Array.prototype.every.call(txHash, function(x) {
    return x === 0
  })
}

function extractInput(txIn) {
  var redeemScript
  var scriptSig = txIn.script
  var prevOutScript
  var prevOutType = scripts.classifyInput(scriptSig, true)
  var scriptType

  // Re-classify if scriptHash
  if (prevOutType === 'scripthash') {
    redeemScript = Script.fromBuffer(scriptSig.chunks.slice(-1)[0])
    prevOutScript = scripts.scriptHashOutput(redeemScript.getHash())

    scriptSig = Script.fromChunks(scriptSig.chunks.slice(0, -1))
    scriptType = scripts.classifyInput(scriptSig, true)

  } else {
    scriptType = prevOutType
  }

  // Extract hashType, pubKeys and signatures
  var hashType, parsed, pubKeys, signatures

  switch (scriptType) {
    case 'pubkeyhash': {
      parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
      hashType = parsed.hashType
      pubKeys = [ECPubKey.fromBuffer(scriptSig.chunks[1])]
      signatures = [parsed.signature]
      prevOutScript = pubKeys[0].getAddress().toOutputScript()

      break
    }

    case 'pubkey': {
      parsed = ECSignature.parseScriptSignature(scriptSig.chunks[0])
      hashType = parsed.hashType
      signatures = [parsed.signature]

      if (redeemScript) {
        pubKeys = [ECPubKey.fromBuffer(redeemScript.chunks[0])]
      }

      break
    }

    case 'multisig': {
      signatures = scriptSig.chunks.slice(1).map(function(chunk) {
        if (chunk === ops.OP_0) return chunk

        var parsed = ECSignature.parseScriptSignature(chunk)
        hashType = parsed.hashType

        return parsed.signature
      })

      if (redeemScript) {
        pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
      }

      break
    }
  }

  return {
    hashType: hashType,
    prevOutScript: prevOutScript,
    prevOutType: prevOutType,
    pubKeys: pubKeys,
    redeemScript: redeemScript,
    scriptType: scriptType,
    signatures: signatures
  }
}

function TransactionBuilder() {
  this.prevTxMap = {}
  this.prevOutScripts = {}
  this.prevOutTypes = {}

  this.inputs = []
  this.tx = new Transaction()
}

TransactionBuilder.fromTransaction = function(transaction) {
  var txb = new TransactionBuilder()

  // Copy other transaction fields
  txb.tx.version = transaction.version
  txb.tx.locktime = transaction.locktime

  // Extract/add inputs
  transaction.ins.forEach(function(txIn) {
    txb.addInput(txIn.hash, txIn.index, txIn.sequence)
  })

  // Extract/add outputs
  transaction.outs.forEach(function(txOut) {
    txb.addOutput(txOut.script, txOut.value)
  })

  // Extract/add signatures
  txb.inputs = transaction.ins.map(function(txIn) {
    // TODO: remove me after testcase added
    assert(!isCoinbase(txIn.hash), 'coinbase inputs not supported')

    // Ignore empty scripts
    if (txIn.script.buffer.length === 0) return

    return extractInput(txIn)
  })

  return txb
}

TransactionBuilder.prototype.addInput = function(prevTx, index, sequence, prevOutScript) {
  var prevOutHash

  if (typeof prevTx === 'string') {
    prevOutHash = new Buffer(prevTx, 'hex')

    // TxId hex is big-endian, we want little-endian hash
    Array.prototype.reverse.call(prevOutHash)

  } else if (prevTx instanceof Transaction) {
    prevOutHash = prevTx.getHash()
    prevOutScript = prevTx.outs[index].script

  } else {
    prevOutHash = prevTx

  }

  var input = {}
  if (prevOutScript) {
    var prevOutType = scripts.classifyOutput(prevOutScript)

    // if we can, extract pubKey information
    switch (prevOutType) {
      case 'multisig':
        input.pubKeys = prevOutScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
        break

      case 'pubkey':
        input.pubKeys = prevOutScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer)
        break
    }

    if (prevOutType !== 'scripthash') {
      input.scriptType = prevOutType
    }

    input.prevOutScript = prevOutScript
    input.prevOutType = prevOutType
  }

  assert(this.inputs.every(function(input2) {
    if (input2.hashType === undefined) return true

    return input2.hashType & Transaction.SIGHASH_ANYONECANPAY
  }), 'No, this would invalidate signatures')

  var prevOut = prevOutHash.toString('hex') + ':' + index
  assert(!(prevOut in this.prevTxMap), 'Transaction is already an input')

  var vin = this.tx.addInput(prevOutHash, index, sequence)
  this.inputs[vin] = input
  this.prevTxMap[prevOut] = vin

  return vin
}

TransactionBuilder.prototype.addOutput = function(scriptPubKey, value) {
  assert(this.inputs.every(function(input) {
    if (input.hashType === undefined) return true

    return (input.hashType & 0x1f) === Transaction.SIGHASH_SINGLE
  }), 'No, this would invalidate signatures')

  return this.tx.addOutput(scriptPubKey, value)
}

TransactionBuilder.prototype.build = function() { return this.__build(false) }
TransactionBuilder.prototype.buildIncomplete = function() { return this.__build(true) }

var canSignTypes = { 'pubkeyhash': true, 'multisig': true, 'pubkey': true }

TransactionBuilder.prototype.__build = function(allowIncomplete) {
  if (!allowIncomplete) {
    assert(this.tx.ins.length > 0, 'Transaction has no inputs')
    assert(this.tx.outs.length > 0, 'Transaction has no outputs')
  }

  var tx = this.tx.clone()

  // Create script signatures from signature meta-data
  this.inputs.forEach(function(input, index) {
    var scriptType = input.scriptType
    var scriptSig

    if (!allowIncomplete) {
      assert(!!scriptType, 'Transaction is not complete')
      assert(scriptType in canSignTypes, scriptType + ' not supported')
      assert(input.signatures, 'Transaction is missing signatures')
    }

    if (input.signatures) {
      switch (scriptType) {
        case 'pubkeyhash':
          var pkhSignature = input.signatures[0].toScriptSignature(input.hashType)
          scriptSig = scripts.pubKeyHashInput(pkhSignature, input.pubKeys[0])
          break

        case 'multisig':
          // Array.prototype.map is sparse-compatible
          var msSignatures = input.signatures.map(function(signature) {
            return signature.toScriptSignature(input.hashType)
          })

          // fill in blanks with OP_0
          for (var i = 0; i < msSignatures.length; ++i) {
            if (msSignatures[i]) continue

            msSignatures[i] = ops.OP_0
          }

          var redeemScript = allowIncomplete ? undefined : input.redeemScript
          scriptSig = scripts.multisigInput(msSignatures, redeemScript)
          break

        case 'pubkey':
          var pkSignature = input.signatures[0].toScriptSignature(input.hashType)
          scriptSig = scripts.pubKeyInput(pkSignature)
          break
      }
    }

    // did we build a scriptSig?
    if (scriptSig) {
      // wrap as scriptHash if necessary
      if (input.prevOutType === 'scripthash') {
        scriptSig = scripts.scriptHashInput(scriptSig, input.redeemScript)
      }

      tx.setInputScript(index, scriptSig)
    }
  })

  return tx
}

TransactionBuilder.prototype.sign = function(index, privKey, redeemScript, hashType) {
  assert(index in this.inputs, 'No input at index: ' + index)
  hashType = hashType || Transaction.SIGHASH_ALL

  var input = this.inputs[index]
  var canSign = input.hashType &&
                input.prevOutScript &&
                input.prevOutType &&
                input.pubKeys &&
                input.scriptType &&
                input.signatures

  // are we almost ready to sign?
  if (canSign) {
    // if redeemScript was provided, enforce consistency
    if (redeemScript) {
      assert.deepEqual(input.redeemScript, redeemScript, 'Inconsistent redeemScript')
    }

    assert.equal(input.hashType, hashType, 'Inconsistent hashType')

  // no? prepare
  } else {
    if (redeemScript) {
      // if we have a prevOutScript, enforce scriptHash equality to the redeemScript
      if (input.prevOutScript) {
        assert.equal(input.prevOutType, 'scripthash', 'PrevOutScript must be P2SH')

        var scriptHash = input.prevOutScript.chunks[1]
        assert.deepEqual(scriptHash, redeemScript.getHash(), 'RedeemScript does not match ' + scriptHash.toString('hex'))
      }

      var scriptType = scripts.classifyOutput(redeemScript)
      assert(scriptType in canSignTypes, 'RedeemScript not supported (' + scriptType + ')')

      var pubKeys = []
      switch (scriptType) {
        case 'multisig':
          pubKeys = redeemScript.chunks.slice(1, -2).map(ECPubKey.fromBuffer)
          break

        case 'pubkeyhash':
          var pkh1 = redeemScript.chunks[2]
          var pkh2 = privKey.pub.getAddress().hash

          assert.deepEqual(pkh1, pkh2, 'privateKey cannot sign for this input')
          pubKeys = [privKey.pub]
          break

        case 'pubkey':
          pubKeys = redeemScript.chunks.slice(0, 1).map(ECPubKey.fromBuffer)
          break
      }

      if (!input.prevOutScript) {
        input.prevOutScript = scripts.scriptHashOutput(redeemScript.getHash())
        input.prevOutType = 'scripthash'
      }

      input.pubKeys = pubKeys
      input.redeemScript = redeemScript
      input.scriptType = scriptType

    } else {
      assert.notEqual(input.prevOutType, 'scripthash', 'PrevOutScript is P2SH, missing redeemScript')

      // can we sign this?
      if (input.scriptType) {
        assert(input.pubKeys, input.scriptType + ' not supported')

      // we know nothin' Jon Snow, assume pubKeyHash
      } else {
        input.prevOutScript = privKey.pub.getAddress().toOutputScript()
        input.prevOutType = 'pubkeyhash'
        input.pubKeys = [privKey.pub]
        input.scriptType = input.prevOutType

      }
    }

    input.hashType = hashType
    input.signatures = input.signatures || []
  }

  // enforce in order signing of public keys
  assert(input.pubKeys.some(function(pubKey, i) {
    if (!privKey.pub.Q.equals(pubKey.Q)) return false

    assert(!input.signatures[i], 'Signature already exists')
    var signatureScript = input.redeemScript || input.prevOutScript
    var signatureHash = this.tx.hashForSignature(index, signatureScript, hashType)
    var signature = privKey.sign(signatureHash)
    input.signatures[i] = signature

    return true
  }, this), 'privateKey cannot sign for this input')
}

module.exports = TransactionBuilder
<|endoftext|>


<commit_before>'use strict';
import express from 'express';
import morgan from 'morgan';
import React from 'react';
import {renderToString} from 'react-dom/server';
import {RoutingContext, match} from 'react-router';
import createLocation from 'history/lib/createLocation';
import routes from './shared/routes';
import api from './api/api-router';
import createStoreWithMiddleware from './middleware/middleware';
import fetchComponentData from './shared/fetchComponentData';
import path from 'path';
import reducers from './reducers/reducers';

const app = express();

app.use(morgan('dev'));
app.set('view engine', 'jade');

app.use(express.static(path.join(__dirname, 'client')));

app.use('/api', api);

app.use((req, res) => {
    let dom = '',
        location = createLocation(req.url),
        store = createStoreWithMiddleware(reducers),
        bootstrap;

    match({routes, location}, (error, redirectLocation, renderProps) => {
        if (error) {
            console.log(error);
            res.status(500).send(error.message);
        }
        else if (redirectLocation) {
            res.redirect(302, redirectLocation.pathname + redirectLocation.search);
        }
        else if (renderProps) {
            fetchComponentData(store.dispatch, renderProps.components, renderProps.params)
                .then(() => {
                    const view = (
                        <Provider store={store}>
                            <RoutingContext {...renderProps} />
                        </Provider>
                    );

                    dom = renderToString(view);
                    bootstrap = JSON.stringify(store.getState());

                    res.render('index', {dom, bootstrap});
                })
                .catch((error) => {
                    res.status(500).send(error.message);
                })
        }
        else {
            res.status(404).send('Not found');
        }
    });
});

app.listen(3000, () => {
    console.log('listening');
});<commit_msg>import Provider<commit_after>'use strict';
import express from 'express';
import morgan from 'morgan';
import React from 'react';
import {renderToString} from 'react-dom/server';
import {RoutingContext, match} from 'react-router';
import {Provider} from 'react-redux';
import createLocation from 'history/lib/createLocation';
import routes from './shared/routes';
import api from './api/api-router';
import createStoreWithMiddleware from './middleware/middleware';
import fetchComponentData from './shared/fetchComponentData';
import path from 'path';
import reducers from './reducers/reducers';

const app = express();

app.use(morgan('dev'));
app.set('view engine', 'jade');

app.use(express.static(path.join(__dirname, 'client')));

app.use('/api', api);

app.use((req, res) => {
    let dom = '',
        location = createLocation(req.url),
        store = createStoreWithMiddleware(reducers),
        bootstrap;

    match({routes, location}, (error, redirectLocation, renderProps) => {
        if (error) {
            console.log(error);
            res.status(500).send(error.message);
        }
        else if (redirectLocation) {
            res.redirect(302, redirectLocation.pathname + redirectLocation.search);
        }
        else if (renderProps) {
            fetchComponentData(store.dispatch, renderProps.components, renderProps.params)
                .then(() => {
                    const view = (
                        <Provider store={store}>
                            <RoutingContext {...renderProps} />
                        </Provider>
                    );

                    dom = renderToString(view);
                    bootstrap = JSON.stringify(store.getState());

                    res.render('index', {dom, bootstrap});
                })
                .catch((error) => {
                    res.status(500).send(error.message);
                })
        }
        else {
            res.status(404).send('Not found');
        }
    });
});

app.listen(3000, () => {
    console.log('listening');
});<|endoftext|>


<commit_before>// CONSTANTS
var fieldWidth = 54, // the width of every of the 24 fields
    offsetBetweenFields = 5, // between small field(white) and big field(dark)
    boardSide = 324, // the width of one side of the board
    boardBar = 34, // the thing between the board sides in pixels
    boardFrameOffset = 18, // the offset in the corners between the board itself and the frame in pixels
    checkerHeight = 42, // the height of the checker after being fully drawn in pixels
    checkerRadius = 21, // full width = 44; outer stroke 1px
    checkerInnerCircleRadius = 10;

// GAME ELEMENTS - canvas, ctx, keystate
var canvas,
    ctx,
    clickedField;

// DEFINING GAME OBJECTS - player, checker, dice, board(not if it is just a background) ...
var player = (function () {
    var player = {
        init: function (name, color) {
            this.name = name;
            this.color = color;
            this.currentCheckersCount = 15;
            this.hasHitChecker = false;
            this.hitCheckersCount = 0;
            this.canTakeChecker = false;
            return this;
        },
        tookChecker: function () {
            // TODO: Validate depending on call.
            this.currentCheckersCount -= 1;
        }
    };

    Object.defineProperty(player, 'name', {
        get: function () {
            return this._name;
        },
        set: function (value) {
            //TODO: Validate
            this._name = value;
        }
    });

    Object.defineProperty(player, 'currentCheckersCount', {
        get: function () {
            return this._currentCheckersCount;
        },
        set: function (value) {
            //TODO: Validate
            this._currentCheckersCount = value;
        }
    });

    Object.defineProperty(player, 'color', {
        get: function () {
            return this._color;
        },
        set: function (value) {
            // TODO: Validate
            this._color = value;
        }
    });

    Object.defineProperty(player, 'hasHitChecker', {
        get: function () {
            return this._hasHitChecker;
        },
        set: function (value) {
            // TODO: Validate
            this._hasHitChecker = value;
        }
    });

    Object.defineProperty(player, 'hitCheckersCount', {
        get: function () {
            return this._hitCheckersCount;
        },
        set: function (value) {
            // TODO: Validate
            this._hitCheckersCount = value;
        }
    });

    Object.defineProperty(player, 'canTakeChecker', {
        get: function () {
            return this._canTakeChecker;
        },
        set: function (value) {
            // TODO: Validate
            this._canTakeChecker = value;
        }
    });

    return player;
}());

var field = function () { /* the board is filled with 24 fields,
 IT IS A RESPONSIBILITY OF THE FIELDS TO GIVE COORDINATES TO THE CHECKERS, WITH RESPECT TO THEIR OWN X,Y COORDINATES
 IN THIS WAY WE DON'T CARE HOW TO STACK CHECKERS AND TO TAKE INTO ACCOUNT THEIR Xs AND Ys,
 THE FIELD JUST STACKS THEM DEPENDING ON THE COUNT IT IS HOLDING, GIVING HIS OWN X, Y */
    var field = {
        init: function (x, y) {
            this.checkers = [];
            this.x = x;
            this.y = y;
            /* if field is 0~11 y = canvas.height - boardFrameOffset; else y = boardFrameOffset;
             this is needed only for knowing at which side are we, so we can draw the checkers properly */
            return this;
        },
        addChecker: function (checker) {
            this.checkers.push(checker);
        },
        removeChecker: function () {
            this.checkers.pop();
        },
        draw: function () {
            var count = this.checkers.length, // count checkers, if more than 5 draw stacked
                i,
                fieldCenter;
            for (i = 0; i < count; i += 1) {
                if (i > 4) {
                    // draw stacked
                    ctx.save();
                    ctx.fillStyle = 'red';
                    ctx.font = "12px Verdana";
                    ctx.fillText('x' + (i - 3), (this.x - 6) + fieldWidth / 2, this.y + checkerRadius + 4);
                    // x2 for the 6th checker because it represents how many checkers are stacked
                    // 6 and 4 are just a magic numbers to position the text in the center of the checker, because the text has also its own offset
                    ctx.restore();
                } else {
                    if (this.y < canvas.height / 2) { // if field is in the upper half of the board, should stack them up to bottom
                        fieldCenter = this.x + (fieldWidth / 2); // x coordinate for the checker center
                        this.checkers[i].draw(fieldCenter, this.y + i * checkerHeight + checkerRadius + 2); /* +2 just to look better,
                                                                                the checker from the board frame */
                    } else { // when the field is in the lower part, should stack them from bottom to up
                        fieldCenter = this.x + (fieldWidth / 2); // x coordinate for the checker center
                        this.checkers[i].draw(fieldCenter, this.y - i * checkerHeight + checkerRadius - 2); // -2 just to look better
                    }
                }
            }
        }
    };

    Object.defineProperty(field, 'checkers', {
        get: function () {
            return this._checkers;
        },
        set: function (value) {
            this._checkers = value;
        }
    });

    Object.defineProperty(field, 'x', {
        get: function () {
            return this._x;
        },
        set: function (value) {
            this._x = value;
        }
    });

    Object.defineProperty(field, 'y', {
        get: function () {
            return this._y;
        },
        set: function (value) {
            this._y = value;
        }
    });

    return field;
}();

var checker = function () {
    var checker = {
        init: function (color) {
            this.color = color; // can be only 'black' or 'white'
            return this;
        },
        draw: function (x, y) {
            ctx.save();
            if (this.color === 'black') {
                ctx.strokeStyle = 'white';
            }
            // outer circle
            ctx.beginPath();
            ctx.fillStyle = this.color;
            ctx.lineWidth = 1;
            ctx.arc(x, y, checkerRadius, 0, 2 * Math.PI);
            ctx.fill();
            ctx.stroke();

            // inner circle
            ctx.beginPath();
            ctx.strokeStyle = '#808080';
            ctx.lineWidth = 2;
            ctx.arc(x, y, checkerInnerCircleRadius, 0, 2 * Math.PI);
            ctx.stroke();

            ctx.restore();
        }
    };

    Object.defineProperty(checker, 'color', {
        get: function () {
            return this._color;
        },
        set: function (value) {
            this._color = value;
        }
    });

    return checker;
}();

var board = function () {
    var bottomSideAllSet, // flag to indicate that we must start with a field having 5 checkers in it(the 12th field)
    // at bottom we start with  12. 5 3 5 2 .23
    // at top we start with     11. 5 3 5 2 .0
        patternToPutColors = []; // colors are inverted in the opposite sides of the field, sorry it truly looks ugly..

    var gameboard = {
        init: function () {
            this.fields = [];
            bottomSideAllSet = false;
            patternToPutColors[0] = 1;
            patternToPutColors[5] = 0;
            patternToPutColors[7] = 0;
            patternToPutColors[11] = 1;
            var self = this;
            setupHalfGameBoard(self, bottomSideAllSet);
            bottomSideAllSet = true;
            setupHalfGameBoard(self, bottomSideAllSet);
            return this;
        },
        addField: function (value) {
            this.fields.push(value);
        }
    };

    function setupHalfGameBoard(self, bottomSideAllSet) {
        var i,
            len,
            x,
            y,
            currentField,
            patternOfTheNumberOfCheckersToPut = [2, 0, 0, 0, 0, 5, 0, 3, 0, 0, 0, 5],// on 0 field put 2, on field 1 put 0, etc.. the setup rules..
            j,  // needed to go trough the patternToPutCheckers
            colorToPut,
            countPassedFields = 0; // needed to add a boardBar offset to the X coordinate

        if (bottomSideAllSet) {
            i = 12;
            j = 11;
        } else {
            i = 0;
            j = 0;
        }
        for (len = i + 12; i < len; i += 1, (i >= 12) ? j -= 1 : j += 1, countPassedFields += 1) {
            if (countPassedFields >= 6) {  // after every 6 fields we must consider the boardBar also, in both the upper and the lower side of the board
                x = (!bottomSideAllSet) * canvas.width - boardFrameOffset - ((countPassedFields + !bottomSideAllSet) * fieldWidth) - boardBar;
            } else {
                x = (!bottomSideAllSet) * canvas.width - boardFrameOffset - ((countPassedFields + !bottomSideAllSet) * fieldWidth);
                // if we are at the bottom we must consider the canvas width and to subtract from it
            }
            y = (!bottomSideAllSet) * (canvas.height - checkerHeight) - boardFrameOffset;

            if (x < 0) { // because we are extracting everything from the canvas width or height
                x *= -1; // when we are at the bottom side, we start from the MOST-RIGHT field(our 0 field) so canvas height, and width must be considered,
            }            // while when we are at the upper side of the board, the MOST-LEFT field(the 12th field) must be filled first,
            if (y < 0) { // so canvas width and height in the upper side are 0, and we get a negative number but we actually need that number to be positive,
                y *= -1; // to go to the right.. to fill the rest of the fields.. it's all because of how the fields position in backgammon
            }
            if (patternToPutColors[j] === 1) {
                colorToPut = 'white';
                patternToPutColors[j] = 0; // swapping the pattern for the next half of the board
            } else if (patternToPutColors[j] === 0) {
                colorToPut = 'black';
                patternToPutColors[j] = 1;
            }
            currentField = Object.create(field).init(x, y); // creating one of the 24 fields in the board
            putCheckersOnField(patternOfTheNumberOfCheckersToPut[j], currentField, colorToPut); // assigning checkers to it with respect to the Backgammon setup rules
            self.addField(currentField); // adding the field to the board, used 'self' because the scope of this has changed
        }
    }

    function putCheckersOnField(checkersToPut, givenField, color) {
        var i;
        for (i = 0; i < checkersToPut; i += 1) {
            givenField.addChecker(Object.create(checker).init(color));
        }
    }

    return gameboard;
}();

// function newGame() or main()
// create initiate and append game canvas
// keep track of keyboard presses
// INITIATE GAME OBJECTS;
// GAME LOOP, STARTS THE ANIMATION;
function newGame() {
    canvas = document.getElementById('board-canvas');
    ctx = canvas.getContext('2d');

    // INIT GAME OBJECTS, SETS UP GAME
    board.init();
}
newGame();
// canvas.addEventListener('click', findPressedField);

function play() {
    // GAME LOOP - game logic, updating the fields, players turns, dices etc. Update update update
    // change fields depending on how the player interact(key presses)
    canvas.addEventListener('click', findPressedField);

    // calls function update()
    // checkForWinner etc... this all should go here

    // draws every time and if we have changes its ok
    draw();
    requestAnimationFrame(play);
}
play();

function findPressedField(event) {
    var x = event.offsetX;
    var y = event.offsetY;
    if (((x < canvas.width - boardFrameOffset && x > boardFrameOffset + boardSide + boardBar) ||
        (x < boardFrameOffset + boardSide && x > boardFrameOffset)) &&
        (y < canvas.height - boardFrameOffset && y > boardFrameOffset)) { // ignoring every piece of the frame
        var i = 0,
            len,
            foundField,
            upperSide = false;
        // determining in which quadrant are we exactly
        if (y < canvas.height / 2 && y > boardFrameOffset) {
            i = 12; // last field of the upper side, last because if we take the first our condition in the for-loop will be achieved every time
            upperSide = true;
        } else {
            i = 0; // first field of the lower side
        }
        if (x < boardSide + boardFrameOffset && x > boardFrameOffset) { // left side of the board
            if (i === 0) { // bottom left side
                i = 6;
            } else { // upper left side
                i = 12;
            }
        } else { // right side of the board
            if (i === 0) { // bottom right side
                i = 0;
            } else { // upper left side
                i = 18; // again last of the array
            }
        }
        for (len = i + 6; i < len; i += 1) {
            var currentField = board.fields[i];
            if (upperSide) { /* its all because of the fields..
             the start position of the lower side is most-right and it starts from 0,
             while the start position of the upper side is the most-left which confuses the algorithm */
                var previousField = board.fields[i - 1];
                if (currentField.x > x) {
                    foundField = previousField;
                    break;
                }
            } else {
                if (x > currentField.x) {
                    foundField = currentField;
                    break;
                }
            }
        }
        if (typeof foundField === 'undefined') { // when we are going out of the for-in and the condition for the upperSide is not met,
            // because we take the previous field element we could not get to check the last one
            foundField = board.fields[len - 1];
        }
        clickedField = foundField;
        console.log(clickedField); // testing purposes
    }
}

function draw() {
    ctx.clearRect(0,0,canvas.width,canvas.height); // refresh canvas

    board.fields.forEach(function (field) {
        field.draw(); // redraw every field again
    });
}<commit_msg>Added dice  element and started play method<commit_after>// CONSTANTS
var fieldWidth = 54, // the width of every of the 24 fields
    offsetBetweenFields = 5, // between small field(white) and big field(dark)
    boardSide = 324, // the width of one side of the board
    boardBar = 34, // the thing between the board sides in pixels
    boardFrameOffset = 18, // the offset in the corners between the board itself and the frame in pixels
    checkerHeight = 42, // the height of the checker after being fully drawn in pixels
    checkerRadius = 21, // full width = 44; outer stroke 1px
    checkerInnerCircleRadius = 10,
    currentPlayer = 0,
    playerLooper = -1,
    INITIALDICEVALUE = 6;

// GAME ELEMENTS - canvas, ctx, keystate
var canvas,
    ctx,
    clickedField;

// DEFINING GAME OBJECTS - player, checker, dice, board(not if it is just a background) ...
var player = (function () {
    var player = {
        init: function (name, color) {
            this.name = name;
            this.color = color;
            this.currentCheckersCount = 15;
            this.hasHitChecker = false;
            this.hitCheckersCount = 0;
            this.canTakeChecker = false;
            return this;
        },
        tookChecker: function () {
            // TODO: Validate depending on call.
            this.currentCheckersCount -= 1;
        }
    };

    Object.defineProperty(player, 'name', {
        get: function () {
            return this._name;
        },
        set: function (value) {
            //TODO: Validate
            this._name = value;
        }
    });

    Object.defineProperty(player, 'currentCheckersCount', {
        get: function () {
            return this._currentCheckersCount;
        },
        set: function (value) {
            //TODO: Validate
            this._currentCheckersCount = value;
        }
    });

    Object.defineProperty(player, 'color', {
        get: function () {
            return this._color;
        },
        set: function (value) {
            // TODO: Validate
            this._color = value;
        }
    });

    Object.defineProperty(player, 'hasHitChecker', {
        get: function () {
            return this._hasHitChecker;
        },
        set: function (value) {
            // TODO: Validate
            this._hasHitChecker = value;
        }
    });

    Object.defineProperty(player, 'hitCheckersCount', {
        get: function () {
            return this._hitCheckersCount;
        },
        set: function (value) {
            // TODO: Validate
            this._hitCheckersCount = value;
        }
    });

    Object.defineProperty(player, 'canTakeChecker', {
        get: function () {
            return this._canTakeChecker;
        },
        set: function (value) {
            // TODO: Validate
            this._canTakeChecker = value;
        }
    });

    return player;
}());

var field = function () { /* the board is filled with 24 fields,
 IT IS A RESPONSIBILITY OF THE FIELDS TO GIVE COORDINATES TO THE CHECKERS, WITH RESPECT TO THEIR OWN X,Y COORDINATES
 IN THIS WAY WE DON'T CARE HOW TO STACK CHECKERS AND TO TAKE INTO ACCOUNT THEIR Xs AND Ys,
 THE FIELD JUST STACKS THEM DEPENDING ON THE COUNT IT IS HOLDING, GIVING HIS OWN X, Y */
    var field = {
        init: function (x, y) {
            this.checkers = [];
            this.x = x;
            this.y = y;
            /* if field is 0~11 y = canvas.height - boardFrameOffset; else y = boardFrameOffset;
             this is needed only for knowing at which side are we, so we can draw the checkers properly */
            return this;
        },
        addChecker: function (checker) {
            this.checkers.push(checker);
        },
        removeChecker: function () {
            this.checkers.pop();
        },
        draw: function () {
            var count = this.checkers.length, // count checkers, if more than 5 draw stacked
                i,
                fieldCenter;
            for (i = 0; i < count; i += 1) {
                if (i > 4) {
                    // draw stacked
                    ctx.save();
                    ctx.fillStyle = 'red';
                    ctx.font = "12px Verdana";
                    ctx.fillText('x' + (i - 3), (this.x - 6) + fieldWidth / 2, this.y + checkerRadius + 4);
                    // x2 for the 6th checker because it represents how many checkers are stacked
                    // 6 and 4 are just a magic numbers to position the text in the center of the checker, because the text has also its own offset
                    ctx.restore();
                } else {
                    if (this.y < canvas.height / 2) { // if field is in the upper half of the board, should stack them up to bottom
                        fieldCenter = this.x + (fieldWidth / 2); // x coordinate for the checker center
                        this.checkers[i].draw(fieldCenter, this.y + i * checkerHeight + checkerRadius + 2); /* +2 just to look better,
                                                                                the checker from the board frame */
                    } else { // when the field is in the lower part, should stack them from bottom to up
                        fieldCenter = this.x + (fieldWidth / 2); // x coordinate for the checker center
                        this.checkers[i].draw(fieldCenter, this.y - i * checkerHeight + checkerRadius - 2); // -2 just to look better
                    }
                }
            }
        }
    };

    Object.defineProperty(field, 'checkers', {
        get: function () {
            return this._checkers;
        },
        set: function (value) {
            this._checkers = value;
        }
    });

    Object.defineProperty(field, 'x', {
        get: function () {
            return this._x;
        },
        set: function (value) {
            this._x = value;
        }
    });

    Object.defineProperty(field, 'y', {
        get: function () {
            return this._y;
        },
        set: function (value) {
            this._y = value;
        }
    });

    return field;
}();

var checker = function () {
    var checker = {
        init: function (color) {
            this.color = color; // can be only 'black' or 'white'
            return this;
        },
        draw: function (x, y) {
            ctx.save();
            if (this.color === 'black') {
                ctx.strokeStyle = 'white';
            }
            // outer circle
            ctx.beginPath();
            ctx.fillStyle = this.color;
            ctx.lineWidth = 1;
            ctx.arc(x, y, checkerRadius, 0, 2 * Math.PI);
            ctx.fill();
            ctx.stroke();

            // inner circle
            ctx.beginPath();
            ctx.strokeStyle = '#808080';
            ctx.lineWidth = 2;
            ctx.arc(x, y, checkerInnerCircleRadius, 0, 2 * Math.PI);
            ctx.stroke();

            ctx.restore();
        }
    };

    Object.defineProperty(checker, 'color', {
        get: function () {
            return this._color;
        },
        set: function (value) {
            this._color = value;
        }
    });

    return checker;
}();

var board = function () {
    var bottomSideAllSet, // flag to indicate that we must start with a field having 5 checkers in it(the 12th field)
    // at bottom we start with  12. 5 3 5 2 .23
    // at top we start with     11. 5 3 5 2 .0
        patternToPutColors = []; // colors are inverted in the opposite sides of the field, sorry it truly looks ugly..

    var gameboard = {
        init: function () {
            this.fields = [];
            bottomSideAllSet = false;
            patternToPutColors[0] = 1;
            patternToPutColors[5] = 0;
            patternToPutColors[7] = 0;
            patternToPutColors[11] = 1;
            var self = this;
            setupHalfGameBoard(self, bottomSideAllSet);
            bottomSideAllSet = true;
            setupHalfGameBoard(self, bottomSideAllSet);
            return this;
        },
        addField: function (value) {
            this.fields.push(value);
        }
    };

    function setupHalfGameBoard(self, bottomSideAllSet) {
        var i,
            len,
            x,
            y,
            currentField,
            patternOfTheNumberOfCheckersToPut = [2, 0, 0, 0, 0, 5, 0, 3, 0, 0, 0, 5],// on 0 field put 2, on field 1 put 0, etc.. the setup rules..
            j,  // needed to go trough the patternToPutCheckers
            colorToPut,
            countPassedFields = 0; // needed to add a boardBar offset to the X coordinate

        if (bottomSideAllSet) {
            i = 12;
            j = 11;
        } else {
            i = 0;
            j = 0;
        }
        for (len = i + 12; i < len; i += 1, (i >= 12) ? j -= 1 : j += 1, countPassedFields += 1) {
            if (countPassedFields >= 6) {  // after every 6 fields we must consider the boardBar also, in both the upper and the lower side of the board
                x = (!bottomSideAllSet) * canvas.width - boardFrameOffset - ((countPassedFields + !bottomSideAllSet) * fieldWidth) - boardBar;
            } else {
                x = (!bottomSideAllSet) * canvas.width - boardFrameOffset - ((countPassedFields + !bottomSideAllSet) * fieldWidth);
                // if we are at the bottom we must consider the canvas width and to subtract from it
            }
            y = (!bottomSideAllSet) * (canvas.height - checkerHeight) - boardFrameOffset;

            if (x < 0) { // because we are extracting everything from the canvas width or height
                x *= -1; // when we are at the bottom side, we start from the MOST-RIGHT field(our 0 field) so canvas height, and width must be considered,
            }            // while when we are at the upper side of the board, the MOST-LEFT field(the 12th field) must be filled first,
            if (y < 0) { // so canvas width and height in the upper side are 0, and we get a negative number but we actually need that number to be positive,
                y *= -1; // to go to the right.. to fill the rest of the fields.. it's all because of how the fields position in backgammon
            }
            if (patternToPutColors[j] === 1) {
                colorToPut = 'white';
                patternToPutColors[j] = 0; // swapping the pattern for the next half of the board
            } else if (patternToPutColors[j] === 0) {
                colorToPut = 'black';
                patternToPutColors[j] = 1;
            }
            currentField = Object.create(field).init(x, y); // creating one of the 24 fields in the board
            putCheckersOnField(patternOfTheNumberOfCheckersToPut[j], currentField, colorToPut); // assigning checkers to it with respect to the Backgammon setup rules
            self.addField(currentField); // adding the field to the board, used 'self' because the scope of this has changed
        }
    }

    function putCheckersOnField(checkersToPut, givenField, color) {
        var i;
        for (i = 0; i < checkersToPut; i += 1) {
            givenField.addChecker(Object.create(checker).init(color));
        }
    }

    return gameboard;
}();

var dice = (function () {

    var dice = Object.create({});

    Object.defineProperty(dice, 'init', {
        value: function () {
            this.number = INITIALDICEVALUE;
            return this;
        }
    });   // DICE SHOULD BE CREATED WHEN THE BOARD IS CREATED  !!!!!!!!!

    Object.defineProperty(dice, 'number', {
        get: function () {
            return this._number;
        },
        set: function (value) {
            checkIfDiceValueIsValid(value);
            this._number = value;
        }
    });

    Object.defineProperty(dice, 'drawNewNumber', {
        value: function () {
            this.number = Math.round(Math.random() * 5) + 1;
        }
    });

    return dice;
}());

function checkIfDiceValueIsValid(number) {
    if (isNaN(number) || number % 1 != 0 || number < 1 || number > 6) {
        throw new Error('Dice number is invalid!');
    }

}
// function newGame() or main()
// create initiate and append game canvas
// keep track of keyboard presses
// INITIATE GAME OBJECTS;
// GAME LOOP, STARTS THE ANIMATION;

function newGame() {
    canvas = document.getElementById('board-canvas');
    ctx = canvas.getContext('2d');

    // INIT GAME OBJECTS, SETS UP GAME
    board.init();
}
newGame();
// canvas.addEventListener('click', findPressedField);

function play() {
    // GAME LOOP - game logic, updating the fields, players turns, dices etc. Update update update
    // change fields depending on how the player interact(key presses)

    while (true) {

        // CHANGE PLAYER
        playerLooper++;
        currentPlayer = (playerLooper % 2) + 1;    //if   playerLooper % 2 ===0 -> currentPlayer = 1     , else current player = 2
        //LOGIC NEEDS TO BE IMPLEMENTED FOR PLAYER
        //--------------------------------------------------------------

        //THROW DISE

        //CHECK IF ANY POSSIBLE MOVE
        //EXPECT ONLY THE POSSIBLE MOVES AND LOOK FOR POSSIBLE PLACES TO START THEM FROM AND HIGHLIGHT
        //CHECK FOR NEW CLICKS AND CATCH START POSITION
        //CHECK IF NEW SET POSITION IS CORRECT
        //MOVE PULL

        canvas.addEventListener('click', findPressedField);

        // calls function update()
        // checkForWinner etc... this all should go here

        // draws every time and if we have changes its ok
        draw();
        requestAnimationFrame(play);

    }

}

play();

function findPressedField(event) {
    var x = event.offsetX;
    var y = event.offsetY;
    if (((x < canvas.width - boardFrameOffset && x > boardFrameOffset + boardSide + boardBar) ||
        (x < boardFrameOffset + boardSide && x > boardFrameOffset)) &&
        (y < canvas.height - boardFrameOffset && y > boardFrameOffset)) { // ignoring every piece of the frame
        var i = 0,
            len,
            foundField,
            upperSide = false;
        // determining in which quadrant are we exactly
        if (y < canvas.height / 2 && y > boardFrameOffset) {
            i = 12; // last field of the upper side, last because if we take the first our condition in the for-loop will be achieved every time
            upperSide = true;
        } else {
            i = 0; // first field of the lower side
        }
        if (x < boardSide + boardFrameOffset && x > boardFrameOffset) { // left side of the board
            if (i === 0) { // bottom left side
                i = 6;
            } else { // upper left side
                i = 12;
            }
        } else { // right side of the board
            if (i === 0) { // bottom right side
                i = 0;
            } else { // upper left side
                i = 18; // again last of the array
            }
        }
        for (len = i + 6; i < len; i += 1) {
            var currentField = board.fields[i];
            if (upperSide) { /* its all because of the fields..
             the start position of the lower side is most-right and it starts from 0,
             while the start position of the upper side is the most-left which confuses the algorithm */
                var previousField = board.fields[i - 1];
                if (currentField.x > x) {
                    foundField = previousField;
                    break;
                }
            } else {
                if (x > currentField.x) {
                    foundField = currentField;
                    break;
                }
            }
        }
        if (typeof foundField === 'undefined') { // when we are going out of the for-in and the condition for the upperSide is not met,
            // because we take the previous field element we could not get to check the last one
            foundField = board.fields[len - 1];
        }
        clickedField = foundField;
        console.log(clickedField); // testing purposes
    }
}

function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height); // refresh canvas

    board.fields.forEach(function (field) {
        field.draw(); // redraw every field again
    });
}<|endoftext|>