<commit_before>
var SimResult=[];
var TotalSimsForMulticore;

var WorkerMessageHandler = function (e) {
	//console.log(e.data.result);

	// There are 3 main message types that are handled
	// Messages to the WorkerStatusText (to be put somewhere on screen to indicate what is currently occurring)
	// Messages to the ProgressBar
	// Message to return result/indicate completeness

	// Messages to the console
	if (typeof e.data.WorkerStatusText != 'undefined'){
		console.log(e.data.WorkerStatusText);
	}
	// Messages to the ProgressBar
	if (typeof e.data.ProgressBarValue != 'undefined'){
		MainProgress.value=e.data.ProgressBarValue;
	}
	if (typeof e.data.Result != 'undefined'){
		SimNumber=e.data.SimNumber;
		SimResult[SimNumber]=e.data.Result;

		//prompt a function that determines if all simulations are complete or not, then cleans up all remaining informations

		HCVTestResult=SimResult[SimNumber].HCVTestResult;
		console.log(HCVTestResult);
		RowLabel=[];
		for (i=0; i<HCVTestResult[0].length; i++){RowLabel[i]=i;}
		HCVResultsTable.innerHTML=MakeTableHTML(HCVTestResult, ["F0", "F1", "F2", "F3", "F4", "LF"], RowLabel);
	}
}

function HCVTest(){
	//Check that nothing else is running

	// Load information from form into population
	var SimData={};
	SimData.NoPeople=100000;
	// Set progress bar to zero
	MainProgress.value=0;

	// Create a simulation object

	// Start a webworker

	for (var SimNumber = 0; SimNumber < NoCores; SimNumber++) {
        var worker = new Worker("model/runsimulation.js");
        worker.onmessage = WorkerMessageHandler;

        // Sending canvas data to the worker using a copy memory operation
        worker.postMessage({ SimNumber: SimNumber, SimData: SimData });
    }
	//worker.terminate();
}

function HCVTestPlot(){
	// Get the relevant data
	HCVTestResult=SimResult[0].HCVTestResult;
	//create an x axis
	TimeAxis=[];
	for (i=0; i<HCVTestResult[0].length; i++){TimeAxis[i]=i;}
	// convert to a form that plot will accept
	PlotData=ConvertDataToLinePlot(TimeAxis, HCVTestResult);
	//Set up plot appearance // http://www.pikemere.co.uk/blog/flot-tutorial-how-to-create-area-charts/
	PlotSettings={xaxis: {
					axisLabel: 'Time (years)',
					axisLabelUseCanvas: true,
					axisLabelFontSizePixels: 12,
					axisLabelFontFamily: 'Verdana, Arial, Helvetica, Tahoma, sans-serif',
					axisLabelPadding: 5,
					tickLength: 0
				},
				yaxis: {
					min: 0,
					max: 100000,
					axisLabel: 'Number of people',
					axisLabelUseCanvas: true,
					axisLabelFontSizePixels: 12,
					axisLabelFontFamily: 'Verdana, Arial, Helvetica, Tahoma, sans-serif',
					axisLabelPadding: 5
				},
				series: {
					lines: {
						show: true,
						fill: true
					},
					stack: true
				}
			};

	//plot of HCVTestPlotHolder
	$.plot("#HCVTestPlotHolder", PlotData, PlotSettings);

}

function ConvertDataToLinePlot(x, InputMatrix){//Accepts [param][time] or [y][x]. Future systems will accept [param][time][sim]
	LinePlotData=[];
	NumberOfLines=InputMatrix.length;
	for (i=0; i<NumberOfLines; i++){
		ThisLine=[];
		for (var j = 0; j < InputMatrix[i].length; j++) {
			ThisLine.push([x[j], InputMatrix[i][j]]);
		}
		LinePlotData.push(ThisLine);
	}
	return LinePlotData;
}<commit_msg>Pushing the limits of memory storage<commit_after>
var SimResult=[];
var TotalSimsForMulticore;

var WorkerMessageHandler = function (e) {
	//console.log(e.data.result);

	// There are 3 main message types that are handled
	// Messages to the WorkerStatusText (to be put somewhere on screen to indicate what is currently occurring)
	// Messages to the ProgressBar
	// Message to return result/indicate completeness

	// Messages to the console
	if (typeof e.data.WorkerStatusText != 'undefined'){
		console.log(e.data.WorkerStatusText);
	}
	// Messages to the ProgressBar
	if (typeof e.data.ProgressBarValue != 'undefined'){
		MainProgress.value=e.data.ProgressBarValue;
	}
	if (typeof e.data.Result != 'undefined'){
		SimNumber=e.data.SimNumber;
		SimResult[SimNumber]=e.data.Result;

		//prompt a function that determines if all simulations are complete or not, then cleans up all remaining informations

		HCVTestResult=SimResult[SimNumber].HCVTestResult;
		console.log(HCVTestResult);
		RowLabel=[];
		for (i=0; i<HCVTestResult[0].length; i++){RowLabel[i]=i;}
		HCVResultsTable.innerHTML=MakeTableHTML(HCVTestResult, ["F0", "F1", "F2", "F3", "F4", "LF"], RowLabel);
	}
}

function HCVTest(){
	//Check that nothing else is running

	// Load information from form into population
	var SimData={};
	SimData.NoPeople=1000000;
	// Set progress bar to zero
	MainProgress.value=0;

	// Create a simulation object

	// Start a webworker

	for (var SimNumber = 0; SimNumber < NoCores; SimNumber++) {
        var worker = new Worker("model/runsimulation.js");
        worker.onmessage = WorkerMessageHandler;

        // Sending canvas data to the worker using a copy memory operation
        worker.postMessage({ SimNumber: SimNumber, SimData: SimData });
    }
	//worker.terminate();
}

function HCVTestPlot(){
	// Get the relevant data
	HCVTestResult=SimResult[0].HCVTestResult;
	//create an x axis
	TimeAxis=[];
	for (i=0; i<HCVTestResult[0].length; i++){TimeAxis[i]=i;}
	// convert to a form that plot will accept
	PlotData=ConvertDataToLinePlot(TimeAxis, HCVTestResult);
	//Set up plot appearance // http://www.pikemere.co.uk/blog/flot-tutorial-how-to-create-area-charts/
	PlotSettings={xaxis: {
					axisLabel: 'Time (years)',
					axisLabelUseCanvas: true,
					axisLabelFontSizePixels: 12,
					axisLabelFontFamily: 'Verdana, Arial, Helvetica, Tahoma, sans-serif',
					axisLabelPadding: 5,
					tickLength: 0
				},
				yaxis: {
					min: 0,
					max: 100000,
					axisLabel: 'Number of people',
					axisLabelUseCanvas: true,
					axisLabelFontSizePixels: 12,
					axisLabelFontFamily: 'Verdana, Arial, Helvetica, Tahoma, sans-serif',
					axisLabelPadding: 5
				},
				series: {
					lines: {
						show: true,
						fill: true
					},
					stack: true
				}
			};

	//plot of HCVTestPlotHolder
	$.plot("#HCVTestPlotHolder", PlotData, PlotSettings);

}

function ConvertDataToLinePlot(x, InputMatrix){//Accepts [param][time] or [y][x]. Future systems will accept [param][time][sim]
	LinePlotData=[];
	NumberOfLines=InputMatrix.length;
	for (i=0; i<NumberOfLines; i++){
		ThisLine=[];
		for (var j = 0; j < InputMatrix[i].length; j++) {
			ThisLine.push([x[j], InputMatrix[i][j]]);
		}
		LinePlotData.push(ThisLine);
	}
	return LinePlotData;
}<|endoftext|>


<commit_before>var constants = require('../constants/constants.json');

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var deviceSchema = mongoose.Schema({

	deviceName 		: String,
	deviceId		: String,
	registrationId	: String

});

mongoose.connect(constants.mongo_db_server + 'android');

module.exports = mongoose.model('device', deviceSchema);       <commit_msg>config mongodb server<commit_after>var constants = require('../constants/constants.json');

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var deviceSchema = mongoose.Schema({

	deviceName 		: String,
	deviceId		: String,
	registrationId	: String

});

mongoose.connect(constants.mongo_db_server + 'node-android-push');

module.exports = mongoose.model('device', deviceSchema);       <|endoftext|>


<commit_before>importScripts('https://codehubplatform.github.io/EnglishWebContent/cache-polyfill.js');
var cacheName = 'my-site-cache-v1';
var filesToCache = [
  '/EnglishWebContent/css/main.css',
  '/EnglishWebContent/javascript/marksheet.js',
  'index.html',
  '/EnglishWebContent//2015/01/01/introduction.html',
  '/EnglishWebContent//2015/01/02/internet.html',
  '/EnglishWebContent//2015/01/03/web.html',
  '/EnglishWebContent//2015/01/04/browser.html',
  '/EnglishWebContent//2015/02/01/html-basics.html',
  '/EnglishWebContent//2015/02/02/html-syntax.html',
  '/EnglishWebContent//2015/02/03/html-block-inline.html',
  '/EnglishWebContent//2015/02/04/html-hierarchy.html',
  '/EnglishWebContent//2015/02/05/html-semantics.html',
  '/EnglishWebContent//2015/02/06/html-formatting.html',
  '/EnglishWebContent//2015/02/07/html-valid-document.html',
  '/EnglishWebContent//2015/03/01/html-content.html',
  '/EnglishWebContent//2015/03/02/html-text.html',
  '/EnglishWebContent//2015/03/03/html-inline-semantics.html',
  '/EnglishWebContent//2015/03/03/html-links.html',
  '/EnglishWebContent//2015/03/04/html-images.html',
  '/EnglishWebContent//2015/03/05/html-tables.html',
  '/EnglishWebContent//2015/03/06/html-structure.html',
  '/EnglishWebContent//2015/03/07/html-forms.html',
  '/EnglishWebContent//2015/04/01/css-basics.html',
  '/EnglishWebContent//2015/04/02/why-css-exists.html',
  '/EnglishWebContent//2015/04/03/css-syntax.html',
  '/EnglishWebContent//2015/04/04/css-selectors.html',
  '/EnglishWebContent//2015/04/05/css-inheritance.html',
  '/EnglishWebContent//2015/04/06/css-priority.html',
  '/EnglishWebContent//2015/04/07/css-color-units.html',
  '/EnglishWebContent//2015/04/08/css-size-units.html',
  '/EnglishWebContent//2015/04/09/css-reset.html',
  '/EnglishWebContent//2015/05/01/css-text.html',
  '/EnglishWebContent//2015/05/02/css-font-family.html',
  '/EnglishWebContent//2015/05/03/css-font-size-style-weight.html',
  '/EnglishWebContent//2015/05/04/css-line-height.html',
  '/EnglishWebContent//2015/05/05/css-font-shorthand.html',
  '/EnglishWebContent//2015/05/06/css-text-properties.html',
  '/EnglishWebContent//2015/06/01/css-box-model.html',
  '/EnglishWebContent//2015/06/02/css-background.html',
  '/EnglishWebContent//2015/06/03/css-display.html',
  '/EnglishWebContent//2015/06/04/css-height-width-overflow.html',
  '/EnglishWebContent//2015/06/05/css-border.html',
  '/EnglishWebContent//2015/06/06/css-padding.html',
  '/EnglishWebContent//2015/06/07/css-margin.html',
  '/EnglishWebContent//2015/06/08/css-size-shorthand-wheel.html',
  '/EnglishWebContent//2015/07/01/css-positioning.html',
  '/EnglishWebContent//2015/07/02/css-the-flow.html',
  '/EnglishWebContent//2015/07/03/css-position.html',
  '/EnglishWebContent//2015/07/04/css-float-clear.html',
  '/EnglishWebContent//2015/08/01/css-advanced.html',
  '/EnglishWebContent//2015/08/02/css-pseudo-classes.html',
  '/EnglishWebContent//2015/08/03/css-gradients.html',
  '/EnglishWebContent//2015/08/04/css-transitions.html',
  '/EnglishWebContent//2015/08/05/css-animations.html',
  '/EnglishWebContent//2015/08/06/css-transform.html',
  '/EnglishWebContent//2015/08/07/css-responsiveness.html',
  '/EnglishWebContent/javascript/codemirror.js',
  '/EnglishWebContent/javascript/mode/xml/xml.js',
  '/EnglishWebContent/javascript/mode/htmlmixed/htmlmixed.js'

];

self.addEventListener('install', function(event) {
    event.waitUntil(
        caches.open(cacheName).then(function(cache) {
            return cache.addAll(filesToCache);
        })
    );
});

self.addEventListener('fetch', function(event) {
    event.respondWith(
        caches.match(event.request)
            .then(function(response) {
                if (response) {
                    console.log('[*] Serving cached: ' + event.request.url);
                    return response;
                }

                console.log('[*] Fetching: ' + event.request.url);
                return fetch(event.request);
            }
        )
    );
});<commit_msg>service worker;<commit_after>importScripts('https://codehubplatform.github.io/EnglishWebContent/cache-polyfill.js');
var cacheName = 'my-site-cache-v1';
var filesToCache = [
'/',
  '/EnglishWebContent/css/main.css',
  '/EnglishWebContent/javascript/marksheet.js',
  '/EnglishWebContent/index.html',
  '/EnglishWebContent//2015/01/01/introduction.html',
  '/EnglishWebContent//2015/01/02/internet.html',
  '/EnglishWebContent//2015/01/03/web.html',
  '/EnglishWebContent//2015/01/04/browser.html',
  '/EnglishWebContent//2015/02/01/html-basics.html',
  '/EnglishWebContent//2015/02/02/html-syntax.html',
  '/EnglishWebContent//2015/02/03/html-block-inline.html',
  '/EnglishWebContent//2015/02/04/html-hierarchy.html',
  '/EnglishWebContent//2015/02/05/html-semantics.html',
  '/EnglishWebContent//2015/02/06/html-formatting.html',
  '/EnglishWebContent//2015/02/07/html-valid-document.html',
  '/EnglishWebContent//2015/03/01/html-content.html',
  '/EnglishWebContent//2015/03/02/html-text.html',
  '/EnglishWebContent//2015/03/03/html-inline-semantics.html',
  '/EnglishWebContent//2015/03/03/html-links.html',
  '/EnglishWebContent//2015/03/04/html-images.html',
  '/EnglishWebContent//2015/03/05/html-tables.html',
  '/EnglishWebContent//2015/03/06/html-structure.html',
  '/EnglishWebContent//2015/03/07/html-forms.html',
  '/EnglishWebContent//2015/04/01/css-basics.html',
  '/EnglishWebContent//2015/04/02/why-css-exists.html',
  '/EnglishWebContent//2015/04/03/css-syntax.html',
  '/EnglishWebContent//2015/04/04/css-selectors.html',
  '/EnglishWebContent//2015/04/05/css-inheritance.html',
  '/EnglishWebContent//2015/04/06/css-priority.html',
  '/EnglishWebContent//2015/04/07/css-color-units.html',
  '/EnglishWebContent//2015/04/08/css-size-units.html',
  '/EnglishWebContent//2015/04/09/css-reset.html',
  '/EnglishWebContent//2015/05/01/css-text.html',
  '/EnglishWebContent//2015/05/02/css-font-family.html',
  '/EnglishWebContent//2015/05/03/css-font-size-style-weight.html',
  '/EnglishWebContent//2015/05/04/css-line-height.html',
  '/EnglishWebContent//2015/05/05/css-font-shorthand.html',
  '/EnglishWebContent//2015/05/06/css-text-properties.html',
  '/EnglishWebContent//2015/06/01/css-box-model.html',
  '/EnglishWebContent//2015/06/02/css-background.html',
  '/EnglishWebContent//2015/06/03/css-display.html',
  '/EnglishWebContent//2015/06/04/css-height-width-overflow.html',
  '/EnglishWebContent//2015/06/05/css-border.html',
  '/EnglishWebContent//2015/06/06/css-padding.html',
  '/EnglishWebContent//2015/06/07/css-margin.html',
  '/EnglishWebContent//2015/06/08/css-size-shorthand-wheel.html',
  '/EnglishWebContent//2015/07/01/css-positioning.html',
  '/EnglishWebContent//2015/07/02/css-the-flow.html',
  '/EnglishWebContent//2015/07/03/css-position.html',
  '/EnglishWebContent//2015/07/04/css-float-clear.html',
  '/EnglishWebContent//2015/08/01/css-advanced.html',
  '/EnglishWebContent//2015/08/02/css-pseudo-classes.html',
  '/EnglishWebContent//2015/08/03/css-gradients.html',
  '/EnglishWebContent//2015/08/04/css-transitions.html',
  '/EnglishWebContent//2015/08/05/css-animations.html',
  '/EnglishWebContent//2015/08/06/css-transform.html',
  '/EnglishWebContent//2015/08/07/css-responsiveness.html',
  '/EnglishWebContent/javascript/codemirror.js',
  '/EnglishWebContent/javascript/mode/xml/xml.js',
  '/EnglishWebContent/javascript/mode/htmlmixed/htmlmixed.js'

];

self.addEventListener('install', function(event) {
    event.waitUntil(
        caches.open(cacheName).then(function(cache) {
            return cache.addAll(filesToCache);
        })
    );
});

self.addEventListener('fetch', function(event) {
    event.respondWith(
        caches.match(event.request)
            .then(function(response) {
                if (response) {
                    console.log('[*] Serving cached: ' + event.request.url);
                    return response;
                }

                console.log('[*] Fetching: ' + event.request.url);
                return fetch(event.request);
            }
        )
    );
});<|endoftext|>


<commit_before>var VERSION = "1.0.2";
var CACHE_NAME = 'fireworks-cache-v' + VERSION;
var urlsToCache = [
  'index.html',
  'elements/card.html',
  'elements/counter.html',
  'elements/elements.html',
  'elements/game.html',
  'elements/gamecontroller.html',
  'elements/player.html',
  'elements/routing.html',
  'images/board.jpg',
  'images/bombicon.jpg',
  'images/fireworks.png',
  'images/hanabi.jpg',
  'images/hinticon.jpg',
  'scripts/app.js',
  'styles/app-theme.html',
  'styles/main.css'
];

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

self.addEventListener('fetch', function(event) {
  var regex = /client\/version$/;
  if (event.request.url.match(regex)) {
    event.respondWith(new Response(VERSION, {
          headers: {'Content-Type': 'text/plain'}
    }));
  }
  else {
    event.respondWith(
      caches.match(event.request)
        .then(function(response) {
          // Cache hit - return response
          if (response) {
            return response;
          }

          // IMPORTANT: Clone the request. A request is a stream and
          // can only be consumed once. Since we are consuming this
          // once by cache and once by the browser for fetch, we need
          // to clone the response.
          var fetchRequest = event.request.clone();

          return fetch(fetchRequest).then(
            function(response) {
              // Check if we received a valid response
              if(!response || response.status !== 200 || response.type !== 'basic' || event.request.method == 'POST') {
                return response;
              }

              // IMPORTANT: Clone the response. A response is a stream
              // and because we want the browser to consume the response
              // as well as the cache consuming the response, we need
              // to clone it so we have two streams.
              var responseToCache = response.clone();

              caches.open(CACHE_NAME)
                .then(function(cache) {
                  cache.put(event.request, responseToCache);
                });

              return response;
            }
          );
        })
      );
  }
});

self.addEventListener('activate', function(event) {

  var cacheWhitelist = [CACHE_NAME];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-messaging.js');
firebase.initializeApp({
  'messagingSenderId': '168641906858'
});

const messaging = firebase.messaging();

messaging.setBackgroundMessageHandler(function(payload) {
  console.log('Received background message ', payload);
  // Customize notification here
  const notificationTitle = "Fireworks - it's your turn!";
  const notificationOptions = {
    body: 'Other players are waiting for you! Take your turn.',
    icon: '/firebase-logo.png',
    click_action: 'https://fellyeah.dlinkddns.com:80/#!/games/' + payload.data.Game
  };

  return self.registration.showNotification(notificationTitle,
      notificationOptions);
});<commit_msg>Made SW skip waiting on install<commit_after>var VERSION = "1.0.3";
var CACHE_NAME = 'fireworks-cache-v' + VERSION;
var urlsToCache = [
  'index.html',
  'elements/card.html',
  'elements/counter.html',
  'elements/elements.html',
  'elements/game.html',
  'elements/gamecontroller.html',
  'elements/player.html',
  'elements/routing.html',
  'images/board.jpg',
  'images/bombicon.jpg',
  'images/fireworks.png',
  'images/hanabi.jpg',
  'images/hinticon.jpg',
  'scripts/app.js',
  'styles/app-theme.html',
  'styles/main.css'
];

self.addEventListener('install', function(event) {
  self.skipWaiting();
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

self.addEventListener('fetch', function(event) {
  var regex = /client\/version$/;
  if (event.request.url.match(regex)) {
    event.respondWith(new Response(VERSION, {
          headers: {'Content-Type': 'text/plain'}
    }));
  }
  else {
    event.respondWith(
      caches.match(event.request)
        .then(function(response) {
          // Cache hit - return response
          if (response) {
            return response;
          }

          // IMPORTANT: Clone the request. A request is a stream and
          // can only be consumed once. Since we are consuming this
          // once by cache and once by the browser for fetch, we need
          // to clone the response.
          var fetchRequest = event.request.clone();

          return fetch(fetchRequest).then(
            function(response) {
              // Check if we received a valid response
              if(!response || response.status !== 200 || response.type !== 'basic' || event.request.method == 'POST') {
                return response;
              }

              // IMPORTANT: Clone the response. A response is a stream
              // and because we want the browser to consume the response
              // as well as the cache consuming the response, we need
              // to clone it so we have two streams.
              var responseToCache = response.clone();

              caches.open(CACHE_NAME)
                .then(function(cache) {
                  cache.put(event.request, responseToCache);
                });

              return response;
            }
          );
        })
      );
  }
});

self.addEventListener('activate', function(event) {

  var cacheWhitelist = [CACHE_NAME];

  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-app.js');
importScripts('https://www.gstatic.com/firebasejs/3.5.2/firebase-messaging.js');
firebase.initializeApp({
  'messagingSenderId': '168641906858'
});

const messaging = firebase.messaging();

messaging.setBackgroundMessageHandler(function(payload) {
  console.log('Received background message ', payload);
  // Customize notification here
  const notificationTitle = "Fireworks - it's your turn!";
  const notificationOptions = {
    body: 'Other players are waiting for you! Take your turn.',
    icon: '/firebase-logo.png',
    click_action: 'https://fellyeah.dlinkddns.com:80/#!/games/' + payload.data.Game
  };

  return self.registration.showNotification(notificationTitle,
      notificationOptions);
});<|endoftext|>


<commit_before>var async = require('async'),
	util = require('util'),
	slots = require('../helpers/slots.js'),
	sandboxHelper = require('../helpers/sandbox.js'),
	constants = require('../helpers/constants.js');

// Private fields
var modules, library, self, private = {}, shared = {};

private.loaded = false;

private.feesByRound = {};
private.rewardsByRound = {};
private.delegatesByRound = {};
private.unFeesByRound = {};
private.unRewardsByRound = {};
private.unDelegatesByRound = {};

// Constructor
function Round(cb, scope) {
	library = scope;
	self = this;
	self.__private = private;
	setImmediate(cb, null, self);
}

// Round changes
function RoundChanges (round) {
  var roundFees = parseInt(private.feesByRound[round]) || 0;
  var roundRewards = (private.rewardsByRound[round] || []);

  this.at = function (index) {
    var fees = Math.floor(roundFees / slots.delegates),
        feesRemaining = roundFees - (fees * slots.delegates),
        rewards = parseInt(roundRewards[index]) || 0;

    return {
      fees : fees,
      feesRemaining : feesRemaining,
      rewards : rewards,
      balance : fees + rewards
    };
  }
}

Round.prototype.loaded = function () {
	return private.loaded;
}

// Public methods
Round.prototype.calc = function (height) {
	return Math.floor(height / slots.delegates) + (height % slots.delegates > 0 ? 1 : 0);
}

Round.prototype.getVotes = function (round, cb) {
	library.db.query("SELECT d.\"delegate\", d.\"amount\" FROM ( " +
		"SELECT m.\"delegate\", SUM(m.\"amount\") AS \"amount\", \"round\" FROM mem_round m " +
		"GROUP BY m.\"delegate\", m.\"round\" " +
		") AS d WHERE \"round\" = ${round}", { round: round }).then(function (rows) {
		return cb(null, rows);
	}).catch(function (err) {
		return cb("Round#getVotes error");
	});
}

Round.prototype.flush = function (round, cb) {
	library.db.none("DELETE FROM mem_round WHERE \"round\" = ${round}", { round: round }).then(function () {
		return cb();
	}).catch(function (err) {
		return cb("Round#flush error");
	});
}

Round.prototype.directionSwap = function (direction, lastBlock, cb) {
	if (direction == 'backward') {
		private.feesByRound = {};
		private.rewardsByRound = {};
		private.delegatesByRound = {};
		self.flush(self.calc(lastBlock.height), cb);
	} else {
		private.unFeesByRound = {};
		private.unRewardsByRound = {};
		private.unDelegatesByRound = {};
		self.flush(self.calc(lastBlock.height), cb);
	}
}

Round.prototype.backwardTick = function (block, previousBlock, cb) {
	function done(err) {
		cb && cb(err);
	}

	modules.accounts.mergeAccountAndGet({
		publicKey: block.generatorPublicKey,
		producedblocks: -1,
		blockId: block.id,
		round: modules.round.calc(block.height)
	}, function (err) {
		if (err) {
			return done(err);
		}

		var round = self.calc(block.height);

		var prevRound = self.calc(previousBlock.height);

		private.unFeesByRound[round] = (private.unFeesByRound[round] || 0);
		private.unFeesByRound[round] += block.totalFee;

		private.unRewardsByRound[round] = (private.rewardsByRound[round] || []);
		private.unRewardsByRound[round].push(block.reward);

		private.unDelegatesByRound[round] = private.unDelegatesByRound[round] || [];
		private.unDelegatesByRound[round].push(block.generatorPublicKey);

		if (prevRound !== round || previousBlock.height == 1) {
			if (private.unDelegatesByRound[round].length == slots.delegates || previousBlock.height == 1) {
				var outsiders = [];
				async.series([
					function (cb) {
						if (block.height != 1) {
							modules.delegates.generateDelegateList(block.height, function (err, roundDelegates) {
								if (err) {
									return cb(err);
								}
								for (var i = 0; i < roundDelegates.length; i++) {
									if (private.unDelegatesByRound[round].indexOf(roundDelegates[i]) == -1) {
										outsiders.push(modules.accounts.generateAddressByPublicKey(roundDelegates[i]));
									}
								}
								cb();
							});
						} else {
							cb();
						}
					},
					function (cb) {
						if (!outsiders.length) {
							return cb();
						}
						var escaped = outsiders.map(function (item) {
							return "'" + item + "'";
						});
						library.db.none("UPDATE mem_accounts SET \"missedblocks\" = \"missedblocks\" + 1 WHERE \"address\" IN (" + escaped.join(",") + ")").then(function () {
							return cb();
						}).catch(function (err) {
							return cb("Round#backwardTick error");
						});
					},
					function (cb) {
						self.getVotes(round, function (err, votes) {
							if (err) {
								return cb(err);
							}
							async.eachSeries(votes, function (vote, cb) {
								library.db.none("UPDATE mem_accounts SET \"vote\" = \"vote\" + ${amount} WHERE \"address\" = ${address}", {
									address: modules.accounts.generateAddressByPublicKey(vote.delegate),
									amount: vote.amount
								}).then(function () {
									return cb();
								}).catch(function (err) {
									return cb("Round#backwardTick error");
								});
							}, function (err) {
								self.flush(round, function (err2) {
									cb(err || err2);
								});
							})
						});
					},
					function (cb) {
						var roundChanges = new RoundChanges(round);

						async.forEachOfSeries(private.unDelegatesByRound[round], function (delegate, index, cb) {
							var changes = roundChanges.at(index);

							modules.accounts.mergeAccountAndGet({
								publicKey: delegate,
								balance: -changes.balance,
								u_balance: -changes.balance,
								blockId: block.id,
								round: modules.round.calc(block.height),
								fees: -changes.fees,
								rewards: -changes.rewards
							}, function (err) {
								if (err) {
									return cb(err);
								}
								if (index === 0) {
									modules.accounts.mergeAccountAndGet({
										publicKey: delegate,
										balance: -changes.feesRemaining,
										u_balance: -changes.feesRemaining,
										blockId: block.id,
										round: modules.round.calc(block.height),
										fees: -changes.feesRemaining,
									}, cb);
								} else {
									cb();
								}
							});
						}, cb);
					},
					function (cb) {
						self.getVotes(round, function (err, votes) {
							if (err) {
								return cb(err);
							}
							async.eachSeries(votes, function (vote, cb) {
								library.db.none("UPDATE mem_accounts SET \"vote\" = \"vote\" + ${amount} WHERE \"address\" = ${address}", {
									address: modules.accounts.generateAddressByPublicKey(vote.delegate),
									amount: vote.amount
								}).then(function () {
									return cb();
								}).catch(function (err) {
									return cb("Round#backwardTick error");
								});
							}, function (err) {
								self.flush(round, function (err2) {
									cb(err || err2);
								});
							})
						});
					}
				], function (err) {
					delete private.unFeesByRound[round];
					delete private.unRewardsByRound[round];
					delete private.unDelegatesByRound[round];
					done(err)
				});
			} else {
				done();
			}
		} else {
			done();
		}
	});
}

Round.prototype.tick = function (block, cb) {
	function done(err) {
		cb && setImmediate(cb, err);
	}

	modules.accounts.mergeAccountAndGet({
		publicKey: block.generatorPublicKey,
		producedblocks: 1,
		blockId: block.id,
		round: modules.round.calc(block.height)
	}, function (err) {
		if (err) {
			return done(err);
		}
		var round = self.calc(block.height);

		private.feesByRound[round] = (private.feesByRound[round] || 0);
		private.feesByRound[round] += block.totalFee;

		private.rewardsByRound[round] = (private.rewardsByRound[round] || []);
		private.rewardsByRound[round].push(block.reward);

		private.delegatesByRound[round] = private.delegatesByRound[round] || [];
		private.delegatesByRound[round].push(block.generatorPublicKey);

		var nextRound = self.calc(block.height + 1);

		if (round !== nextRound || block.height == 1) {
			if (private.delegatesByRound[round].length == slots.delegates || block.height == 1 || block.height == 101) {
				var outsiders = [];

				async.series([
					function (cb) {
						if (block.height != 1) {
							modules.delegates.generateDelegateList(block.height, function (err, roundDelegates) {
								if (err) {
									return cb(err);
								}
								for (var i = 0; i < roundDelegates.length; i++) {
									if (private.delegatesByRound[round].indexOf(roundDelegates[i]) == -1) {
										outsiders.push(modules.accounts.generateAddressByPublicKey(roundDelegates[i]));
									}
								}
								cb();
							});
						} else {
							cb();
						}
					},
					function (cb) {
						if (!outsiders.length) {
							return cb();
						}
						var escaped = outsiders.map(function (item) {
							return "'" + item + "'";
						});
						library.db.none("UPDATE mem_accounts SET \"missedblocks\" = \"missedblocks\" + 1 WHERE \"address\" IN (" + escaped.join(",") + ")").then(function () {
							return cb();
						}).catch(function (err) {
							return cb("Round#tick error");
						});
					},
					function (cb) {
						self.getVotes(round, function (err, votes) {
							if (err) {
								return cb(err);
							}
							async.eachSeries(votes, function (vote, cb) {
								library.db.none("UPDATE mem_accounts SET \"vote\" = \"vote\" + ${amount} WHERE \"address\" = ${address}", {
									address: modules.accounts.generateAddressByPublicKey(vote.delegate),
									amount: vote.amount
								}).then(function () {
									return cb();
								}).catch(function (err) {
									return cb("Round#tick error");
								});
							}, function (err) {
								self.flush(round, function (err2) {
									cb(err || err2);
								});
							});
						});
					},
					function (cb) {
						var roundChanges = new RoundChanges(round);

						async.forEachOfSeries(private.delegatesByRound[round], function (delegate, index, cb) {
							var changes = roundChanges.at(index);

							modules.accounts.mergeAccountAndGet({
								publicKey: delegate,
								balance: changes.balance,
								u_balance: changes.balance,
								blockId: block.id,
								round: modules.round.calc(block.height),
								fees: changes.fees,
								rewards: changes.rewards
							}, function (err) {
								if (err) {
									return cb(err);
								}
								if (index === private.delegatesByRound[round].length - 1) {
									modules.accounts.mergeAccountAndGet({
										publicKey: delegate,
										balance: changes.feesRemaining,
										u_balance: changes.feesRemaining,
										blockId: block.id,
										round: modules.round.calc(block.height),
										fees: changes.feesRemaining
									}, cb);
								} else {
									cb();
								}
							});
						}, cb);
					},
					function (cb) {
						self.getVotes(round, function (err, votes) {
							if (err) {
								return cb(err);
							}
							async.eachSeries(votes, function (vote, cb) {
								library.db.none("UPDATE mem_accounts SET \"vote\" = \"vote\" + ${amount} WHERE \"address\" = ${address}", {
									address: modules.accounts.generateAddressByPublicKey(vote.delegate),
									amount: vote.amount
								}).then(function () {
									return cb();
								}).catch(function (err) {
									return cb("Round#tick error");
								});
							}, function (err) {
								library.bus.message('finishRound', round);
								self.flush(round, function (err2) {
									cb(err || err2);
								});
							})
						});
					}
				], function (err) {
					delete private.feesByRound[round];
					delete private.rewardsByRound[round];
					delete private.delegatesByRound[round];
					done(err);
				});
			} else {
				done();
			}
		} else {
			done();
		}
	});
}

Round.prototype.sandboxApi = function (call, args, cb) {
	sandboxHelper.callMethod(shared, call, args, cb);
}

// Events
Round.prototype.onBind = function (scope) {
	modules = scope;
}

Round.prototype.onBlockchainReady = function () {
	var round = self.calc(modules.blocks.getLastBlock().height);
	library.db.query("SELECT SUM(b.\"totalFee\") AS \"fees\", ARRAY_AGG(b.\"reward\") AS \"rewards\", ARRAY_AGG(ENCODE(b.\"generatorPublicKey\", 'hex')) AS \"delegates\" " +
		"FROM blocks b WHERE (SELECT (CAST(b.\"height\" / 101 AS INTEGER) + (CASE WHEN b.\"height\" % 101 > 0 THEN 1 ELSE 0 END))) = ${round}", { round: round }).then(function (rows) {

		var rewards = [];
		rows[0].rewards.forEach(function (reward) {
			rewards.push(parseInt(reward));
		});

		private.feesByRound[round] = rows[0].fees;
		private.rewardsByRound[round] = rewards;
		private.delegatesByRound[round] = rows[0].delegates;
		private.loaded = true;

	}).catch(function (err) {
		return cb("Round#onBlockchainReady error");
	});
}

Round.prototype.onFinishRound = function (round) {
	library.network.io.sockets.emit('rounds/change', {number: round});
}

Round.prototype.cleanup = function (cb) {
	private.loaded = false;
	cb();
}

// Shared

// Export
module.exports = Round;
<commit_msg>Casting / flooring integers.<commit_after>var async = require('async'),
	util = require('util'),
	slots = require('../helpers/slots.js'),
	sandboxHelper = require('../helpers/sandbox.js'),
	constants = require('../helpers/constants.js');

// Private fields
var modules, library, self, private = {}, shared = {};

private.loaded = false;

private.feesByRound = {};
private.rewardsByRound = {};
private.delegatesByRound = {};
private.unFeesByRound = {};
private.unRewardsByRound = {};
private.unDelegatesByRound = {};

// Constructor
function Round(cb, scope) {
	library = scope;
	self = this;
	self.__private = private;
	setImmediate(cb, null, self);
}

// Round changes
function RoundChanges (round) {
  var roundFees = Math.floor(private.feesByRound[round]) || 0;
  var roundRewards = (private.rewardsByRound[round] || []);

  this.at = function (index) {
    var fees = Math.floor(roundFees / slots.delegates),
        feesRemaining = roundFees - (fees * slots.delegates),
        rewards = Math.floor(roundRewards[index]) || 0;

    return {
      fees : fees,
      feesRemaining : feesRemaining,
      rewards : rewards,
      balance : fees + rewards
    };
  }
}

Round.prototype.loaded = function () {
	return private.loaded;
}

// Public methods
Round.prototype.calc = function (height) {
	return Math.floor(height / slots.delegates) + (height % slots.delegates > 0 ? 1 : 0);
}

Round.prototype.getVotes = function (round, cb) {
	library.db.query("SELECT d.\"delegate\", d.\"amount\" FROM ( " +
		"SELECT m.\"delegate\", SUM(m.\"amount\") AS \"amount\", \"round\" FROM mem_round m " +
		"GROUP BY m.\"delegate\", m.\"round\" " +
		") AS d WHERE \"round\" = ${round}", { round: round }).then(function (rows) {
		return cb(null, rows);
	}).catch(function (err) {
		return cb("Round#getVotes error");
	});
}

Round.prototype.flush = function (round, cb) {
	library.db.none("DELETE FROM mem_round WHERE \"round\" = ${round}", { round: round }).then(function () {
		return cb();
	}).catch(function (err) {
		return cb("Round#flush error");
	});
}

Round.prototype.directionSwap = function (direction, lastBlock, cb) {
	if (direction == 'backward') {
		private.feesByRound = {};
		private.rewardsByRound = {};
		private.delegatesByRound = {};
		self.flush(self.calc(lastBlock.height), cb);
	} else {
		private.unFeesByRound = {};
		private.unRewardsByRound = {};
		private.unDelegatesByRound = {};
		self.flush(self.calc(lastBlock.height), cb);
	}
}

Round.prototype.backwardTick = function (block, previousBlock, cb) {
	function done(err) {
		cb && cb(err);
	}

	modules.accounts.mergeAccountAndGet({
		publicKey: block.generatorPublicKey,
		producedblocks: -1,
		blockId: block.id,
		round: modules.round.calc(block.height)
	}, function (err) {
		if (err) {
			return done(err);
		}

		var round = self.calc(block.height);

		var prevRound = self.calc(previousBlock.height);

		private.unFeesByRound[round] = (private.unFeesByRound[round] || 0);
		private.unFeesByRound[round] += block.totalFee;

		private.unRewardsByRound[round] = (private.rewardsByRound[round] || []);
		private.unRewardsByRound[round].push(block.reward);

		private.unDelegatesByRound[round] = private.unDelegatesByRound[round] || [];
		private.unDelegatesByRound[round].push(block.generatorPublicKey);

		if (prevRound !== round || previousBlock.height == 1) {
			if (private.unDelegatesByRound[round].length == slots.delegates || previousBlock.height == 1) {
				var outsiders = [];
				async.series([
					function (cb) {
						if (block.height != 1) {
							modules.delegates.generateDelegateList(block.height, function (err, roundDelegates) {
								if (err) {
									return cb(err);
								}
								for (var i = 0; i < roundDelegates.length; i++) {
									if (private.unDelegatesByRound[round].indexOf(roundDelegates[i]) == -1) {
										outsiders.push(modules.accounts.generateAddressByPublicKey(roundDelegates[i]));
									}
								}
								cb();
							});
						} else {
							cb();
						}
					},
					function (cb) {
						if (!outsiders.length) {
							return cb();
						}
						var escaped = outsiders.map(function (item) {
							return "'" + item + "'";
						});
						library.db.none("UPDATE mem_accounts SET \"missedblocks\" = \"missedblocks\" + 1 WHERE \"address\" IN (" + escaped.join(",") + ")").then(function () {
							return cb();
						}).catch(function (err) {
							return cb("Round#backwardTick error");
						});
					},
					function (cb) {
						self.getVotes(round, function (err, votes) {
							if (err) {
								return cb(err);
							}
							async.eachSeries(votes, function (vote, cb) {
								library.db.none("UPDATE mem_accounts SET \"vote\" = \"vote\" + ${amount} WHERE \"address\" = ${address}", {
									address: modules.accounts.generateAddressByPublicKey(vote.delegate),
									amount: vote.amount
								}).then(function () {
									return cb();
								}).catch(function (err) {
									return cb("Round#backwardTick error");
								});
							}, function (err) {
								self.flush(round, function (err2) {
									cb(err || err2);
								});
							})
						});
					},
					function (cb) {
						var roundChanges = new RoundChanges(round);

						async.forEachOfSeries(private.unDelegatesByRound[round], function (delegate, index, cb) {
							var changes = roundChanges.at(index);

							modules.accounts.mergeAccountAndGet({
								publicKey: delegate,
								balance: -changes.balance,
								u_balance: -changes.balance,
								blockId: block.id,
								round: modules.round.calc(block.height),
								fees: -changes.fees,
								rewards: -changes.rewards
							}, function (err) {
								if (err) {
									return cb(err);
								}
								if (index === 0) {
									modules.accounts.mergeAccountAndGet({
										publicKey: delegate,
										balance: -changes.feesRemaining,
										u_balance: -changes.feesRemaining,
										blockId: block.id,
										round: modules.round.calc(block.height),
										fees: -changes.feesRemaining,
									}, cb);
								} else {
									cb();
								}
							});
						}, cb);
					},
					function (cb) {
						self.getVotes(round, function (err, votes) {
							if (err) {
								return cb(err);
							}
							async.eachSeries(votes, function (vote, cb) {
								library.db.none("UPDATE mem_accounts SET \"vote\" = \"vote\" + ${amount} WHERE \"address\" = ${address}", {
									address: modules.accounts.generateAddressByPublicKey(vote.delegate),
									amount: vote.amount
								}).then(function () {
									return cb();
								}).catch(function (err) {
									return cb("Round#backwardTick error");
								});
							}, function (err) {
								self.flush(round, function (err2) {
									cb(err || err2);
								});
							})
						});
					}
				], function (err) {
					delete private.unFeesByRound[round];
					delete private.unRewardsByRound[round];
					delete private.unDelegatesByRound[round];
					done(err)
				});
			} else {
				done();
			}
		} else {
			done();
		}
	});
}

Round.prototype.tick = function (block, cb) {
	function done(err) {
		cb && setImmediate(cb, err);
	}

	modules.accounts.mergeAccountAndGet({
		publicKey: block.generatorPublicKey,
		producedblocks: 1,
		blockId: block.id,
		round: modules.round.calc(block.height)
	}, function (err) {
		if (err) {
			return done(err);
		}
		var round = self.calc(block.height);

		private.feesByRound[round] = Math.floor(private.feesByRound[round]) || 0;
		private.feesByRound[round] += Math.floor(block.totalFee);

		private.rewardsByRound[round] = (private.rewardsByRound[round] || []);
		private.rewardsByRound[round].push(block.reward);

		private.delegatesByRound[round] = private.delegatesByRound[round] || [];
		private.delegatesByRound[round].push(block.generatorPublicKey);

		var nextRound = self.calc(block.height + 1);

		if (round !== nextRound || block.height == 1) {
			if (private.delegatesByRound[round].length == slots.delegates || block.height == 1 || block.height == 101) {
				var outsiders = [];

				async.series([
					function (cb) {
						if (block.height != 1) {
							modules.delegates.generateDelegateList(block.height, function (err, roundDelegates) {
								if (err) {
									return cb(err);
								}
								for (var i = 0; i < roundDelegates.length; i++) {
									if (private.delegatesByRound[round].indexOf(roundDelegates[i]) == -1) {
										outsiders.push(modules.accounts.generateAddressByPublicKey(roundDelegates[i]));
									}
								}
								cb();
							});
						} else {
							cb();
						}
					},
					function (cb) {
						if (!outsiders.length) {
							return cb();
						}
						var escaped = outsiders.map(function (item) {
							return "'" + item + "'";
						});
						library.db.none("UPDATE mem_accounts SET \"missedblocks\" = \"missedblocks\" + 1 WHERE \"address\" IN (" + escaped.join(",") + ")").then(function () {
							return cb();
						}).catch(function (err) {
							return cb("Round#tick error");
						});
					},
					function (cb) {
						self.getVotes(round, function (err, votes) {
							if (err) {
								return cb(err);
							}
							async.eachSeries(votes, function (vote, cb) {
								library.db.none("UPDATE mem_accounts SET \"vote\" = \"vote\" + ${amount} WHERE \"address\" = ${address}", {
									address: modules.accounts.generateAddressByPublicKey(vote.delegate),
									amount: vote.amount
								}).then(function () {
									return cb();
								}).catch(function (err) {
									return cb("Round#tick error");
								});
							}, function (err) {
								self.flush(round, function (err2) {
									cb(err || err2);
								});
							});
						});
					},
					function (cb) {
						var roundChanges = new RoundChanges(round);

						async.forEachOfSeries(private.delegatesByRound[round], function (delegate, index, cb) {
							var changes = roundChanges.at(index);

							modules.accounts.mergeAccountAndGet({
								publicKey: delegate,
								balance: changes.balance,
								u_balance: changes.balance,
								blockId: block.id,
								round: modules.round.calc(block.height),
								fees: changes.fees,
								rewards: changes.rewards
							}, function (err) {
								if (err) {
									return cb(err);
								}
								if (index === private.delegatesByRound[round].length - 1) {
									modules.accounts.mergeAccountAndGet({
										publicKey: delegate,
										balance: changes.feesRemaining,
										u_balance: changes.feesRemaining,
										blockId: block.id,
										round: modules.round.calc(block.height),
										fees: changes.feesRemaining
									}, cb);
								} else {
									cb();
								}
							});
						}, cb);
					},
					function (cb) {
						self.getVotes(round, function (err, votes) {
							if (err) {
								return cb(err);
							}
							async.eachSeries(votes, function (vote, cb) {
								library.db.none("UPDATE mem_accounts SET \"vote\" = \"vote\" + ${amount} WHERE \"address\" = ${address}", {
									address: modules.accounts.generateAddressByPublicKey(vote.delegate),
									amount: vote.amount
								}).then(function () {
									return cb();
								}).catch(function (err) {
									return cb("Round#tick error");
								});
							}, function (err) {
								library.bus.message('finishRound', round);
								self.flush(round, function (err2) {
									cb(err || err2);
								});
							})
						});
					}
				], function (err) {
					delete private.feesByRound[round];
					delete private.rewardsByRound[round];
					delete private.delegatesByRound[round];
					done(err);
				});
			} else {
				done();
			}
		} else {
			done();
		}
	});
}

Round.prototype.sandboxApi = function (call, args, cb) {
	sandboxHelper.callMethod(shared, call, args, cb);
}

// Events
Round.prototype.onBind = function (scope) {
	modules = scope;
}

Round.prototype.onBlockchainReady = function () {
	var round = self.calc(modules.blocks.getLastBlock().height);
	library.db.query("SELECT SUM(b.\"totalFee\")::bigint AS \"fees\", ARRAY_AGG(b.\"reward\") AS \"rewards\", ARRAY_AGG(ENCODE(b.\"generatorPublicKey\", 'hex')) AS \"delegates\" " +
		"FROM blocks b WHERE (SELECT (CAST(b.\"height\" / 101 AS INTEGER) + (CASE WHEN b.\"height\" % 101 > 0 THEN 1 ELSE 0 END))) = ${round}", { round: round }).then(function (rows) {

		var rewards = [];

		rows[0].rewards.forEach(function (reward) {
			rewards.push(Math.floor(reward));
		});

		private.feesByRound[round] = Math.floor(rows[0].fees);
		private.rewardsByRound[round] = rewards;
		private.delegatesByRound[round] = rows[0].delegates;
		private.loaded = true;

	}).catch(function (err) {
		return cb("Round#onBlockchainReady error");
	});
}

Round.prototype.onFinishRound = function (round) {
	library.network.io.sockets.emit('rounds/change', {number: round});
}

Round.prototype.cleanup = function (cb) {
	private.loaded = false;
	cb();
}

// Shared

// Export
module.exports = Round;
<|endoftext|>


<commit_before>
import { get } from '../../fn/fn.js';
import { now } from '../../dom/dom.js';

const DEBUG  = window.DEBUG || false;

// Render queue
const maxFrameDuration = 0.015;

const queue = new Set();

const addons = [];

const errors = [];

var mutationCount = 0;

var frame;

function logRenders(tStart, tStop, mutations, errors) {
	// Pass some information to the frame cuer for debugging
	//const renderers = Array.from(queue).concat(addons);
	//const data      = renderers.reduce(collate, {});
	//console.table(data);

	if (DEBUG) {
		console.log('%c' + queue.size + ' cued renderer' + (queue.size === 1 ? '' : 's') + '. ' + addons.length + ' added renderer'+ (addons.length === 1 ? '' : 's') + '. ' + mutations + ' DOM mutations %c' + (tStop - tStart).toFixed(3) + 's', 'color: #6894ab; font-weight: 300;', '');
		console.groupEnd();
	}

	if (errors.length) {
		console.log('       %c' + errors.length + ' Errors rendering ' + errors.join(' '), 'color: #d34515; font-weight: 400;');
	}

	if ((tStop - tStart) > maxFrameDuration) {
		console.log('       %c' + mutations + ' DOM mutations took ' + (tStop - tStart).toFixed(3) + 's', 'color: #d34515; font-weight: 400;');
	}
}

function fire(queue) {
	var count = 0;
	var renderer;

	if (DEBUG) {
		for (renderer of queue) {
			try {
				count += (renderer.fire ? renderer.fire() : renderer.render()) || 0;
			}
			catch(e) {
				console.log('%cError rendering ' + renderer.label + ' with', 'color: #d34515; font-weight: 300;', renderer.scope);
				console.error(e);
				errors.push(renderer.token);
			}
		}
	}
	else {
		for (renderer of queue) {
			count += (renderer.fire ? renderer.fire() : renderer.render()) || 0;
		}
	}

	return count;
}

function run(time) {
	if (DEBUG) {
		console.groupCollapsed('%cSparky %cframe ' + (time / 1000).toFixed(3), 'color: #a3b31f; font-weight: 600;', 'color: #6894ab; font-weight: 400;');
	}

	addons.length = 0;
	errors.length = 0;
	mutationCount = 0;
	frame = true;

	const tStart = now();
	const count  = fire(queue);
	const tStop  = now();

	mutationCount += count;

	if (DEBUG || errors.length || ((tStop - tStart) > maxFrameDuration)) {
		logRenders(tStart, tStop, mutationCount, errors);
	}

	queue.clear();
	frame = undefined;
}

export function cue(renderer) {
	if (queue.has(renderer)) {
		//if (DEBUG) { console.warn('frame: Trying to add an existing fn. Dropped', fn.name + '()'); }
		return;
	}

	// Functions cued during frame are run syncronously (to preserve
	// inner-DOM-first order of execution during setup)
	if (frame === true) {
		const count = (renderer.fire ? renderer.fire() : renderer.render()) || 0;
		mutationCount += count;
		addons.push(renderer);
		return;
	}

	queue.add(renderer);

	if (frame === undefined) {
		//if (DEBUG) { console.log('(request head frame)'); }
		frame = requestAnimationFrame(run);
	}
}

export function uncue(renderer) {
	queue.delete(renderer);

	if (frame !== undefined && frame !== true && queue.size === 0) {
		//if (DEBUG) { console.log('(cancel master frame)'); }
		cancelAnimationFrame(frame);
		frame = undefined;
	}
}
<commit_msg>Render counts<commit_after>
import { get } from '../../fn/fn.js';
import { now } from '../../dom/dom.js';

const DEBUG  = window.DEBUG || false;

// Render queue
const maxFrameDuration = 0.015;

const queue = new Set();

const addons = [];

const errors = [];

var mutationCount = 0;

var frame;

function logRenders(tStart, tStop, mutations, errors) {
	// Pass some information to the frame cuer for debugging
	//const renderers = Array.from(queue).concat(addons);
	//const data      = renderers.reduce(collate, {});
	//console.table(data);

	if (DEBUG) {
		console.log('%c' + queue.size + ' cued renderer' + (queue.size === 1 ? '' : 's') + '. ' + addons.length + ' added renderer'+ (addons.length === 1 ? '' : 's') + '. ' + mutations + ' DOM mutations %c' + (tStop - tStart).toFixed(3) + 's', 'color: #6894ab; font-weight: 300;', '');
		console.groupEnd();
	}

	if (errors.length) {
		console.log('       %c' + errors.length + ' Errors rendering ' + errors.join(' '), 'color: #d34515; font-weight: 400;');
	}

	if ((tStop - tStart) > maxFrameDuration) {
		console.log('       %c' + mutations + ' DOM mutations took ' + (tStop - tStart).toFixed(3) + 's', 'color: #d34515; font-weight: 400;');
	}
}

function fire(queue) {
	var count = 0;
	var renderer;

	if (DEBUG) {
		for (renderer of queue) {
			try {
				count += (renderer.fire ? renderer.fire() : renderer.render()) || 0;
			}
			catch(e) {
				console.log('%cError rendering ' + renderer.label + ' with', 'color: #d34515; font-weight: 300;', renderer.scope);
				console.error(e);
				errors.push(renderer.token);
			}
		}
	}
	else {
		for (renderer of queue) {
			count += (renderer.fire ? renderer.fire() : renderer.render()) || 0;
		}
	}

	return count;
}

function run(time) {
	if (DEBUG) {
		console.groupCollapsed('%cSparky %cframe ' + (time / 1000).toFixed(3), 'color: #a3b31f; font-weight: 600;', 'color: #6894ab; font-weight: 400;');
	}

	addons.length = 0;
	errors.length = 0;
	mutationCount = 0;
	frame = true;

	const tStart = now();
	const count  = fire(queue);
	const tStop  = now();

	mutationCount += count;

	if (DEBUG || errors.length || ((tStop - tStart) > maxFrameDuration)) {
		logRenders(tStart, tStop, mutationCount, errors);
	}

	queue.clear();
	frame = undefined;
}

export function cue(renderer) {
	if (queue.has(renderer)) {
		return;
	}

	// Functions cued during frame are run syncronously (to preserve
	// inner-DOM-first order of execution during setup)
	if (frame === true) {
		const count = (renderer.fire ? renderer.fire() : renderer.render()) || 0;
		mutationCount += count;
		addons.push(renderer);
		return;
	}

	queue.add(renderer);

	if (frame === undefined) {
		frame = requestAnimationFrame(run);
	}
}

export function uncue(renderer) {
	queue.delete(renderer);

	if (frame !== undefined && frame !== true && queue.size === 0) {
		//if (DEBUG) { console.log('(cancel master frame)'); }
		cancelAnimationFrame(frame);
		frame = undefined;
	}
}
<|endoftext|>


<commit_before>var Telegram = require('node-telegram-bot-api');
var fs = require('fs');
var path = require('path');
var irc = require('./irc');
var nodeStatic = require('node-static');
var mkdirp = require('mkdirp');
var crypto = require('crypto');
var nickcolor = require('./nickcolor');

var myUser = {};
var seenNames = [];

// tries to read chat ids from a file
var readChatIds = function(arr) {
    console.log('\n');
    console.log('NOTE!');
    console.log('=====');

    var idMissing = false;
    try {
        var json = JSON.parse(fs.readFileSync(process.env.HOME + '/.teleirc/chat_ids'));
        for (var i = 0; i < arr.length; i++) {
            var key = arr[i].tgGroup;
            if (key in json) {
                arr[i].tgChatId = json[key];
                console.log('id found for:', key, ':', json[key]);
            } else {
                console.log('id not found:', key);
                idMissing = true;
            }
        }
    } catch (e) {
        console.log('~/.teleirc/chat_ids file not found!');
        idMissing = true;
    }

    if (idMissing) {
        console.log(
            '\nPlease add your Telegram bot to a Telegram group and have' +
            '\nsomeone send a message to that group.' +
            '\nteleirc will then automatically store your group chat_id.');
    }

    console.log('\n');
};

var writeChatIds = function(config) {
    var json = {};
    for (var i = 0; i < config.channels.length; i++) {
        if (config.channels[i].tgChatId) {
            json[config.channels[i].tgGroup] = config.channels[i].tgChatId;
        }
    }
    json = JSON.stringify(json);
    fs.writeFile(process.env.HOME + '/.teleirc/chat_ids', json, function(err) {
        if (err) {
            console.log('error while storing chat ID:');
            console.log(err);
        } else {
            console.log('successfully stored chat ID in ~/.teleirc/chat_ids');
        }
    });
};

var getName = function(user, config) {
    var name = config.nameFormat;

    if (user.username) {
        name = name.replace('%username%', user.username, 'g');
    } else {
        // if user lacks username, use fallback format string instead
        name = name.replace('%username%', config.usernameFallbackFormat, 'g');
    }

    name = name.replace('%firstName%', user.first_name || '', 'g');
    name = name.replace('%lastName%', user.last_name || '', 'g');

    // get rid of leading and trailing whitespace
    name = name.replace(/(^\s*)|(\s*$)/g, '');

    if (config.nickcolor) {
        return nickcolor(name);
    }

    return name;
};

var getIRCName = function(msg, config) {
    var ircNickMatchRE = /^<(.*)>/;
    var results = ircNickMatchRE.exec(msg.text);
    var name;
    if (!results) {
        // Fall back to telegram name (i.e. for the topic change message)
        name = getName(msg.from, config);
    } else {
        name = results[1];
    }

    return name;
};

function randomValueBase64(len) {
    return crypto.randomBytes(Math.ceil(len * 3 / 4))
        .toString('base64')
        .slice(0, len)
        .replace(/\+/g, '0')
        .replace(/\//g, '0');
}

var serveFile = function(fileId, config, tg, callback) {
    var randomString = randomValueBase64(config.mediaRandomLenght);
    mkdirp(process.env.HOME + '/.teleirc/files/' + randomString);
    tg.downloadFile(fileId, process.env.HOME + '/.teleirc/files/' +
                                   randomString).then(function(filePath) {
        callback(config.httpLocation + '/' + randomString + '/' + path.basename(filePath));
    });
};

module.exports = function(config, sendTo) {
    // start HTTP server for media files if configured to do so
    if (config.showMedia) {
        var fileServer = new nodeStatic.Server(process.env.HOME + '/.teleirc/files');
        mkdirp(process.env.HOME + '/.teleirc/files');

        require('http').createServer(function(req, res) {
            req.addListener('end', function() {
                fileServer.serve(req, res);
            }).resume();
        }).listen(config.httpPort);
    }

    var tg = new Telegram(config.tgToken, {polling: true});

    // Get our own Telegram user
    tg.getMe().then(function(me) {
        myUser = me;
    });
    readChatIds(config.channels);

    tg.on('message', function(msg) {
        var age = Math.floor(Date.now() / 1000) - msg.date;
        if (config.maxMsgAge && age > config.maxMsgAge) {
            return console.log('skipping ' + age + ' seconds old message! ' +
                'NOTE: change this behaviour with config.maxMsgAge, also check your system clock');
        }

        var channel = config.channels.filter(function(channel) {
            return channel.tgGroup === msg.chat.title;
        })[0];

        if (!channel) {
            return;
        }

        if (!channel.tgChatId) {
            console.log('storing chat ID: ' + msg.chat.id);
            channel.tgChatId = msg.chat.id;
            writeChatIds(config);
        }

        if (msg.text && !msg.text.indexOf('/names')) {
            var names = sendTo.ircNames(channel);
            names.sort();
            names = 'Users on ' + (channel.chanAlias || channel.ircChan) + ':\n\n' +
                names.join(', ');

            return tg.sendMessage(channel.tgChatId, names);
        }

        // skip posts containing media if it's configured off
        if ((msg.audio || msg.document || msg.photo || msg.sticker || msg.video ||
            msg.voice || msg.contact || msg.location) && !config.showMedia) {
            return;
        }

        // track usernames for creating mentions
        if (seenNames.indexOf(msg.from.username) == -1) {
            seenNames.push(msg.from.username);
        }
        var text;
        var prefix = '';
        if (!config.soloUse) {
            prefix = '<' + getName(msg.from, config) + '>: ';
        }
        if (msg.reply_to_message && msg.text) {
            var replyName;
            if (msg.reply_to_message.from.username == myUser.username) {
                replyName = getIRCName(msg.reply_to_message, config);
            } else {
                replyName = getName(msg.reply_to_message.from, config);
            }
            text = msg.text.replace(/\n/g , prefix);
            sendTo.irc(channel.ircChan, prefix +
                '@' + replyName + ', ' + text);
        } else if (msg.audio) {
            serveFile(msg.audio.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Audio, ' + msg.audio.duration + 's)' + url);
            });
        } else if (msg.document) {
            serveFile(msg.document.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Document) ' + url);
            });
        } else if (msg.photo) {
            // pick the highest quality photo
            var photo = msg.photo[msg.photo.length - 1];

            serveFile(photo.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Photo, ' + photo.width + 'x' + photo.height + ') ' +
                    url + (msg.caption ? ' ' + msg.caption : ''));
            });
        } else if (msg.new_chat_photo) {
            // pick the highest quality photo
            var chatPhoto = msg.new_chat_photo[msg.new_chat_photo.length - 1];

            serveFile(chatPhoto.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(New chat photo, ' + chatPhoto.width + 'x' + chatPhoto.height + ') ' + url);
            });
        } else if (msg.sticker) {
            serveFile(msg.sticker.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Sticker, ' + msg.sticker.width + 'x' + msg.sticker.height + ') ' + url);
            });
        } else if (msg.video) {
            serveFile(msg.video.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Video, ' + msg.video.duration + 's)' +
                    url + (msg.caption ? ' ' + msg.caption : ''));
            });
        } else if (msg.voice) {
            serveFile(msg.voice.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Voice, ' + msg.voice.duration + 's)' + url);
            });
        } else if (msg.contact) {
            sendTo.irc(channel.ircChan, prefix +
                '(Contact, ' + '"' + msg.contact.first_name + ' ' +
                msg.contact.last_name + '", ' +
                msg.contact.phone_number + ')');
        } else if (msg.location) {
            sendTo.irc(channel.ircChan, prefix +
                '(Location, ' + 'lon: ' + msg.location.longitude +
                              ', lat: ' + msg.location.latitude + ')');
        } else if (msg.new_chat_participant) {
            sendTo.irc(channel.ircChan, getName(msg.new_chat_participant, config) +
                ' was added by: ' + getName(msg.from, config));
        } else if (msg.left_chat_participant) {
            sendTo.irc(channel.ircChan, getName(msg.left_chat_participant, config) +
                ' was removed by: ' + getName(msg.from, config));
        } else {
            text = msg.text.replace(/\n/g , '\n' + prefix);
            sendTo.irc(channel.ircChan, prefix + text);
        }
    });

    sendTo.tg = function(channel, msg) {
        if (!channel.tgChatId) {
            var err = 'ERROR: No chat_id set! Add me to a Telegram group ' +
                      'and say hi so I can find your group\'s chat_id!';
            sendTo.irc(channel.ircChan, err);
            console.error(err);
            return;
        }

        seenNames.forEach(function(name) {
            var rx = new RegExp('\\b' + name + '\\b', 'i');
            msg = msg.replace(rx, '@' + name);
        });

        console.log('  >> relaying to TG: ' + msg);
        tg.sendMessage(channel.tgChatId, msg);
    };
};
<commit_msg>handle upgrading group to supergroup correctly (#73)<commit_after>var Telegram = require('node-telegram-bot-api');
var fs = require('fs');
var path = require('path');
var irc = require('./irc');
var nodeStatic = require('node-static');
var mkdirp = require('mkdirp');
var crypto = require('crypto');
var nickcolor = require('./nickcolor');

var myUser = {};
var seenNames = [];

// tries to read chat ids from a file
var readChatIds = function(arr) {
    console.log('\n');
    console.log('NOTE!');
    console.log('=====');

    var idMissing = false;
    try {
        var json = JSON.parse(fs.readFileSync(process.env.HOME + '/.teleirc/chat_ids'));
        for (var i = 0; i < arr.length; i++) {
            var key = arr[i].tgGroup;
            if (key in json) {
                arr[i].tgChatId = json[key];
                console.log('id found for:', key, ':', json[key]);
            } else {
                console.log('id not found:', key);
                idMissing = true;
            }
        }
    } catch (e) {
        console.log('~/.teleirc/chat_ids file not found!');
        idMissing = true;
    }

    if (idMissing) {
        console.log(
            '\nPlease add your Telegram bot to a Telegram group and have' +
            '\nsomeone send a message to that group.' +
            '\nteleirc will then automatically store your group chat_id.');
    }

    console.log('\n');
};

var writeChatIds = function(config) {
    var json = {};
    for (var i = 0; i < config.channels.length; i++) {
        if (config.channels[i].tgChatId) {
            json[config.channels[i].tgGroup] = config.channels[i].tgChatId;
        }
    }
    json = JSON.stringify(json);
    console.log('INFO: Storing new chatId...');
    try {
        fs.writeFileSync(process.env.HOME + '/.teleirc/chat_ids', json);
        console.log('successfully stored chat ID in ~/.teleirc/chat_ids');
    } catch (e) {
        console.log('error while storing chat ID:');
        console.log(e);
    }
};

var getName = function(user, config) {
    var name = config.nameFormat;

    if (user.username) {
        name = name.replace('%username%', user.username, 'g');
    } else {
        // if user lacks username, use fallback format string instead
        name = name.replace('%username%', config.usernameFallbackFormat, 'g');
    }

    name = name.replace('%firstName%', user.first_name || '', 'g');
    name = name.replace('%lastName%', user.last_name || '', 'g');

    // get rid of leading and trailing whitespace
    name = name.replace(/(^\s*)|(\s*$)/g, '');

    if (config.nickcolor) {
        return nickcolor(name);
    }

    return name;
};

var getIRCName = function(msg, config) {
    var ircNickMatchRE = /^<(.*)>/;
    var results = ircNickMatchRE.exec(msg.text);
    var name;
    if (!results) {
        // Fall back to telegram name (i.e. for the topic change message)
        name = getName(msg.from, config);
    } else {
        name = results[1];
    }

    return name;
};

function randomValueBase64(len) {
    return crypto.randomBytes(Math.ceil(len * 3 / 4))
        .toString('base64')
        .slice(0, len)
        .replace(/\+/g, '0')
        .replace(/\//g, '0');
}

var serveFile = function(fileId, config, tg, callback) {
    var randomString = randomValueBase64(config.mediaRandomLenght);
    mkdirp(process.env.HOME + '/.teleirc/files/' + randomString);
    tg.downloadFile(fileId, process.env.HOME + '/.teleirc/files/' +
                                   randomString).then(function(filePath) {
        callback(config.httpLocation + '/' + randomString + '/' + path.basename(filePath));
    });
};

module.exports = function(config, sendTo) {
    // start HTTP server for media files if configured to do so
    if (config.showMedia) {
        var fileServer = new nodeStatic.Server(process.env.HOME + '/.teleirc/files');
        mkdirp(process.env.HOME + '/.teleirc/files');

        require('http').createServer(function(req, res) {
            req.addListener('end', function() {
                fileServer.serve(req, res);
            }).resume();
        }).listen(config.httpPort);
    }

    var tg = new Telegram(config.tgToken, {polling: true});

    // Get our own Telegram user
    tg.getMe().then(function(me) {
        myUser = me;
    });
    readChatIds(config.channels);

    tg.on('message', function(msg) {
        console.log('got msg:');
        console.log(msg);

        var channel = config.channels.filter(function(channel) {
            return channel.tgGroup === msg.chat.title;
        })[0];

        if (!channel) {
            console.log('VERBOSE: Telegram group not found in config: "' +
                        msg.chat.title + '", dropping message...');
            return;
        }

        // check if message contains a migrate command
        if (msg.migrate_to_chat_id) {
            console.log('INFO: chat migrated to supergroup.');
            channel.tgChatId = msg.migrate_to_chat_id;
            writeChatIds(config);
            return console.log('INFO: stored new chatId');
        } else if (!channel.tgChatId) {
            console.log('storing chat ID: ' + msg.chat.id);
            channel.tgChatId = msg.chat.id;
            writeChatIds(config);
        }

        var age = Math.floor(Date.now() / 1000) - msg.date;
        if (config.maxMsgAge && age > config.maxMsgAge) {
            return console.log('skipping ' + age + ' seconds old message! ' +
                'NOTE: change this behaviour with config.maxMsgAge, also check your system clock');
        }

        if (msg.text && !msg.text.indexOf('/names')) {
            var names = sendTo.ircNames(channel);
            names.sort();
            names = 'Users on ' + (channel.chanAlias || channel.ircChan) + ':\n\n' +
                names.join(', ');

            return tg.sendMessage(channel.tgChatId, names);
        }

        // skip posts containing media if it's configured off
        if ((msg.audio || msg.document || msg.photo || msg.sticker || msg.video ||
            msg.voice || msg.contact || msg.location) && !config.showMedia) {
            return;
        }

        // track usernames for creating mentions
        if (seenNames.indexOf(msg.from.username) == -1) {
            seenNames.push(msg.from.username);
        }
        var text;
        var prefix = '';
        if (!config.soloUse) {
            prefix = '<' + getName(msg.from, config) + '>: ';
        }
        if (msg.reply_to_message && msg.text) {
            var replyName;
            if (msg.reply_to_message.from.username == myUser.username) {
                replyName = getIRCName(msg.reply_to_message, config);
            } else {
                replyName = getName(msg.reply_to_message.from, config);
            }
            text = msg.text.replace(/\n/g , prefix);
            sendTo.irc(channel.ircChan, prefix +
                '@' + replyName + ', ' + text);
        } else if (msg.audio) {
            serveFile(msg.audio.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Audio, ' + msg.audio.duration + 's)' + url);
            });
        } else if (msg.document) {
            serveFile(msg.document.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Document) ' + url);
            });
        } else if (msg.photo) {
            // pick the highest quality photo
            var photo = msg.photo[msg.photo.length - 1];

            serveFile(photo.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Photo, ' + photo.width + 'x' + photo.height + ') ' +
                    url + (msg.caption ? ' ' + msg.caption : ''));
            });
        } else if (msg.new_chat_photo) {
            // pick the highest quality photo
            var chatPhoto = msg.new_chat_photo[msg.new_chat_photo.length - 1];

            serveFile(chatPhoto.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(New chat photo, ' + chatPhoto.width + 'x' + chatPhoto.height + ') ' + url);
            });
        } else if (msg.sticker) {
            serveFile(msg.sticker.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Sticker, ' + msg.sticker.width + 'x' + msg.sticker.height + ') ' + url);
            });
        } else if (msg.video) {
            serveFile(msg.video.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Video, ' + msg.video.duration + 's)' +
                    url + (msg.caption ? ' ' + msg.caption : ''));
            });
        } else if (msg.voice) {
            serveFile(msg.voice.file_id, config, tg, function(url) {
                sendTo.irc(channel.ircChan, prefix +
                    '(Voice, ' + msg.voice.duration + 's)' + url);
            });
        } else if (msg.contact) {
            sendTo.irc(channel.ircChan, prefix +
                '(Contact, ' + '"' + msg.contact.first_name + ' ' +
                msg.contact.last_name + '", ' +
                msg.contact.phone_number + ')');
        } else if (msg.location) {
            sendTo.irc(channel.ircChan, prefix +
                '(Location, ' + 'lon: ' + msg.location.longitude +
                              ', lat: ' + msg.location.latitude + ')');
        } else if (msg.new_chat_participant) {
            sendTo.irc(channel.ircChan, getName(msg.new_chat_participant, config) +
                ' was added by: ' + getName(msg.from, config));
        } else if (msg.left_chat_participant) {
            sendTo.irc(channel.ircChan, getName(msg.left_chat_participant, config) +
                ' was removed by: ' + getName(msg.from, config));
        } else if (msg.text) {
            text = msg.text.replace(/\n/g , '\n' + prefix);
            sendTo.irc(channel.ircChan, prefix + text);
        } else {
            console.log('WARNING: unhandled message:');
            console.log(msg);
        }
    });

    sendTo.tg = function(channel, msg) {
        if (!channel.tgChatId) {
            var err = 'ERROR: No chat_id set! Add me to a Telegram group ' +
                      'and say hi so I can find your group\'s chat_id!';
            sendTo.irc(channel.ircChan, err);
            console.error(err);
            return;
        }

        seenNames.forEach(function(name) {
            var rx = new RegExp('\\b' + name + '\\b', 'i');
            msg = msg.replace(rx, '@' + name);
        });

        console.log('  >> relaying to TG: ' + msg);
        tg.sendMessage(channel.tgChatId, msg);
    };
};
<|endoftext|>


<commit_before>'use strict';
let fs = require('fs');
let gulp = require('gulp');
let browserify = require('browserify');
let mergeStream = require('merge-stream');
let runSequence = require('run-sequence').use(gulp);
let streamToPromise = require('stream-to-promise');
let source = require('vinyl-source-stream');
let plumber = require('gulp-plumber');
let sourcemaps = require('gulp-sourcemaps');
let stylish = require('gulp-tslint-stylish');
let tslint = require('gulp-tslint');
let typescript = require('gulp-typescript');

module.exports = function (opts) {
    opts = opts || {};
    opts.lint = opts.lint || ['src/**/*.ts'];
    opts.umd = opts.umd || {
        src: ['src/**/*.ts', '!src/test/**', '!src/public/script/**'],
        dest: 'lib/',
        configPath: 'src/tsconfig.json'
    }
    opts.browserify = opts.browserify || {
        src: 'src/public/script/main.ts',
        dest: ['lib/public/script/', 'main.js']
    }

    let project = typescript.createProject(opts.umd.configPath, {
        typescript: require('typescript')
    });

    let releaseProject = typescript.createProject(opts.umd.configPath, {
        removeComments: true,
        typescript: require('typescript')
    });

    gulp.task('ts:build', function (callback) {
        runSequence('ts:lint', 'ts:compile', callback);
    });
    gulp.task('ts:release', function (callback) {
        runSequence('ts:lint', 'ts:release-compile', callback);
    });

    gulp.task('ts:lint', function () {
        return gulp.src(opts.lint)
            .pipe(plumber())
            .pipe(tslint())
            .pipe(tslint.report(stylish, {
                emitError: false,
                sort: true,
                bell: false
            }));
    });

    gulp.task('ts:compile:umd', function () {
        return gulp.src(opts.umd.src)
            .pipe(sourcemaps.init())
            .pipe(typescript(project))
            .pipe(sourcemaps.write())
            .pipe(gulp.dest(opts.umd.dest));
    });

    gulp.task('ts:release-compile:umd', function () {
        return gulp.src(opts.umd.src)
            .pipe(typescript(releaseProject))
            .pipe(gulp.dest(opts.umd.dest));
    });

    gulp.task('ts:compile:browserify', function () {
        return new Promise(function (resolve, reject) {
            fs.exists(opts.browserify.src, function (exists) {
                if (!exists) {
                    resolve();
                    return;
                }
                let id = setTimeout(function () {
                    reject(new Error('Timeout'));
                }, 10 * 1000);
                browserify({
                    entries: [opts.browserify.src],
                    debug: true
                })
                    .plugin('tsify', {
                        target: 'ES5',
                        typescript: require('typescript')
                    })
                    .bundle()
                    .on('error', function (err) { console.error(err.message); })
                    .pipe(source(opts.browserify.dest[1]))
                    .pipe(gulp.dest(opts.browserify.dest[0]))
                    .on('end', function () {
                        clearTimeout(id);
                        resolve();
                    });
            });
        });
    });

    gulp.task('ts:release-compile:browserify', function () {
        return new Promise(function (resolve, reject) {
            fs.exists(opts.browserify.src, function (exists) {
                if (!exists) {
                    resolve();
                    return;
                }
                let id = setTimeout(function () {
                    reject(new Error('Timeout'));
                }, 10 * 1000);
                browserify({
                    entries: [opts.browserify.src]
                })
                    .plugin('tsify', {
                        target: 'ES5',
                        removeComments: true,
                        typescript: require('typescript')
                    })
                    .bundle()
                    .on('error', function (err) { console.error(err.message); })
                    .pipe(source(opts.browserify.dest[1]))
                    .pipe(gulp.dest(opts.browserify.dest[0]))
                    .on('end', function () {
                        clearTimeout(id);
                        resolve();
                    });
            });
        });
    });

    gulp.task('ts:compile', ['ts:compile:umd', 'ts:compile:browserify']);

    gulp.task('ts:release-compile', ['ts:release-compile:umd', 'ts:release-compile:browserify']);
};
<commit_msg>Add multi file support to browserify<commit_after>'use strict';
let fs = require('fs');
let path = require('path');
let gulp = require('gulp');
let browserify = require('browserify');
let mergeStream = require('merge-stream');
let runSequence = require('run-sequence').use(gulp);
let streamToPromise = require('stream-to-promise');
let source = require('vinyl-source-stream');
let plumber = require('gulp-plumber');
let sourcemaps = require('gulp-sourcemaps');
let stylish = require('gulp-tslint-stylish');
let tslint = require('gulp-tslint');
let typescript = require('gulp-typescript');

module.exports = function (opts) {
    opts = opts || {};
    opts.lint = opts.lint || ['src/**/*.ts'];
    opts.umd = opts.umd || {
        src: ['src/**/*.ts', '!src/test/**', '!src/public/script/**'],
        dest: 'lib/',
        configPath: 'src/tsconfig.json'
    };
    opts.browserify = opts.browserify || [{
        src: 'src/public/script/main.ts',
        dest: 'lib/public/script/'
    }];

    let project = typescript.createProject(opts.umd.configPath, {
        typescript: require('typescript')
    });

    let releaseProject = typescript.createProject(opts.umd.configPath, {
        removeComments: true,
        typescript: require('typescript')
    });

    gulp.task('ts:build', function (callback) {
        runSequence('ts:lint', 'ts:compile', callback);
    });
    gulp.task('ts:release', function (callback) {
        runSequence('ts:lint', 'ts:release-compile', callback);
    });

    gulp.task('ts:lint', function () {
        return gulp.src(opts.lint)
            .pipe(plumber())
            .pipe(tslint())
            .pipe(tslint.report(stylish, {
                emitError: false,
                sort: true,
                bell: false
            }));
    });

    gulp.task('ts:compile:umd', function () {
        return gulp.src(opts.umd.src)
            .pipe(sourcemaps.init())
            .pipe(typescript(project))
            .pipe(sourcemaps.write())
            .pipe(gulp.dest(opts.umd.dest));
    });

    gulp.task('ts:release-compile:umd', function () {
        return gulp.src(opts.umd.src)
            .pipe(typescript(releaseProject))
            .pipe(gulp.dest(opts.umd.dest));
    });

    gulp.task('ts:compile:browserify', function () {
        return Promise.all(opts.browserify.map(x => {
            new Promise(function (resolve, reject) {
                fs.exists(x.src, function (exists) {
                    if (!exists) {
                        resolve();
                        return;
                    }
                    let id = setTimeout(function () {
                        resolve = () => { };
                        reject(new Error('Timeout'));
                    }, 10 * 1000);

                    let basename = path.basename(x.src);
                    let outputName = basename.replace(new RegExp(path.extname(basename) + '$'), '.js');
                    browserify({
                        entries: [x.src],
                        debug: true
                    })
                        .plugin('tsify', {
                            target: 'ES5',
                            typescript: require('typescript')
                        })
                        .bundle()
                        .on('error', function (err) { console.error(err.message); })
                        .pipe(source(outputName))
                        .pipe(gulp.dest(x.dest))
                        .on('end', function () {
                            clearTimeout(id);
                            resolve();
                        });
                });
            })
        }));
    });

    gulp.task('ts:release-compile:browserify', function () {
        return new Promise(function (resolve, reject) {
            fs.exists(opts.browserify.src, function (exists) {
                if (!exists) {
                    resolve();
                    return;
                }
                let id = setTimeout(function () {
                    reject(new Error('Timeout'));
                }, 10 * 1000);
                browserify({
                    entries: [opts.browserify.src]
                })
                    .plugin('tsify', {
                        target: 'ES5',
                        removeComments: true,
                        typescript: require('typescript')
                    })
                    .bundle()
                    .on('error', function (err) { console.error(err.message); })
                    .pipe(source(opts.browserify.dest[1]))
                    .pipe(gulp.dest(opts.browserify.dest[0]))
                    .on('end', function () {
                        clearTimeout(id);
                        resolve();
                    });
            });
        });
    });

    gulp.task('ts:compile', ['ts:compile:umd', 'ts:compile:browserify']);

    gulp.task('ts:release-compile', ['ts:release-compile:umd', 'ts:release-compile:browserify']);
};
<|endoftext|>


<commit_before>// my script now
(function($) {
    $.fn.db = new Array();
    $.fn.hearbeatTime = 3000;
    $.fn.angle = 9;
    $.fn.twrequest = 'rpp=50&q=%23nantes';
    $.fn.hashtag = '#nantes';
    $.fn.log = function(msg) {
        if (console) {
            console.log(msg);
        }
    };
    $.fn.feedTheDB = function()
    {
        $.ajax({
            url: ($.fn.feedTheDB.lastcall.refresh_url ? "https://search.twitter.com/search.json" + $().feedTheDB.lastcall.refresh_url: "https://search.twitter.com/search.json?" + $().twrequest),
            dataType: "jsonp",
            success: function(result) {
                for (i in result.results) {
                    var r = result.results[i];
                    r.played = 0;
                    $().db.push(r);
                }
                $.fn.feedTheDB.lastcall = result;
                $().log($.fn.feedTheDB.lastcall.refresh_url);
                $().log(result);
            }
        });
        $().log("another feed");
    };
    $.fn.feedTheDB.lastcall = {};

    $.fn.feedTheDB.sortfunction = function(a, b) {
        var playcom = (a.played - b.played);
        if (playcom == 0) {
            var playcom = (new Date(b.created_at)).getTime() - (new Date(a.created_at)).getTime();
        }
        return playcom;
        //causes an array to be sorted numerically and ascending
    };
    $.fn.sortDB = function() {
        $.fn.db.sort($.fn.feedTheDB.sortfunction);
        if ($.fn.db.length > 100) {
            $.fn.db = $.fn.db.slice(0, 100);
        }
    }

})(jQuery);

function hearbeat() {
    if ($().db.length < 1) {
        return false;
    }
    $().sortDB();

    jQuery('body').append('

');
    var domelem = jQuery('div.tweet:last');
    var elem = $().db[0];
    domelem.append('');
    domelem.append('' + elem.from_user + '');
    domelem.append('');
    domelem.append('
' + elem.text.linkify().tagify() + '
');
    domelem.updateTimeField();
    elem.played++;

    domelem.css('top', '-200px');
    domelem.css('left', '500px');
    domelem.animate({
        left: $().getViewport().width - 600,
        top: $().getViewport().height / 2
    },
    {
        duration: $().hearbeatTime * 0.25,
        step: function(now, fx) {
            var where_we_are = fx.now / fx.end;
            if (!isNaN(where_we_are)) {
                var deg = where_we_are * $().angle;
                $this = $(this);
                $this.css("-moz-transform", 'rotate(' + deg + 'deg)');
                $this.css("-webkit-transform", 'rotate(' + deg + 'deg)');
                $this.css("transform", 'rotate(' + deg + 'deg)');
            }
        },
        complete: function() {
            $this.animate({
                top: '+=40',
                backgroundColor: '#eeeeee'
            },
            {
                specialEasing: {
                    top: 'easeOutQuad'
                },
                duration: $().hearbeatTime * 0.75
            });
        },
        specialEasing: {
            top: 'easeOutQuad'
        }
    }
    );
    window.setTimeout(followupannimation.bind(domelem), $().hearbeatTime);
}

function followupannimation2() {
    if (parseFloat(this.css('top')) < -200) {
        this.remove();
    } else {
        this.animate({
            left: 20,
            top: parseFloat(this.css('top')) - 100
        },
        $().hearbeatTime * 0.25);
        window.setTimeout(followupannimation2.bind(this), $().hearbeatTime);
    }
}
function followupannimation() {
    $this = $(this);

    $this.animate({
        left: 20,
        top: $().getViewport().height - 120
    },
    {
        duration: $().hearbeatTime * 0.25,
        step: function(now, fx) {
            var where_we_are = Math.abs(fx.now / (fx.end - fx.start));
            if (!isNaN(where_we_are)) {

                if (fx.prop == 'left') {

                    //   $().log(fx);
                    var deg = where_we_are * $().angle;
                    $this = $(this);
                    $this.css("-moz-transform", 'rotate(' + deg + 'deg)');
                    $this.css("-webkit-transform", 'rotate(' + deg + 'deg)');
                    $this.css("transform", 'rotate(' + deg + 'deg)');
                }
            }
        },
        specialEasing: {
            top: 'easeInQuad'
        }
    });
    window.setTimeout(followupannimation2.bind($this), $().hearbeatTime);
}

function areWeUp() {
    $.ajax({
        url: 'howweare.status',
        success: function(result) {
            if (result == "1") {
                hearbeat();
                $('#soon').animate({
                    opacity: 0
                },
                {
                    duration: 1000,
                    complete: function() {
                        $(this).remove()
                    }
                });
                var elemens = $('.reveal');
                elemens.css('display', 'block');
                elemens..animate({
                    opacity: 1
                },
                {
                    duration: 1000
                });

                window.setInterval(hearbeat, $().hearbeatTime);
            } else {
                window.setTimeout(areWeUp, 5000);

            }
        }
    });
}

$(function() {

    $().feedTheDB();
    areWeUp();

    //    testpouris();
    window.setInterval($().feedTheDB, 120000);
});

<commit_msg>stausation en cours<commit_after>// my script now
(function($) {
    $.fn.db = new Array();
    $.fn.hearbeatTime = 3000;
    $.fn.angle = 9;
    $.fn.twrequest = 'rpp=50&q=%23nantes';
    $.fn.hashtag = '#nantes';
    $.fn.log = function(msg) {
        if (console) {
            console.log(msg);
        }
    };
    $.fn.feedTheDB = function()
    {
        $.ajax({
            url: ($.fn.feedTheDB.lastcall.refresh_url ? "https://search.twitter.com/search.json" + $().feedTheDB.lastcall.refresh_url: "https://search.twitter.com/search.json?" + $().twrequest),
            dataType: "jsonp",
            success: function(result) {
                for (i in result.results) {
                    var r = result.results[i];
                    r.played = 0;
                    $().db.push(r);
                }
                $.fn.feedTheDB.lastcall = result;
                $().log($.fn.feedTheDB.lastcall.refresh_url);
                $().log(result);
            }
        });
        $().log("another feed");
    };
    $.fn.feedTheDB.lastcall = {};

    $.fn.feedTheDB.sortfunction = function(a, b) {
        var playcom = (a.played - b.played);
        if (playcom == 0) {
            var playcom = (new Date(b.created_at)).getTime() - (new Date(a.created_at)).getTime();
        }
        return playcom;
        //causes an array to be sorted numerically and ascending
    };
    $.fn.sortDB = function() {
        $.fn.db.sort($.fn.feedTheDB.sortfunction);
        if ($.fn.db.length > 100) {
            $.fn.db = $.fn.db.slice(0, 100);
        }
    }

})(jQuery);

function hearbeat() {
    if ($().db.length < 1) {
        return false;
    }
    $().sortDB();

    jQuery('body').append('

');
    var domelem = jQuery('div.tweet:last');
    var elem = $().db[0];
    domelem.append('');
    domelem.append('' + elem.from_user + '');
    domelem.append('');
    domelem.append('
' + elem.text.linkify().tagify() + '
');
    domelem.updateTimeField();
    elem.played++;

    domelem.css('top', '-200px');
    domelem.css('left', '500px');
    domelem.animate({
        left: $().getViewport().width - 600,
        top: $().getViewport().height / 2
    },
    {
        duration: $().hearbeatTime * 0.25,
        step: function(now, fx) {
            var where_we_are = fx.now / fx.end;
            if (!isNaN(where_we_are)) {
                var deg = where_we_are * $().angle;
                $this = $(this);
                $this.css("-moz-transform", 'rotate(' + deg + 'deg)');
                $this.css("-webkit-transform", 'rotate(' + deg + 'deg)');
                $this.css("transform", 'rotate(' + deg + 'deg)');
            }
        },
        complete: function() {
            $this.animate({
                top: '+=40',
                backgroundColor: '#eeeeee'
            },
            {
                specialEasing: {
                    top: 'easeOutQuad'
                },
                duration: $().hearbeatTime * 0.75
            });
        },
        specialEasing: {
            top: 'easeOutQuad'
        }
    }
    );
    window.setTimeout(followupannimation.bind(domelem), $().hearbeatTime);
}

function followupannimation2() {
    if (parseFloat(this.css('top')) < -200) {
        this.remove();
    } else {
        this.animate({
            left: 20,
            top: parseFloat(this.css('top')) - 100
        },
        $().hearbeatTime * 0.25);
        window.setTimeout(followupannimation2.bind(this), $().hearbeatTime);
    }
}
function followupannimation() {
    $this = $(this);

    $this.animate({
        left: 20,
        top: $().getViewport().height - 120
    },
    {
        duration: $().hearbeatTime * 0.25,
        step: function(now, fx) {
            var where_we_are = Math.abs(fx.now / (fx.end - fx.start));
            if (!isNaN(where_we_are)) {

                if (fx.prop == 'left') {

                    //   $().log(fx);
                    var deg = where_we_are * $().angle;
                    $this = $(this);
                    $this.css("-moz-transform", 'rotate(' + deg + 'deg)');
                    $this.css("-webkit-transform", 'rotate(' + deg + 'deg)');
                    $this.css("transform", 'rotate(' + deg + 'deg)');
                }
            }
        },
        specialEasing: {
            top: 'easeInQuad'
        }
    });
    window.setTimeout(followupannimation2.bind($this), $().hearbeatTime);
}

function areWeUp() {
    $.ajax({
        url: 'howweare.status',
        success: function(result) {
            if (result == "1") {
                hearbeat();
                $('#soon').animate({
                    opacity: 0
                },
                {
                    duration: 1000,
                    complete: function() {
                        $(this).remove()
                    }
                });
                var elemens = $('.reveal');
                elemens.css('display', 'block');
                elemens.animate({
                    opacity: 1
                },
                {
                    duration: 1000
                });

                window.setInterval(hearbeat, $().hearbeatTime);
            } else {
                window.setTimeout(areWeUp, 5000);

            }
        }
    });
}

$(function() {

    $().feedTheDB();
    areWeUp();

    //    testpouris();
    window.setInterval($().feedTheDB, 120000);
});

<|endoftext|>


<commit_before>/*
LINKS
http://joseph-harrington.com/2012/03/controlling-processingjs-jqueryui/
http://processingjs.org/articles/PomaxGuide.html#jstosketch.html
http://processingjs.nihongoresources.com/interfacing/

*/

// Numeric only control handler
jQuery.fn.ForceNumericOnly =
function()
{
    return this.each(function()
    {
        $(this).keydown(function(e)
        {
            var key = e.charCode || e.keyCode || 0;
            // allow backspace, tab, delete, enter, arrows, numbers and keypad numbers ONLY
            // home, end, period, and numpad decimal
            return (
                key == 8 ||
                key == 9 ||
                key == 13 ||
                key == 46 ||
                key == 190 ||
                (key >= 35 && key <= 40) ||
                (key >= 48 && key <= 57) ||
                (key >= 96 && key <= 105));
        });
    });
};

/*
$(function() {
  $('#staticParent').on('keydown', '#child', function(e){
  -1!==$.inArray(e.keyCode,[46,8,9,27,13,110,190]) ||
/65|67|86|88/.test(e.keyCode)&&
(!0===e.ctrlKey||!0===e.metaKey)||
35<=e.keyCode&&40>=e.keyCode||
(e.shiftKey||48>e.keyCode||57<e.keyCode)&&
(96>e.keyCode||105<e.keyCode)&&
e.preventDefault()});
})
*/

$(function() {

  $("#uiId").ForceNumericOnly();
  $("#uiId").keyup(function ()
  {                                                     // whenever text is entered into input box...

    uivars.id = $(this).val();                       // update word variable,
    var p = Processing.getInstanceById('imgGen');
    if (p) p.importId();                                // and call updateWord function in pjs sketch.
  });
  $("#uiId").val(uivars.id);                // initialize input textbox contents.

  $("#uiIdSlider").on("input change", function()
  {
    uivars.slider = $(this).val();
    var p = Processing.getInstanceById('imgGen');
    if (p) p.importId();
  });
  $("#uiIdSlider").val(uivars.slider);

});

<commit_msg>Delete ui.js<commit_after><|endoftext|>