<commit_before>var orderLog = require('../DB/orderLog.js');

function calculateNumberOfCandles(startTime, endTime, candleSize){
 return Math.ceil((endTime - startTime)/candleSize);
}

function subtractSeconds(endDate, secondsToSubtract) {
  var startDate = new Date(endDate);
	startDate.setTime(startDate.getTime() - secondsToSubtract*1000);
  return startDate.getTime();
}

function getCandleStickData(interval, cb){
  var noSecondsToQuery = 0;
  var noGraphIntervals = 50;
  var trades = [];
  var endTime = new Date();
  endTime.setSeconds(0, 0);
  var candleSize = 60000;

  switch(interval.toLowerCase()) {
    case 'day'    :  {
      noSecondsToQuery = noGraphIntervals * 3600 * 24;
      endTime.setHours(0);
      candleSize = candleSize * 60 * 24;
      break;
    }
    case 'hour'   :  {
      noSecondsToQuery = noGraphIntervals * 3600;
      endTime.setMinutes(0);
      candleSize = candleSize * 60;
      break;
    }
    case 'minute' :  {
      noSecondsToQuery = noGraphIntervals * 60;
      break;
    }
    default       :  {
      noSecondsToQuery = noGraphIntervals * 60;
      break;
    }
  }

  endTime = endTime.getTime();

  var startTime = subtractSeconds(endTime, noSecondsToQuery);
  endTime = Date.now();

	orderLog.FetchLog(startTime, endTime, function(docs){
    for(index in docs){
			trades.push({
				timestamp: docs[index].order2.timestamp,
				amount: docs[index].amount,
				price: docs[index].order1.price
			});
		}

		getOHLCCandles(startTime, endTime, trades, candleSize, function(candles){
			cb(candles);
		});
  });
}

// Candle size in seconds
function getOHLCCandles(startTime, endTime, tradeList, candleSize, cb){
 var endOfCurrentCandle = startTime + candleSize;
 var numberOfCandles = calculateNumberOfCandles(startTime, endTime, candleSize);

 var trade = { timestamp: startTime, amount: 0, price: 0 };
 var tradeListIndex = 0;
 if(tradeList.length>0){
    trade = tradeList[tradeListIndex];
 }
 var candleList = [];

 for(var i = 0; i < numberOfCandles; i++){
   endOfCurrentCandle = startTime + (i + 1)*candleSize;
   var d = new Date(endOfCurrentCandle);
   var endOfCurrentCandleTime = (d.getHours()<10?'0':'') + d.getHours() + ':' + (d.getMinutes()<10?'0':'') + d.getMinutes();
   if(tradeList[tradeListIndex].timestamp > endOfCurrentCandle){
     var emptyCandleInfo = {
       open: 0,
       high: 0,
       low: 0,
       close: 0,
       volume: 0,
       endOfCurrentCandle: endOfCurrentCandle,
       endOfCurrentCandleTime: endOfCurrentCandleTime
     };
     candleList.push(emptyCandleInfo);
   } else {
     var open = Number(trade.price);
     if(candleList.length > 0 && trade.timestamp > endOfCurrentCandle){
       open = candleList[candleList.length-1].close;
     }
     var high = open;
     var low = open;
     var close = open;
     var volume = 0;

     for(;trade && trade.timestamp <= endOfCurrentCandle && tradeListIndex < (tradeList.length-1);){
       var tradePrice = Number(trade.price);
       if(tradePrice > high){
         high = tradePrice;
       }
       if(tradePrice < low){
         low = tradePrice;
       }
       volume += Number(trade.amount);

       if(tradeListIndex < (tradeList.length-1)){
         tradeListIndex++;
       }
       trade = tradeList[tradeListIndex];
     }

     close = Number(tradeList[tradeListIndex-1].price);

     var candleInfo = {
       open: open,
       high: high,
       low: low,
       close: close,
       volume: volume,
       endOfCurrentCandle: endOfCurrentCandle,
       endOfCurrentCandleTime: endOfCurrentCandleTime
     };
     candleList.push(candleInfo);
   }
 }
 cb(candleList);
}

exports.GetCandleStickData = getCandleStickData;
<commit_msg>Added candlestick caching<commit_after>var orderLog = require('../DB/orderLog.js');
var candlestickCache = require('../DB/candlestickCache.js');

function calculateNumberOfCandles(startTime, endTime, candleSize){
 return Math.ceil((endTime - startTime)/candleSize);
}

function subtractSeconds(endDate, secondsToSubtract) {
  var startDate = new Date(endDate);
	startDate.setTime(startDate.getTime() - secondsToSubtract*1000);
  return startDate.getTime();
}

function getCandleStickData(interval, cb){
  var noSecondsToQuery = 0;
  var noGraphIntervals = 50;
  var trades = [];
  var endOfSecondLastCandlestick = new Date();
  endOfSecondLastCandlestick.setSeconds(0, 0);
  var candleSize = 60000;

  switch(interval.toLowerCase()) {
    case 'day'    :  {
      noSecondsToQuery = noGraphIntervals * 3600 * 24;
      endOfSecondLastCandlestick.setHours(0);
      candleSize = candleSize * 60 * 24;
      break;
    }
    case 'hour'   :  {
      noSecondsToQuery = noGraphIntervals * 3600;
      endOfSecondLastCandlestick.setMinutes(0);
      candleSize = candleSize * 60;
      break;
    }
    case 'minute' :  {
      noSecondsToQuery = noGraphIntervals * 60;
      break;
    }
    default       :  {
      noSecondsToQuery = noGraphIntervals * 60;
      break;
    }
  }

  endOfSecondLastCandlestick = endOfSecondLastCandlestick.getTime();

  var startTime = subtractSeconds(endOfSecondLastCandlestick, noSecondsToQuery);
  var endTime = Date.now();

  //First check to see if the previous candlesticks are cached

  candlestickCache.FetchCandlesticks(startTime, endOfSecondLastCandlestick, interval, function(candlesticks){
    if(candlesticks){

    } else {

    }
  }

	orderLog.FetchLog(startTime, endTime, function(docs){
    for(index in docs){
			trades.push({
				timestamp: docs[index].order2.timestamp,
				amount: docs[index].amount,
				price: docs[index].order1.price
			});
		}

		getOHLCCandles(startTime, endTime, trades, candleSize, function(candles){
			cb(candles);
		});
  });
}

// Candle size in seconds
function getOHLCCandles(startTime, endTime, tradeList, candleSize, cb){
 var endOfCurrentCandle = startTime + candleSize;
 var numberOfCandles = calculateNumberOfCandles(startTime, endTime, candleSize);

 var trade = { timestamp: startTime, amount: 0, price: 0 };
 var tradeListIndex = 0;
 if(tradeList.length>0){
    trade = tradeList[tradeListIndex];
 }
 var candleList = [];

 for(var i = 0; i < numberOfCandles; i++){
   endOfCurrentCandle = startTime + (i + 1)*candleSize;
   var d = new Date(endOfCurrentCandle);
   var endOfCurrentCandleTime = (d.getHours()<10?'0':'') + d.getHours() + ':' + (d.getMinutes()<10?'0':'') + d.getMinutes();
   if(tradeList[tradeListIndex].timestamp > endOfCurrentCandle){
     var emptyCandleInfo = {
       open: 0,
       high: 0,
       low: 0,
       close: 0,
       volume: 0,
       endOfCurrentCandle: endOfCurrentCandle,
       endOfCurrentCandleTime: endOfCurrentCandleTime
     };
     candleList.push(emptyCandleInfo);
   } else {
     var open = Number(trade.price);
     if(candleList.length > 0 && trade.timestamp > endOfCurrentCandle){
       open = candleList[candleList.length-1].close;
     }
     var high = open;
     var low = open;
     var close = open;
     var volume = 0;

     for(;trade && trade.timestamp <= endOfCurrentCandle && tradeListIndex < (tradeList.length-1);){
       var tradePrice = Number(trade.price);
       if(tradePrice > high){
         high = tradePrice;
       }
       if(tradePrice < low){
         low = tradePrice;
       }
       volume += Number(trade.amount);

       if(tradeListIndex < (tradeList.length-1)){
         tradeListIndex++;
       }
       trade = tradeList[tradeListIndex];
     }

     close = Number(tradeList[tradeListIndex-1].price);

     var candleInfo = {
       open: open,
       high: high,
       low: low,
       close: close,
       volume: volume,
       endOfCurrentCandle: endOfCurrentCandle,
       endOfCurrentCandleTime: endOfCurrentCandleTime
     };
     candleList.push(candleInfo);
   }
 }
 cb(candleList);
}

exports.GetCandleStickData = getCandleStickData;
<|endoftext|>


<commit_before>var models= require('../models/models.js');

exports.set = function(req, res, next) {

	if(req.param.userId == req.session.user.id)
		models.User.addQuiz(req.quiz);

	res.redirect('/user/' + req.user.id + '/favourites');
};

exports.unset = function(req, res, next) {

	if(req.param.userId == req.session.user.id)
		models.User.removeQuiz(req.quiz);

	res.redirect('/user/' + req.user.id + '/favourites');
};

exports.index = function(req, res, next) {
console.log(req.user);
console.log("************************************");
	var favourites = models.User.findAll( { where: { id: Number(req.user.id)}, include: [{ model: models.Quiz }] }).then(function(user){

console.log(user.Quizzes);

      res.render('quizes/index', {quizes: user.favourites, errors : []});
    }).catch(function(error){next(error);})
};<commit_msg>Favoritos<commit_after>var models= require('../models/models.js');

exports.set = function(req, res, next) {

	if(req.param.userId == req.session.user.id)
		models.User.addQuiz(req.quiz);

	res.redirect('/user/' + req.user.id + '/favourites');
};

exports.unset = function(req, res, next) {

	if(req.param.userId == req.session.user.id)
		models.User.removeQuiz(req.quiz);

	res.redirect('/user/' + req.user.id + '/favourites');
};

exports.index = function(req, res, next) {
	models.User.findAll( { where: { id: Number(req.param.userId)}, include: [{ model: models.Quiz }] }).then(function(user){

    }).catch(function(error){next(error);})
};<|endoftext|>


<commit_before>module.exports = {

//---------------------------------------------------------------------
// Action Name
//
// This is the name of the action displayed in the editor.
//---------------------------------------------------------------------

name: "Store Bot Client Info #3",

//---------------------------------------------------------------------
// Action Section
//
// This is the section the action will fall into.
//---------------------------------------------------------------------

section: "Bot Client Control",

//---------------------------------------------------------------------
// Action Subtitle
//
// This function generates the subtitle displayed next to the name.
//---------------------------------------------------------------------

subtitle: function(data) {
	const info = ['Total Amount of Channels', 'Total Amount of Emojis', 'Bot\'s Previous Pings', 'Uptime in Days', 'Uptime in Days (Rounded)', 'Memory (RAM) Usage'];
	return `${info[parseInt(data.info)]}`;
},

//---------------------------------------------------------------------
// Action Storage Function
//
// Stores the relevant variable info for the editor.
//---------------------------------------------------------------------

variableStorage: function(data, varType) {
	const type = parseInt(data.storage);
	if(type !== varType) return;
	const info = parseInt(data.info);
	let dataType = 'Unknown Type';
	switch(info) {
		case 0:
			dataType = "Number";
			break;
		case 1:
			dataType = "Number";
			break;
		case 2:
			dataType = "Number";
			break;
		case 3:
			dataType = "Time";
			break;
		case 4:
			dataType = "Time";
			break;
		case 5:
			dataType = "Number";
			break;
	}
	return ([data.varName2, dataType]);
},

//---------------------------------------------------------------------
// Action Fields
//
// These are the fields for the action. These fields are customized
// by creating elements with corresponding IDs in the HTML. These
// are also the names of the fields stored in the action's JSON data.
//---------------------------------------------------------------------

fields: ["info", "storage", "varName2"],

//---------------------------------------------------------------------
// Command HTML
//
// This function returns a string containing the HTML used for
// editting actions.
//
// The "isEvent" parameter will be true if this action is being used
// for an event. Due to their nature, events lack certain information,
// so edit the HTML to reflect this.
//
// The "data" parameter stores constants for select elements to use.
// Each is an array: index 0 for commands, index 1 for events.
// The names are: sendTargets, members, roles, channels,
//                messages, servers, variables
//---------------------------------------------------------------------

html: function(isEvent, data) {
	return `

			Mod Info:

			Created by EGGSY!

	Source Info:

	<select id="info" class="round">
		<option value="0">Total Amount of Channels</option>
		<option value="1">Total Amount of Emojis</option>
		<option value="2">Bot's Previous Pings</option>
		<option value="3">Uptime in Days</option>
		<option value="4">Uptime in Days (Rounded)</option>
		<option value="5">Memory (RAM) Usage</option>
	</select>

		Store In:

		<select id="storage" class="round">
			${data.variables[1]}
		</select>

		Variable Name:

		<input id="varName2" class="round" type="text">

`
},

//---------------------------------------------------------------------
// Action Editor Init Code
//
// When the HTML is first applied to the action editor, this code
// is also run. This helps add modifications or setup reactionary
// functions for the DOM elements.
//---------------------------------------------------------------------

init: function() {
	const {glob, document} = this;

	glob.messageChange(document.getElementById('message'), 'varNameContainer')
},

//---------------------------------------------------------------------
// Action Bot Function
//
// This is the function for the action within the Bot's Action class.
// Keep in mind event calls won't have access to the "msg" parameter,
// so be sure to provide checks for variable existance.
//---------------------------------------------------------------------

action: function(cache) {
	const data = cache.actions[cache.index];
	const botClient = this.getDBM().Bot.bot;
	const info = parseInt(data.info);
	const msToDay = (1000*60*60*24);
	if(!botClient) {
		this.callNextAction(cache);
		return;
	}
	switch(info) {
		case 0:
			result = botClient.channels.size;
			break;
		case 1:
			result = botClient.emojis.size;
			break;
		case 2:
			result = botClient.pings;
			break;
		case 3:
			result = botClient.uptime/msToDay;
			break;
		case 4:
			result = Math.floor(botClient.uptime/msToDay);
			break;
		case 5:
			result = "%" + ((process.memoryUsage().heapUsed / 1024) / 1024).toFixed(2);
			break;
		default:
		break;
	}
	if(result !== undefined) {
		const storage = parseInt(data.storage);
		const varName2 = this.evalMessage(data.varName2, cache);
		this.storeValue(result, storage, varName2, cache);
	}
	this.callNextAction(cache);
},

//---------------------------------------------------------------------
// Action Bot Mod
//
// Upon initialization of the bot, this code is run. Using the bot's
// DBM namespace, one can add/modify existing functions if necessary.
// In order to reduce conflictions between mods, be sure to alias
// functions you wish to overwrite.
//---------------------------------------------------------------------

mod: function(DBM) {
}

}; // End of module, thanks to Lasse btw!
<commit_msg>Added Compatiblity with DBM Mod Manager!<commit_after>module.exports = {

//---------------------------------------------------------------------
// Action Name
//
// This is the name of the action displayed in the editor.
//---------------------------------------------------------------------

name: "Store Bot Client Info #3",

//---------------------------------------------------------------------
// Action Section
//
// This is the section the action will fall into.
//---------------------------------------------------------------------

section: "Bot Client Control",

//---------------------------------------------------------------------
// Action Subtitle
//
// This function generates the subtitle displayed next to the name.
//---------------------------------------------------------------------

subtitle: function(data) {
	const info = ['Total Amount of Channels', 'Total Amount of Emojis', 'Bot\'s Previous Pings', 'Uptime in Days', 'Uptime in Days (Rounded)', 'Memory (RAM) Usage'];
	return `${info[parseInt(data.info)]}`;
},

//---------------------------------------------------------------------
	 // DBM Mods Manager Variables (Optional but nice to have!)
	 //
	 // These are variables that DBM Mods Manager uses to show information
	 // about the mods for people to see in the list.
	 //---------------------------------------------------------------------

	 // Who made the mod (If not set, defaults to "DBM Mods")
	 author: "EGGSY",

	 // The version of the mod (Defaults to 1.0.0)
	 version: "1.0.3",

	 // A short description to show on the mod line for this mod (Must be on a single line)
	 short_description: "Stores more Bot Client Information by EGGSY",

	 // If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods

	 //---------------------------------------------------------------------

//---------------------------------------------------------------------
// Action Storage Function
//
// Stores the relevant variable info for the editor.
//---------------------------------------------------------------------

variableStorage: function(data, varType) {
	const type = parseInt(data.storage);
	if(type !== varType) return;
	const info = parseInt(data.info);
	let dataType = 'Unknown Type';
	switch(info) {
		case 0:
			dataType = "Number";
			break;
		case 1:
			dataType = "Number";
			break;
		case 2:
			dataType = "Number";
			break;
		case 3:
			dataType = "Time";
			break;
		case 4:
			dataType = "Time";
			break;
		case 5:
			dataType = "Number";
			break;
	}
	return ([data.varName2, dataType]);
},

//---------------------------------------------------------------------
// Action Fields
//
// These are the fields for the action. These fields are customized
// by creating elements with corresponding IDs in the HTML. These
// are also the names of the fields stored in the action's JSON data.
//---------------------------------------------------------------------

fields: ["info", "storage", "varName2"],

//---------------------------------------------------------------------
// Command HTML
//
// This function returns a string containing the HTML used for
// editting actions.
//
// The "isEvent" parameter will be true if this action is being used
// for an event. Due to their nature, events lack certain information,
// so edit the HTML to reflect this.
//
// The "data" parameter stores constants for select elements to use.
// Each is an array: index 0 for commands, index 1 for events.
// The names are: sendTargets, members, roles, channels,
//                messages, servers, variables
//---------------------------------------------------------------------

html: function(isEvent, data) {
	return `

			Mod Info:

			Created by EGGSY!

	Source Info:

	<select id="info" class="round">
		<option value="0">Total Amount of Channels</option>
		<option value="1">Total Amount of Emojis</option>
		<option value="2">Bot's Previous Pings</option>
		<option value="3">Uptime in Days</option>
		<option value="4">Uptime in Days (Rounded)</option>
		<option value="5">Memory (RAM) Usage</option>
	</select>

		Store In:

		<select id="storage" class="round">
			${data.variables[1]}
		</select>

		Variable Name:

		<input id="varName2" class="round" type="text">

`
},

//---------------------------------------------------------------------
// Action Editor Init Code
//
// When the HTML is first applied to the action editor, this code
// is also run. This helps add modifications or setup reactionary
// functions for the DOM elements.
//---------------------------------------------------------------------

init: function() {
	const {glob, document} = this;

	glob.messageChange(document.getElementById('message'), 'varNameContainer')
},

//---------------------------------------------------------------------
// Action Bot Function
//
// This is the function for the action within the Bot's Action class.
// Keep in mind event calls won't have access to the "msg" parameter,
// so be sure to provide checks for variable existance.
//---------------------------------------------------------------------

action: function(cache) {
	const data = cache.actions[cache.index];
	const botClient = this.getDBM().Bot.bot;
	const info = parseInt(data.info);
	const msToDay = (1000*60*60*24);
	if(!botClient) {
		this.callNextAction(cache);
		return;
	}
	switch(info) {
		case 0:
			result = botClient.channels.size;
			break;
		case 1:
			result = botClient.emojis.size;
			break;
		case 2:
			result = botClient.pings;
			break;
		case 3:
			result = botClient.uptime/msToDay;
			break;
		case 4:
			result = Math.floor(botClient.uptime/msToDay);
			break;
		case 5:
			result = "%" + ((process.memoryUsage().heapUsed / 1024) / 1024).toFixed(2);
			break;
		default:
		break;
	}
	if(result !== undefined) {
		const storage = parseInt(data.storage);
		const varName2 = this.evalMessage(data.varName2, cache);
		this.storeValue(result, storage, varName2, cache);
	}
	this.callNextAction(cache);
},

//---------------------------------------------------------------------
// Action Bot Mod
//
// Upon initialization of the bot, this code is run. Using the bot's
// DBM namespace, one can add/modify existing functions if necessary.
// In order to reduce conflictions between mods, be sure to alias
// functions you wish to overwrite.
//---------------------------------------------------------------------

mod: function(DBM) {
}

}; // End of module, thanks to Lasse btw!
<|endoftext|>


<commit_before>function Board(
  boardState,
  lineColor,
  deadCellColor,
  aliveYoungCellColor,
  aliveOldCellColor,
  cellWidth,
  cellHeight,
  rowPadding,
  colPadding,
  canvas
) {

  this.onClick = function(clickHandler) {
    canvas.addEventListener('click', (e) => {
      const x = e.clientX - canvas.getBoundingClientRect().left
      const y = e.clientY - canvas.getBoundingClientRect().top
      const cellX = Math.floor(x / 14)
      const cellY = Math.floor(y / 14)
      clickHandler(cellX, cellY)
    })
  }

  this.draw = function() {
    canvasWidth = (cellWidth + rowPadding) * 50 - 2
    canvasHeight = (cellHeight + colPadding) * 30 - 2
    canvas.width = canvasWidth
    canvas.height = canvasHeight
    console.log(canvas.width, canvas.height)
    canvas.style.background =  lineColor
    canvas.style.boxShadow = '5px 5px 25px 0px rgba(46, 61, 73, 0.2)'
    this.ctx = canvas.getContext('2d')
    this.cellWidth = cellWidth
    this.cellHeight = cellHeight
    this.update(boardState)
  }

  this.update = function(state) {
    const cellColorFromState = [deadCellColor, aliveOldCellColor, aliveYoungCellColor]
    state.forEach((row, rowIndex) => {
      const y = (this.cellHeight + colPadding) * rowIndex
      row.forEach((cell, cellIndex) => {
        const x = (this.cellWidth + rowPadding) * cellIndex
        this.ctx.fillStyle = cellColorFromState[cell]
        this.ctx.fillRect(x, y, this.cellWidth, this.cellHeight)
      })
    })
  }

  this.handleResize = function(windowWidth, state) {
    const scale = windowWidth / canvasWidth
    if (scale < 1) {
      canvas.width = canvasWidth * (scale - 0.1)
      canvas.height = canvasHeight * (scale - 0.1)
      this.cellWidth = (canvas.width - (2 * 50)) / 50
      this.cellHeight = (canvas.height - (2 * 30)) / 30
      console.log(canvas.width, this.cellWidth)
      this.update(state)
    } else {
      canvas.width = canvasWidth
      canvas.height = canvasHeight
      this.cellWidth = cellWidth
      this.cellHeight = cellHeight
      this.update(state)
    }
  }
}

define(() => Board)<commit_msg>fixed clicked bug<commit_after>function Board(
  boardState,
  lineColor,
  deadCellColor,
  aliveYoungCellColor,
  aliveOldCellColor,
  cellWidth,
  cellHeight,
  rowPadding,
  colPadding,
  canvas
) {

  this.onClick = function(clickHandler) {
    canvas.addEventListener('click', (e) => {
      console.log(e.clientX, e.clientY)
      const x = e.clientX - canvas.getBoundingClientRect().left
      const y = e.clientY - canvas.getBoundingClientRect().top
      const cellX = Math.floor(x / (this.cellWidth + 2))
      const cellY = Math.floor(y / (this.cellHeight + 2))
      clickHandler(cellX, cellY)
    })
  }

  this.draw = function() {
    canvasWidth = (cellWidth + rowPadding) * 50 - 2
    canvasHeight = (cellHeight + colPadding) * 30 - 2
    canvas.width = canvasWidth
    canvas.height = canvasHeight
    console.log(canvas.width, canvas.height)
    canvas.style.background =  lineColor
    canvas.style.boxShadow = '5px 5px 25px 0px rgba(46, 61, 73, 0.2)'
    this.ctx = canvas.getContext('2d')
    this.cellWidth = cellWidth
    this.cellHeight = cellHeight
    this.update(boardState)
  }

  this.update = function(state) {
    const cellColorFromState = [deadCellColor, aliveOldCellColor, aliveYoungCellColor]
    state.forEach((row, rowIndex) => {
      const y = (this.cellHeight + colPadding) * rowIndex
      row.forEach((cell, cellIndex) => {
        const x = (this.cellWidth + rowPadding) * cellIndex
        this.ctx.fillStyle = cellColorFromState[cell]
        this.ctx.fillRect(x, y, this.cellWidth, this.cellHeight)
      })
    })
  }

  this.handleResize = function(windowWidth, state) {
    const scale = windowWidth / canvasWidth
    if (scale < 1) {
      canvas.width = canvasWidth * (scale - 0.1)
      canvas.height = canvasHeight * (scale - 0.1)
      this.cellWidth = (canvas.width - (2 * 50)) / 50
      this.cellHeight = (canvas.height - (2 * 30)) / 30
      console.log(canvas.width, this.cellWidth)
      this.update(state)
    } else {
      canvas.width = canvasWidth
      canvas.height = canvasHeight
      this.cellWidth = cellWidth
      this.cellHeight = cellHeight
      this.update(state)
    }
  }
}

define(() => Board)<|endoftext|>


<commit_before>import PropTypes from 'prop-types';
import React from 'react';

import { Textarea } from '@storybook/components';

function formatArray(value, separator) {
  if (value === '') {
    return [];
  }
  return value.split(separator);
}

class ArrayType extends React.Component {
  shouldComponentUpdate(nextProps) {
    const { knob } = this.props;

    return nextProps.knob.value !== knob.value;
  }

  handleChange = e => {
    const { knob, onChange } = this.props;
    const { value } = e.target;
    const newVal = formatArray(value, knob.separator);

    onChange(newVal);
  };

  render() {
    const { knob } = this.props;

    return <Textarea id={knob.name} value={knob.value} onChange={this.handleChange} size="flex" />;
  }
}

ArrayType.defaultProps = {
  knob: {},
  onChange: value => value,
};

ArrayType.propTypes = {
  knob: PropTypes.shape({
    name: PropTypes.string,
    value: PropTypes.array,
    separator: PropTypes.string,
  }),
  onChange: PropTypes.func,
};

ArrayType.serialize = value => value;
ArrayType.deserialize = value => {
  if (Array.isArray(value)) return value;

  return Object.keys(value)
    .sort()
    .reduce((array, key) => [...array, value[key]], []);
};

export default ArrayType;
<commit_msg>fix Array value types to string<commit_after>import PropTypes from 'prop-types';
import React from 'react';

import { Textarea } from '@storybook/components';

function formatArray(value, separator) {
  if (value === '') {
    return [];
  }
  return value.split(separator);
}

class ArrayType extends React.Component {
  shouldComponentUpdate(nextProps) {
    const { knob } = this.props;

    return nextProps.knob.value !== knob.value;
  }

  handleChange = e => {
    const { knob, onChange } = this.props;
    const { value } = e.target;
    const newVal = formatArray(value, knob.separator);

    onChange(newVal);
  };

  render() {
    const { knob } = this.props;

    const value = knob.value.join(knob.separator);

    return <Textarea id={knob.name} value={value} onChange={this.handleChange} size="flex" />;
  }
}

ArrayType.defaultProps = {
  knob: {},
  onChange: value => value,
};

ArrayType.propTypes = {
  knob: PropTypes.shape({
    name: PropTypes.string,
    value: PropTypes.array,
    separator: PropTypes.string,
  }),
  onChange: PropTypes.func,
};

ArrayType.serialize = value => value;
ArrayType.deserialize = value => {
  if (Array.isArray(value)) return value;

  return Object.keys(value)
    .sort()
    .reduce((array, key) => [...array, value[key]], []);
};

export default ArrayType;
<|endoftext|>


<commit_before>/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */
'use strict'

var React = require('react-native')
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ScrollView,
  TouchableHighlight
} = React

var styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    alignItems: 'center'
  },
  heading: {
    flex: 1,
    fontSize: 36,
    paddingTop: 40,
    margin: 10
  },
  instructions: {
    color: '#333333',
    marginBottom: 15,
  },
  button: {
    color: '#111',
    marginBottom: 15,
    borderWidth: 1,
    borderColor: 'blue',
    padding: 10,
  	borderRadius: 20,
    fontWeight: '600'
  },
  buttons: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'flex-start'
  }
})

AppRegistry.registerComponent('timer', () => TimerWrapper)

const timerOptions = [5, 7, 10, 12, 15, 20]

var TimerWrapper = React.createClass({
  getInitialState () {
    return {time: null, int: null}
  },
  startTimer(time) {
    clearInterval(this.state.int)
    var _this= this
    var int = setInterval(function() {
      console.log('2: Inside of setInterval')
      var tl = _this.state.time - 1
      if (tl == 0) clearInterval(int)
      _this.setState({time: tl})
    }, 1000)
    console.log('1: After setInterval')
    return this.setState({time: time, int: int})
  },
  render() {
    return (
      <ScrollView><View style={styles.container}>
        <Text style={styles.heading}>Timer</Text>
        <Text style={styles.instructions}>Press a button</Text>
        <View style={styles.buttons}>{timerOptions.map((item, index, list)=>{
          return <Button key={index} time={item} startTimer={this.startTimer}/>
        })}</View>
        <Timer time={this.state.time}/>
      </View></ScrollView>
    )
  }
})

var Button = React.createClass({
  startTimer(event) {
    return this.props.startTimer(this.props.time)
  },
  render() {
    return (
      <TouchableHighlight onPress={this.startTimer}>
      <Text style={styles.button}>{this.props.time} minutes</Text>
    </TouchableHighlight>
    )
  }
})

var Timer = React.createClass({
   render() {
     if (this.props.time == 0) {
      var AudioPlayer = require('react-native-audioplayer')
      AudioPlayer.play('flute_c_long_01.wav')
     }
     if (this.props.time == null || this.props.time == 0) return <View><Text  style={styles.heading}> </Text></View>
     return (
       <View>
         <Text style={styles.heading}>{this.props.time}</Text>
         <Text>Seconds left</Text>
       </View>
     )
    }
})
<commit_msg>add changes :new:<commit_after>/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 */
'use strict'

var React = require('react-native'),
  AudioPlayer = require('react-native-audioplayer')

var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ScrollView,
  TouchableHighlight,
  Switch
} = React

const timerOptions = [5, 7, 10, 12, 15, 20]

var TimerWrapper = React.createClass({
  getInitialState () {
    return {time: null, int: null, isMinutes: false}
  },
  toggleTime(){
    let time = this.state.time
    if (time == 0 ) time = null
    this.setState({isMinutes: !this.state.isMinutes, time: time})
  },
  startTimer(time) {
    clearInterval(this.state.int)
    var _this= this
    var int = setInterval(function() {
      console.log('2: Inside of setInterval')
      var tl = _this.state.time - 1
      if (tl == 0) clearInterval(int)
      _this.setState({time: tl})
    }, 1000)
    console.log('1: After setInterval')
    return this.setState({time: time, int: int})
  },
  render() {
    return (
      <ScrollView><View style={styles.container}>
        <Text style={styles.heading}>Timer</Text>
        <Text style={styles.instructions}>Press a button</Text>
        <View style={styles.buttons}>{timerOptions.map((item, index, list)=>{
          return <Button key={index} time={item} startTimer={this.startTimer} isMinutes={this.state.isMinutes}/>
        })}</View>
      <Text>Minutes</Text><Switch onValueChange={this.toggleTime} value={this.state.isMinutes}></Switch>
        <Timer time={this.state.time}/>

      </View></ScrollView>
    )
  }
})

var Button = React.createClass({
  startTimer(event) {
    let time = (this.props.isMinutes) ? this.props.time*60 : this.props.time
    return this.props.startTimer(time)
  },
  render() {
    return (
      <TouchableHighlight onPress={this.startTimer}>
      <Text style={styles.button}>{this.props.time} {(this.props.isMinutes) ? 'minutes' : 'seconds'}</Text>
    </TouchableHighlight>
    )
  }
})

var Timer = React.createClass({
   render() {
     if (this.props.time == 0) {
      AudioPlayer.play('flute_c_long_01.wav')
     }
     if (this.props.time == null || this.props.time == 0) return <View><Text  style={styles.heading}> </Text></View>
     return (
       <View>
         <Text style={styles.heading}>{this.props.time}</Text>
         <Text>Seconds left</Text>
       </View>
     )
    }
})

var styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    alignItems: 'center'
  },
  heading: {
    flex: 1,
    fontSize: 36,
    paddingTop: 40,
    margin: 10
  },
  instructions: {
    color: '#333333',
    marginBottom: 15,
  },
  button: {
    color: '#111',
    marginBottom: 15,
    borderWidth: 1,
    borderColor: 'blue',
    padding: 10,
  	borderRadius: 20,
    fontWeight: '600'
  },
  buttons: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'flex-start'
  }
})

AppRegistry.registerComponent('timer', () => TimerWrapper)
<|endoftext|>


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

  function setButtonState(button, enabled) {
    if ( enabled ) {
      button.removeAttr('disabled');
    } else {
      button.attr('disabled', true);
    }
  }

  function authenticate() {
    if ( $("#setup-begin").length === 0 ) {
      return false;
    }

    $("#setup-admin-code").keyup(function() {
      var code = $("#setup-admin-code").val();
      var enabled = !!code;

      setButtonState($("#setup-begin"), enabled);
    });
    $("#setup-begin").attr('disabled', true);

    return true;
  }

  function setup() {
    function nextStep() {
      var currentIndex = $(".steps").attr('data-current');
      console.log(currentIndex);
      currentIndex++;
      setStep(currentIndex);
    }
    function prevStep() {
      var currentIndex = $(".steps").attr('data-current');
      currentIndex--;
      setStep(currentIndex);
    }
    function setStep(index) {
      var currentIndex = $(".steps").attr('data-current');
      if ( currentIndex === undefined ) {
        console.log("inital step:", index);
        $(".steps li").fadeOut(0);
        $(".steps li").eq(index).fadeIn(0);
        $(".steps").attr('data-current', index);
      } else {

        if ( currentIndex == index ) {
          return;
        }
        console.log("set index", index, "with current index", currentIndex);

        $(".steps li").fadeOut(250).eq(index).fadeIn();
        $(".steps").attr('data-current', index);
      }
    }

    function collectData() {
      return {};
    }
    function sendData(data, callback) {
      setTimeout(callback, 1000);
    }
    function submitData() {
      var data = collectData();
      sendData(data, function() {
        $("#setup-end").removeAttr('disabled');
      });
    }

    $("#setup-admin input").keyup(function() {
      var username = $("#setup-admin-username").val();
      var password = $("#setup-admin-password").val();
      var passwordRepeat = $("#setup-admin-password-repeat").val();

      var nextOK = !!username && !!password && !!passwordRepeat && password === passwordRepeat;
      if ( nextOK ) {
        $("#setup-save-admin").removeAttr('disabled');
      } else {
        $("#setup-save-admin").attr('disabled', true);
      }
    });
    $("#setup-save-admin").click(function() {
      nextStep();
    });
    $("#setup-back-admin").click(function() {
      prevStep();
    });
    $("#setup-save-settings").click(function() {
      nextStep();
      submitData();
    });

    setStep(0);
    $("#setup-save-admin").attr('disabled', true);
    $("#setup-end").attr('disabled', true);
  }

  if ( !authenticate() ) {
    setup();
  }

}());
<commit_msg>Added actual upload of data.<commit_after>(function() {
  "use strict";

  function setButtonState(button, enabled) {
    if ( enabled ) {
      button.removeAttr('disabled');
    } else {
      button.attr('disabled', true);
    }
  }

  function authenticate() {
    if ( $("#setup-begin").length === 0 ) {
      return false;
    }

    $("#setup-admin-code").keyup(function() {
      var code = $("#setup-admin-code").val();
      var enabled = !!code;

      setButtonState($("#setup-begin"), enabled);
    });
    $("#setup-begin").attr('disabled', true);

    return true;
  }

  function setup() {
    function nextStep() {
      var currentIndex = $(".steps").attr('data-current');
      console.log(currentIndex);
      currentIndex++;
      setStep(currentIndex);
    }
    function prevStep() {
      var currentIndex = $(".steps").attr('data-current');
      currentIndex--;
      setStep(currentIndex);
    }
    function setStep(index) {
      var currentIndex = $(".steps").attr('data-current');
      if ( currentIndex === undefined ) {
        console.log("inital step:", index);
        $(".steps li").fadeOut(0);
        $(".steps li").eq(index).fadeIn(0);
        $(".steps").attr('data-current', index);
      } else {

        if ( currentIndex == index ) {
          return;
        }
        console.log("set index", index, "with current index", currentIndex);

        $(".steps li").fadeOut(250).eq(index).fadeIn();
        $(".steps").attr('data-current', index);
      }
    }

    function collectData() {
      var data = {};

      data.admin = {};
      data.admin.username = $("#setup-admin-username").val();
      data.admin.password = $("#setup-admin-password").val();
      data.admin.passwordRepeat = $("#setup-admin-password-repeat").val();

      return data;
    }
    function sendData(data, callback) {
      $.post("/api/v1/setup", data, function(response) {
        console.log("response:", response);

        callback();
      });
    }
    function submitData() {
      var data = collectData();
      sendData(data, function() {
        $("#setup-end").removeAttr('disabled');
      });
    }

    $("#setup-admin input").keyup(function() {
      var username = $("#setup-admin-username").val();
      var password = $("#setup-admin-password").val();
      var passwordRepeat = $("#setup-admin-password-repeat").val();

      var nextOK = !!username && !!password && !!passwordRepeat && password === passwordRepeat;
      if ( nextOK ) {
        $("#setup-save-admin").removeAttr('disabled');
      } else {
        $("#setup-save-admin").attr('disabled', true);
      }
    });
    $("#setup-save-admin").click(function() {
      nextStep();
    });
    $("#setup-back-admin").click(function() {
      prevStep();
    });
    $("#setup-save-settings").click(function() {
      nextStep();
      submitData();
    });

    setStep(0);
    $("#setup-save-admin").attr('disabled', true);
    $("#setup-end").attr('disabled', true);
  }

  if ( !authenticate() ) {
    setup();
  }

}());
<|endoftext|>


<commit_before>define(['text!./document-sharing.html', 'app', 'angular', 'lodash', 'ngDialog', 'scbd-angularjs-services/generic-service'], function(template, app, angular, _) { 'use strict';

    app.directive('documentSharing', ["$http", "$q", "$route", 'ngDialog', '$timeout', 'IGenericService', '$document', '$window', '$rootScope', 'realm', 'locale',
     function ($http, $q, $route, ngDialog, $timeout, genericService, $document, $window, $rootScope, realm, locale) {
        return {
            restrict   : 'E',
            template   : template,
            replace    : true,
            transclude : false,
            scope      : {
                title : '@',
                identifier : '=',
                restrictionField : '@',
                restrictionFieldValue : '='
            },
            link : function($scope, $element)
            {
                $scope.self = $scope;
                $scope.status   = "";
                $scope.error    = null;

                $scope.shareDocument = function(){

                    ngDialog.open({
                        template: 'shareDocumentTemplate.html',
                        closeByDocument: true,
                        closeByEscape: true,
                        showClose: true,
                        closeByNavigation: false,
                        scope: $scope

                    });
                }

                $scope.getPdf = function(){

                    ngDialog.open({
                        template: 'documentPdfTemplate.html',
                        closeByDocument: true,
                        closeByEscape: true,
                        showClose: true,
                        closeByNavigation: false,
                        scope: $scope
                    });
                    $q.when($scope.loadDocument())
                    .then(function(document){
                        if(document && document.urlHash){
                            var url = '/api/v2017/generate-pdf/' + realm + '/draft-documents/'+ locale + '?code='+ $scope.document.urlHash
                            console.log(url)
                            window.open(url)
                            ngDialog.close();
                        }
                        else{
                            // $scope.document.expiry
                            $q.when($scope.createLink())
                            .then(function(){
                                var url = '/api/v2017/generate-pdf/' + realm + '/draft-documents/'+ locale + '?code='+ $scope.document.urlHash
                                console.log(url)
                                window.open(url)
                                ngDialog.close();
                            })
                        }
                    })
                }

                $scope.createLink = function(){

                    var newDocument = angular.copy($scope.document || {});
                     if(newDocument.sharedWith && newDocument.sharedWith.link)
                        return;
                    if(!newDocument.sharedWith)
                        newDocument.sharedWith = {};

                    newDocument.sharedWith["link"] = true;

                    return saveLink(newDocument);
                }

                $scope.shareEmail = function(){
                    saveLink($scope.document);
                }

                function saveLink(document){

                    var operation;

                    if(document._id)
                        operation = genericService.update('v2018', 'document-sharing', document._id, document);
                    else
                        operation = genericService.create('v2018', 'document-sharing', document);

                    $scope.status = "creatingLink";
                    return $q.when(operation)
                    .then(function(response){
                        var id= response.id || document._id;
                        $q.when(get(id))
                        .then(function(data){
                            $scope.document = data;
                        })
                    })
                    .finally(function(){
                        $scope.status = '';
                    })

                }

                $scope.loadDocument = function(){

                    var q = {
                        "sharedData.identifier"            : $scope.identifier,
                        "sharedData.restrictionField"      : $scope.restrictionField,
                        "sharedData.restrictionFieldValue" : $scope.restrictionFieldValue.toString(),
                        "sharedBy"                         : $rootScope.user.userID
                    }
                    return $q.when(genericService.query('v2018', 'document-sharing', q))
                    .then(function(response){
                        if(response && response.length > 0){
                            $scope.document = _.head(response);
                        }
                        else{
                            $scope.document = {}
                            $scope.document = $scope.document || {};
                            $scope.document.storageType = "km-document"
                                // "sharedWith":   {
                                //         "email" :           "blaisefonseca@gmail.com"
                                // },
                            $scope.document.sharedData = {
                                "identifier"            : $scope.identifier,
                                "restrictionField"      : $scope.restrictionField,
                                "restrictionFieldValue" : $scope.restrictionFieldValue
                            };
                        }
                        return $scope.document;
                    })

                }

                $scope.getUrl = function(hash){

                    return location.origin + '/database/share/' + hash;
                }

                $scope.copyUrl = function(){
                    var body = angular.element($window.document.body);
                    var textarea = angular.element('<textarea/>');
                    textarea.css({
                        position: 'fixed',
                        opacity: '0'
                    });
                    textarea.val($document.find('#shareUrl').val());
                    body.append(textarea);
                    textarea[0].select();

                    try {
                        var successful = $window.document.execCommand('copy');
                        if (!successful) throw successful;
                    } catch (err) {
                    } finally {
                        textarea.remove();
                    }
                }

                function get(id, count){
                    count = count || 0;
                    return $q.when(genericService.get('v2018', 'document-sharing',id))
                            .then(function(response){
                                return response
                            })
                            .catch(function(error){
                                if(error.status == 404 && count < 10)
                                    return $timeout(function(){return get(id, count++)}, 2000);
                            })
                }
                $scope.loadDocument();
            }
        };
    }]);
});
<commit_msg>make value string<commit_after>define(['text!./document-sharing.html', 'app', 'angular', 'lodash', 'ngDialog', 'scbd-angularjs-services/generic-service'], function(template, app, angular, _) { 'use strict';

    app.directive('documentSharing', ["$http", "$q", "$route", 'ngDialog', '$timeout', 'IGenericService', '$document', '$window', '$rootScope', 'realm', 'locale',
     function ($http, $q, $route, ngDialog, $timeout, genericService, $document, $window, $rootScope, realm, locale) {
        return {
            restrict   : 'E',
            template   : template,
            replace    : true,
            transclude : false,
            scope      : {
                title : '@',
                identifier : '=',
                restrictionField : '@',
                restrictionFieldValue : '='
            },
            link : function($scope, $element)
            {
                $scope.self = $scope;
                $scope.status   = "";
                $scope.error    = null;

                $scope.shareDocument = function(){

                    ngDialog.open({
                        template: 'shareDocumentTemplate.html',
                        closeByDocument: true,
                        closeByEscape: true,
                        showClose: true,
                        closeByNavigation: false,
                        scope: $scope

                    });
                }

                $scope.getPdf = function(){

                    ngDialog.open({
                        template: 'documentPdfTemplate.html',
                        closeByDocument: true,
                        closeByEscape: true,
                        showClose: true,
                        closeByNavigation: false,
                        scope: $scope
                    });
                    $q.when($scope.loadDocument())
                    .then(function(document){
                        if(document && document.urlHash){
                            var url = '/api/v2017/generate-pdf/' + realm + '/draft-documents/'+ locale + '?code='+ $scope.document.urlHash
                            console.log(url)
                            window.open(url)
                            ngDialog.close();
                        }
                        else{
                            // $scope.document.expiry
                            $q.when($scope.createLink())
                            .then(function(){
                                var url = '/api/v2017/generate-pdf/' + realm + '/draft-documents/'+ locale + '?code='+ $scope.document.urlHash
                                console.log(url)
                                window.open(url)
                                ngDialog.close();
                            })
                        }
                    })
                }

                $scope.createLink = function(){

                    var newDocument = angular.copy($scope.document || {});
                     if(newDocument.sharedWith && newDocument.sharedWith.link)
                        return;
                    if(!newDocument.sharedWith)
                        newDocument.sharedWith = {};

                    newDocument.sharedWith["link"] = true;

                    return saveLink(newDocument);
                }

                $scope.shareEmail = function(){
                    saveLink($scope.document);
                }

                function saveLink(document){

                    var operation;

                    if(document._id)
                        operation = genericService.update('v2018', 'document-sharing', document._id, document);
                    else
                        operation = genericService.create('v2018', 'document-sharing', document);

                    $scope.status = "creatingLink";
                    return $q.when(operation)
                    .then(function(response){
                        var id= response.id || document._id;
                        return $q.when(get(id))
                                .then(function(data){
                                    $scope.document = data;
                                })
                    })
                    .finally(function(){
                        $scope.status = '';
                    })

                }

                $scope.loadDocument = function(){

                    var q = {
                        "sharedData.identifier"            : $scope.identifier,
                        "sharedData.restrictionField"      : $scope.restrictionField,
                        "sharedData.restrictionFieldValue" : $scope.restrictionFieldValue.toString(),
                        "sharedBy"                         : $rootScope.user.userID
                    }
                    return $q.when(genericService.query('v2018', 'document-sharing', q))
                    .then(function(response){
                        if(response && response.length > 0){
                            $scope.document = _.head(response);
                        }
                        else{
                            $scope.document = {}
                            $scope.document = $scope.document || {};
                            $scope.document.storageType = "km-document"
                                // "sharedWith":   {
                                //         "email" :           "blaisefonseca@gmail.com"
                                // },
                            $scope.document.sharedData = {
                                "identifier"            : $scope.identifier,
                                "restrictionField"      : $scope.restrictionField
                            };
                            if($scope.restrictionFieldValue)
                                $scope.document.sharedData.restrictionFieldValue = $scope.restrictionFieldValue.toString();
                        }
                        return $scope.document;
                    })

                }

                $scope.getUrl = function(hash){

                    return location.origin + '/database/share/' + hash;
                }

                $scope.copyUrl = function(){
                    var body = angular.element($window.document.body);
                    var textarea = angular.element('<textarea/>');
                    textarea.css({
                        position: 'fixed',
                        opacity: '0'
                    });
                    textarea.val($document.find('#shareUrl').val());
                    body.append(textarea);
                    textarea[0].select();

                    try {
                        var successful = $window.document.execCommand('copy');
                        if (!successful) throw successful;
                    } catch (err) {
                    } finally {
                        textarea.remove();
                    }
                }

                function get(id, count){
                    count = count || 0;
                    return $q.when(genericService.get('v2018', 'document-sharing',id))
                            .then(function(response){
                                return response
                            })
                            .catch(function(error){
                                if(error.status == 404 && count < 10)
                                    return $timeout(function(){return get(id, count++)}, 2000);
                            })
                }
                $scope.loadDocument();
            }
        };
    }]);
});
<|endoftext|>


<commit_before>var path = require('path');
var oxr = require('open-exchange-rates');
var fx = require('money');
var fs = require('fs');
var rfr = require('rfr');
var config = rfr('includes/config.js');

var openExchangeRatesAppId = config.openexchangerates.app_id || '';
var openExchangeRatesUpdateInterval = config.openexchangerates.update_interval || 86400;

if (config.openexchangerates.use_env_variable)
	openExchangeRatesAppId = process.env[openExchangeRatesAppId];

console.log(openExchangeRatesAppId);

var cache_filename = path.join(__dirname, '..', 'data/cache/exchangerates.json');
var cached = null;

var reloadRates = function(callback) {
	if (!openExchangeRatesAppId)
		return false;

	oxr.latest(function() {
		cached = {};
		cached.rates = oxr.rates;
		cached.base = oxr.base;
		fs.writeFile(cache_filename, JSON.stringify(cached, null, 2));

		if (typeof(callback) === 'function')
			callback(cached);
	});
};

var reloadIfNeeded = function(callback) {
	fs.stat(cache_filename, function(err, stats) {
		if (!stats || (stats.mtime.getTime() / 1000) < (Date.now() / 1000 | 0) - openExchangeRatesUpdateInterval)
			reloadRates(callback);
	});
};

if (!openExchangeRatesAppId) {
	console.error('Please specify openexchangerates app_id in config/config.json. Without it, dimeshift will not be able to do currency conversions');
} else {
	oxr.set({
		app_id: openExchangeRatesAppId
	});

	try {
		var cached = JSON.parse("" + fs.readFileSync(cache_filename, 'utf8'));
	} catch (e) {
		console.log("No cached exchange rates\n");
	}

	if (cached && typeof(cached.rates) !== 'undefined' && typeof(cached.base) !== 'undefined') {
		fx.rates = cached.rates;
		fx.base = cached.base;

		reloadIfNeeded();
	} else {
		reloadRates(function() {
			fx.rates = cached.rates;
			fx.base = cached.base;
		});
	}
}

var getRates = function() {
	reloadIfNeeded();
	return cached;
};

exports.fx = fx;
exports.getRates = getRates;
// fx(100).from('HKD').to('GBP'); // ~8.0424<commit_msg>x rates<commit_after>var path = require('path');
var oxr = require('open-exchange-rates');
var fx = require('money');
var fs = require('fs');
var rfr = require('rfr');
var config = rfr('includes/config.js');

var openExchangeRatesAppId = config.openexchangerates.app_id || '';
var openExchangeRatesUpdateInterval = config.openexchangerates.update_interval || 86400;

if (config.openexchangerates.use_env_variable)
	openExchangeRatesAppId = process.env[openExchangeRatesAppId];

var cache_filename = path.join(__dirname, '..', 'data/cache/exchangerates.json');
var cached = null;

var reloadRates = function(callback) {
	if (!openExchangeRatesAppId)
		return false;

	oxr.latest(function() {
		cached = {};
		cached.rates = oxr.rates;
		cached.base = oxr.base;
		fs.writeFile(cache_filename, JSON.stringify(cached, null, 2));

		if (typeof(callback) === 'function')
			callback(cached);
	});
};

var reloadIfNeeded = function(callback) {
	fs.stat(cache_filename, function(err, stats) {
		if (!stats || (stats.mtime.getTime() / 1000) < (Date.now() / 1000 | 0) - openExchangeRatesUpdateInterval) {
			reloadRates(callback);
		}
	});
};

var cached = {
	rates: {},
	base: 'USD'
};

if (!openExchangeRatesAppId) {
	cached.error = 'Please specify openexchangerates app_id in config/config.json. Without it, dimeshift will not be able to do currency conversions';
	console.error(cached.error);
} else {
	oxr.set({
		app_id: openExchangeRatesAppId
	});

	try {
		cached = JSON.parse("" + fs.readFileSync(cache_filename, 'utf8'));
	} catch (e) {
		console.log("No cached exchange rates\n");
	}

	if (cached && typeof(cached.rates) !== 'undefined' && typeof(cached.base) !== 'undefined') {
		fx.rates = cached.rates;
		fx.base = cached.base;

		reloadIfNeeded();
	} else {
		reloadRates(function() {
			fx.rates = cached.rates;
			fx.base = cached.base;
		});
	}
}

var getRates = function() {
	console.log(cached);
	reloadIfNeeded();
	return cached;
};

exports.fx = fx;
exports.getRates = getRates;
// fx(100).from('HKD').to('GBP'); // ~8.0424<|endoftext|>


<commit_before>/**
 * @copyright: 2011 Intel
 * @description:  This script will replace all drop downs with friendly select controls.  Users can still interact
 * with the old drop down box as normal with javascript, and this will be reflected
 */
 /* global af*/
 /* global numOnly*/
(function($) {
    /*jshint camelcase: false,
    validthis:true
    */
    "use strict";
    function updateOption(prop, oldValue, newValue) {
        if (newValue === true) {
            if (!this.getAttribute("multiple"))
                $.selectBox.updateMaskValue(this.parentNode.id, this.text, this.value);
            this.parentNode.value = this.value;
        }
        return newValue;
    }

    function updateIndex(prop, oldValue, newValue) {
        if (this.options[newValue]) {
            if (!this.getAttribute("multiple"))
                $.selectBox.updateMaskValue(this.linker, this.options[newValue].value, this.options[newValue].text);
            this.value = this.options[newValue].value;
        }
        return newValue;
    }

    function destroy(e) {
        var el = e.target;
        $(el.linker).remove();
        delete el.linker;
        e.stopPropagation();
    }
    $.selectBox = {
        scroller: null,
        currLinker: null,
        getOldSelects: function(elID) {
            if (!$.os.android || $.os.androidICS) return;
            if (!$.fn.scroller) {
                window.alert("This library requires af.scroller");
                return;
            }
            var container = elID && document.getElementById(elID) ? document.getElementById(elID) : document;
            if (!container) {
                window.alert("Could not find container element for af.selectBox " + elID);
                return;
            }
            var sels = container.getElementsByTagName("select");
            var that = this;
            for (var i = 0; i < sels.length; i++) {

                var el = sels[i];
                el.style.display = "none";
                var fixer = $.create("div", {
                    className: "afFakeSelect"
                });
                fixer.get(0).linker = sels[i];
                el.linker = fixer.get(0);
                fixer.insertAfter(sels[i]);

                el.watch("selectedIndex", updateIndex);
                for (var j = 0; j < el.options.length; j++) {
                    var currInd = j;
                    el.options[j].watch("selected", updateOption);
                    if (el.options[j].selected)
                        fixer.html(el.options[j].text);
                }
                $(el).one("destroy", destroy);
            }
            that.createHtml();
        },
        updateDropdown: function(el) {
            if (!el) return;
            for (var j = 0; j < el.options.length; j++) {
                if (el.options[j].selected) el.linker.innerHTML = el.options[j].text;
            }
            el = null;
        },
        initDropDown: function(el) {

            var that = this;
            if (el.disabled) return;
            if (!el || !el.options || el.options.length === 0) return;
            var htmlTemplate = "";
            var foundInd = 0;
            var $scr = $("#afSelectBoxfix");
            $scr.html("

");
            var $list = $scr.find("ul");
            for (var j = 0; j < el.options.length; j++) {
                var currInd = j;
                el.options[j].watch("selected", updateOption);
                var checked = (el.options[j].selected) ? "selected" : "";
                if (checked) foundInd = j + 1;
                var row = $.create("li", {
                    html: el.options[j].text,
                    className: checked
                });
                row.data("ind", j);
                $list.append(row);
            }
            $("#afModalMask").show();
            try {
                if (foundInd > 0 && el.getAttribute("multiple") !== "multiple") {
                    var scrollToPos = 0;
                    var scrollThreshold = numOnly($list.find("li").computedStyle("height"));
                    var theHeight = numOnly($("#afSelectBoxContainer").computedStyle("height"));
                    if (foundInd * scrollThreshold >= theHeight) scrollToPos = (foundInd - 1) * -scrollThreshold;
                    this.scroller.scrollTo({
                        x: 0,
                        y: scrollToPos
                    });
                }
            } catch (e) {
                console.log("error init dropdown" + e);
            }

            var selClose = $("#afSelectClose").css("display") === "block" ? numOnly($("#afSelectClose").height()) : 0;
            $("#afSelectWrapper").height((numOnly($("#afSelectBoxContainer").height()) - selClose) + "px");

        },
        updateMaskValue: function(linker, value, val2) {

            $(linker).html(val2);
        },
        setDropDownValue: function(el, value) {

            if (!el) return;
            var $el = $(el);

            value = parseInt(value, 10);
            if (!el.getAttribute("multiple")) {
                el.selectedIndex = value;
                $el.find("option").prop("selected", false);
                $el.find("option:nth-child(" + (value + 1) + ")").prop("selected", true);
                this.scroller.scrollTo({
                    x: 0,
                    y: 0
                });
                this.hideDropDown();
            } else {
                //multi select

                // var myEl = $el.find("option:nth-child(" + (value + 1) + ")").get(0);
                var myList = $("#afSelectBoxfix li:nth-child(" + (value + 1) + ")");
                if (myList.hasClass("selected")) {
                    myList.removeClass("selected");
                    //  myEl.selected = false;
                } else {
                    myList.addClass("selected");
                    //  myEl.selected = true;
                }
            }
            $(el).trigger("change");
            el = null;
        },
        hideDropDown: function() {
            $("#afModalMask").hide();
            $("#afSelectBoxfix").html("");
        },
        createHtml: function() {
            var that = this;
            if (document.getElementById("afSelectBoxfix")) {
                return;
            }
            $(document).ready(function() {
                $(document).on("click", ".afFakeSelect", function(e) {
                    if (this.linker.disabled)
                        return;
                    that.currLinker = this;

                    if (this.linker.getAttribute("multiple") === "multiple")
                        $("#afSelectClose").show();
                    else
                        $("#afSelectClose").hide();
                    that.initDropDown(this.linker);

                });
                var container = $.create("div", {
                    id: "afSelectBoxContainer"
                });
                var modalDiv = $.create("div", {
                    id: "afSelectBoxfix"
                });
                var modalWrapper = $.create("div", {
                    id: "afSelectWrapper"
                });
                modalWrapper.css("position", "relative");
                modalWrapper.append(modalDiv);
                var closeDiv = $.create("div", {
                    id: "afSelectClose",
                    html: "Done Cancel"
                });

                var modalMask = $.create("div", {
                    id:"afModalMask"
                });

                var $afui = $("#afui");
                container.prepend(closeDiv).append(modalWrapper);
                modalMask.append(container);
                if ($afui.length > 0) $afui.append(modalMask);
                else document.body.appendChild(modalMask.get(0));

                that.scroller = $.query("#afSelectBoxfix").scroller({
                    scroller: false,
                    verticalScroll: true,
                    vScrollCSS: "jqselectscrollBarV"
                });

                $("#afModalMask").on("click",function(e){
                    var $e=$(e.target);
                    if($e.closest("#afSelectBoxContainer").length === 0)
                        that.hideDropDown();
                });

                $("#afSelectBoxfix").on("click", "li", function(e) {
                    var $el = $(e.target);
                    that.setDropDownValue(that.currLinker.linker, $el.data("ind"));
                });
                $("#afSelectBoxContainer").on("click", "a", function(e) {
                    if (e.target.id === "afSelectCancel")
                        return that.hideDropDown();
                    var $sel = $(that.currLinker.linker);
                    $sel.find("option").prop("selected", false);

                    $("#afSelectBoxfix li").each(function(el) {
                        var $el = $(this);
                        if ($el.hasClass("selected")) {
                            var ind = parseInt($el.data("ind"), 10);
                            $sel.find("option:nth-child(" + (ind + 1) + ")").prop("selected", true);
                            that.currLinker.innerHTML = $el.html();
                        }
                    });

                    that.hideDropDown();
                    e.stopPropagation();
                    e.preventDefault();
                    return false;
                });

            });
        }
    };

    //The following is based off Eli Grey's shim
    //https://gist.github.com/384583
    //We use HTMLElement to not cause problems with other objects
    if (!HTMLElement.prototype.watch) {
        HTMLElement.prototype.watch = function(prop, handler) {
            var oldval = this[prop],
                newval = oldval,
                getter = function() {
                    return newval;
                },
                setter = function(val) {
                    oldval = newval;
                    newval = handler.call(this, prop, oldval, val);
                    return newval;
                };
            if (delete this[prop]) { // can't watch constants
                if (HTMLElement.defineProperty) { // ECMAScript 5
                    HTMLElement.defineProperty(this, prop, {
                        get: getter,
                        set: setter,
                        enumerable: false,
                        configurable: true
                    });
                } else if (HTMLElement.prototype.__defineGetter__ && HTMLElement.prototype.__defineSetter__) { // legacy
                    HTMLElement.prototype.__defineGetter__.call(this, prop, getter);
                    HTMLElement.prototype.__defineSetter__.call(this, prop, setter);
                }
            }
        };
    }
    if (!HTMLElement.prototype.unwatch) {
        HTMLElement.prototype.unwatch = function(prop) {
            var val = this[prop];
            delete this[prop]; // remove accessors
            this[prop] = val;
        };
    }
})(af);
<commit_msg>fix multi select and the new scroller not needing a parent.<commit_after>/**
 * @copyright: 2011 Intel
 * @description:  This script will replace all drop downs with friendly select controls.  Users can still interact
 * with the old drop down box as normal with javascript, and this will be reflected
 */
 /* global af*/
 /* global numOnly*/
(function($) {
    /*jshint camelcase: false,
    validthis:true
    */
    "use strict";
    function updateOption(prop, oldValue, newValue) {
        if (newValue === true) {
            if (!this.getAttribute("multiple"))
                $.selectBox.updateMaskValue(this.parentNode.id, this.text, this.value);
            this.parentNode.value = this.value;
        }
        return newValue;
    }

    function updateIndex(prop, oldValue, newValue) {
        if (this.options[newValue]) {
            if (!this.getAttribute("multiple"))
                $.selectBox.updateMaskValue(this.linker, this.options[newValue].value, this.options[newValue].text);
            this.value = this.options[newValue].value;
        }
        return newValue;
    }

    function destroy(e) {
        var el = e.target;
        $(el.linker).remove();
        delete el.linker;
        e.stopPropagation();
    }
    $.selectBox = {
        scroller: null,
        currLinker: null,
        getOldSelects: function(elID) {
            if (!$.os.android || $.os.androidICS) return;
            if (!$.fn.scroller) {
                window.alert("This library requires af.scroller");
                return;
            }
            var container = elID && document.getElementById(elID) ? document.getElementById(elID) : document;
            if (!container) {
                window.alert("Could not find container element for af.selectBox " + elID);
                return;
            }
            var sels = container.getElementsByTagName("select");
            var that = this;
            for (var i = 0; i < sels.length; i++) {

                var el = sels[i];
                el.style.display = "none";
                var fixer = $.create("div", {
                    className: "afFakeSelect"
                });
                fixer.get(0).linker = sels[i];
                el.linker = fixer.get(0);
                fixer.insertAfter(sels[i]);

                el.watch("selectedIndex", updateIndex);
                for (var j = 0; j < el.options.length; j++) {
                    var currInd = j;
                    el.options[j].watch("selected", updateOption);
                    if (el.options[j].selected)
                        fixer.html(el.options[j].text);
                }
                $(el).one("destroy", destroy);
            }
            that.createHtml();
        },
        updateDropdown: function(el) {
            if (!el) return;
            for (var j = 0; j < el.options.length; j++) {
                if (el.options[j].selected) el.linker.innerHTML = el.options[j].text;
            }
            el = null;
        },
        initDropDown: function(el) {

            var that = this;
            if (el.disabled) return;
            if (!el || !el.options || el.options.length === 0) return;
            var htmlTemplate = "";
            var foundInd = 0;
            var $scr = $("#afSelectBoxfix");
            $scr.html("

");
            var $list = $scr.find("ul");
            for (var j = 0; j < el.options.length; j++) {
                var currInd = j;
                el.options[j].watch("selected", updateOption);
                var checked = (el.options[j].selected) ? "selected" : "";
                if (checked) foundInd = j + 1;
                var row = $.create("li", {
                    html: el.options[j].text,
                    className: checked
                });
                row.data("ind", j);
                $list.append(row);
            }
            $("#afModalMask").show();
            try {
                if (foundInd > 0 && el.getAttribute("multiple") !== "multiple") {
                    var scrollToPos = 0;
                    var scrollThreshold = numOnly($list.find("li").computedStyle("height"));
                    var theHeight = numOnly($("#afSelectBoxContainer").computedStyle("height"));
                    if (foundInd * scrollThreshold >= theHeight) scrollToPos = (foundInd - 1) * -scrollThreshold;
                    this.scroller.scrollTo({
                        x: 0,
                        y: scrollToPos
                    });
                }
            } catch (e) {
                console.log("error init dropdown" + e);
            }

            var selClose = $("#afSelectClose").css("display") === "block" ? numOnly($("#afSelectClose").height()) : 0;
            $("#afSelectWrapper").height((numOnly($("#afSelectBoxContainer").height()) - selClose) + "px");

        },
        updateMaskValue: function(linker, value, val2) {

            $(linker).html(val2);
        },
        setDropDownValue: function(el, value) {

            if (!el) return;
            var $el = $(el);

            value = parseInt(value, 10);
            if (!el.getAttribute("multiple")) {
                el.selectedIndex = value;
                $el.find("option").prop("selected", false);
                $el.find("option:nth-child(" + (value + 1) + ")").prop("selected", true);
                this.scroller.scrollTo({
                    x: 0,
                    y: 0
                });
                this.hideDropDown();
            } else {
                //multi select

                // var myEl = $el.find("option:nth-child(" + (value + 1) + ")").get(0);
                var myList = $("#afSelectBoxfix li:nth-child(" + (value + 1) + ")");
                if (myList.hasClass("selected")) {
                    myList.removeClass("selected");
                    //  myEl.selected = false;
                } else {
                    myList.addClass("selected");
                    //  myEl.selected = true;
                }
            }
            $(el).trigger("change");
            el = null;
        },
        hideDropDown: function() {
            $("#afModalMask").hide();
            $("#afSelectBoxfix").html("");
        },
        createHtml: function() {
            var that = this;
            if (document.getElementById("afSelectBoxfix")) {
                return;
            }
            $(document).ready(function() {
                $(document).on("click", ".afFakeSelect", function(e) {
                    if (this.linker.disabled)
                        return;
                    that.currLinker = this;

                    if (this.linker.getAttribute("multiple") === "multiple")
                        $("#afSelectClose").show();
                    else
                        $("#afSelectClose").hide();
                    that.initDropDown(this.linker);

                });
                var container = $.create("div", {
                    id: "afSelectBoxContainer"
                });
                var modalDiv = $.create("div", {
                    id: "afSelectBoxfix"
                });
                var modalWrapper = $.create("div", {
                    id: "afSelectWrapper"
                });
                modalWrapper.css("position", "relative");
                modalWrapper.append(modalDiv);
                var closeDiv = $.create("div", {
                    id: "afSelectClose",
                    html: "Done Cancel"
                });

                var modalMask = $.create("div", {
                    id:"afModalMask"
                });

                var $afui = $("#afui");
                container.prepend(closeDiv).append(modalWrapper);
                modalMask.append(container);
                if ($afui.length > 0) $afui.append(modalMask);
                else document.body.appendChild(modalMask.get(0));
                that.scroller = $.query("#afSelectBoxfix").scroller({
                    scroller: false,
                    verticalScroll: true,
                    vScrollCSS: "afselectscrollBarV",
                    hasParent:true
                });

                $("#afModalMask").on("click",function(e){
                    var $e=$(e.target);
                    if($e.closest("#afSelectBoxContainer").length === 0)
                        that.hideDropDown();
                });

                $("#afSelectBoxfix").on("click", "li", function(e) {
                    var $el = $(e.target);
                    that.setDropDownValue(that.currLinker.linker, $el.data("ind"));
                });
                $("#afSelectBoxContainer").on("click", "a", function(e) {
                    if (e.target.id === "afSelectCancel")
                        return that.hideDropDown();
                    var $sel = $(that.currLinker.linker);
                    $sel.find("option").prop("selected", false);

                    $("#afSelectBoxfix li").each(function(el) {
                        var $el = $(this);
                        if ($el.hasClass("selected")) {
                            var ind = parseInt($el.data("ind"), 10);
                            $sel.find("option:nth-child(" + (ind + 1) + ")").prop("selected", true);
                            that.currLinker.innerHTML = $el.html();
                        }
                    });

                    that.hideDropDown();
                    e.stopPropagation();
                    e.preventDefault();
                    return false;
                });

            });
        }
    };

    //The following is based off Eli Grey's shim
    //https://gist.github.com/384583
    //We use HTMLElement to not cause problems with other objects
    if (!HTMLElement.prototype.watch) {
        HTMLElement.prototype.watch = function(prop, handler) {
            var oldval = this[prop],
                newval = oldval,
                getter = function() {
                    return newval;
                },
                setter = function(val) {
                    oldval = newval;
                    newval = handler.call(this, prop, oldval, val);
                    return newval;
                };
            if (delete this[prop]) { // can't watch constants
                if (HTMLElement.defineProperty) { // ECMAScript 5
                    HTMLElement.defineProperty(this, prop, {
                        get: getter,
                        set: setter,
                        enumerable: false,
                        configurable: true
                    });
                } else if (HTMLElement.prototype.__defineGetter__ && HTMLElement.prototype.__defineSetter__) { // legacy
                    HTMLElement.prototype.__defineGetter__.call(this, prop, getter);
                    HTMLElement.prototype.__defineSetter__.call(this, prop, setter);
                }
            }
        };
    }
    if (!HTMLElement.prototype.unwatch) {
        HTMLElement.prototype.unwatch = function(prop) {
            var val = this[prop];
            delete this[prop]; // remove accessors
            this[prop] = val;
        };
    }
})(af);
<|endoftext|>


<commit_before>const omxp = require('omxplayer-controll');

module.exports = function(RED) {
    function omxControl(config) {
        RED.nodes.createNode(this, config);
        var node = this;

        node.filename = config.filename;
        node.audiooutput = config.audiooutput;
        node.blackbackground = config.blackbackground;
        node.disablekeys = config.disablekeys;
        node.disableosd = config.disableosd;
        node.disableghostbox = config.disableghostbox;
        node.loop = config.loop;
        node.subtitlepath = config.subtitlepath;

        var opts = {
            'audioOutput': node.audiooutput || 'hdmi',
            'blackBackground': node.blackbackground,
            'disableKeys': node.disablekeys,
            'disableOnScreenDisplay': node.disableosd,
            'disableGhostbox': node.disableghostbox,
            'loop': node.loop,
            'subtitlePath': node.subtitlepath || '',
            'startAt': 0,
            'startVolume': 0.8,
            'closeOtherPlayers': true //Should close other players if necessary
        };

        node.on('input', msg => {
            var filename = node.filename || msg.filename || "";

            if (msg.payload == 'open') {
                if (filename == ""){
                    node.warn('No filename provided.');
                    return;
                } else {
                    omxp.open(filename, opts);
                }
            }
            if (msg.payload == 'playpause') {
                omxp.playPause(err => {
                    if (err){
                        node.error(err, msg);
                    } else {
                        setTimeout(updateStatus, 100);
                    }
                });
            }
            if (msg.payload == 'pause') {
                omxp.pause(err => {
                    if (err) {
                        node.error(err, msg);
                    } else {
                        setTimeout(updateStatus, 100);
                    }
                });
            }
            if (msg.payload == 'stop') {
                omxp.stop(err => {
                    if (err) {
                        node.error(err, msg);
                    } else {
                        node.status({fill:"red",shape:"dot",text:"Stopped"});
                    }
                });
            }
            if (msg.payload == 'volumeup') {
                omxp.volumeUp(err => {
                    if (err) node.error(err, msg);
                });
            }
            if (msg.payload == 'volumedown') {
                omxp.volumeDown(err => {
                    if (err) node.error(err, msg);
                });
            }
            if (msg.payload == 'getduration') {
                omxp.getDuration((err, duration) => {
                    if (duration) {
                        msg.status = {};
                        msg.status.duration = duration;
                        node.send(msg);
                    } else {
                        node.error(err);
                    }
                });
            }
            if (msg.payload == 'getposition') {
                omxp.getPosition((err, position) => {
                    if (position) {
                        msg.status = {};
                        msg.status.pos = position;
                        node.send(msg);
                    } else {
                        node.error(err);
                    }
                });
            }
            if (msg.payload == 'getstatus') {
                omxp.getStatus((err, status) => {
                    if (status) {
                        msg.status = {};
                        msg.status.status = status;
                        node.send(msg);
                    } else {
                        node.error(err);
                    }
                });
            }
            if (msg.payload == 'getvolume') {
                omxp.getVolume((err, volume) => {
                    if (volume) {
                        msg.status = {};
                        msg.status.vol = volume;
                        node.send(msg);
                    } else {
                        node.error(err);
                    }
                });
            }
            if (msg.payload.startsWith('setvolume')) {
                var volume = parseFloat(msg.payload.split(' ')[1]);
                if (volume > 1) volume = 1;
                if (volume < 0) volume = 0;
                omxp.setVolume(volume, (err, volume) => {
                    if (err) node.error(err);
                });
            }
            if (msg.payload.startsWith('setposition')) {
                var position = parseInt(msg.payload.split(' ')[1]);
                omxp.setPosition(position, err => {
                    if (err) node.error(err);
                });
            }
        });

        function updateStatus() {
            omxp.getStatus((err, status) => {
                if (status) {
                    switch (status) {
                        case 'Playing':
                            node.status({fill:"green",shape:"dot",text:"Playing"});
                            break;
                        case 'Stopped':
                            node.status({fill:"red",shape:"dot",text:"Stopped"});
                            break;
                        case 'Paused':
                            node.status({fill:"gray",shape:"dot",text:"Paused"});
                            break;
                    }
                }

            });
        }

        omxp.on('changeStatus', (status) => {
            switch (status.status) {
                case 'Playing':
                    node.status({fill:"green",shape:"dot",text:"Playing"});
                    break;
                case 'Stopped':
                    node.status({fill:"red",shape:"dot",text:"Stopped"});
                    break;
                case 'Paused':
                    node.status({fill:"gray",shape:"dot",text:"Paused"});
                    break;
            }
            var msg = {};
            msg.status = status;
            node.send(msg);
        });

        omxp.on('finish', () => {
            node.status({fill:"red",shape:"dot",text:"Stopped"});
            var msg = {};
            msg.status = {};
            msg.status.status = 'Stopped';
            node.send(msg);
        });

        node.on('close', () => {
            omxp.removeAllListeners('finish');
            omxp.removeAllListeners('changeStatus');
        });
    }
    RED.nodes.registerType("rpi-omxplayer", omxControl);
};
<commit_msg>Cleanup on finish<commit_after>const omxp = require('omxplayer-controll');

module.exports = function(RED) {
    function omxControl(config) {
        RED.nodes.createNode(this, config);
        var node = this;

        node.filename = config.filename;
        node.audiooutput = config.audiooutput;
        node.blackbackground = config.blackbackground;
        node.disablekeys = config.disablekeys;
        node.disableosd = config.disableosd;
        node.disableghostbox = config.disableghostbox;
        node.loop = config.loop;
        node.subtitlepath = config.subtitlepath;

        var opts = {
            'audioOutput': node.audiooutput || 'hdmi',
            'blackBackground': node.blackbackground,
            'disableKeys': node.disablekeys,
            'disableOnScreenDisplay': node.disableosd,
            'disableGhostbox': node.disableghostbox,
            'loop': node.loop,
            'subtitlePath': node.subtitlepath || '',
            'startAt': 0,
            'startVolume': 0.8,
            'closeOtherPlayers': true //Should close other players if necessary
        };

        node.on('input', msg => {
            var filename = node.filename || msg.filename || "";

            if (msg.payload == 'open') {
                if (filename == ""){
                    node.warn('No filename provided.');
                    return;
                } else {
                    omxp.open(filename, opts);
                }
            }
            if (msg.payload == 'playpause') {
                omxp.playPause(err => {
                    if (err){
                        node.error(err, msg);
                    } else {
                        setTimeout(updateStatus, 100);
                    }
                });
            }
            if (msg.payload == 'pause') {
                omxp.pause(err => {
                    if (err) {
                        node.error(err, msg);
                    } else {
                        setTimeout(updateStatus, 100);
                    }
                });
            }
            if (msg.payload == 'stop') {
                omxp.stop(err => {
                    if (err) {
                        node.error(err, msg);
                    } else {
                        node.status({fill:"red",shape:"dot",text:"Stopped"});
                    }
                });
            }
            if (msg.payload == 'volumeup') {
                omxp.volumeUp(err => {
                    if (err) node.error(err, msg);
                });
            }
            if (msg.payload == 'volumedown') {
                omxp.volumeDown(err => {
                    if (err) node.error(err, msg);
                });
            }
            if (msg.payload == 'getduration') {
                omxp.getDuration((err, duration) => {
                    if (duration) {
                        msg.status = {};
                        msg.status.duration = duration;
                        node.send(msg);
                    } else {
                        node.error(err);
                    }
                });
            }
            if (msg.payload == 'getposition') {
                omxp.getPosition((err, position) => {
                    if (position) {
                        msg.status = {};
                        msg.status.pos = position;
                        node.send(msg);
                    } else {
                        node.error(err);
                    }
                });
            }
            if (msg.payload == 'getstatus') {
                omxp.getStatus((err, status) => {
                    if (status) {
                        msg.status = {};
                        msg.status.status = status;
                        node.send(msg);
                    } else {
                        node.error(err);
                    }
                });
            }
            if (msg.payload == 'getvolume') {
                omxp.getVolume((err, volume) => {
                    if (volume) {
                        msg.status = {};
                        msg.status.vol = volume;
                        node.send(msg);
                    } else {
                        node.error(err);
                    }
                });
            }
            if (msg.payload.startsWith('setvolume')) {
                var volume = parseFloat(msg.payload.split(' ')[1]);
                if (volume > 1) volume = 1;
                if (volume < 0) volume = 0;
                omxp.setVolume(volume, (err, volume) => {
                    if (err) node.error(err);
                });
            }
            if (msg.payload.startsWith('setposition')) {
                var position = parseInt(msg.payload.split(' ')[1]);
                omxp.setPosition(position, err => {
                    if (err) node.error(err);
                });
            }
        });

        function updateStatus() {
            omxp.getStatus((err, status) => {
                if (status) {
                    switch (status) {
                        case 'Playing':
                            node.status({fill:"green",shape:"dot",text:"Playing"});
                            break;
                        case 'Stopped':
                            node.status({fill:"red",shape:"dot",text:"Stopped"});
                            break;
                        case 'Paused':
                            node.status({fill:"gray",shape:"dot",text:"Paused"});
                            break;
                    }
                }

            });
        }

        omxp.on('changeStatus', (status) => {
            switch (status.status) {
                case 'Playing':
                    node.status({fill:"green",shape:"dot",text:"Playing"});
                    break;
                case 'Stopped':
                    node.status({fill:"red",shape:"dot",text:"Stopped"});
                    break;
                case 'Paused':
                    node.status({fill:"gray",shape:"dot",text:"Paused"});
                    break;
            }
            var msg = {};
            msg.status = status;
            node.send(msg);
        });

        omxp.on('finish', () => {
            node.status({fill:"red",shape:"dot",text:"Stopped"});
            var msg = {};
            msg.status = {};
            msg.status.status = 'Stopped';
            node.send(msg);
            cleanup();
        });

        node.on('close', () => {
            cleanup();
        });

        function cleanup() {
            omxp.removeAllListeners('finish');
            omxp.removeAllListeners('changeStatus');
        }
    }
    RED.nodes.registerType("rpi-omxplayer", omxControl);
};
<|endoftext|>


<commit_before>angular.module('bookDetail').component('bookDetail', {
  templateUrl: 'book-detail/book-detail.template.html',
  controller: function BookDetailController($http, $routeParams) {
    var vm = this;
    vm.bookId = $routeParams.bookId;
    $http.get('singleBookById', {params: {'id': vm.bookId}})
        .then(function(response) {
          vm.book = response.data;
    })

    function getBookInfo() {
      const urlHead = 'https://www.googleapis.com/books/v1/volumes?q=';
      fetch('/book-data').then(response => response.json()).then((bookInfo) => {
        for (key in Object.keys(bookInfo)) {
            console.log("key: " + key);
            var query = bookInfo[key].title.replace(/ /g, '+');
            var url = urlHead + query;
            searchBooks(bookInfo[key], url);
        }
      });
    }

    const bookFields = {
      TITLE: "title",
      GENRE: "genre",
      CATEGORIES: "categories",
      AUTHOR: "author",
      LANGUAGE: "language",
      DESCRIPTION: "description",
      INFO_LINK: "infoLink",
      PAGE_COUNT: "pageCount",
      PUBLISH_DATE: "publishedDate",
      PUBLISHER: "publisher",
      MATURITY_RATING: "maturityRating"
    }

    function searchBooks(book, url){
      $.getJSON(url, function (json){
        var info = json.items[0].volumeInfo;
        var title = book.title;
        var reviews = book.reviews;
        var genre = book.genre; // List of genres from GoodReads
        var categories = info.categories; // List of genres from Books API
        var author = info.authors;
        var language = info.language;
        var description = info.description;
        var infoLink = info.infoLink;
        var pageCount = info.pageCount;
        var publishedDate = info.publishedDate;
        var publisher = info.publisher;
        var maturityRating = info.maturityRating;

        var fieldContentArray = [title, genre, categories, author, language, description, infoLink, pageCount, publishedDate, publisher, maturityRating];
        var fieldsString;
        var index = 0;

        //passing values through as URL parameters
        for (var field in bookFields){
          if(index == 0){
            fieldsString = "?"+field+"="+fieldContentArray[index];
          }else if(index<bookFields.length-1){
            fieldsString += "&"+field+"="+fieldContentArray[index]
          }
          index ++;
        }

        fetch("/data-upload"+fieldsString,{method:"POST"});
      })
      .fail(function (jqxhr, status, errorMessage){
        $("#bookresult").html("Status Code: " + status+"
Error Message: "+errorMessage);
      });
    }
  },
  controllerAs: 'bookDetailCtrl'
});

<commit_msg>starting testing<commit_after>angular.module('bookDetail').component('bookDetail', {
  templateUrl: 'book-detail/book-detail.template.html',
  controller: function BookDetailController($http, $routeParams) {
    var vm = this;
    vm.bookId = $routeParams.bookId;
    $http.get('singleBookById', {params: {'id': vm.bookId}})
        .then(function(response) {
          vm.book = response.data;
    })

    function getBookInfo() {
      const urlHead = 'https://www.googleapis.com/books/v1/volumes?q=';
      fetch('/book-data').then(response => response.json()).then((bookInfo) => {
        for (key in Object.keys(bookInfo)) {
            console.log("key: " + key);
            var query = bookInfo[key].title.replace(/ /g, '+');
            var url = urlHead + query;
            searchBooks(bookInfo[key], url);
        }
      });
    }

    const bookFields = {
      TITLE: "title",
      GENRE: "genre",
      CATEGORIES: "categories",
      AUTHOR: "author",
      LANGUAGE: "language",
      DESCRIPTION: "description",
      INFO_LINK: "infoLink",
      PAGE_COUNT: "pageCount",
      PUBLISH_DATE: "publishedDate",
      PUBLISHER: "publisher",
      MATURITY_RATING: "maturityRating"
    }

    function searchBooks(book, url){
      $.getJSON(url, function (json){
        var info = json.items[0].volumeInfo;
        var title = book.title;
        var reviews = book.reviews;
        var genre = book.genre; // List of genres from GoodReads
        var categories = info.categories; // List of genres from Books API
        var author = info.authors;
        var language = info.language;
        var description = info.description;
        var infoLink = info.infoLink;
        var pageCount = info.pageCount;
        var publishedDate = info.publishedDate;
        var publisher = info.publisher;
        var maturityRating = info.maturityRating;

        var fieldContentArray = [title, genre, categories, author, language, description, infoLink, pageCount, publishedDate, publisher, maturityRating];
        var fieldsString;
        var index = 0;

        console.log("testing");

        //passing values through as URL parameters
        for (var field in bookFields){
          if(index == 0){
            fieldsString = "?"+field+"="+fieldContentArray[index];
          }else if(index<bookFields.length-1){
            fieldsString += "&"+field+"="+fieldContentArray[index]
          }
          index ++;
        }

        fetch("/data-upload"+fieldsString,{method:"POST"});
      })
      .fail(function (jqxhr, status, errorMessage){
        $("#bookresult").html("Status Code: " + status+"
Error Message: "+errorMessage);
      });
    }
  },
  controllerAs: 'bookDetailCtrl'
});

<|endoftext|>