<commit_before>(function(){
	"use strict";

	var root = this,
		Chart = root.Chart,
		//Cache a local reference to Chart.helpers
		helpers = Chart.helpers;

	var defaultConfig = {
		//Boolean - Whether we should show a stroke on each segment
		segmentShowStroke : true,

		//String - The colour of each segment stroke
		segmentStrokeColor : "#fff",

		//Number - The width of each segment stroke
		segmentStrokeWidth : 2,

		//The percentage of the chart that we cut out of the middle.
		percentageInnerCutout : 50,

		//Number - Amount of animation steps
		animationSteps : 100,

		//String - Animation easing effect
		animationEasing : "easeOutBounce",

		//Boolean - Whether we animate the rotation of the Doughnut
		animateRotate : true,

		//Boolean - Whether we animate scaling the Doughnut from the centre
		animateScale : false,

		//String - A legend template
		legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%>
<span style=\"background-color:<%=segments[i].fillColor%>\"><%if(segments[i].label){%><%=segments[i].label%><%}%>
<%}%>
"

	};

	function hue(part, total) {
		// Given the total number of segments (total) and the index of a segment (part) returns a #rrggbb color for the segment
		var h = (part / total) * 360,
			s = 1,
			v = 1,
			c = v * s,
			x =  c * (1 - Math.abs((h / 60) % 2 - 1)),
			m = v - c,
			r,
			g,
			b;

		switch (Math.floor(h / 60)) {
			case 0: // 0 <= h < 60
				r = c + m;
				g = x + m;
				b = 0 + m;
			break;
			case 1: // 60 <= h < 120
				r = x + m;
				g = c + m;
				b = 0 + m;
			break;
			case 2: // 120 <= h < 180
				r = 0 + m;
				g = c + m;
				b = x + m;
			break;
			case 3: // 180 <= h < 240
				r = 0 + m;
				g = x + m;
				b = c + m;
			break;
			case 4: // 240 <= h < 300
				r = x + m;
				g = 0 + m;
				b = c + m;
			break;
			case 5: // 300 <= h < 360
				r = c + m;
				g = 0 + m;
				b = x + m;
			break;
		}

		r = '00' + Math.round(r * 255).toString(16);
		g = '00' + Math.round(g * 255).toString(16);
		b = '00' + Math.round(b * 255).toString(16);

		return '#' + r.substr(r.length - 2) + g.substr(g.length - 2) + b.substr(b.length - 2);
	}

	Chart.Type.extend({
		//Passing in a name registers this chart in the Chart namespace
		name: "Doughnut",
		//Providing a defaults will also register the deafults in the chart namespace
		defaults : defaultConfig,
		//Initialize is fired when the chart is initialized - Data is passed in as a parameter
		//Config is automatically merged by the core of Chart.js, and is available at this.options
		initialize:  function(data){

			//Declare segments as a static property to prevent inheriting across the Chart type prototype
			this.segments = [];
			this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) -	this.options.segmentStrokeWidth/2)/2;

			this.SegmentArc = Chart.Arc.extend({
				ctx : this.chart.ctx,
				x : this.chart.width/2,
				y : this.chart.height/2
			});

			//Set up tooltip events on the chart
			if (this.options.showTooltips){
				helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
					var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];

					helpers.each(this.segments,function(segment){
						segment.restore(["fillColor"]);
					});
					helpers.each(activeSegments,function(activeSegment){
						activeSegment.fillColor = activeSegment.highlightColor;
					});
					this.showTooltip(activeSegments);
				});
			}
			this.calculateTotal(data);

			data = data.map(function (v, i, a){
				if (!v.color) {
					v.color = hue(i, a.length);
					return v;
				}
			});

			helpers.each(data,function(datapoint, index){
				this.addData(datapoint, index, true);
			},this);

			this.render();
		},
		getSegmentsAtEvent : function(e){
			var segmentsArray = [];

			var location = helpers.getRelativePosition(e);

			helpers.each(this.segments,function(segment){
				if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
			},this);
			return segmentsArray;
		},
		addData : function(segment, atIndex, silent){
			var index = atIndex || this.segments.length;
			this.segments.splice(index, 0, new this.SegmentArc({
				value : segment.value,
				outerRadius : (this.options.animateScale) ? 0 : this.outerRadius,
				innerRadius : (this.options.animateScale) ? 0 : (this.outerRadius/100) * this.options.percentageInnerCutout,
				fillColor : segment.color || hue(index, this.segments.length),
				highlightColor : segment.highlight || segment.color,
				showStroke : this.options.segmentShowStroke,
				strokeWidth : this.options.segmentStrokeWidth,
				strokeColor : this.options.segmentStrokeColor,
				startAngle : Math.PI * 1.5,
				circumference : (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value),
				label : segment.label
			}));
			if (!silent){
				this.reflow();
				this.update();
			}
		},
		calculateCircumference : function(value){
			return (Math.PI*2)*(value / this.total);
		},
		calculateTotal : function(data){
			this.total = 0;
			helpers.each(data,function(segment){
				this.total += segment.value;
			},this);
		},
		update : function(){
			this.calculateTotal(this.segments);

			// Reset any highlight colours before updating.
			helpers.each(this.activeElements, function(activeElement){
				activeElement.restore(['fillColor']);
			});

			helpers.each(this.segments,function(segment){
				segment.save();
			});
			this.render();
		},

		removeData: function(atIndex){
			var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
			this.segments.splice(indexToDelete, 1);
			this.reflow();
			this.update();
		},

		reflow : function(){
			helpers.extend(this.SegmentArc.prototype,{
				x : this.chart.width/2,
				y : this.chart.height/2
			});
			this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) -	this.options.segmentStrokeWidth/2)/2;
			helpers.each(this.segments, function(segment){
				segment.update({
					outerRadius : this.outerRadius,
					innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
				});
			}, this);
		},
		draw : function(easeDecimal){
			var animDecimal = (easeDecimal) ? easeDecimal : 1;
			this.clear();
			helpers.each(this.segments,function(segment,index){
				segment.transition({
					circumference : this.calculateCircumference(segment.value),
					outerRadius : this.outerRadius,
					innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
				},animDecimal);

				segment.endAngle = segment.startAngle + segment.circumference;

				segment.draw();
				if (index === 0){
					segment.startAngle = Math.PI * 1.5;
				}
				//Check to see if it's the last segment, if not get the next and update the start angle
				if (index < this.segments.length-1){
					this.segments[index+1].startAngle = segment.endAngle;
				}
			},this);

		}
	});

	Chart.types.Doughnut.extend({
		name : "Pie",
		defaults : helpers.merge(defaultConfig,{percentageInnerCutout : 0})
	});

}).call(this);
<commit_msg>Update Chart.Doughnut.js<commit_after>(function(){
	"use strict";

	var root = this,
		Chart = root.Chart,
		//Cache a local reference to Chart.helpers
		helpers = Chart.helpers;

	var defaultConfig = {
		//Boolean - Whether we should show a stroke on each segment
		segmentShowStroke : true,

		//String - The colour of each segment stroke
		segmentStrokeColor : "#fff",

		//Number - The width of each segment stroke
		segmentStrokeWidth : 2,

		//The percentage of the chart that we cut out of the middle.
		percentageInnerCutout : 50,

		//Number - Amount of animation steps
		animationSteps : 100,

		//String - Animation easing effect
		animationEasing : "easeOutBounce",

		//Boolean - Whether we animate the rotation of the Doughnut
		animateRotate : true,

		//Boolean - Whether we animate scaling the Doughnut from the centre
		animateScale : false,

		//String - A legend template
		legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%>
<span style=\"background-color:<%=segments[i].fillColor%>\"><%if(segments[i].label){%><%=segments[i].label%><%}%>
<%}%>
"

	};

	function hue(part, total) {
		// Given the total number of segments (total) and the index of a segment (part) returns a #rrggbb color for the segment
		var h = (part / total) * 360,
			s = 1,
			v = 1,
			c = v * s,
			x =  c * (1 - Math.abs((h / 60) % 2 - 1)),
			m = v - c,
			r,
			g,
			b;

		switch (Math.floor(h / 60)) {
			case 0: // 0 <= h < 60
				r = c + m;
				g = x + m;
				b = 0 + m;
			break;
			case 1: // 60 <= h < 120
				r = x + m;
				g = c + m;
				b = 0 + m;
			break;
			case 2: // 120 <= h < 180
				r = 0 + m;
				g = c + m;
				b = x + m;
			break;
			case 3: // 180 <= h < 240
				r = 0 + m;
				g = x + m;
				b = c + m;
			break;
			case 4: // 240 <= h < 300
				r = x + m;
				g = 0 + m;
				b = c + m;
			break;
			case 5: // 300 <= h < 360
				r = c + m;
				g = 0 + m;
				b = x + m;
			break;
		}

		r = '00' + Math.round(r * 255).toString(16);
		g = '00' + Math.round(g * 255).toString(16);
		b = '00' + Math.round(b * 255).toString(16);

		return '#' + r.substr(r.length - 2) + g.substr(g.length - 2) + b.substr(b.length - 2);
	}

	Chart.Type.extend({
		//Passing in a name registers this chart in the Chart namespace
		name: "Doughnut",
		//Providing a defaults will also register the deafults in the chart namespace
		defaults : defaultConfig,
		//Initialize is fired when the chart is initialized - Data is passed in as a parameter
		//Config is automatically merged by the core of Chart.js, and is available at this.options
		initialize:  function(data){

			//Declare segments as a static property to prevent inheriting across the Chart type prototype
			this.segments = [];
			this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) -	this.options.segmentStrokeWidth/2)/2;

			this.SegmentArc = Chart.Arc.extend({
				ctx : this.chart.ctx,
				x : this.chart.width/2,
				y : this.chart.height/2
			});

			//Set up tooltip events on the chart
			if (this.options.showTooltips){
				helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
					var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];

					helpers.each(this.segments,function(segment){
						segment.restore(["fillColor"]);
					});
					helpers.each(activeSegments,function(activeSegment){
						activeSegment.fillColor = activeSegment.highlightColor;
					});
					this.showTooltip(activeSegments);
				});
			}
			this.calculateTotal(data);

			data = data.map(function (v, i, a){
				if (!v.color) {
					v.color = hue(i, a.length);
					return v;
				}
			});

			helpers.each(data,function(datapoint, index){
				this.addData(datapoint, index, true);
			},this);

			this.render();
		},
		getSegmentsAtEvent : function(e){
			var segmentsArray = [];

			var location = helpers.getRelativePosition(e);

			helpers.each(this.segments,function(segment){
				if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
			},this);
			return segmentsArray;
		},
		addData : function(segment, atIndex, silent){
			var index = atIndex || this.segments.length;
			this.segments.splice(index, 0, new this.SegmentArc({
				value : segment.value,
				outerRadius : (this.options.animateScale) ? 0 : this.outerRadius,
				innerRadius : (this.options.animateScale) ? 0 : (this.outerRadius/100) * this.options.percentageInnerCutout,
				fillColor : segment.color,
				highlightColor : segment.highlight || segment.color,
				showStroke : this.options.segmentShowStroke,
				strokeWidth : this.options.segmentStrokeWidth,
				strokeColor : this.options.segmentStrokeColor,
				startAngle : Math.PI * 1.5,
				circumference : (this.options.animateRotate) ? 0 : this.calculateCircumference(segment.value),
				label : segment.label
			}));
			if (!silent){
				this.reflow();
				this.update();
			}
		},
		calculateCircumference : function(value){
			return (Math.PI*2)*(value / this.total);
		},
		calculateTotal : function(data){
			this.total = 0;
			helpers.each(data,function(segment){
				this.total += segment.value;
			},this);
		},
		update : function(){
			this.calculateTotal(this.segments);

			// Reset any highlight colours before updating.
			helpers.each(this.activeElements, function(activeElement){
				activeElement.restore(['fillColor']);
			});

			helpers.each(this.segments,function(segment){
				segment.save();
			});
			this.render();
		},

		removeData: function(atIndex){
			var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
			this.segments.splice(indexToDelete, 1);
			this.reflow();
			this.update();
		},

		reflow : function(){
			helpers.extend(this.SegmentArc.prototype,{
				x : this.chart.width/2,
				y : this.chart.height/2
			});
			this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) -	this.options.segmentStrokeWidth/2)/2;
			helpers.each(this.segments, function(segment){
				segment.update({
					outerRadius : this.outerRadius,
					innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
				});
			}, this);
		},
		draw : function(easeDecimal){
			var animDecimal = (easeDecimal) ? easeDecimal : 1;
			this.clear();
			helpers.each(this.segments,function(segment,index){
				segment.transition({
					circumference : this.calculateCircumference(segment.value),
					outerRadius : this.outerRadius,
					innerRadius : (this.outerRadius/100) * this.options.percentageInnerCutout
				},animDecimal);

				segment.endAngle = segment.startAngle + segment.circumference;

				segment.draw();
				if (index === 0){
					segment.startAngle = Math.PI * 1.5;
				}
				//Check to see if it's the last segment, if not get the next and update the start angle
				if (index < this.segments.length-1){
					this.segments[index+1].startAngle = segment.endAngle;
				}
			},this);

		}
	});

	Chart.types.Doughnut.extend({
		name : "Pie",
		defaults : helpers.merge(defaultConfig,{percentageInnerCutout : 0})
	});

}).call(this);
<|endoftext|>


<commit_before>/**
 * @file This file is an importable module to handle neural (web) worker body by worker proxy.
 *
 */

import * as WorkerProxy from "./WorkerProxy.js";
//import * as ValueMax from "../ValueMax.js";
//import * as Net from "./Net.js";

export { Base };

/**
 * The container of WorkerProxy. It orchestrates these WorkerProxy. Especially, it transfers (scaled) source image data to and from
 * web worker. This could maximize parallel computing under the restriction transferring source image data to every web worker serially.
 *
 * Every worker handles one neural network. When processTensor() is called, the input (usually a large memory block)
 * will be transffered to the 1st worker to start computing, and then transffered to the 2nd worker to start computing, ... etc.
 *
 * When passing large data by Worker.postMessage(), it is preferred by transferring (not by copying). If the large data wants to be
 * transferred (not copied) to many workers, the only possible way is to transferring them serially.
 *
 * However, serially transferring hurts the performance. Workers are better to compute parallelly. So every worker should transfer the
 * (possible scaled) source image data back to this WorkerController, and keep computing neural network at the same. And then, this
 * WorkerController will transfer the source image data to the next worker as soon as possible.
 *
 * Finally, this WorkerController collects all web workers' processTensor() results in a promise. The promise will resolve with an array
 * of typed-array. Every typed-array is the output of one neural network.
 */
class Base {

  /**
   * Initialize this worker controller. It will create two web workers and inform them to create a neural network per worker.
   *
   * @param {string} tensorflowJsURL
   *   The URL of tensorflow javascript library. Every worker will load the library from the URL.
   *
   * @param {Net.Config} neuralNetConfig
   *   The configuration of the neural network which will be created by this web worker.
   *
   * @param {string} weightsURL
   *   The URL of neural network weights. Every worker will load weights from the URL to initialize one neural network.
   *
!!! game_object_id_array.length as totalWorkerCount.
!!! Handle game object created and destroyed. Create and destroy web worker in needed.

   * @param {number[]} game_object_id_array
   *   The id for game objects.
   */
  init(
      tensorflowJsURL,
      neuralNetConfig, totalWorkerCount, weightsURL
//      game_object_id_array
  ) {

    this.tensorflowJsURL = tensorflowJsURL;
    this.neuralNetConfig = neuralNetConfig;
    this.weightsURL = weightsURL;

    this.processingId = -1; // The current processing id. Negative means processTensor() has not been called. Every processTensor() call will use a new id.

    this.hardwareConcurrency = navigator.hardwareConcurrency; // logical CPU count.

//!!! ...unfinished... According to logical CPU count, create so many web worker.
//!!! ...unfinished... Perhaps, two web workers are sufficient.
    // Our neural networks are learning by differential evolution. Differential evolution evaluates just two entities every time.
    // The output of one neural network will contain action signals of all game obejcts. However, only half of the output will be used
    // because one neural network only control one alignment of the game world.

    this.initProgressAll = new WorkerProxy.InitProgressAll(); // Statistics of progress of all workers' initialization.

    this.workerProxyArray = new Array( totalWorkerCount );
    for ( let i = 0; i < totalWorkerCount; ++i ) {
      let initProgress = this.initProgressAll.childrren[ i ];
      let workerProxy = this.workerProxyArray[ i ] = new WorkerProxy.Base();
      workerProxy.init( i, tensorflowJsURL, neuralNetConfig, weightsURL, initProgress );
    }

    this.processTensorPromiseArray = new Array( totalWorkerCount ); // Pre-allocation for reducing re-allocation.
  }

  /**
   *
   */
  disposeWorkers() {
    if ( this.workerProxyArray ) {
      for ( let i = 0; i < this.workerProxyArray.length; ++i ) {
        this.workerProxyArray[ i ].disposeWorker();
      }
      this.workerProxyArray = null;
    }

    this.initProgressAll = null;
  }

  /**
   * Download image data from source canvas. Pass source image data to every web worker serially by transferring.
   *
   * @param {HTMLCanvasElement} sourceCanvas
   *   The source canvas to be processed. Its shape [ height, width, channel ] should be the same as the size which is used when
   * training the neural network.
   *
   * @return {Promise}
   *   Return a promise which will be resolved when all worker processing promises of the same processingId are resolved. The promise
   * resolves with an array of typed-array. Every typed-array comes from the output tensor of one worker's neural network.
   */
  async processCanvas_Async_ByTransfer( sourceCanvas ) {
    let ctx = sourceCanvas.getContext( '2d' );
    let sourceImageData = ctx.getImageData( 0, 0, sourceCanvas.width, sourceCanvas.height );
    return this.processImageData_Async_ByTransfer( sourceImageData );
  }

  /**
   * Pass source image data to every web worker serially by transferring.
   *
   * @param {ImageData} sourceImageData
   *   The source image data to be processed. Its shape [ height, width, channel ] should be the same as the size which is used when
   * training the neural network.
   *
   * @return {Promise}
   *   Return a promise which will be resolved when all worker processing promises of the same processingId are resolved. The promise
   * resolves with an array of typed-array. Every typed-array comes from the output tensor of one worker's neural network.
   */
  async processImageData_Async_ByTransfer( sourceImageData ) {

    let processingId = ++this.processingId; // Generate a new processing id so that the result returned from worker could be distinguished.

    let workerProxy, processRelayPromises, sourceTypedArray;

    // For first (i == 0) web worker, passing source ImageData.
    workerProxy = this.workerProxyArray[ 0 ];
    this.processTensorPromiseArray[ 0 ] = workerProxy.imageData_transferBack_processTensor_async( processingId, sourceImageData );
    // Now, sourceImageData.data.buffer has become invalid because it is transferred (not copied) to the above web worker.

    // For all other (i >= 1) web workers, passing scaled source typed-array.
    for ( let i = 1; i < this.workerProxyArray.length; ++i ) {

      // Wait the previous web worker transferring back the scaled source typed-array. (after it has been copied into a new tensor inside the web worker).
      processRelayPromises = workerProxy.processRelayPromisesMap.get( processingId );
      sourceTypedArray = await processRelayPromises.relay.promise;

      workerProxy = this.workerProxyArray[ i ];
      this.processTensorPromiseArray[ i ] = workerProxy.typedArray_transferBack_processTensor_async( processingId, sourceTypedArray );
      // Now, sourceTypedArray.buffer has become invalid because it is transferred (not copied) to the above web worker.
    }

    // Note: Array push() is faster than unshift(), and unshift() is faster than concat().

    // Since all web worker has received the source image data (although serially), wait for all them done.
    let promiseAllSettled = Promise.allSettled( this.processTensorPromiseArray );
    return promiseAllSettled;
  }

  /**
   * Download image data from source canvas, convert to tensor, scale, pass source image data to every web worker parallelly by copying.
   *
   * The tensorflow.js library should have been loaded so that the source image scaling could be done here (not in web worker).
   *
   * @param {HTMLCanvasElement} sourceCanvas
   *   The source canvas to be processed. Its shape [ height, width, channel ] should be the same as the size which is used when
   * training the neural network.
   *
   * @return {Promise}
   *   Return a promise which will be resolved when all worker processing promises of the same processingId are resolved. The promise
   * resolves with an array of typed-array. Every typed-array comes from the output tensor of one worker's neural network.
   */
  async processCanvas_Async_ByCopy( sourceCanvas ) {

    // Create (scaled) source tensor so that every web worker needs not scale again and easier to re-create source tensor.
    //
    // The drawback is that the tensorflow.js library should have been loaded here. And the image scaling is done here (not in web worker).
    let scaledSourceTensor = this.neuralNetConfig.create_ScaledSourceTensor_from_ImageData_or_Canvas( sourceCanvas );
    let scaledSourceTypedArray = await scaledSourceTensor.data();
    scaledSourceTensor.dispose(); // Discard the source tensor because type-array (not tensor) will be past to web worker

//!!! ...unfinished...
    let processingId = ++this.processingId; // Generate a new processing id so that the result returned from worker could be distinguished.

//!!! ...unfinished...

    let workerProxy, processRelayPromises, sourceTypedArray;

    // For first (i == 0) web worker, passing source ImageData.
    workerProxy = this.workerProxyArray[ 0 ];
    this.processTensorPromiseArray[ 0 ] = workerProxy.processImageDataAsync( processingId, sourceImageData );
    // Now, sourceImageData.data.buffer has become invalid because it is transferred (not copied) to the above web worker.

    // For all other (i >= 1) web workers, passing scaled source typed-array.
    for ( let i = 1; i < this.workerProxyArray.length; ++i ) {

      // Wait the previous web worker transferring back the scaled source typed-array. (after it has been copied into a new tensor inside the web worker).
      processRelayPromises = workerProxy.processRelayPromisesMap.get( processingId );
      sourceTypedArray = await processRelayPromises.relay.promise;

      workerProxy = this.workerProxyArray[ i ];
      this.processTensorPromiseArray[ i ] = workerProxy.processTypedArrayAsync( processingId, sourceTypedArray );
      // Now, sourceTypedArray.buffer has become invalid because it is transferred (not copied) to the above web worker.
    }

    // Note: Array push() is faster than unshift(), and unshift() is faster than concat().

    // Since all web worker has received the source image data (although serially), wait for all them done.
    let promiseAllSettled = Promise.allSettled( this.processTensorPromiseArray );
    return promiseAllSettled;
  }

}
<commit_msg>Update WorkerController.js<commit_after>/**
 * @file This file is an importable module to handle neural (web) worker body by worker proxy.
 *
 */

import * as WorkerProxy from "./WorkerProxy.js";
//import * as ValueMax from "../ValueMax.js";
//import * as Net from "./Net.js";

export { Base };

/**
 * The container of WorkerProxy. It orchestrates these WorkerProxy. Especially, it transfers (scaled) source image data to and from
 * web worker. This could maximize parallel computing under the restriction transferring source image data to every web worker serially.
 *
 * Every worker handles one neural network. When processTensor() is called, the input (usually a large memory block)
 * will be transffered to the 1st worker to start computing, and then transffered to the 2nd worker to start computing, ... etc.
 *
 * When passing large data by Worker.postMessage(), it is preferred by transferring (not by copying). If the large data wants to be
 * transferred (not copied) to many workers, the only possible way is to transferring them serially.
 *
 * However, serially transferring hurts the performance. Workers are better to compute parallelly. So every worker should transfer the
 * (possible scaled) source image data back to this WorkerController, and keep computing neural network at the same. And then, this
 * WorkerController will transfer the source image data to the next worker as soon as possible.
 *
 * Finally, this WorkerController collects all web workers' processTensor() results in a promise. The promise will resolve with an array
 * of typed-array. Every typed-array is the output of one neural network.
 */
class Base {

  /**
   * Initialize this worker controller. It will create two web workers and inform them to create a neural network per worker.
   *
   * @param {string} tensorflowJsURL
   *   The URL of tensorflow javascript library. Every worker will load the library from the URL.
   *
   * @param {Net.Config} neuralNetConfig
   *   The configuration of the neural network which will be created by this web worker.
   *
   * @param {string} weightsURL
   *   The URL of neural network weights. Every worker will load weights from the URL to initialize one neural network.
   *
!!! game_object_id_array.length as totalWorkerCount.
!!! Handle game object created and destroyed. Create and destroy web worker in needed.

   * @param {number[]} game_object_id_array
   *   The id for game objects.
   */
  init(
      tensorflowJsURL,
      neuralNetConfig, totalWorkerCount, weightsURL
//      game_object_id_array
  ) {

    this.tensorflowJsURL = tensorflowJsURL;
    this.neuralNetConfig = neuralNetConfig;
    this.weightsURL = weightsURL;

    this.processingId = -1; // The current processing id. Negative means processTensor() has not been called. Every processTensor() call will use a new id.

    this.hardwareConcurrency = navigator.hardwareConcurrency; // logical CPU count.

//!!! ...unfinished... According to logical CPU count, create so many web worker.
//!!! ...unfinished... Perhaps, two web workers are sufficient.
    // Our neural networks are learning by differential evolution. Differential evolution evaluates just two entities every time.
    // The output of one neural network will contain action signals of all game obejcts. However, only half of the output will be used
    // because one neural network only control one alignment of the game world.

    this.initProgressAll = new WorkerProxy.InitProgressAll(); // Statistics of progress of all workers' initialization.

    this.workerProxyArray = new Array( totalWorkerCount );
    for ( let i = 0; i < totalWorkerCount; ++i ) {
      let initProgress = this.initProgressAll.childrren[ i ];
      let workerProxy = this.workerProxyArray[ i ] = new WorkerProxy.Base();
      workerProxy.init( i, tensorflowJsURL, neuralNetConfig, weightsURL, initProgress );
    }

    this.processTensorPromiseArray = new Array( totalWorkerCount ); // Pre-allocation for reducing re-allocation.
  }

  /**
   *
   */
  disposeWorkers() {
    if ( this.workerProxyArray ) {
      for ( let i = 0; i < this.workerProxyArray.length; ++i ) {
        this.workerProxyArray[ i ].disposeWorker();
      }
      this.workerProxyArray = null;
    }

    this.initProgressAll = null;
  }

  /**
   * Download image data from source canvas. Pass source image data to every web worker serially by transferring.
   *
   * @param {HTMLCanvasElement} sourceCanvas
   *   The source canvas to be processed. Its shape [ height, width, channel ] should be the same as the size which is used when
   * training the neural network.
   *
   * @return {Promise}
   *   Return a promise which will be resolved when all worker processing promises of the same processingId are resolved. The promise
   * resolves with an array of typed-array. Every typed-array comes from the output tensor of one worker's neural network.
   */
  async processCanvas_Async_ByTransfer( sourceCanvas ) {
    let ctx = sourceCanvas.getContext( '2d' );
    let sourceImageData = ctx.getImageData( 0, 0, sourceCanvas.width, sourceCanvas.height );
    return this.processImageData_Async_ByTransfer( sourceImageData );
  }

  /**
   * Pass source image data to every web worker serially by transferring.
   *
   * @param {ImageData} sourceImageData
   *   The source image data to be processed. Its shape [ height, width, channel ] should be the same as the size which is used when
   * training the neural network.
   *
   * @return {Promise}
   *   Return a promise which will be resolved when all worker processing promises of the same processingId are resolved. The promise
   * resolves with an array of typed-array. Every typed-array comes from the output tensor of one worker's neural network.
   */
  async processImageData_Async_ByTransfer( sourceImageData ) {

    let processingId = ++this.processingId; // Generate a new processing id so that the result returned from worker could be distinguished.

    let workerProxy, processRelayPromises, sourceTypedArray;

    // For first (i == 0) web worker, passing source ImageData.
    workerProxy = this.workerProxyArray[ 0 ];
    this.processTensorPromiseArray[ 0 ] = workerProxy.imageData_transferBack_processTensor_async( processingId, sourceImageData );
    // Now, sourceImageData.data.buffer has become invalid because it is transferred (not copied) to the above web worker.

    // For all other (i >= 1) web workers, passing scaled source typed-array.
    for ( let i = 1; i < this.workerProxyArray.length; ++i ) {

      // Wait the previous web worker transferring back the scaled source typed-array. (after it has been copied into a new tensor inside the web worker).
      processRelayPromises = workerProxy.processRelayPromisesMap.get( processingId );
      sourceTypedArray = await processRelayPromises.relay.promise;

      workerProxy = this.workerProxyArray[ i ];
      this.processTensorPromiseArray[ i ] = workerProxy.typedArray_transferBack_processTensor_async( processingId, sourceTypedArray );
      // Now, sourceTypedArray.buffer has become invalid because it is transferred (not copied) to the above web worker.
    }

    // Note: Array push() is faster than unshift(), and unshift() is faster than concat().

    // Since all web worker has received the source image data (although serially), wait for all them done.
    let promiseAllSettled = Promise.allSettled( this.processTensorPromiseArray );
    return promiseAllSettled;
  }

  /**
   * Download image data from source canvas, convert to tensor, scale, pass source image data to every web worker parallelly by copying.
   *
   * The tensorflow.js library should have been loaded so that the source image scaling could be done here (not in web worker).
   *
   * @param {HTMLCanvasElement} sourceCanvas
   *   The source canvas to be processed. Its shape [ height, width, channel ] should be the same as the size which is used when
   * training the neural network.
   *
   * @return {Promise}
   *   Return a promise which will be resolved when all worker processing promises of the same processingId are resolved. The promise
   * resolves with an array of typed-array. Every typed-array comes from the output tensor of one worker's neural network.
   */
  async processCanvas_Async_ByCopy( sourceCanvas ) {

    // Create (scaled) source tensor so that every web worker needs not scale again and easier to re-create source tensor.
    //
    // The drawback is that the tensorflow.js library should have been loaded here. And the image scaling is done here (not in web worker).
    let scaledSourceTensor = this.neuralNetConfig.create_ScaledSourceTensor_from_ImageData_or_Canvas( sourceCanvas );
    let sourceTypedArray = await scaledSourceTensor.data();
    scaledSourceTensor.dispose(); // Discard the source tensor because type-array (not tensor) will be past to web worker

    let processingId = ++this.processingId; // Generate a new processing id so that the result returned from worker could be distinguished.

    let workerProxy, processRelayPromises;

    for ( let i = 0; i < this.workerProxyArray.length; ++i ) {
      workerProxy = this.workerProxyArray[ i ];
      this.processTensorPromiseArray[ i ] = workerProxy.typedArray_processTensor_async( processingId, sourceTypedArray );
      // The sourceTypedArray is still valid here because it is copied (not transferred) to the above web worker.
    }

    // Since all web worker has received the source typed-array (parallelly), wait for all them done.
    let promiseAllSettled = Promise.allSettled( this.processTensorPromiseArray );
    return promiseAllSettled;
  }

}
<|endoftext|>


<commit_before>!function(w){
  let thumbnailElements = [];
  let spacingX; // the distance to space eachElement
  let dimX;     //the actual width of the elements, they're all treated as though they are this, even if it is not true, users should supply equally sized elements for best experience
  let dimY;     //height of the elements.
  let offset; //current position?
  let _root;
  let count; // number of elemnts to show
  let xform;
  let shift; // Distance away from centre to show non-centered element
  let dist; // how far back (z-axis) to move non-centred elements
  let angle;
  let target;
  let backgroundScale;
  let timeConstant;

  w.coverflowPreview = function coverflowPreview(rootElement, opts){
    _root = rootElement;
    _root.style.position='relative';
    for(let e of opts.thumbnails){
      thumbnailElements.push(e);
      e.style.position = 'absolute';
      rootElement.appendChild(e);
    }
    count = thumbnailElements.length;
    spacingX = 125;
    dimX = 175;
    dimY = 300;
    dist = -100;
    shift = spacingX/2;
    angle = -60;
    offset = target = 0;
    backgroundScale = 0.65;
    timeConstant = 250; //ms
    scroll(0);
    autoScroll();

    var mc = new Hammer.Manager(_root);
    mc.add(new Hammer.Pan({threshold: 0, pointers: 0}));
    mc.add(new Hammer.Swipe({direction:Hammer.DIRECTION_HORIZONTAL}).recognizeWith(mc.get('pan')))
    mc.on("panstart", onPanStart);
    mc.on("panmove", onPan);
    mc.on("panend swipe", onRelease);

    window.addEventListener("resize",onResize);
  };

  let panStartPos;
  function onPanStart(ev){
      panStartPos = offset;
      onPan(ev);
  }

  function onPan(ev){
    amplitude=0;
    if(panStartPos !== undefined && ev.deltaX){
      scroll(panStartPos-ev.deltaX); //when panning positively (thumb motion right), the images need to move right, which move the focus left.
    }
  }

  function onResize(ev){
    scroll(offset);
  }

  let beginAutoTime;
  let amplitude;
  let autoReqId;
  function onRelease(ev){
    target = offset;
    let velocity=  ev.velocityX * 100;
    if(velocity > 10 || velocity < -10){
      target = offset - 0.9 * velocity
    }
    let targetIndex = Math.round(target/spacingX);
    targetIndex = targetIndex < 0 ? 0 : targetIndex;
    targetIndex = targetIndex >= count ? count -1 : targetIndex;

    target = targetIndex * spacingX;
    amplitude = target-offset;
    beginAutoTime = Date.now();
    if(autoReqId){
      window.cancelAnimationFrame(autoReqId);
    }
    autoReqId = window.requestAnimationFrame(autoScroll);
  }

  function autoScroll(){
    autoReqId = undefined;
    let elapsed, delta;
    if(amplitude){
      elapsed = Date.now() - beginAutoTime;
      let adjust =  0.008; //adjust the exponential decay function by subtracting this from it so it reaches 0
                           //It is also then multiplied so that it still has a y-intercept of 1
      delta = amplitude *  (Math.exp( -elapsed / timeConstant) - adjust)/(1-adjust);
      if(delta * amplitude > 0) {
        scroll(target-delta);
        window.requestAnimationFrame(autoScroll);
      }else{
        scroll(target);
      }
    }
  }

  let rafRequestId;
  function scroll(x){
    //limits
    let maxOffset = spacingX * (count - 1) + spacingX/2 - 1;
    let minOffset = -spacingX/2 + 1;

    offset = (typeof x === 'number') ? x : offset; //move to x
    offset = offset > maxOffset ? maxOffset : offset;
    offset = offset < minOffset ? minOffset : offset;
    if(rafRequestId){
      window.cancelAnimationFrame(rafRequestId);
    }
    rafRequestId = window.requestAnimationFrame(animateScroll);
  }

  function animateScroll(){
    rafRequestId = undefined;
    let center = Math.floor((offset + spacingX / 2) / spacingX); //the image to show at the centre;
    let delta = offset - center * spacingX; //how close to the centred the cental element is
    let dir = (delta < 0) ? 1 : -1; //moving left or right? (left=positive)
    let tween = -dir * delta / spacingX; //proportion between properly centered and fully rotated to show central element

    //basic centering of everything
    var alignment = 'translateX(' + (parseInt(_root.clientWidth) - dimX) / 2 + 'px) ';
    alignment += 'translateY(' + (parseInt(_root.clientHeight) - dimY) / 2 + 'px)';

    //central element
    let el = thumbnailElements[center];
    el.style[xform] = alignment +
      ' translateX(' + (-delta / 2) + 'px)' + //account for off-centre
      ' translateX(' + (dir * shift * tween) + 'px)' + //partial shift from center
      ' translateZ(' + (dist * tween) + 'px)' + //partial going backwards
      ' rotateY(' + (dir * angle * tween) + 'deg)' + //partial rotation
      ' scale(' + (1 - (1-backgroundScale)*tween ) + ')';
    el.style.zIndex = 0; //set in front of others
    el.style.opacity = 1; // set fully visible

    //other elements
    //left
    let i = 1;
    while(center - i >= 0){
      el = thumbnailElements[center - i];
      el.style[xform] = alignment +
        ' translateX(' + (-shift + (-spacingX * i - delta) / 2) + 'px)' +
        ' translateZ(' + dist + 'px)' +
        ' rotateY(' + -angle + 'deg)' +
        ' scale(' + backgroundScale + ')';
        ;
      el.style.zIndex = -i;
      el.style.opacity = 1;

      i++;
    }
    //right
    i = 1;
    while(center + i < count){
      el = thumbnailElements[center + i];
      el.style[xform] = alignment +
        ' translateX(' + (shift + (spacingX * i - delta) / 2) + 'px)' +
        ' translateZ(' + dist + 'px)' +
        ' rotateY(' + angle + 'deg)' +
        ' scale(' + backgroundScale + ')';
      el.style.zIndex = -i;
      i++;
    }
    //redo the slightly off center element, to tween like the centre element
    if(center-dir >= 0 && center-dir < count){
      el = thumbnailElements[center-dir];
      tween = 1 - tween;
      delta = delta + dir * spacingX;
      dir = dir * -1;
      el.style[xform] = alignment +
        ' translateX(' + (-delta / 2) + 'px)' + //account for off-centre
        ' translateX(' + (dir * shift * tween) + 'px)' + //partial shift from center
        ' translateZ(' + (dist * tween) + 'px)' + //partial going backwards
        ' rotateY(' + (dir * angle * tween) + 'deg)' + //partial rotation
        ' scale(' + (1 - (1-backgroundScale)*tween ) + ')';
    }
  }

  xform = 'transform';
  ['','webkit', 'Moz', 'O', 'ms'].every(function (prefix) {
    var e = prefix + 'Transform';
    if (typeof document.body.style[e] !== 'undefined') {
      xform = e;
      return false;
    }
    return true;
  });
}(window);

!function(w){
  let g = [];
  let n = 15;
  for(i=0;i<n;++i){
    var grey = parseInt(i*255/n);
    let e = document.createElement("img");
    e.style.height='300px';
    e.style.width='175px';
    e.style.backgroundColor = `rgba(${grey},${grey},${grey},1)`;
    e.style.border = '1px solid limegreen';
    g.push(e);
  }

  let el = document.getElementById("coverfluent");
  w.coverflowPreview(el,{
    thumbnails:g,
  });
}(window);
<commit_msg>changed let to var (ios)<commit_after>!function(w){
  var thumbnailElements = [];
  var spacingX; // the distance to space eachElement
  var dimX;     //the actual width of the elements, they're all treated as though they are this, even if it is not true, users should supply equally sized elements for best experience
  var dimY;     //height of the elements.
  var offset; //current position?
  var _root;
  var count; // number of elemnts to show
  var xform;
  var shift; // Distance away from centre to show non-centered element
  var dist; // how far back (z-axis) to move non-centred elements
  var angle;
  var target;
  var backgroundScale;
  var timeConstant;

  w.coverflowPreview = function coverflowPreview(rootElement, opts){
    _root = rootElement;
    _root.style.position='relative';
    for(var e of opts.thumbnails){
      thumbnailElements.push(e);
      e.style.position = 'absolute';
      rootElement.appendChild(e);
    }
    count = thumbnailElements.length;
    spacingX = 125;
    dimX = 175;
    dimY = 300;
    dist = -100;
    shift = spacingX/2;
    angle = -60;
    offset = target = 0;
    backgroundScale = 0.65;
    timeConstant = 250; //ms
    scroll(0);
    autoScroll();

    var mc = new Hammer.Manager(_root);
    mc.add(new Hammer.Pan({threshold: 0, pointers: 0}));
    mc.add(new Hammer.Swipe({direction:Hammer.DIRECTION_HORIZONTAL}).recognizeWith(mc.get('pan')))
    mc.on("panstart", onPanStart);
    mc.on("panmove", onPan);
    mc.on("panend swipe", onRelease);

    window.addEventListener("resize",onResize);
  };

  var panStartPos;
  function onPanStart(ev){
      panStartPos = offset;
      onPan(ev);
  }

  function onPan(ev){
    amplitude=0;
    if(panStartPos !== undefined && ev.deltaX){
      scroll(panStartPos-ev.deltaX); //when panning positively (thumb motion right), the images need to move right, which move the focus left.
    }
  }

  function onResize(ev){
    scroll(offset);
  }

  var beginAutoTime;
  var amplitude;
  var autoReqId;
  function onRelease(ev){
    target = offset;
    var velocity=  ev.velocityX * 100;
    if(velocity > 10 || velocity < -10){
      target = offset - 0.9 * velocity
    }
    var targetIndex = Math.round(target/spacingX);
    targetIndex = targetIndex < 0 ? 0 : targetIndex;
    targetIndex = targetIndex >= count ? count -1 : targetIndex;

    target = targetIndex * spacingX;
    amplitude = target-offset;
    beginAutoTime = Date.now();
    if(autoReqId){
      window.cancelAnimationFrame(autoReqId);
    }
    autoReqId = window.requestAnimationFrame(autoScroll);
  }

  function autoScroll(){
    autoReqId = undefined;
    var elapsed, delta;
    if(amplitude){
      elapsed = Date.now() - beginAutoTime;
      var adjust =  0.008; //adjust the exponential decay function by subtracting this from it so it reaches 0
                           //It is also then multiplied so that it still has a y-intercept of 1
      delta = amplitude *  (Math.exp( -elapsed / timeConstant) - adjust)/(1-adjust);
      if(delta * amplitude > 0) {
        scroll(target-delta);
        window.requestAnimationFrame(autoScroll);
      }else{
        scroll(target);
      }
    }
  }

  var rafRequestId;
  function scroll(x){
    //limits
    var maxOffset = spacingX * (count - 1) + spacingX/2 - 1;
    var minOffset = -spacingX/2 + 1;

    offset = (typeof x === 'number') ? x : offset; //move to x
    offset = offset > maxOffset ? maxOffset : offset;
    offset = offset < minOffset ? minOffset : offset;
    if(rafRequestId){
      window.cancelAnimationFrame(rafRequestId);
    }
    rafRequestId = window.requestAnimationFrame(animateScroll);
  }

  function animateScroll(){
    rafRequestId = undefined;
    var center = Math.floor((offset + spacingX / 2) / spacingX); //the image to show at the centre;
    var delta = offset - center * spacingX; //how close to the centred the cental element is
    var dir = (delta < 0) ? 1 : -1; //moving left or right? (left=positive)
    var tween = -dir * delta / spacingX; //proportion between properly centered and fully rotated to show central element

    //basic centering of everything
    var alignment = 'translateX(' + (parseInt(_root.clientWidth) - dimX) / 2 + 'px) ';
    alignment += 'translateY(' + (parseInt(_root.clientHeight) - dimY) / 2 + 'px)';

    //central element
    var el = thumbnailElements[center];
    el.style[xform] = alignment +
      ' translateX(' + (-delta / 2) + 'px)' + //account for off-centre
      ' translateX(' + (dir * shift * tween) + 'px)' + //partial shift from center
      ' translateZ(' + (dist * tween) + 'px)' + //partial going backwards
      ' rotateY(' + (dir * angle * tween) + 'deg)' + //partial rotation
      ' scale(' + (1 - (1-backgroundScale)*tween ) + ')';
    el.style.zIndex = 0; //set in front of others
    el.style.opacity = 1; // set fully visible

    //other elements
    //left
    var i = 1;
    while(center - i >= 0){
      el = thumbnailElements[center - i];
      el.style[xform] = alignment +
        ' translateX(' + (-shift + (-spacingX * i - delta) / 2) + 'px)' +
        ' translateZ(' + dist + 'px)' +
        ' rotateY(' + -angle + 'deg)' +
        ' scale(' + backgroundScale + ')';
        ;
      el.style.zIndex = -i;
      el.style.opacity = 1;

      i++;
    }
    //right
    i = 1;
    while(center + i < count){
      el = thumbnailElements[center + i];
      el.style[xform] = alignment +
        ' translateX(' + (shift + (spacingX * i - delta) / 2) + 'px)' +
        ' translateZ(' + dist + 'px)' +
        ' rotateY(' + angle + 'deg)' +
        ' scale(' + backgroundScale + ')';
      el.style.zIndex = -i;
      i++;
    }
    //redo the slightly off center element, to tween like the centre element
    if(center-dir >= 0 && center-dir < count){
      el = thumbnailElements[center-dir];
      tween = 1 - tween;
      delta = delta + dir * spacingX;
      dir = dir * -1;
      el.style[xform] = alignment +
        ' translateX(' + (-delta / 2) + 'px)' + //account for off-centre
        ' translateX(' + (dir * shift * tween) + 'px)' + //partial shift from center
        ' translateZ(' + (dist * tween) + 'px)' + //partial going backwards
        ' rotateY(' + (dir * angle * tween) + 'deg)' + //partial rotation
        ' scale(' + (1 - (1-backgroundScale)*tween ) + ')';
    }
  }

  xform = 'transform';
  ['','webkit', 'Moz', 'O', 'ms'].every(function (prefix) {
    var e = prefix + 'Transform';
    if (typeof document.body.style[e] !== 'undefined') {
      xform = e;
      return false;
    }
    return true;
  });
}(window);

!function(w){
  var g = [];
  var n = 15;
  for(i=0;i<n;++i){
    var grey = parseInt(i*255/n);
    var e = document.createElement("img");
    e.style.height='300px';
    e.style.width='175px';
    e.style.backgroundColor = `rgba(${grey},${grey},${grey},1)`;
    e.style.border = '1px solid limegreen';
    g.push(e);
  }

  var el = document.getElementById("coverfluent");
  w.coverflowPreview(el,{
    thumbnails:g,
  });
}(window);
<|endoftext|>


<commit_before>import bootstrap from 'bootstrap';
import axios from 'axios';

<commit_msg>Removed saved defaults from github.<commit_after>
<|endoftext|>


<commit_before>// @flow
import { type Predicate } from "lodash";
import cloneDeep from "lodash/clonedeep";
import sample from "lodash/sample";
import isFunction from "lodash/isfunction";
import assign from "lodash/assign";
import filter from "lodash/filter";
import first from "lodash/first";
import random from "lodash/random";
import sampleSize from "lodash/sampleSize";
import last from "lodash/last";
import some from "lodash/some";

const databaseCollectionStores: WeakMap<
  Database<any>,
  CollectionStore<Object>
> = new WeakMap();

export type DatabaseSchema = {
  +[collectionName: string]: Object
};

export type CollectionStore<M: DatabaseSchema, K: $Keys<M> = $Keys<M>> = {
  [collectionName: K]: $ElementType<M, K> | typeof undefined
};

export type Collection<T> = {
  +uuid: number,
  +factory: DataFactory<T>,
  +records: Record<T>[]
};

export type DataFactory<T> = () => T;

export opaque type RecordId = number;

export type Record<T> = {
  +id: RecordId,
  +data: T
};

export class Database<M: DatabaseSchema = Object> {
  constructor() {
    this.reset();
  }

  all<K: $Keys<M>>(collectionName: K): Record<$ElementType<M, K>>[] {
    const { records } = this.getCollection(collectionName);
    return records;
  }

  belongsTo<K: $Keys<M>>(
    collectionName: K,
    conditions: ?Predicate<$ElementType<M, K>>
  ): () => Record<$ElementType<M, K>> {
    return () => {
      if (conditions) {
        return this.findOne(collectionName, conditions);
      } else {
        return sample(this.all(collectionName));
      }
    };
  }

  create<K: $Keys<M>>(
    collectionName: K,
    size: number = 1,
    factory?: DataFactory<$ElementType<M, K>>
  ): Record<$ElementType<M, K>>[] {
    const dataFactory = factory || this.getCollection(collectionName).factory;
    const records = [];

    for (let index = 0; index < size; index++) {
      const data = dataFactory();
      const record = this.push(collectionName, data);
      records.push(record);
    }

    return records;
  }

  delete<K: $Keys<M>>(
    collectionName: K,
    id: RecordId
  ): Record<$ElementType<M, K>> | null {
    const collection = this.getCollection(collectionName);
    const { records } = collection;
    const record = records.find(record => record.id === id);

    if (record) {
      const index = records.indexOf(record);
      records.splice(index, 1);
      return record;
    } else {
      return null;
    }
  }

  exists<K: $Keys<M>>(collectionName: K): boolean {
    const collectionStore = this.getCollectionStore();
    return !!collectionStore[collectionName];
  }

  find<K: $Keys<M>>(
    collectionName: K,
    conditions: ?Predicate<$ElementType<M, K>>
  ): Record<$ElementType<M, K>>[] {
    const { records } = this.getCollection(collectionName);
    return filter(records, { data: conditions });
  }

  findOne<K: $Keys<M>>(
    collectionName: K,
    conditions: ?Predicate<$ElementType<M, K>>
  ): Record<$ElementType<M, K>> {
    return first(this.find(collectionName, conditions));
  }

  first<K: $Keys<M>>(collectionName: K): Record<$ElementType<M, K>> {
    const { records } = this.getCollection(collectionName);
    return first(records);
  }

  last<K: $Keys<M>>(collectionName: K): Record<$ElementType<M, K>> {
    const { records } = this.getCollection(collectionName);
    return last(records);
  }

  push<K: $Keys<M>>(
    collectionName: K,
    data: $ElementType<M, K>
  ): Record<$ElementType<M, K>> {
    const collection = this.getCollection(collectionName);
    const { uuid, records } = collection;
    const record = {
      id: uuid,
      data
    };

    records.push(record);
    collection.uuid++;

    return record;
  }

  register<K: $Keys<M>>(
    collectionName: K,
    factory: DataFactory<$ElementType<M, K>>
  ) {
    this.getCollectionStore()[collectionName] = {
      uuid: 0,
      records: [],
      factory
    };
  }

  reset() {
    databaseCollectionStores.set(this, new Map());
  }

  update<K: $Keys<M>>(
    collectionName: K,
    id: RecordId,
    data: $Shape<$ElementType<M, K>>
  ): Record<$ElementType<M, K>> {
    const collection = this.getCollection(collectionName);
    const { records } = collection;
    const oldRecord = this.delete(collectionName, id);

    if (oldRecord) {
      const record = {
        ...oldRecord,
        data: {
          ...oldRecord.data,
          ...data
        }
      };
      records.push(record);
      return record;
    } else {
      throw new RecordNotFoundError(collectionName, id);
    }
  }

  getCollectionStore(): CollectionStore<M> {
    const collectionStore = databaseCollectionStores.get(this);
    if (collectionStore) {
      return collectionStore;
    } else {
      throw new Error("This database needs to be initialized.");
    }
  }

  getCollection<K: $Keys<M>>(
    collectionName: K
  ): Collection<$ElementType<M, K>> {
    const collectionStore = this.getCollectionStore();
    const collection = collectionStore[collectionName];
    if (collection) {
      return collection;
    } else {
      throw new CollectionNotFoundError(collectionName);
    }
  }
}

export class CollectionNotFoundError extends Error {
  constructor(collectionName: string) {
    super(`Collection ${collectionName} not found`);
  }
}

export class RecordNotFoundError extends Error {
  constructor(collectionName: string, id: RecordId) {
    super(`Record ${id} not found in collection ${collectionName}`);
  }
}
<commit_msg>fix: remove unused imports<commit_after>// @flow
import { type Predicate } from "lodash";
import sample from "lodash/sample";
import filter from "lodash/filter";
import first from "lodash/first";
import last from "lodash/last";

const databaseCollectionStores: WeakMap<
  Database<any>,
  CollectionStore<Object>
> = new WeakMap();

export type DatabaseSchema = {
  +[collectionName: string]: Object
};

export type CollectionStore<M: DatabaseSchema, K: $Keys<M> = $Keys<M>> = {
  [collectionName: K]: $ElementType<M, K> | typeof undefined
};

export type Collection<T> = {
  +uuid: number,
  +factory: DataFactory<T>,
  +records: Record<T>[]
};

export type DataFactory<T> = () => T;

export opaque type RecordId = number;

export type Record<T> = {
  +id: RecordId,
  +data: T
};

export class Database<M: DatabaseSchema = Object> {
  constructor() {
    this.reset();
  }

  all<K: $Keys<M>>(collectionName: K): Record<$ElementType<M, K>>[] {
    const { records } = this.getCollection(collectionName);
    return records;
  }

  belongsTo<K: $Keys<M>>(
    collectionName: K,
    conditions: ?Predicate<$ElementType<M, K>>
  ): () => Record<$ElementType<M, K>> {
    return () => {
      if (conditions) {
        return this.findOne(collectionName, conditions);
      } else {
        return sample(this.all(collectionName));
      }
    };
  }

  create<K: $Keys<M>>(
    collectionName: K,
    size: number = 1,
    factory?: DataFactory<$ElementType<M, K>>
  ): Record<$ElementType<M, K>>[] {
    const dataFactory = factory || this.getCollection(collectionName).factory;
    const records = [];

    for (let index = 0; index < size; index++) {
      const data = dataFactory();
      const record = this.push(collectionName, data);
      records.push(record);
    }

    return records;
  }

  delete<K: $Keys<M>>(
    collectionName: K,
    id: RecordId
  ): Record<$ElementType<M, K>> | null {
    const collection = this.getCollection(collectionName);
    const { records } = collection;
    const record = records.find(record => record.id === id);

    if (record) {
      const index = records.indexOf(record);
      records.splice(index, 1);
      return record;
    } else {
      return null;
    }
  }

  exists<K: $Keys<M>>(collectionName: K): boolean {
    const collectionStore = this.getCollectionStore();
    return !!collectionStore[collectionName];
  }

  find<K: $Keys<M>>(
    collectionName: K,
    conditions: ?Predicate<$ElementType<M, K>>
  ): Record<$ElementType<M, K>>[] {
    const { records } = this.getCollection(collectionName);
    return filter(records, { data: conditions });
  }

  findOne<K: $Keys<M>>(
    collectionName: K,
    conditions: ?Predicate<$ElementType<M, K>>
  ): Record<$ElementType<M, K>> {
    return first(this.find(collectionName, conditions));
  }

  first<K: $Keys<M>>(collectionName: K): Record<$ElementType<M, K>> {
    const { records } = this.getCollection(collectionName);
    return first(records);
  }

  last<K: $Keys<M>>(collectionName: K): Record<$ElementType<M, K>> {
    const { records } = this.getCollection(collectionName);
    return last(records);
  }

  push<K: $Keys<M>>(
    collectionName: K,
    data: $ElementType<M, K>
  ): Record<$ElementType<M, K>> {
    const collection = this.getCollection(collectionName);
    const { uuid, records } = collection;
    const record = {
      id: uuid,
      data
    };

    records.push(record);
    collection.uuid++;

    return record;
  }

  register<K: $Keys<M>>(
    collectionName: K,
    factory: DataFactory<$ElementType<M, K>>
  ) {
    this.getCollectionStore()[collectionName] = {
      uuid: 0,
      records: [],
      factory
    };
  }

  reset() {
    databaseCollectionStores.set(this, new Map());
  }

  update<K: $Keys<M>>(
    collectionName: K,
    id: RecordId,
    data: $Shape<$ElementType<M, K>>
  ): Record<$ElementType<M, K>> {
    const collection = this.getCollection(collectionName);
    const { records } = collection;
    const oldRecord = this.delete(collectionName, id);

    if (oldRecord) {
      const record = {
        ...oldRecord,
        data: {
          ...oldRecord.data,
          ...data
        }
      };
      records.push(record);
      return record;
    } else {
      throw new RecordNotFoundError(collectionName, id);
    }
  }

  getCollectionStore(): CollectionStore<M> {
    const collectionStore = databaseCollectionStores.get(this);
    if (collectionStore) {
      return collectionStore;
    } else {
      throw new Error("This database needs to be initialized.");
    }
  }

  getCollection<K: $Keys<M>>(
    collectionName: K
  ): Collection<$ElementType<M, K>> {
    const collectionStore = this.getCollectionStore();
    const collection = collectionStore[collectionName];
    if (collection) {
      return collection;
    } else {
      throw new CollectionNotFoundError(collectionName);
    }
  }
}

export class CollectionNotFoundError extends Error {
  constructor(collectionName: string) {
    super(`Collection ${collectionName} not found`);
  }
}

export class RecordNotFoundError extends Error {
  constructor(collectionName: string, id: RecordId) {
    super(`Record ${id} not found in collection ${collectionName}`);
  }
}
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

var _FirebugCommandLine =
{
    init: function()
    {
        // Define console functions.
        var commands = ["$", "$$", "$x", "$n", "cd", "clear", "inspect", "keys",
            "values", "debug", "undebug", "monitor", "unmonitor", "traceCalls", "untraceCalls",
            "traceAll", "untraceAll", "monitorEvents", "unmonitorEvents", "profile", "profileEnd", "copy"];
        for (var i=0; i<commands.length; i++)
        {
            var command = commands[i];

            // If the method is already defined, don't override it.
            if (window[command])
                continue;

            this[command] = new Function(
                "return window.console.notifyFirebug(arguments, '" + command + "', 'firebugExecuteCommand');");
        }

        // Define console shortcuts
        var consoleShortcuts = ["dir", "dirxml"];
        for (var i=0; i<consoleShortcuts.length; i++)
        {
            var command = consoleShortcuts[i];
            this[command] = new Function("return window.console." + command + ".apply(window.console, arguments)");
        }

        // Define console variables.
        var props = ["$0", "$1"];
        for (var j=0; j<props.length; j++)
        {
            var prop = props[j];
            if (window[prop])
                continue;

            this.__defineGetter__(prop, new Function(
                "return window.console.notifyFirebug(arguments, '" + prop + "', 'firebugExecuteCommand');"));
        }

        this.attachCommandLine();
    },

    attachCommandLine: function()
    {
        // DBG window.dump("attachCommandLine "+window.location+"\n");
        if (!window.console)
        {
            // DBG 	debugger;
            window.loadFirebugConsole();
        }
        var element = window.console.getFirebugElement();
        var self = this;
        element.addEventListener("firebugCommandLine", function _firebugEvalEvent(event)
        {
            // DBG window.dump("attachCommandLine firebugCommandLine "+window.location+"\n");
            var element = event.target;
            var expr = element.getAttribute("expr"); // see commandLine.js
            self.evaluate(expr);
            // DBG window.dump("attachCommandLine did evaluate on "+expr+"\n");
        }, true);
        element.setAttribute("firebugCommandLineAttached", "true")
        // DBG window.dump("Added listener for firebugCommandLine event "+window.location+"\n");
    },

    evaluate: function(expr)
    {
        try
        {
            var result = window.eval(expr);
            if (typeof result != "undefined")
                window.console.notifyFirebug([result], "evaluated", "firebugAppendConsole");
        }
        catch(exc)
        {
            var result = exc;
            result.source = expr;
            window.console.notifyFirebug([result], "evaluateError", "firebugAppendConsole");
        }
    },
};

(function()
{
    try
    {
        // DBG window.dump("_FirebugCommandLine init console is "+window.console+" in "+window.location+"\n");
        _FirebugCommandLine.init();
    }
    catch(exc)
    {
        var wrappedException = {
            cause: exc,
            message: "_FirebugCommandLine init failed in "+window.location+" because "+exc,
            toString: function() { return this.message; }
        };
        throw wrappedException;
    }
})();
<commit_msg>Issue 1169:  	 Console init function clobbers other init functions<commit_after>/* See license.txt for terms of usage */

var _FirebugCommandLine =
{
    initFirebugCommandLine: function()
    {
        // Define console functions.
        var commands = ["$", "$$", "$x", "$n", "cd", "clear", "inspect", "keys",
            "values", "debug", "undebug", "monitor", "unmonitor", "traceCalls", "untraceCalls",
            "traceAll", "untraceAll", "monitorEvents", "unmonitorEvents", "profile", "profileEnd", "copy"];
        for (var i=0; i<commands.length; i++)
        {
            var command = commands[i];

            // If the method is already defined, don't override it.
            if (window[command])
                continue;

            this[command] = new Function(
                "return window.console.notifyFirebug(arguments, '" + command + "', 'firebugExecuteCommand');");
        }

        // Define console shortcuts
        var consoleShortcuts = ["dir", "dirxml"];
        for (var i=0; i<consoleShortcuts.length; i++)
        {
            var command = consoleShortcuts[i];
            this[command] = new Function("return window.console." + command + ".apply(window.console, arguments)");
        }

        // Define console variables.
        var props = ["$0", "$1"];
        for (var j=0; j<props.length; j++)
        {
            var prop = props[j];
            if (window[prop])
                continue;

            this.__defineGetter__(prop, new Function(
                "return window.console.notifyFirebug(arguments, '" + prop + "', 'firebugExecuteCommand');"));
        }

        this.attachCommandLine();
    },

    attachCommandLine: function()
    {
        // DBG window.dump("attachCommandLine "+window.location+"\n");
        if (!window.console)
        {
            // DBG 	debugger;
            window.loadFirebugConsole();
        }
        var element = window.console.getFirebugElement();
        var self = this;
        element.addEventListener("firebugCommandLine", function _firebugEvalEvent(event)
        {
            // DBG window.dump("attachCommandLine firebugCommandLine "+window.location+"\n");
            var element = event.target;
            var expr = element.getAttribute("expr"); // see commandLine.js
            self.evaluate(expr);
            // DBG window.dump("attachCommandLine did evaluate on "+expr+"\n");
        }, true);
        element.setAttribute("firebugCommandLineAttached", "true")
        // DBG window.dump("Added listener for firebugCommandLine event "+window.location+"\n");
    },

    evaluate: function(expr)
    {
        try
        {
            var result = window.eval(expr);
            if (typeof result != "undefined")
                window.console.notifyFirebug([result], "evaluated", "firebugAppendConsole");
        }
        catch(exc)
        {
            var result = exc;
            result.source = expr;
            window.console.notifyFirebug([result], "evaluateError", "firebugAppendConsole");
        }
    },
};

(function()
{
    try
    {
        // DBG window.dump("_FirebugCommandLine init console is "+window.console+" in "+window.location+"\n");
        _FirebugCommandLine.initFirebugCommandLine();
    }
    catch(exc)
    {
        var wrappedException = {
            cause: exc,
            message: "_FirebugCommandLine init failed in "+window.location+" because "+exc,
            toString: function() { return this.message; }
        };
        throw wrappedException;
    }
})();
<|endoftext|>


<commit_before>import { getAbsolutePath } from 'roc';
import autoprefixer from 'autoprefixer';
import ExtractTextPlugin from 'extract-text-webpack-plugin';

import { invokeHook } from '../roc/util';

import cssPipeline from './pipeline';

export default ({ context: { config: { settings } }, previousValue: webpackConfig }) => (target) => () => {
    const newWebpackConfig = { ...webpackConfig };
    const DEV = settings.build.mode === 'dev';
    const DIST = settings.build.mode === 'dist';
    const WEB = target === 'web';
    const NODE = target === 'node';

    const getGlobalStylePaths = (toMatch) => {
        if (WEB && settings.build.resources) {
            return settings.build.resources.map((path) => {
                if (toMatch.test(path)) {
                    return getAbsolutePath(path);
                }

                return undefined;
            }).filter((path) => path !== undefined);
        }

        return [];
    };

    // Get extensions and loaders
    let currentExtensions = ['css'];
    let currentLoaders = [];
    invokeHook('add-style')(({ extensions, loaders }) => {
        currentExtensions = currentExtensions.concat(extensions);
        currentLoaders = currentLoaders.concat(loaders);
    });

    const toMatch = new RegExp(currentExtensions.map((extension) => `\\.${extension}$`).join('|'));
    const globalStylePaths = getGlobalStylePaths(toMatch);

    // Create general style loader
    const loader = NODE ?
        'css-loader/locals' :
        'css-loader';
    const styleLoader = cssPipeline(loader, currentLoaders, settings, DIST);

    newWebpackConfig.module.loaders.push({
        test: (absPath) => {
            if (globalStylePaths.indexOf(absPath) === -1 && toMatch.test(absPath)) {
                return true;
            }

            return false;
        },
        loader: WEB ?
            ExtractTextPlugin.extract(require.resolve('style-loader'), styleLoader) :
            styleLoader,
    });

    // Create global style loader
    if (WEB) {
        newWebpackConfig.module.loaders.push({
            test: (absPath) => {
                if (globalStylePaths.indexOf(absPath) !== -1) {
                    return true;
                }

                return false;
            },
            loader: ExtractTextPlugin.extract(require.resolve('style-loader'),
                cssPipeline('css-loader', currentLoaders, settings, DIST, false)),
        });
    }

    // Update resolve extensions
    newWebpackConfig.resolve = {
        ...newWebpackConfig.resolve,
        extensions: newWebpackConfig.resolve.extensions.concat(currentExtensions.map((extension) => `.${extension}`)),
    };

    // Configure autoprefixer
    newWebpackConfig.postcss = [
        autoprefixer(settings.build.style.autoprefixer),
    ];

    // Configure ExtractTextPlugin
    newWebpackConfig.plugins.push(
        new ExtractTextPlugin(settings.build.style.name, {
            disable: WEB && DEV,
        })
    );

    return newWebpackConfig;
};
<commit_msg>Added css-loader to resolveLoader so it's easier to use it directly<commit_after>import { getAbsolutePath } from 'roc';
import autoprefixer from 'autoprefixer';
import ExtractTextPlugin from 'extract-text-webpack-plugin';

import { invokeHook } from '../roc/util';

import cssPipeline from './pipeline';

export default ({ context: { config: { settings } }, previousValue: webpackConfig }) => (target) => () => {
    const newWebpackConfig = { ...webpackConfig };
    const DEV = settings.build.mode === 'dev';
    const DIST = settings.build.mode === 'dist';
    const WEB = target === 'web';
    const NODE = target === 'node';

    const getGlobalStylePaths = (toMatch) => {
        if (WEB && settings.build.resources) {
            return settings.build.resources.map((path) => {
                if (toMatch.test(path)) {
                    return getAbsolutePath(path);
                }

                return undefined;
            }).filter((path) => path !== undefined);
        }

        return [];
    };

    // Get extensions and loaders
    let currentExtensions = ['css'];
    let currentLoaders = [];
    invokeHook('add-style')(({ extensions, loaders }) => {
        currentExtensions = currentExtensions.concat(extensions);
        currentLoaders = currentLoaders.concat(loaders);
    });

    const toMatch = new RegExp(currentExtensions.map((extension) => `\\.${extension}$`).join('|'));
    const globalStylePaths = getGlobalStylePaths(toMatch);

    // Create general style loader
    const loader = NODE ?
        'css-loader/locals' :
        'css-loader';
    const styleLoader = cssPipeline(loader, currentLoaders, settings, DIST);

    newWebpackConfig.module.loaders.push({
        test: (absPath) => {
            if (globalStylePaths.indexOf(absPath) === -1 && toMatch.test(absPath)) {
                return true;
            }

            return false;
        },
        loader: WEB ?
            ExtractTextPlugin.extract(require.resolve('style-loader'), styleLoader) :
            styleLoader,
    });

    // Create global style loader
    if (WEB) {
        newWebpackConfig.module.loaders.push({
            test: (absPath) => {
                if (globalStylePaths.indexOf(absPath) !== -1) {
                    return true;
                }

                return false;
            },
            loader: ExtractTextPlugin.extract(require.resolve('style-loader'),
                cssPipeline('css-loader', currentLoaders, settings, DIST, false)),
        });
    }

    // Update resolve extensions
    newWebpackConfig.resolve = {
        ...newWebpackConfig.resolve,
        extensions: newWebpackConfig.resolve.extensions.concat(currentExtensions.map((extension) => `.${extension}`)),
    };

    // Configure autoprefixer
    newWebpackConfig.postcss = [
        autoprefixer(settings.build.style.autoprefixer),
    ];

    // Configure ExtractTextPlugin
    newWebpackConfig.plugins.push(
        new ExtractTextPlugin(settings.build.style.name, {
            disable: WEB && DEV,
        })
    );

    // We want to be able to use the css-loader in projects without the user needing to install them directly.
    newWebpackConfig.resolveLoader.root.push(join(__dirname, '../../node_modules'));

    return newWebpackConfig;
};
<|endoftext|>