<commit_before>var toggleTradeForm, clearTradeForm, updateSidebarStock, createStockDiv, updateBankAccountHtml, dollarAttributes, makeTrade, sellStock, buyStock, updateStock, newStock, myBankAccount, offset, offsetCheck, marketOpenCheck, updateAllStocks

myBankAccount = new BankAccount;

toggleTradeForm = function(type) {
	if ( $('#buy_sell_button').val()===type ){
		if ( $('#sidebar_new_stock_search').is(":visible") ){
			$('#sidebar_new_stock_search').hide();
		} else {
			$('#sidebar_new_stock_search').show();
		};
	} else {
		$('#buy_sell_button').val(type);
		$('#sidebar_new_stock_search').show();
	};
};

clearTradeForm = function() {
	$('#sidebar_get_stock_type').val("");
	$('#sidebar_get_stock_amount').val("");
};

createStockDiv = function(myNewStock) {
	var newClass = 'row '+myNewStock.symbol.toLowerCase();
	var newClassSelector = '.'+myNewStock.symbol.toLowerCase();
	$('#sidebar').append($('#sample').html());
	$('#sidebar').children('div').last().attr('class', newClass);
	updateSidebarStock(myNewStock);
	$(newClassSelector).show();
};

updateSidebarStock = function(stock) {
	var  newClassSelector = '.'+stock.symbol.toLowerCase();
	$.each(stock, function(type,value){
		if (stock.hasOwnProperty(type)){
			$(newClassSelector+' .'+type).html(dollarAttributes(type)+value);
		};
	});
	// $(newClassSelector+' .symbol').html(symbol);
	// $(newClassSelector+' .amount').html(amount);
	// $(newClassSelector+' .priceBought').html(thePrice);
	// $(newClassSelector+' .currentPrice').html(thePrice);
	// $(newClassSelector+' .currentValue').html(Math.round(amount*thePrice));
	// $(newClassSelector+' .gainLoss').html("0");
};

updateBankAccountHtml = function() {
	$('#bank_cash').text("$"+myBankAccount.cash.toFixed(2))
	$('#bank_stock_value').text("$"+myBankAccount.stockValue.toFixed(2))
	$('#bank_total').text("$"+(parseFloat(myBankAccount.cash)+parseFloat(myBankAccount.stockValue)).toFixed(2))
};

dollarAttributes = function(atty){
	var dollarAttys = {"priceBought":1,"currentPrice":1,"currentValue":1, "gainLoss":1};
	if (dollarAttys[atty]) {
		return "$"
	} else {
		return ""
	}
};

offsetCheck = function(){
	$.ajax({
	  url: "stock_market_game/offset",
	  dataType: "json"
  }).done(function(offsetData){
  	console.log("offsetCheck" + offsetData.offset)
  	offset = offsetData.offset;
  });
};

marketOpenCheck = function(){
	var offsetHours = offset / 3600;
	d = new Date;
	var newYorkTime = d.getUTCHours() + offsetHours;
	var dayOfWeek = d.getUTCDay();
	if (newYorkTime>9 && newYorkTime<16 && dayOfWeek!=0 && dayOfWeek!=6) {
		updateAllStocks();
	} else {
		console.log('not updated')
	};
};

updateAllStocks = function() {
	if (Object.keys(myBankAccount.myOwnedStock).length>0){
		$.support.cors = true;
		var theStocks = '"' + Object.keys(myBankAccount.myOwnedStock).join('","') + '"';
		console.log(theStocks);
		var theUrl = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20("+theStocks+")&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=updateStocks";
		$.ajax({
		  url: theUrl,
		  dataType: "jsonp",
	    jsonp: "callback",
	    jsonpCallback: "updateStocks"
	  });
	  updateStocks = function(data){
	  	console.log(data)
	  	var stocksData = data.query.results.quote;
	  	$.each(stocksData, function(index,stock){
	  		myBankAccount.myOwnedStock[stock.symbol].updatePrice(stock.LastTradePriceOnly);
	  		updateSidebarStock(myBankAccount.myOwnedStock[stock.symbol]);
	  	});
	  	console.log("all updated")
	  };
	};
};

makeTrade = function(symbol,amount,callback) {
	$.support.cors = true;
	var theUrl = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%3D%22"+symbol+"%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback="+callback;
	$.ajax({
	  url: theUrl,
	  dataType: "jsonp",
    jsonp: "callback",
    jsonpCallback: "updateStocks"
  });
	newStock = function(data) {
		var thePrice = data.query.results.quote.LastTradePriceOnly;
		if (thePrice === null){
			alert('that is not a valid stock')
		} else if (thePrice*amount<myBankAccount.cash) {
		  var myNewStock = new OwnedStock(symbol, amount, thePrice);
			myBankAccount.myOwnedStock[symbol.toLowerCase()] = myNewStock;
			createStockDiv(myNewStock);
			myBankAccount.updateStockValue();
			updateBankAccountHtml();
		} else {
			alert('you dont have that much cash')
		};
	};
	updateStock = function(data) {
	  var updateThePrice = data.query.results.quote.LastTradePriceOnly;
	  var updateTheStock = myBankAccount.myOwnedStock[symbol.toLowerCase()];
	  updateTheStock.updatePrice(updateThePrice);
		updateSidebarStock(updateTheStock);
	};
	buyStock = function(data) {
	  var thePrice = data.query.results.quote.LastTradePriceOnly;
		if (thePrice*amount<myBankAccount.cash) {
		  var theStock = myBankAccount.myOwnedStock[symbol.toLowerCase()];
		  theStock.buyPrice(amount,thePrice);
			updateSidebarStock(theStock);
		} else {
			alert('you dont have that much cash')
		};
	};
	sellStock = function(data) {
	  var theStock = myBankAccount.myOwnedStock[symbol.toLowerCase()];
		var thePrice = data.query.results.quote.LastTradePriceOnly;
	  if (theStock.amount + amount > 0 ) {
		  theStock.sellPrice(amount,thePrice);
		} else if (theStock.amount + amount < 0) {
			alert('you dont have that many shares');
		} else {
			confirm('do you want to sell all of '+symbol.toUpperCase());
		  theStock.sellPrice(amount,thePrice);
			$('.'+symbol).hide();
		};
		updateSidebarStock(theStock);
	};
}

$(document).on("ready page:load", function() {
	$("#stock_market_info_modal").foundation('reveal', 'open');
	$('#buy_stock_link').on('click', function(event){
		event.preventDefault();
		clearTradeForm();
		toggleTradeForm("Buy");
	});
	$('#sell_stock_link').on('click', function(event){
		event.preventDefault();
		clearTradeForm();
		toggleTradeForm("Sell");
	});
	$('#sidebar_get_stock').submit(function(event){
		event.preventDefault();
		var symbol, amount
		symbol = $('#sidebar_get_stock_type').val().toLowerCase();
		amount = $('#sidebar_get_stock_amount').val();
		clearTradeForm();
		toggleTradeForm($('#buy_sell_button').val());
		if (!myBankAccount.myOwnedStock[symbol]){
			makeTrade(symbol,amount,'newStock');
		} else if( $('#buy_sell_button').val()==="Sell" ) {
			makeTrade(symbol,-Math.abs(amount),'sellStock');
		} else if( $('#buy_sell_button').val()==="Buy") {
			makeTrade(symbol,amount,'buyStock');
			$('.'+symbol).show();
		};
	});
	$(document).on('click', '.buy_stock_link', function(event){
		event.preventDefault();
		var symbol = $(this).parent().parent().children().first().text().toLowerCase();
		$('#sidebar_get_stock_type').val(symbol);
		toggleTradeForm("Buy");
	});
	$(document).on('click', '.sell_stock_link', function(event){
		event.preventDefault();
		var symbol = $(this).parent().parent().children().first().text().toLowerCase();
		$('#sidebar_get_stock_type').val(symbol);
		toggleTradeForm("Sell");
	});
	offsetCheck();
	var offsetChecker = setInterval(offsetCheck,32400000);
	var updateInterval = setInterval(marketOpenCheck,10000);
});

function OwnedStock(symbol, amount, priceBought){
	this.symbol = symbol.toUpperCase();
	this.amount = parseFloat(amount);
	this.priceBought = parseFloat(priceBought).toFixed(2);
	this.currentPrice = parseFloat(priceBought).toFixed(2);
	this.currentValue = parseFloat(priceBought*amount).toFixed(2);
	this.gainLoss = (0.00).toFixed(2);
	myBankAccount.updateCash(((amount*priceBought)*-1).toFixed(2));
	// update OwnedStock
};

OwnedStock.prototype.updatePrice = function(price){
	this.currentPrice = parseFloat(price).toFixed(2);
	this.currentValue = parseFloat(this.amount * price).toFixed(2);
	this.gainLoss = parseFloat(this.currentValue - (this.amount * this.priceBought)).toFixed(2);
	// update account
	myBankAccount.updateStockValue(price);
};

OwnedStock.prototype.buyPrice = function(addedAmount, price){
	var oldPrice = this.priceBought;
	var oldAmount = this.amount;
	this.amount += parseFloat(addedAmount);
	this.priceBought = parseFloat(((oldPrice * oldAmount)+(price * addedAmount))/this.amount).toFixed(2);
	this.currentPrice = parseFloat(price);
	this.currentValue = parseFloat(this.amount * price).toFixed(2);
	this.gainLoss = parseFloat(this.currentValue - (this.amount * this.priceBought)).toFixed(2);
	// update account
	myBankAccount.updateCash((addedAmount*price)*-1);
};

OwnedStock.prototype.sellPrice = function(removedAmount, price){
	this.amount += parseFloat(removedAmount);
	this.currentPrice = parseFloat(price);
	this.currentValue = parseFloat(this.amount * price).toFixed(2);
	this.gainLoss = parseFloat(this.currentValue - (this.amount * this.priceBought)).toFixed(2);
	// update account
	myBankAccount.updateCash((removedAmount*price)*-1);
};

function BankAccount(){
	this.cash = parseFloat(10000.00);
	this.stockValue = parseFloat(0.00);
	this.myOwnedStock = {};
};

BankAccount.prototype.updateCash = function(cashAmount){
	this.cash += parseFloat(cashAmount);
	this.updateStockValue();
	updateBankAccountHtml();
};

BankAccount.prototype.updateStockValue = function(){
	this.stockValue = parseFloat(0);
	that = this
	$.each(this.myOwnedStock, function(symb,obj){
		that.stockValue += parseFloat(obj.currentValue);
	});
	updateBankAccountHtml();
};<commit_msg>fixing offset url for ajax call<commit_after>var toggleTradeForm, clearTradeForm, updateSidebarStock, createStockDiv, updateBankAccountHtml, dollarAttributes, makeTrade, sellStock, buyStock, updateStock, newStock, myBankAccount, offset, offsetCheck, marketOpenCheck, updateAllStocks

myBankAccount = new BankAccount;

toggleTradeForm = function(type) {
	if ( $('#buy_sell_button').val()===type ){
		if ( $('#sidebar_new_stock_search').is(":visible") ){
			$('#sidebar_new_stock_search').hide();
		} else {
			$('#sidebar_new_stock_search').show();
		};
	} else {
		$('#buy_sell_button').val(type);
		$('#sidebar_new_stock_search').show();
	};
};

clearTradeForm = function() {
	$('#sidebar_get_stock_type').val("");
	$('#sidebar_get_stock_amount').val("");
};

createStockDiv = function(myNewStock) {
	var newClass = 'row '+myNewStock.symbol.toLowerCase();
	var newClassSelector = '.'+myNewStock.symbol.toLowerCase();
	$('#sidebar').append($('#sample').html());
	$('#sidebar').children('div').last().attr('class', newClass);
	updateSidebarStock(myNewStock);
	$(newClassSelector).show();
};

updateSidebarStock = function(stock) {
	var  newClassSelector = '.'+stock.symbol.toLowerCase();
	$.each(stock, function(type,value){
		if (stock.hasOwnProperty(type)){
			$(newClassSelector+' .'+type).html(dollarAttributes(type)+value);
		};
	});
	// $(newClassSelector+' .symbol').html(symbol);
	// $(newClassSelector+' .amount').html(amount);
	// $(newClassSelector+' .priceBought').html(thePrice);
	// $(newClassSelector+' .currentPrice').html(thePrice);
	// $(newClassSelector+' .currentValue').html(Math.round(amount*thePrice));
	// $(newClassSelector+' .gainLoss').html("0");
};

updateBankAccountHtml = function() {
	$('#bank_cash').text("$"+myBankAccount.cash.toFixed(2))
	$('#bank_stock_value').text("$"+myBankAccount.stockValue.toFixed(2))
	$('#bank_total').text("$"+(parseFloat(myBankAccount.cash)+parseFloat(myBankAccount.stockValue)).toFixed(2))
};

dollarAttributes = function(atty){
	var dollarAttys = {"priceBought":1,"currentPrice":1,"currentValue":1, "gainLoss":1};
	if (dollarAttys[atty]) {
		return "$"
	} else {
		return ""
	}
};

offsetCheck = function(){
	$.ajax({
	  url: "/stock_market_game/offset",
	  dataType: "json"
  }).done(function(offsetData){
  	console.log("offsetCheck" + offsetData.offset)
  	offset = offsetData.offset;
  });
};

marketOpenCheck = function(){
	var offsetHours = offset / 3600;
	d = new Date;
	var newYorkTime = d.getUTCHours() + offsetHours;
	var dayOfWeek = d.getUTCDay();
	if (newYorkTime>9 && newYorkTime<16 && dayOfWeek!=0 && dayOfWeek!=6) {
		updateAllStocks();
	} else {
		console.log('not updated')
	};
};

updateAllStocks = function() {
	if (Object.keys(myBankAccount.myOwnedStock).length>0){
		$.support.cors = true;
		var theStocks = '"' + Object.keys(myBankAccount.myOwnedStock).join('","') + '"';
		console.log(theStocks);
		var theUrl = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in%20("+theStocks+")&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback=updateStocks";
		$.ajax({
		  url: theUrl,
		  dataType: "jsonp",
	    jsonp: "callback",
	    jsonpCallback: "updateStocks"
	  });
	  updateStocks = function(data){
	  	console.log(data)
	  	var stocksData = data.query.results.quote;
	  	$.each(stocksData, function(index,stock){
	  		myBankAccount.myOwnedStock[stock.symbol].updatePrice(stock.LastTradePriceOnly);
	  		updateSidebarStock(myBankAccount.myOwnedStock[stock.symbol]);
	  	});
	  	console.log("all updated")
	  };
	};
};

makeTrade = function(symbol,amount,callback) {
	$.support.cors = true;
	var theUrl = "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%3D%22"+symbol+"%22&format=json&diagnostics=true&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys&callback="+callback;
	$.ajax({
	  url: theUrl,
	  dataType: "jsonp",
    jsonp: "callback",
    jsonpCallback: "updateStocks"
  });
	newStock = function(data) {
		var thePrice = data.query.results.quote.LastTradePriceOnly;
		if (thePrice === null){
			alert('that is not a valid stock')
		} else if (thePrice*amount<myBankAccount.cash) {
		  var myNewStock = new OwnedStock(symbol, amount, thePrice);
			myBankAccount.myOwnedStock[symbol.toLowerCase()] = myNewStock;
			createStockDiv(myNewStock);
			myBankAccount.updateStockValue();
			updateBankAccountHtml();
		} else {
			alert('you dont have that much cash')
		};
	};
	updateStock = function(data) {
	  var updateThePrice = data.query.results.quote.LastTradePriceOnly;
	  var updateTheStock = myBankAccount.myOwnedStock[symbol.toLowerCase()];
	  updateTheStock.updatePrice(updateThePrice);
		updateSidebarStock(updateTheStock);
	};
	buyStock = function(data) {
	  var thePrice = data.query.results.quote.LastTradePriceOnly;
		if (thePrice*amount<myBankAccount.cash) {
		  var theStock = myBankAccount.myOwnedStock[symbol.toLowerCase()];
		  theStock.buyPrice(amount,thePrice);
			updateSidebarStock(theStock);
		} else {
			alert('you dont have that much cash')
		};
	};
	sellStock = function(data) {
	  var theStock = myBankAccount.myOwnedStock[symbol.toLowerCase()];
		var thePrice = data.query.results.quote.LastTradePriceOnly;
	  if (theStock.amount + amount > 0 ) {
		  theStock.sellPrice(amount,thePrice);
		} else if (theStock.amount + amount < 0) {
			alert('you dont have that many shares');
		} else {
			confirm('do you want to sell all of '+symbol.toUpperCase());
		  theStock.sellPrice(amount,thePrice);
			$('.'+symbol).hide();
		};
		updateSidebarStock(theStock);
	};
}

$(document).on("ready page:load", function() {
	$("#stock_market_info_modal").foundation('reveal', 'open');
	$('#buy_stock_link').on('click', function(event){
		event.preventDefault();
		clearTradeForm();
		toggleTradeForm("Buy");
	});
	$('#sell_stock_link').on('click', function(event){
		event.preventDefault();
		clearTradeForm();
		toggleTradeForm("Sell");
	});
	$('#sidebar_get_stock').submit(function(event){
		event.preventDefault();
		var symbol, amount
		symbol = $('#sidebar_get_stock_type').val().toLowerCase();
		amount = $('#sidebar_get_stock_amount').val();
		clearTradeForm();
		toggleTradeForm($('#buy_sell_button').val());
		if (!myBankAccount.myOwnedStock[symbol]){
			makeTrade(symbol,amount,'newStock');
		} else if( $('#buy_sell_button').val()==="Sell" ) {
			makeTrade(symbol,-Math.abs(amount),'sellStock');
		} else if( $('#buy_sell_button').val()==="Buy") {
			makeTrade(symbol,amount,'buyStock');
			$('.'+symbol).show();
		};
	});
	$(document).on('click', '.buy_stock_link', function(event){
		event.preventDefault();
		var symbol = $(this).parent().parent().children().first().text().toLowerCase();
		$('#sidebar_get_stock_type').val(symbol);
		toggleTradeForm("Buy");
	});
	$(document).on('click', '.sell_stock_link', function(event){
		event.preventDefault();
		var symbol = $(this).parent().parent().children().first().text().toLowerCase();
		$('#sidebar_get_stock_type').val(symbol);
		toggleTradeForm("Sell");
	});
	offsetCheck();
	var offsetChecker = setInterval(offsetCheck,32400000);
	var updateInterval = setInterval(marketOpenCheck,10000);
});

function OwnedStock(symbol, amount, priceBought){
	this.symbol = symbol.toUpperCase();
	this.amount = parseFloat(amount);
	this.priceBought = parseFloat(priceBought).toFixed(2);
	this.currentPrice = parseFloat(priceBought).toFixed(2);
	this.currentValue = parseFloat(priceBought*amount).toFixed(2);
	this.gainLoss = (0.00).toFixed(2);
	myBankAccount.updateCash(((amount*priceBought)*-1).toFixed(2));
	// update OwnedStock
};

OwnedStock.prototype.updatePrice = function(price){
	this.currentPrice = parseFloat(price).toFixed(2);
	this.currentValue = parseFloat(this.amount * price).toFixed(2);
	this.gainLoss = parseFloat(this.currentValue - (this.amount * this.priceBought)).toFixed(2);
	// update account
	myBankAccount.updateStockValue(price);
};

OwnedStock.prototype.buyPrice = function(addedAmount, price){
	var oldPrice = this.priceBought;
	var oldAmount = this.amount;
	this.amount += parseFloat(addedAmount);
	this.priceBought = parseFloat(((oldPrice * oldAmount)+(price * addedAmount))/this.amount).toFixed(2);
	this.currentPrice = parseFloat(price);
	this.currentValue = parseFloat(this.amount * price).toFixed(2);
	this.gainLoss = parseFloat(this.currentValue - (this.amount * this.priceBought)).toFixed(2);
	// update account
	myBankAccount.updateCash((addedAmount*price)*-1);
};

OwnedStock.prototype.sellPrice = function(removedAmount, price){
	this.amount += parseFloat(removedAmount);
	this.currentPrice = parseFloat(price);
	this.currentValue = parseFloat(this.amount * price).toFixed(2);
	this.gainLoss = parseFloat(this.currentValue - (this.amount * this.priceBought)).toFixed(2);
	// update account
	myBankAccount.updateCash((removedAmount*price)*-1);
};

function BankAccount(){
	this.cash = parseFloat(10000.00);
	this.stockValue = parseFloat(0.00);
	this.myOwnedStock = {};
};

BankAccount.prototype.updateCash = function(cashAmount){
	this.cash += parseFloat(cashAmount);
	this.updateStockValue();
	updateBankAccountHtml();
};

BankAccount.prototype.updateStockValue = function(){
	this.stockValue = parseFloat(0);
	that = this
	$.each(this.myOwnedStock, function(symb,obj){
		that.stockValue += parseFloat(obj.currentValue);
	});
	updateBankAccountHtml();
};<|endoftext|>


<commit_before>// Use this file to change prototype configuration.

// Note: prototype config can be overridden using environment variables (eg on heroku)

module.exports = {
  welcome_title: 'Welcome',
  applicant_title: 'Applicant',
  applicant_header:'About the applicant',
  applicant_firstname_question:'First name',
  applicant_lastname_question:'Last name',
  applicant_address_question:'Address',
  applicant_home_phone_number_question:'Home phone number',
  applicant_mobilework_phone_number_question:'Mobile phone number',
  applicant_email_address_question:'Email address',
  applicant_relationship_deceased:'Relationship to the person who died',
  applicant_executor_question:'Are you named as an executor in their will?’,

  nameanddate_header: 'About the person who died',
  nameanddate_question_1:'What was their full name?',
  nameanddate_question_hint_1: 'Exactly as it is  shown on their death certificate.',
  nameanddate_question_firstname:'First name',
  nameanddate_question_lastname:'Last name',
  nameanddate_stop_1: 'You need the death certificate to complete this application.',
  nameanddate_question_2: 'Was the person who died known by another name?',
  nameanddate_question_hint_2: 'A nickname, maiden name or title.',
  nameanddate_question_3: 'What is the date they were born?',
  nameanddate_question_4: 'What is the date they died?',
  nameanddate_question_hint_4: 'As shown on their death certificate.',
  nameanddate_stop_4: 'You need the death certificate to complete this application.',

  address_header: 'About the person who died',
  address_question_1: 'Were they domiciled in England or Wales at the time of their death?',
  address_question_hint_1: 'Where they considered to be their permanent home.',
  address_question_2: 'What was their address at the time of their death?’,

  maritalstatus_title: 'Marital Status',
  maritalstatus_header: 'About the person who died',
  maritalstatus_question_1: 'What was their Marital Status?',
  maritalstatus_question_hint_1: 'Their martial status at the time of their death.',
  maritalstatus_radio_1: 'Married',
  maritalstatus_radio_2: 'Never married',
  maritalstatus_radio_hint_2: 'They were a bachelor or spinster.',
  maritalstatus_radio_3: 'Widowed',
  maritalstatus_radio_hint_3: 'Their spouse died.',
  maritalstatus_radio_4: 'Divorced, or their civil partnership was dissolved',
  maritalstatus_radio_5: 'Judicially separated',
  maritalstatus_radio_hint_5: 'They were legally separated.',

  will_title: 'Will and Codicil',
  will_header: 'About the will',
  will_question_1: 'Did the person who died leave a will?',
  will_question_stop_1: 'Stop content: You will need the original will to complete this application.',
  will_question_2: 'Do you have the original will?',
  will_question_stop_2: 'Stop content: You will need the original will to complete this application.',
  will_question_3: 'What is the date of the will?',
  will_question_hint_3: 'The date the will was made.',
  will_question_4: ‘Were there any wills outside of England and Wales?',
  will_question_hint_4: 'Will made in another country apart from England and Wales.',
  will_question_5: 'Are there any codicils?',
  will_question_hint_5: 'Changes or updates to the will.',

  iht_question_1: 'Did you submit an inheritance tax summary online?',
  iht_question_2: 'What is the IHT Identifier',
  iht_question_hint_2: ‘The reference number’,
  iht_question_3: 'Gross Estate figure (Â£)',
  iht_question_hint_3: 'Whole pounds only',
  iht_question_4: 'Net Estate figure (Â£)',
  iht_question_hint_4: 'Whole pounds only',

  executors_question_1: 'Please list all of the executors named in the Will',
  executors_link_add_executor: 'Add another Executor named on the Will',

  executorsnotapplying_question_listall: 'Please list any executors who are not making this application with you an explain why',
  executorsnotapplying_radio_diedbefore: 'They died before the deceased person',
  executorsnotapplying_radio_diedafter: 'They died after the deceased person',
  executorsnotapplying_radio_reserved: 'Power reserved',
  executorsnotapplying_radio_renunciation: 'Renunciation',
  executorsnotapplying_radio_attorney: 'Power of Attorney',

  executors_title: 'The executors',
  summary_title: 'Summary',
  nextsteps_title: 'Next steps',

  stop_foreign_domicile: ‘The person who died was not domiciled in England or Wales. You cannot complete the application online. Contact the Probate Registry for help.',
  stop_no_will: ‘The original will is not available. You cannot complete the application online without the original will. Contact the Probate Registry for help.',
  address_title: 'Address',
  nameanddate_title: 'nameanddate',

};	<commit_msg>removed smart quotes in message file<commit_after>// Use this file to change prototype configuration.

// Note: prototype config can be overridden using environment variables (eg on heroku)

module.exports = {
  welcome_title: 'Welcome',
  applicant_title: 'Applicant',
  applicant_header:'About the applicant',
  applicant_firstname_question:'First name',
  applicant_lastname_question:'Last name',
  applicant_address_question:'Address',
  applicant_home_phone_number_question:'Home phone number',
  applicant_mobilework_phone_number_question:'Mobile phone number',
  applicant_email_address_question:'Email address',
  applicant_relationship_deceased:'Relationship to the person who died',
  applicant_executor_question:'Are you named as an executor in their will?',
  nameanddate_header: 'About the person who died',
  nameanddate_question_1:'What was their full name?',
  nameanddate_question_hint_1: 'Exactly as it is  shown on their death certificate.',
  nameanddate_question_firstname:'First name',
  nameanddate_question_lastname:'Last name',
  nameanddate_stop_1: 'You need the death certificate to complete this application.',
  nameanddate_question_2: 'Was the person who died known by another name?',
  nameanddate_question_hint_2: 'A nickname, maiden name or title.',
  nameanddate_question_3: 'What is the date they were born?',
  nameanddate_question_4: 'What is the date they died?',
  nameanddate_question_hint_4: 'As shown on their death certificate.',
  nameanddate_stop_4: 'You need the death certificate to complete this application.',
  address_header: 'About the person who died',
  address_question_1: 'Were they domiciled in England or Wales at the time of their death?',
  address_question_hint_1: 'Where they considered to be their permanent home.',
  address_question_2: 'What was their address at the time of their death?',
  maritalstatus_title: 'Marital Status',
  maritalstatus_header: 'About the person who died',
  maritalstatus_question_1: 'What was their Marital Status?',
  maritalstatus_question_hint_1: 'Their martial status at the time of their death.',
  maritalstatus_radio_1: 'Married',
  maritalstatus_radio_2: 'Never married',
  maritalstatus_radio_hint_2: 'They were a bachelor or spinster.',
  maritalstatus_radio_3: 'Widowed',
  maritalstatus_radio_hint_3: 'Their spouse died.',
  maritalstatus_radio_4: 'Divorced, or their civil partnership was dissolved',
  maritalstatus_radio_5: 'Judicially separated',
  maritalstatus_radio_hint_5: 'They were legally separated.',
  will_title: 'Will and Codicil',
  will_header: 'About the will',
  will_question_1: 'Did the person who died leave a will?',
  will_question_stop_1: 'Stop content: You will need the original will to complete this application.',
  will_question_2: 'Do you have the original will?',
  will_question_stop_2: 'Stop content: You will need the original will to complete this application.',
  will_question_3: 'What is the date of the will?',
  will_question_hint_3: 'The date the will was made.',
  will_question_4: 'Were there any wills outside of England and Wales?',
  will_question_hint_4: 'Will made in another country apart from England and Wales.',
  will_question_5: 'Are there any codicils?',
  will_question_hint_5: 'Changes or updates to the will.',
  iht_question_1: 'Did you submit an inheritance tax summary online?',
  iht_question_2: 'What is the IHT Identifier',
  iht_question_hint_2: 'The reference number',
  iht_question_3: 'Gross Estate figure (Â£)',
  iht_question_hint_3: 'Whole pounds only',
  iht_question_4: 'Net Estate figure (Â£)',
  iht_question_hint_4: 'Whole pounds only',
  executors_question_1: 'Please list all of the executors named in the Will',
  executors_link_add_executor: 'Add another Executor named on the Will',
  executorsnotapplying_question_listall: 'Please list any executors who are not making this application with you an explain why',
  executorsnotapplying_radio_diedbefore: 'They died before the deceased person',
  executorsnotapplying_radio_diedafter: 'They died after the deceased person',
  executorsnotapplying_radio_reserved: 'Power reserved',
  executorsnotapplying_radio_renunciation: 'Renunciation',
  executorsnotapplying_radio_attorney: 'Power of Attorney',
  executors_title: 'The executors',
  summary_title: 'Summary',
  nextsteps_title: 'Next steps',

  stop_foreign_domicile: 'The person who died was not domiciled in England or Wales. You cannot complete the application online. Contact the Probate Registry for help.',
  stop_no_will: 'The original will is not available. You cannot complete the application online without the original will. Contact the Probate Registry for help.',
  address_title: 'Address',
  nameanddate_title: 'nameanddate',

};	<|endoftext|>


<commit_before>import { DOMUtils, ContenteditableExtension } from 'nylas-exports';

export default class ListManager extends ContenteditableExtension {
  static keyCommandHandlers() {
    return {
      "contenteditable:numbered-list": this._insertNumberedList,
      "contenteditable:bulleted-list": this._insertBulletedList,
    };
  }

  static onContentChanged({editor}) {
    if (this._spaceEntered && this.hasListStartSignature(editor.currentSelection())) {
      this.createList(editor);
    }

    return this._collapseAdjacentLists(editor);
  }

  static onKeyDown({editor, event}) {
    this._spaceEntered = event.key === " ";
    if (DOMUtils.isInList()) {
      if (event.key === "Backspace" && DOMUtils.atStartOfList()) {
        event.preventDefault();
        this.outdentListItem(editor);
      } else if (event.key === "Tab" && editor.currentSelection().isCollapsed) {
        event.preventDefault();
        if (event.shiftKey) {
          this.outdentListItem(editor);
        } else {
          editor.indent();
        }
      } else {
        // Do nothing, let the event through.
        this.originalInput = null;
      }
    } else {
      this.originalInput = null;
    }

    return event;
  }

  static bulletRegex() { return /^[*-]\s/; }

  static numberRegex() { return /^\d\.\s/; }

  static hasListStartSignature(selection) {
    if (!selection || !selection.anchorNode) {
      return false;
    }
    if (!selection.isCollapsed) {
      return false;
    }

    const sibling = selection.anchorNode.previousElementSibling;
    if (!sibling || DOMUtils.looksLikeBlockElement(sibling)) {
      const text = selection.anchorNode.textContent;
      return this.numberRegex().test(text) || this.bulletRegex().test(text);
    }
    return false;
  }

  static createList(editor) {
    const anchorNode = editor.currentSelection().anchorNode;
    const text = anchorNode ? anchorNode.textContent : null;
    if (!text) {
      return;
    }
    if (this.numberRegex().test(text)) {
      this.originalInput = text.slice(0, 3);
      this.insertList(editor, {ordered: true});
      this.removeListStarter(this.numberRegex(), editor.currentSelection());
    } else if (this.bulletRegex().test(text)) {
      this.originalInput = text.slice(0, 2);
      this.insertList(editor, {ordered: false});
      this.removeListStarter(this.bulletRegex(), editor.currentSelection());
    } else {
      return;
    }
    const el = DOMUtils.closest(editor.currentSelection().anchorNode, "li");
    DOMUtils.Mutating.removeEmptyNodes(el);
  }

  static removeListStarter(starterRegex, selection) {
    const el = DOMUtils.closest(selection.anchorNode, "li");
    const textContent = el.textContent.replace(starterRegex, "");

    if (textContent.trim().length === 0) {
      el.innerHTML = "
";
    } else {
      const textNode = DOMUtils.findFirstTextNode(el);
      textNode.textContent = textNode.textContent.replace(starterRegex, "");
    }
  }

  // From a newly-created list
  // Outdent returns to a

 structure
  // I need to turn into
-

  //
  // From a list with content
  // Outent returns to
sometext

  // We need to turn that into
- sometext

  static restoreOriginalInput(editor) {
    const node = editor.currentSelection().anchorNode;
    if (!node) {
      return;
    }

    if (node.nodeType === Node.TEXT_NODE) {
      node.textContent = this.originalInput + node.textContent;
    } else if (node.nodeType === Node.ELEMENT_NODE) {
      const textNode = DOMUtils.findFirstTextNode(node);
      if (!textNode) {
        node.innerHTML = this.originalInput.replace(" ", " ") + node.innerHTML;
      } else {
        textNode.textContent = this.originalInput + textNode.textContent;
      }
    }

    if (this.numberRegex().test(this.originalInput)) {
      DOMUtils.Mutating.moveSelectionToIndexInAnchorNode(editor.currentSelection(), 3); // digit plus dot
    }
    if (this.bulletRegex().test(this.originalInput)) {
      DOMUtils.Mutating.moveSelectionToIndexInAnchorNode(editor.currentSelection(), 2); // dash or star
    }

    this.originalInput = null;
  }

  static insertList(editor, {ordered}) {
    const node = editor.currentSelection().anchorNode;
    if (this.isInsideListItem(node)) {
      editor.indent();
    } else {
      if (ordered === true) {
        editor.insertOrderedList();
      } else {
        editor.insertUnorderedList();
      }
    }
  }

  static _insertNumberedList({editor}) {
    return editor.insertOrderedList();
  }

  static _insertBulletedList({editor}) {
    return editor.insertUnorderedList();
  }

  static outdentListItem(editor) {
    if (this.originalInput) {
      editor.outdent();
      this.restoreOriginalInput(editor);
    }
    editor.outdent();
  }

  static isInsideListItem(node) {
    return DOMUtils.isDescendantOf(node, parent => parent.tagName === 'LI');
  }

  // If users ended up with two
 lists adjacent to each other, we
  // collapse them into one. We leave adjacent
 lists intact in case
  // the user wanted to restart the numbering sequence
  static _collapseAdjacentLists(editor) {
    const els = editor.rootNode.querySelectorAll('ul, ol');

    // This mutates the DOM in place.
    return DOMUtils.Mutating.collapseAdjacentElements(els);
  }
}
<commit_msg>fix(composer): don't create bullets after text insert<commit_after>import { DOMUtils, ContenteditableExtension } from 'nylas-exports';

export default class ListManager extends ContenteditableExtension {
  static keyCommandHandlers() {
    return {
      "contenteditable:numbered-list": this._insertNumberedList,
      "contenteditable:bulleted-list": this._insertBulletedList,
    };
  }

  static onContentChanged({editor}) {
    if (this._spaceEntered && this.hasListStartSignature(editor.currentSelection())) {
      this.createList(editor);
    }

    return this._collapseAdjacentLists(editor);
  }

  static onKeyDown({editor, event}) {
    this._spaceEntered = event.key === " ";
    if (DOMUtils.isInList()) {
      if (event.key === "Backspace" && DOMUtils.atStartOfList()) {
        event.preventDefault();
        this.outdentListItem(editor);
      } else if (event.key === "Tab" && editor.currentSelection().isCollapsed) {
        event.preventDefault();
        if (event.shiftKey) {
          this.outdentListItem(editor);
        } else {
          editor.indent();
        }
      } else {
        // Do nothing, let the event through.
        this.originalInput = null;
      }
    } else {
      this.originalInput = null;
    }

    return event;
  }

  static bulletRegex() { return /^[*-]\s[^\S]*/; }

  static numberRegex() { return /^\d\.\s[^\S]*/; }

  static hasListStartSignature(selection) {
    if (!selection || !selection.anchorNode) {
      return false;
    }
    if (!selection.isCollapsed) {
      return false;
    }

    const sibling = selection.anchorNode.previousElementSibling;
    if (!sibling || DOMUtils.looksLikeBlockElement(sibling)) {
      const text = selection.anchorNode.textContent;
      return this.numberRegex().test(text) || this.bulletRegex().test(text);
    }
    return false;
  }

  static createList(editor) {
    const anchorNode = editor.currentSelection().anchorNode;
    const text = anchorNode ? anchorNode.textContent : null;
    if (!text) {
      return;
    }
    if (this.numberRegex().test(text)) {
      this.originalInput = text.slice(0, 3);
      this.insertList(editor, {ordered: true});
      this.removeListStarter(this.numberRegex(), editor.currentSelection());
    } else if (this.bulletRegex().test(text)) {
      this.originalInput = text.slice(0, 2);
      this.insertList(editor, {ordered: false});
      this.removeListStarter(this.bulletRegex(), editor.currentSelection());
    } else {
      return;
    }
    const el = DOMUtils.closest(editor.currentSelection().anchorNode, "li");
    DOMUtils.Mutating.removeEmptyNodes(el);
  }

  static removeListStarter(starterRegex, selection) {
    const el = DOMUtils.closest(selection.anchorNode, "li");
    const textContent = el.textContent.replace(starterRegex, "");

    if (textContent.trim().length === 0) {
      el.innerHTML = "
";
    } else {
      const textNode = DOMUtils.findFirstTextNode(el);
      textNode.textContent = textNode.textContent.replace(starterRegex, "");
    }
  }

  // From a newly-created list
  // Outdent returns to a

 structure
  // I need to turn into
-

  //
  // From a list with content
  // Outent returns to
sometext

  // We need to turn that into
- sometext

  static restoreOriginalInput(editor) {
    const node = editor.currentSelection().anchorNode;
    if (!node) {
      return;
    }

    if (node.nodeType === Node.TEXT_NODE) {
      node.textContent = this.originalInput + node.textContent;
    } else if (node.nodeType === Node.ELEMENT_NODE) {
      const textNode = DOMUtils.findFirstTextNode(node);
      if (!textNode) {
        node.innerHTML = this.originalInput.replace(" ", " ") + node.innerHTML;
      } else {
        textNode.textContent = this.originalInput + textNode.textContent;
      }
    }

    if (this.numberRegex().test(this.originalInput)) {
      DOMUtils.Mutating.moveSelectionToIndexInAnchorNode(editor.currentSelection(), 3); // digit plus dot
    }
    if (this.bulletRegex().test(this.originalInput)) {
      DOMUtils.Mutating.moveSelectionToIndexInAnchorNode(editor.currentSelection(), 2); // dash or star
    }

    this.originalInput = null;
  }

  static insertList(editor, {ordered}) {
    const node = editor.currentSelection().anchorNode;
    if (this.isInsideListItem(node)) {
      editor.indent();
    } else {
      if (ordered === true) {
        editor.insertOrderedList();
      } else {
        editor.insertUnorderedList();
      }
    }
  }

  static _insertNumberedList({editor}) {
    return editor.insertOrderedList();
  }

  static _insertBulletedList({editor}) {
    return editor.insertUnorderedList();
  }

  static outdentListItem(editor) {
    if (this.originalInput) {
      editor.outdent();
      this.restoreOriginalInput(editor);
    }
    editor.outdent();
  }

  static isInsideListItem(node) {
    return DOMUtils.isDescendantOf(node, parent => parent.tagName === 'LI');
  }

  // If users ended up with two
 lists adjacent to each other, we
  // collapse them into one. We leave adjacent
 lists intact in case
  // the user wanted to restart the numbering sequence
  static _collapseAdjacentLists(editor) {
    const els = editor.rootNode.querySelectorAll('ul, ol');

    // This mutates the DOM in place.
    return DOMUtils.Mutating.collapseAdjacentElements(els);
  }
}
<|endoftext|>


<commit_before>module.exports = {
    port: process.env.PORT || 54321,
    cacheExpiration: 2 * 60 * 60 * 1000, //2h
    globalTickInterval: 2 * 60 * 1000, //2m
    parserTimeout: 20 * 1000, //20s
    restaurants: [
        { id: 0, name: "Jedáleň u Daňováka II", url: "https://www.zomato.com/sk/bratislava/jed%C3%A1le%C5%88-u-da%C5%88ov%C3%A1ka-2-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 1, name: "U Daňováka", url: "https://www.zomato.com/sk/bratislava/re%C5%A1taur%C3%A1cia-u-da%C5%88ov%C3%A1ka-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 2, name: "Giuliano", url: "http://www.giuliano.sk/sk/denne-menu/", module: "giuliano" },
        { id: 3, name: "ITB", url: "http://www.citycantina.sk/index.php?id=1&type=main_menu&t=1", module: "itb" },
        { id: 4, name: "Alfa", url: "http://restauracie.sme.sk/restauracia/restauracia-alfa_2512-petrzalka_664/denne-menu", module: "sme" },
        { id: 5, name: "Škôlka", url: "http://jedalen.vysnivany.sk/ukazka-strany", module: "skolka" },
        { id: 6, name: "Pizza Pazza", url: "http://www.pizzapazza.sk/sk/denne-menu/", module: "pizzapazza" },
        { id: 7, name: "Kamenica - Corleone Pizza", url: "http://restauracie.sme.sk/restauracia/kamenica-corleone-pizza_660-petrzalka_664/denne-menu", module: "sme" },
        { id: 8, name: "Numero Uno", url: "http://www.numerouno.sk/denne-menu-5/", module: "numerouno" },
        { id: 9, name: "Engerau restaurant", url: "https://www.zomato.com/sk/bratislava/engerau-restaurant-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" }
    ],
    themes: {
        "jano": { name: "Jano", template: "../views/index.html" },
        "matus": { name: "Matúš", template: "../views/index3.html" },
        "iveta": { name: "Iveta", template: "../views/index4.html" },
        "telka": { name: "Telka", template: "../views/index5.html" }
    }
};
<commit_msg>updated ITB URL<commit_after>module.exports = {
    port: process.env.PORT || 54321,
    cacheExpiration: 2 * 60 * 60 * 1000, //2h
    globalTickInterval: 2 * 60 * 1000, //2m
    parserTimeout: 20 * 1000, //20s
    restaurants: [
        { id: 0, name: "Jedáleň u Daňováka II", url: "https://www.zomato.com/sk/bratislava/jed%C3%A1le%C5%88-u-da%C5%88ov%C3%A1ka-2-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 1, name: "U Daňováka", url: "https://www.zomato.com/sk/bratislava/re%C5%A1taur%C3%A1cia-u-da%C5%88ov%C3%A1ka-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" },
        { id: 2, name: "Giuliano", url: "http://www.giuliano.sk/sk/denne-menu/", module: "giuliano" },
        { id: 3, name: "ITB", url: "http://www.citycantina.sk/prevadzka/1", module: "itb" },
        { id: 4, name: "Alfa", url: "http://restauracie.sme.sk/restauracia/restauracia-alfa_2512-petrzalka_664/denne-menu", module: "sme" },
        { id: 5, name: "Škôlka", url: "http://jedalen.vysnivany.sk/ukazka-strany", module: "skolka" },
        { id: 6, name: "Pizza Pazza", url: "http://www.pizzapazza.sk/sk/denne-menu/", module: "pizzapazza" },
        { id: 7, name: "Kamenica - Corleone Pizza", url: "http://restauracie.sme.sk/restauracia/kamenica-corleone-pizza_660-petrzalka_664/denne-menu", module: "sme" },
        { id: 8, name: "Numero Uno", url: "http://www.numerouno.sk/denne-menu-5/", module: "numerouno" },
        { id: 9, name: "Engerau restaurant", url: "https://www.zomato.com/sk/bratislava/engerau-restaurant-petr%C5%BEalka-bratislava-v/menu#tabtop", module: "obedovat" }
    ],
    themes: {
        "jano": { name: "Jano", template: "../views/index.html" },
        "matus": { name: "Matúš", template: "../views/index3.html" },
        "iveta": { name: "Iveta", template: "../views/index4.html" },
        "telka": { name: "Telka", template: "../views/index5.html" }
    }
};
<|endoftext|>


<commit_before>/*
  expressive.js wraps express, inserting middleware to track how the server
  response and client request objects change as they travel through the developer's
  middleware.

  TODO: express.static
  TODO: wrap response methods?
  TODO: figure out how to handle multiple app.method calls for the same method.
  currently it will not be tracked when it goes past the first one.
  TODO: reconfigure listen method for all possible sets and configurations of listen
   arguments: (port, [hostname], [backlog], [callback]) or (path, [callback])
*/

const express = require('express');
const app = express();
const getAppMethodArgs = require('./util/getAppMethodArgs.js');
const jsonController = require('./util/jsonController.js');
const serverListeners = require('./util/serverListeners.js');

//wrapper for app.METHOD
//intersperses tracking midware between developer midware
function insertExpressiveMidware(method, ...args) {
  let expressiveMidware = getAppMethodArgs(args);
  return app[method.toLowerCase()](...expressiveMidware);
}

//stores route and method in json object for creation of default config file
//then wraps app.METHOD
function set(method, ...args) {
  const route = args[0];
  jsonController.addRoute(method, route);
  return insertExpressiveMidware(method, ...args);
}

const requestMethods = ['ALL', 'CHECKOUT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LOCK', 'MERGE',
  'MKACTIVITY', 'MKCOL', 'MOVE', 'M-SEARCH', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST',
  'PURGE', 'PUT', 'REPORT', 'SEARCH', 'SUBSCRIBE', 'TRACE', 'UNLOCK', 'UNSUBSCRIBE'];

const expressive = () => {
  const expressiveObj = {

    listen: (...args) => {
      const server = app.listen(...args);
      //set up server listeners!
      Object.keys(serverListeners).forEach(event => {
        server.on(event, serverListeners[event]);
      });
      //sends message to parent process that it may start firing requests!
      process.send('listening');
      return server;
    },

    use: (...args) => insertExpressiveMidware('use', ...args),

    route: (path) => {
      const returnedRoute = app.route(path);
      requestMethods.forEach(method => {
        returnedRoute[method.toLowerCase()] = (...args) => set(method, path, ...args);
      });
      returnedRoute.use = (...args) => insertExpressiveMidware('use', path, ...args);
      return returnedRoute;
    },

    // disable: () => {},
    // disabled: () => {},
    // enable: () => {},
    // enabled: () => {},
    // engine: () => {},
    // param: () => {},
    // path: () => {},
    // render: () => {},
    // set: () => {},
  }

  //assigns app.METHOD for all request methods
  requestMethods.forEach(method => {
    expressiveObj[method.toLowerCase()] = (...args) => set(method, ...args);
  });

  expressive.Router = (...args) => {
    //router instance returned by app.Router()
    const router = express.Router(...args);
    const newRouteFunc = router.route.bind(router);
    router.route = (path) => {
      //route instance returned by router.route()
      const returnedRoute = newRouteFunc(path);
      //assign all app.METHODS to the route instance
      requestMethods.forEach(method => {
        returnedRoute[method.toLowerCase()] = (...args) => set(method, path, ...args);
      });
      returnedRoute.use = (...args) => insertExpressiveMidware('use', path, ...args);
      return returnedRoute;
    };
    //assign all app.METHODS to the router instance
    router.use = (...args) => insertExpressiveMidware('use', ...args);
    requestMethods.forEach(method => {
      router[method.toLowerCase()] = (...args) => set(method, ...args);
    })
    return router;
  };

  //assign all properties and methods of the express app to the expressiveObj that
  //aren't explicitly defined
  Object.keys(app).forEach(key => {
    if (!expressiveObj.hasOwnProperty(key)) expressiveObj[key] = app[key];
  });

  return expressiveObj;
}

module.exports = expressive;
<commit_msg>added expressive.static<commit_after>/*
  expressive.js wraps express, inserting middleware to track how the server
  response and client request objects change as they travel through the developer's
  middleware.

  TODO: express.static
  TODO: wrap response methods?
  TODO: figure out how to handle multiple app.method calls for the same method.
  currently it will not be tracked when it goes past the first one.
  TODO: reconfigure listen method for all possible sets and configurations of listen
   arguments: (port, [hostname], [backlog], [callback]) or (path, [callback])
*/

const express = require('express');
const app = express();
const getAppMethodArgs = require('./util/getAppMethodArgs.js');
const jsonController = require('./util/jsonController.js');
const serverListeners = require('./util/serverListeners.js');

//wrapper for app.METHOD
//intersperses tracking midware between developer midware
function insertExpressiveMidware(method, ...args) {
  let expressiveMidware = getAppMethodArgs(args);
  return app[method.toLowerCase()](...expressiveMidware);
}

//stores route and method in json object for creation of default config file
//then wraps app.METHOD
function set(method, ...args) {
  const route = args[0];
  jsonController.addRoute(method, route);
  return insertExpressiveMidware(method, ...args);
}

const requestMethods = ['ALL', 'CHECKOUT', 'COPY', 'DELETE', 'GET', 'HEAD', 'LOCK', 'MERGE',
  'MKACTIVITY', 'MKCOL', 'MOVE', 'M-SEARCH', 'NOTIFY', 'OPTIONS', 'PATCH', 'POST',
  'PURGE', 'PUT', 'REPORT', 'SEARCH', 'SUBSCRIBE', 'TRACE', 'UNLOCK', 'UNSUBSCRIBE'];

const expressive = () => {
  const expressiveObj = {

    listen: (...args) => {
      const server = app.listen(...args);
      //set up server listeners!
      Object.keys(serverListeners).forEach(event => {
        server.on(event, serverListeners[event]);
      });
      //sends message to parent process that it may start firing requests!
      process.send('listening');
      return server;
    },

    use: (...args) => insertExpressiveMidware('use', ...args),

    route: (path) => {
      const returnedRoute = app.route(path);
      requestMethods.forEach(method => {
        returnedRoute[method.toLowerCase()] = (...args) => set(method, path, ...args);
      });
      returnedRoute.use = (...args) => insertExpressiveMidware('use', path, ...args);
      return returnedRoute;
    },

    // disable: () => {},
    // disabled: () => {},
    // enable: () => {},
    // enabled: () => {},
    // engine: () => {},
    // param: () => {},
    // path: () => {},
    // render: () => {},
    // set: () => {},
  }

  //assigns app.METHOD for all request methods
  requestMethods.forEach(method => {
    expressiveObj[method.toLowerCase()] = (...args) => set(method, ...args);
  });

  expressive.Router = (...args) => {
    //router instance returned by app.Router()
    const router = express.Router(...args);
    const newRouteFunc = router.route.bind(router);
    router.route = (path) => {
      //route instance returned by router.route()
      const returnedRoute = newRouteFunc(path);
      //assign all app.METHODS to the route instance
      requestMethods.forEach(method => {
        returnedRoute[method.toLowerCase()] = (...args) => set(method, path, ...args);
      });
      returnedRoute.use = (...args) => insertExpressiveMidware('use', path, ...args);
      return returnedRoute;
    };
    //assign all app.METHODS to the router instance
    router.use = (...args) => insertExpressiveMidware('use', ...args);
    requestMethods.forEach(method => {
      router[method.toLowerCase()] = (...args) => set(method, ...args);
    })
    return router;
  };

  expressive.static = (...args) => express.static(...args);

  //assign all properties and methods of the express app to the expressiveObj that
  //aren't explicitly defined
  Object.keys(app).forEach(key => {
    if (!expressiveObj.hasOwnProperty(key)) expressiveObj[key] = app[key];
  });

  return expressiveObj;
}

module.exports = expressive;
<|endoftext|>


<commit_before><commit_msg>Add comments explaining the sh script.<commit_after><|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var AvatarLogic = require("../../../Avatar");
import sdk from '../../../index';
import AccessibleButton from '../elements/AccessibleButton';

module.exports = React.createClass({
    displayName: 'BaseAvatar',

    propTypes: {
        name: React.PropTypes.string.isRequired, // The name (first initial used as default)
        idName: React.PropTypes.string, // ID for generating hash colours
        title: React.PropTypes.string, // onHover title text
        url: React.PropTypes.string, // highest priority of them all, shortcut to set in urls[0]
        urls: React.PropTypes.array, // [highest_priority, ... , lowest_priority]
        width: React.PropTypes.number,
        height: React.PropTypes.number,
        resizeMethod: React.PropTypes.string,
        defaultToInitialLetter: React.PropTypes.bool // true to add default url
    },

    getDefaultProps: function() {
        return {
            width: 40,
            height: 40,
            resizeMethod: 'crop',
            defaultToInitialLetter: true
        };
    },

    getInitialState: function() {
        return this._getState(this.props);
    },

    componentWillReceiveProps: function(nextProps) {
        // work out if we need to call setState (if the image URLs array has changed)
        var newState = this._getState(nextProps);
        var newImageUrls = newState.imageUrls;
        var oldImageUrls = this.state.imageUrls;
        if (newImageUrls.length !== oldImageUrls.length) {
            this.setState(newState); // detected a new entry
        }
        else {
            // check each one to see if they are the same
            for (var i = 0; i < newImageUrls.length; i++) {
                if (oldImageUrls[i] !== newImageUrls[i]) {
                    this.setState(newState); // detected a diff
                    break;
                }
            }
        }
    },

    _getState: function(props) {
        // work out the full set of urls to try to load. This is formed like so:
        // imageUrls: [ props.url, props.urls, default image ]

        var urls = props.urls || [];
        if (props.url) {
            urls.unshift(props.url); // put in urls[0]
        }

        var defaultImageUrl = null;
        if (props.defaultToInitialLetter) {
            defaultImageUrl = AvatarLogic.defaultAvatarUrlForString(
                props.idName || props.name
            );
            urls.push(defaultImageUrl); // lowest priority
        }
        return {
            imageUrls: urls,
            defaultImageUrl: defaultImageUrl,
            urlsIndex: 0
        };
    },

    onError: function(ev) {
        var nextIndex = this.state.urlsIndex + 1;
        if (nextIndex < this.state.imageUrls.length) {
            // try the next one
            this.setState({
                urlsIndex: nextIndex
            });
        }
    },

    /**
     * returns the first (non-sigil) character of 'name',
     * converted to uppercase
     */
    _getInitialLetter: function(name) {
        if (name.length < 1) {
            return undefined;
        }

        var idx = 0;
        var initial = name[0];
        if ((initial === '@' || initial === '#') && name[1]) {
            idx++;
        }

        // string.codePointAt(0) would do this, but that isn't supported by
        // some browsers (notably PhantomJS).
        var chars = 1;
        var first = name.charCodeAt(idx);

        // check if it’s the start of a surrogate pair
        if (first >= 0xD800 && first <= 0xDBFF && name[idx+1]) {
            var second = name.charCodeAt(idx+1);
            if (second >= 0xDC00 && second <= 0xDFFF) {
                chars++;
            }
        }

        var firstChar = name.substring(idx, idx+chars);
        return firstChar.toUpperCase();
    },

    render: function() {
        const EmojiText = sdk.getComponent('elements.EmojiText');
        var imageUrl = this.state.imageUrls[this.state.urlsIndex];

        const {
            name, idName, title, url, urls, width, height, resizeMethod,
            defaultToInitialLetter, onClick,
            ...otherProps
        } = this.props;

        if (imageUrl === this.state.defaultImageUrl) {
            const initialLetter = this._getInitialLetter(name);
            return (

                    <EmojiText className="mx_BaseAvatar_initial" aria-hidden="true"
                            style={{ fontSize: (width * 0.65) + "px",
                                    width: width + "px",
                                    lineHeight: height + "px" }}>{initialLetter}</EmojiText>

            );
        }
        if (onClick != null) {
            return (
                <AccessibleButton className="mx_BaseAvatar mx_BaseAvatar_image"
                    element='img'
                    src={imageUrl}
                    onClick={onClick}
                    onError={this.onError}
                    width={width} height={height}
                    title={title} alt=""
                    {...otherProps} />
            );
        } else {
            return (

            );
        }
    }
});
<commit_msg>Make default avatars clickable<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

'use strict';

var React = require('react');
var AvatarLogic = require("../../../Avatar");
import sdk from '../../../index';
import AccessibleButton from '../elements/AccessibleButton';

module.exports = React.createClass({
    displayName: 'BaseAvatar',

    propTypes: {
        name: React.PropTypes.string.isRequired, // The name (first initial used as default)
        idName: React.PropTypes.string, // ID for generating hash colours
        title: React.PropTypes.string, // onHover title text
        url: React.PropTypes.string, // highest priority of them all, shortcut to set in urls[0]
        urls: React.PropTypes.array, // [highest_priority, ... , lowest_priority]
        width: React.PropTypes.number,
        height: React.PropTypes.number,
        resizeMethod: React.PropTypes.string,
        defaultToInitialLetter: React.PropTypes.bool // true to add default url
    },

    getDefaultProps: function() {
        return {
            width: 40,
            height: 40,
            resizeMethod: 'crop',
            defaultToInitialLetter: true
        };
    },

    getInitialState: function() {
        return this._getState(this.props);
    },

    componentWillReceiveProps: function(nextProps) {
        // work out if we need to call setState (if the image URLs array has changed)
        var newState = this._getState(nextProps);
        var newImageUrls = newState.imageUrls;
        var oldImageUrls = this.state.imageUrls;
        if (newImageUrls.length !== oldImageUrls.length) {
            this.setState(newState); // detected a new entry
        }
        else {
            // check each one to see if they are the same
            for (var i = 0; i < newImageUrls.length; i++) {
                if (oldImageUrls[i] !== newImageUrls[i]) {
                    this.setState(newState); // detected a diff
                    break;
                }
            }
        }
    },

    _getState: function(props) {
        // work out the full set of urls to try to load. This is formed like so:
        // imageUrls: [ props.url, props.urls, default image ]

        var urls = props.urls || [];
        if (props.url) {
            urls.unshift(props.url); // put in urls[0]
        }

        var defaultImageUrl = null;
        if (props.defaultToInitialLetter) {
            defaultImageUrl = AvatarLogic.defaultAvatarUrlForString(
                props.idName || props.name
            );
            urls.push(defaultImageUrl); // lowest priority
        }
        return {
            imageUrls: urls,
            defaultImageUrl: defaultImageUrl,
            urlsIndex: 0
        };
    },

    onError: function(ev) {
        var nextIndex = this.state.urlsIndex + 1;
        if (nextIndex < this.state.imageUrls.length) {
            // try the next one
            this.setState({
                urlsIndex: nextIndex
            });
        }
    },

    /**
     * returns the first (non-sigil) character of 'name',
     * converted to uppercase
     */
    _getInitialLetter: function(name) {
        if (name.length < 1) {
            return undefined;
        }

        var idx = 0;
        var initial = name[0];
        if ((initial === '@' || initial === '#') && name[1]) {
            idx++;
        }

        // string.codePointAt(0) would do this, but that isn't supported by
        // some browsers (notably PhantomJS).
        var chars = 1;
        var first = name.charCodeAt(idx);

        // check if it’s the start of a surrogate pair
        if (first >= 0xD800 && first <= 0xDBFF && name[idx+1]) {
            var second = name.charCodeAt(idx+1);
            if (second >= 0xDC00 && second <= 0xDFFF) {
                chars++;
            }
        }

        var firstChar = name.substring(idx, idx+chars);
        return firstChar.toUpperCase();
    },

    render: function() {
        const EmojiText = sdk.getComponent('elements.EmojiText');
        var imageUrl = this.state.imageUrls[this.state.urlsIndex];

        const {
            name, idName, title, url, urls, width, height, resizeMethod,
            defaultToInitialLetter, onClick,
            ...otherProps
        } = this.props;

        if (imageUrl === this.state.defaultImageUrl) {
            const initialLetter = this._getInitialLetter(name);
            if (onClick != null) {
                return (
                    <AccessibleButton element='span' className="mx_BaseAvatar"
                        onClick={onClick} {...otherProps}
                    >
                        <EmojiText className="mx_BaseAvatar_initial" aria-hidden="true"
                                style={{ fontSize: (width * 0.65) + "px",
                                        width: width + "px",
                                        lineHeight: height + "px" }}>{initialLetter}</EmojiText>

                    </AccessibleButton>
                );
            } else {
                return (

                        <EmojiText className="mx_BaseAvatar_initial" aria-hidden="true"
                                style={{ fontSize: (width * 0.65) + "px",
                                        width: width + "px",
                                        lineHeight: height + "px" }}>{initialLetter}</EmojiText>

                );
            }
        }
        if (onClick != null) {
            return (
                <AccessibleButton className="mx_BaseAvatar mx_BaseAvatar_image"
                    element='img'
                    src={imageUrl}
                    onClick={onClick}
                    onError={this.onError}
                    width={width} height={height}
                    title={title} alt=""
                    {...otherProps} />
            );
        } else {
            return (

            );
        }
    }
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Button, Icon, Label, Tab, Menu } from 'semantic-ui-react';
import { TrendGraph } from './TrendGraph';
import { Sources } from './Sources';
import { SourceEntities } from './SourceEntities';
import { MetricParameters } from './MetricParameters';
import { FocusableTab } from './FocusableTab';

class MeasurementDetails extends Component {
  delete_metric(event) {
    event.preventDefault();
    const self = this;
    fetch(`${window.server_url}/report/${this.props.report.report_uuid}/metric/${this.props.metric_uuid}`, {
      method: 'delete',
      mode: 'cors',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({})
    }).then(
      () => self.props.reload()
    );
  }
  render() {
    const props = this.props;
    const metric = props.report.subjects[props.subject_uuid].metrics[props.metric_uuid];
    const panes = [];
    if (props.measurement) {
      props.measurement.sources.forEach((source) => {
        const report_source = metric.sources[source.source_uuid];
        if (!report_source) { return }  // source was deleted, continue
        const nr_entities = (source.entities && source.entities.length) || 0;
        if (nr_entities === 0) { return } // no entities to show, continue
        const source_type = report_source.type;
        const source_name = report_source.name || props.datamodel.sources[source_type].name;
        panes.push({
          menuItem: <Menu.Item key={source.source_uuid}><FocusableTab>{source_name}</FocusableTab></Menu.Item>,
          render: () => <Tab.Pane>
            <SourceEntities
              datamodel={props.datamodel}
              metric={metric}
              metric_uuid={props.metric_uuid}
              readOnly={props.readOnly}
              report_uuid={props.report_uuid}
              set_entity_attribute={props.set_entity_attribute}
              source={source}
            />
          </Tab.Pane>
        });
      });
    }
    if (props.measurements.length > 0) {
      const unit_name = props.unit.charAt(0).toUpperCase() + props.unit.slice(1);
      panes.push(
        {
          menuItem: <Menu.Item key='trend'><FocusableTab>{'Trend'}</FocusableTab></Menu.Item>,
          render: () => <Tab.Pane>
            <TrendGraph measurements={props.measurements} unit={unit_name} title={this.props.metric_name} />
          </Tab.Pane>
        }
      );
    }
    panes.push(
      {
        menuItem: <Menu.Item key='metric'><FocusableTab>{'Metric'}</FocusableTab></Menu.Item>,
        render: () => <Tab.Pane>
          <MetricParameters datamodel={props.datamodel} metric={metric}
            readOnly={props.readOnly} set_metric_attribute={props.set_metric_attribute} />
        </Tab.Pane>
      }
    );
    panes.push(
      {
        menuItem: <Menu.Item key='sources'><FocusableTab>{'Sources'}</FocusableTab></Menu.Item>,
        render: () => <Tab.Pane>
          <Sources
            datamodel={props.datamodel}
            measurement={props.measurement}
            metric_type={metric.type}
            metric_uuid={props.metric_uuid}
            readOnly={props.readOnly}
            reload={props.reload}
            report={props.report}
            sources={metric.sources}
          />
        </Tab.Pane>
      }
    );
    return (
      <>
        <Tab panes={panes} />
        {!props.readOnly &&
          <Button icon style={{ marginTop: "10px" }} floated='right' negative basic primary
            onClick={(e) => this.delete_metric(e)}>
            <Icon name='trash' /> Delete metric
          </Button>
        }
      </>
    )
  }
}

export { MeasurementDetails };
<commit_msg>Remove unused import.<commit_after>import React, { Component } from 'react';
import { Button, Icon, Tab, Menu } from 'semantic-ui-react';
import { TrendGraph } from './TrendGraph';
import { Sources } from './Sources';
import { SourceEntities } from './SourceEntities';
import { MetricParameters } from './MetricParameters';
import { FocusableTab } from './FocusableTab';

class MeasurementDetails extends Component {
  delete_metric(event) {
    event.preventDefault();
    const self = this;
    fetch(`${window.server_url}/report/${this.props.report.report_uuid}/metric/${this.props.metric_uuid}`, {
      method: 'delete',
      mode: 'cors',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({})
    }).then(
      () => self.props.reload()
    );
  }
  render() {
    const props = this.props;
    const metric = props.report.subjects[props.subject_uuid].metrics[props.metric_uuid];
    const panes = [];
    if (props.measurement) {
      props.measurement.sources.forEach((source) => {
        const report_source = metric.sources[source.source_uuid];
        if (!report_source) { return }  // source was deleted, continue
        const nr_entities = (source.entities && source.entities.length) || 0;
        if (nr_entities === 0) { return } // no entities to show, continue
        const source_type = report_source.type;
        const source_name = report_source.name || props.datamodel.sources[source_type].name;
        panes.push({
          menuItem: <Menu.Item key={source.source_uuid}><FocusableTab>{source_name}</FocusableTab></Menu.Item>,
          render: () => <Tab.Pane>
            <SourceEntities
              datamodel={props.datamodel}
              metric={metric}
              metric_uuid={props.metric_uuid}
              readOnly={props.readOnly}
              report_uuid={props.report_uuid}
              set_entity_attribute={props.set_entity_attribute}
              source={source}
            />
          </Tab.Pane>
        });
      });
    }
    if (props.measurements.length > 0) {
      const unit_name = props.unit.charAt(0).toUpperCase() + props.unit.slice(1);
      panes.push(
        {
          menuItem: <Menu.Item key='trend'><FocusableTab>{'Trend'}</FocusableTab></Menu.Item>,
          render: () => <Tab.Pane>
            <TrendGraph measurements={props.measurements} unit={unit_name} title={this.props.metric_name} />
          </Tab.Pane>
        }
      );
    }
    panes.push(
      {
        menuItem: <Menu.Item key='metric'><FocusableTab>{'Metric'}</FocusableTab></Menu.Item>,
        render: () => <Tab.Pane>
          <MetricParameters datamodel={props.datamodel} metric={metric}
            readOnly={props.readOnly} set_metric_attribute={props.set_metric_attribute} />
        </Tab.Pane>
      }
    );
    panes.push(
      {
        menuItem: <Menu.Item key='sources'><FocusableTab>{'Sources'}</FocusableTab></Menu.Item>,
        render: () => <Tab.Pane>
          <Sources
            datamodel={props.datamodel}
            measurement={props.measurement}
            metric_type={metric.type}
            metric_uuid={props.metric_uuid}
            readOnly={props.readOnly}
            reload={props.reload}
            report={props.report}
            sources={metric.sources}
          />
        </Tab.Pane>
      }
    );
    return (
      <>
        <Tab panes={panes} />
        {!props.readOnly &&
          <Button icon style={{ marginTop: "10px" }} floated='right' negative basic primary
            onClick={(e) => this.delete_metric(e)}>
            <Icon name='trash' /> Delete metric
          </Button>
        }
      </>
    )
  }
}

export { MeasurementDetails };
<|endoftext|>


<commit_before>import ons from 'onsenui';
import {Router} from 'aurelia-router';
import {inject, bindable} from 'aurelia-framework';
import {Database} from '../services/db';
import {Search} from '../services/search';
import {Storage} from '../services/storage';
import {Building} from '../models/building';
import {RoomType} from '../models/room-type';
import {System} from '../models/system';
import {Organisation} from '../models/organisation';

@inject(Router, Database, Storage, Search)
export class Home {
  @bindable selection;
  @bindable currentResults;
  categories;
  results;
  isFiltered;

  constructor(router, db, storage, search) {
    this.router = router;
    this.db = db;
    this.storage = storage;
    this.search = search;
  }

  attached() {
    if (ons.platform.isAndroid()) {
      this._map.classList.add('map--material');
    }
    this.map = L.map(this._map, {
      attributionControl: false
    });

    this.basemap = L.gridLayer.googleMutant({
      type: 'roadmap', // valid values are 'roadmap', 'satellite', 'terrain' and 'hybrid'
      styles: [{
        featureType: "poi",
        elementType: "labels.icon",
        stylers: [{ visibility: "off" }]
      }]
    }).addTo(this.map);

    this.buildingsLayer = L.markerClusterGroup({
      maxClusterRadius: function(zoom) {
        if (zoom < 13) {
          return 80;
        } else if (zoom < 15) {
          return 50;
        } else if (zoom < 17) {
          return 30;
        } else {
          return 20;
        }
      },
      iconCreateFunction: function(cluster) {
    		var childCount = cluster.getChildCount();

    		var c = ' marker-cluster-';
        var size = 22;
    		if (childCount < 10) {
    			c += 'small';
    		} else if (childCount < 100) {
    			c += 'medium';
          size = 26;
    		} else {
    			c += 'large';
          size = 30;
    		}

    		return new L.DivIcon({
          html: '<div>' + childCount + '</div>',
          className: 'marker-cluster' + c,
          iconSize: size
        });
    	}
    }).addTo(this.map);

    this.markers = L.featureGroup().addTo(this.map);

    this.locateControl = L.control.locate({
      showPopup: false,
      locateControl: {}
    }).addTo(this.map);
    this.locateControl._start = this.locateControl.start.bind(this.locateControl);
    this.locateControl._stop = this.locateControl.stop.bind(this.locateControl);
    this.locateControl._setView = this.locateControl.setView.bind(this.locateControl);
    this.locateControl.stop = this.onLocateControlStop.bind(this);
    this.locateControl.start = this.onLocateControlStart.bind(this);
    this.locateControl.setView = this.onLocateControlSetView.bind(this);

    let mapbounds = this.storage.getItem('mapbounds');
    if (mapbounds) {
      this.map.fitBounds(mapbounds);
    } else {
      this.map.setView([46.801111, 8.226667], 7);
    }

    if (this.storage.getItem('geolocation')) {
      this.locateControl.start();
    }

    this.map.on('moveend', this.updateMapView, this);
    this.markers.on('click', this.onMarkerClick, this);
    this.buildingsLayer.on('click', this.onBuildingClick, this);
    this.buildingsLayer.on('dblclick', this.onBuildingDoubleClick, this);

    this.buildings = this.db.query(System).groupByRelation(Building).all();
    this.categories = this.db.query(RoomType).all();
    this.search.sort(this.map.getCenter());
  }

  onBuildingClick(e) {
    if (this.selection === e.layer.data && this.selection.systems.length === 1) {
      this.showInfo(this.selection.systems[0]);
    } else {
      this.selection = e.layer.data;
    }
  }

  onBuildingDoubleClick(e) {
    this.selection = e.layer.data;
    if (this.selection.systems.length === 1) {
      this.showInfo(this.selection.systems[0]);
    }
  }

  onMarkerClick(e) {
    if (this.selection && this.selection.systems.length === 1) {
      this.showInfo(this.selection.systems[0]);
    }
  }

  deselect() {
    this.selection = null;
  }

  selectionChanged(newValue, oldValue) {
    this.markers.clearLayers();
    if (newValue) {
      let marker = L.marker([newValue.lat, newValue.lng]);
      this.markers.addLayer(marker);
      this._selectionList.scrollTop = 0;
      setTimeout(() => {
        this.map.invalidateSize({
          pan: false
        });
        if (!this.map.getBounds().contains(marker.getLatLng())) {
          this.locateControl._onDrag();
          this.map.setView(marker.getLatLng(), this.map.getZoom());
          marker._bringToFront();
        }
      }, 50);
    } else {
      setTimeout(() => {
        this.map.invalidateSize({
          pan: false
        });
      }, 50);
    }
  }

  set buildings(value) {
    this.buildingsLayer.clearLayers();
    value.forEach(building => {
      let markerIcon;
      let buildingIcon = building.icon;
      if (buildingIcon) {
        markerIcon = L.divIcon({
          className: `leaflet-system-icon`,
          iconSize: 28,
          html: `<div style="background-color:${buildingIcon.color}"><span class="ons-icon ${buildingIcon.prefix} ${buildingIcon.prefix}-${buildingIcon.name}"></span></div>`
        });
      } else {
        markerIcon = L.divIcon({
          className: 'leaflet-system-icon',
          iconSize: 28,
          html: `<div>${building.systems.length}</div>`
        })
      }
      let marker = L.marker([building.lat, building.lng], {icon: markerIcon});
      marker.data = building;
      this.buildingsLayer.addLayer(marker);
    });
  }

  get buildings() {
    return this.buildingsLayer.getLayers().map(layer => layer.data);
  }

  updateMapView(evt) {
    let bounds = evt.target.getBounds();
    this.storage.setItem('mapbounds', [
      [bounds.getSouth(), bounds.getWest()],
      [bounds.getNorth(), bounds.getEast()]
    ]);
  }

  onLocateControlStart() {
    this.storage.setItem('geolocation', true);
    this.locateControl.isLocatingStart = true;
    this.locateControl._start();
  }

  onLocateControlStop() {
    this.storage.setItem('geolocation', false);
    this.locateControl._stop();
  }

  onLocateControlSetView() {
    if (this.locateControl.isLocatingStart) {
      this.locateControl.isLocatingStart = false;
      this.locateControl.options.keepCurrentZoomLevel = false;
      this.locateControl.options.locateOptions.maxZoom = this.map.getZoom() < 15 ? 15 : this.map.getZoom();
      this.locateControl._setView();
      this.locateControl.options.keepCurrentZoomLevel = true;
      this.locateControl.options.locateOptions.maxZoom = Infinity;
    } else {
      this.locateControl._setView();
    }
  }

  showMenu() {
    let menu = document.getElementById('menu');
    menu.open();
  }

  showSearch() {
    let center = this.map.getCenter();
    this.searchExec = false;
    this._search.show();
    this._searchinput.focus();
    this.search.sort(this.map.getCenter());
    this.currentSearchText = this.search.text;
    this.currentResults = this.search.results;
  }

  cancelSearch() {
    this._search.hide();
  }

  clearSearch() {
    this.search.reset();
    this.searchText = this.currentSearchText = this.search.text;
    this.buildings = this.db.query(System).groupByRelation(Building).all();
    this.selection = null;
  }

  showList() {
    this.router.navigateToRoute('list');
  }

  showInfo(system) {
    this.router.navigateToRoute('system', {id: system.id});
  }

  searchCategory(item) {
    this._search.hide().then(() => {
      let systems = this.db.query(System).filterBy('typID', item.id);
      this.search.isFiltered = true;
      this.search.text = item.typ;
      this.searchText = this.currentSearchText = this.search.text;
      this.buildings = systems.groupByRelation(Building).all();
      this.selection = null;
      this.zoomToNearest();

      let center = this.map.getCenter();
      this.search.filter(systems.all());
      this.search.sort(this.map.getCenter());
    });
  }

  zoomToNearest() {
    let center = this.map.getCenter();
    let closest = L.GeometryUtil.closestLayer(this.map, this.buildingsLayer.getLayers(), center);
    if (!this.map.getBounds().contains(closest.layer.getLatLng())) {
      let bounds = L.latLngBounds(closest.layer.getLatLng(), center);
      this.locateControl._onDrag();
      this.map.fitBounds(bounds, {
        maxZoom: this.map.getZoom(),
        padding: [40, 40]
      });
    }
  }

  clearCurrentSearch() {
    this.currentSearchText = '';
    this.currentResults = {
      systems: [],
      locations: []
    };
    this._searchinput.focus();
  }

  onResultClick(system) {
    this._search.hide().then(() => {
      let query = this.db.query(System).groupByRelation(Building);
      if (!this.search.isFiltered) {
        this.buildings = query.all();
      }
      this.search.text = this.currentSearchText;
      this.search.results = this.currentResults;
      this.searchText = this.search.text ;
      this.results = this.currentResults;
      this.selection = null;
      this.map.once('moveend', () => {
        this.selection = query.getById(system.building.id);
      });
      this.locateControl._onDrag();
      this.map.setView([system.building.lat, system.building.lng], 17);
    });
  }

  onLocationResultClick(location) {
    this._search.hide().then(() => {
      this.buildings = this.db.query(System).groupByRelation(Building).all();
      this.search.text = this.currentSearchText;
      this.search.results = this.currentResults;
      this.searchText = this.currentSearchText;
      this.results = this.currentResults;
      this.selection = null;
      this.locateControl._onDrag();
      this.map.fitBounds(location.bounds);
    });
  }

  onSearch() {
    this.onSearchInput();
  }

  onSearchInput() {
    let value = this._searchinput.value;
    if (this.searchTimeout) {
      clearTimeout(this.searchTimeout);
    }
    this.searchTimeout = setTimeout(() => {
      if (this.search.isFiltered) {
        this.search.isFiltered = false;
        this.search.reset();
        this.search.sort(this.map.getCenter());
      }
      this.currentResults = this.search.execute(value);
      this.searchExec = true;
    }, 500);
  }
}
<commit_msg>refactor map initialization<commit_after>import ons from 'onsenui';
import {Router} from 'aurelia-router';
import {inject, bindable} from 'aurelia-framework';
import {Database} from '../services/db';
import {Search} from '../services/search';
import {Storage} from '../services/storage';
import {Building} from '../models/building';
import {RoomType} from '../models/room-type';
import {System} from '../models/system';
import {Organisation} from '../models/organisation';

@inject(Router, Database, Storage, Search)
export class Home {
  @bindable selection;
  @bindable currentResults;
  categories;
  results;
  isFiltered;

  constructor(router, db, storage, search) {
    this.router = router;
    this.db = db;
    this.storage = storage;
    this.search = search;

    // init basemaps
    this.basemaps = new Map();
    this.basemaps.set('roadmap', L.gridLayer.googleMutant({
      type: 'roadmap', // valid values are 'roadmap', 'satellite', 'terrain' and 'hybrid'
      styles: [{
        featureType: "poi",
        elementType: "labels.icon",
        stylers: [{ visibility: "off" }]
      }]
    }));

    // init map overlays
    this.overlays = new Map();
    this.overlays.set('buildings', L.markerClusterGroup({
      maxClusterRadius: this.getMaxClusterRadius,
      iconCreateFunction: this.createClusterIcon
    }));
    this.overlays.set('marker', L.marker());

    // init map controls
    this.controls = new Map();

    let locateControl = L.control.locate({
      showPopup: false,
      locateControl: {}
    });

    // locate control tweaks to intercept geolocation start and stop
    locateControl._start = locateControl.start.bind(locateControl);
    locateControl._stop = locateControl.stop.bind(locateControl);
    locateControl._setView = locateControl.setView.bind(locateControl);
    locateControl.stop = this.onLocateControlStop.bind(this);
    locateControl.start = this.onLocateControlStart.bind(this);
    locateControl.setView = this.onLocateControlSetView.bind(this);

    this.controls.set('locate', locateControl);
  }

  attached() {
    let basemapLayer = this.basemaps.get('roadmap');
    let buildingsLayer = this.overlays.get('buildings');
    let markerLayer = this.overlays.get('marker');
    let locateControl = this.controls.get('locate');
    let mapbounds = this.storage.getItem('mapbounds');
    let geolocation = this.storage.getItem('geolocation');

    if (ons.platform.isAndroid()) {
      this._map.classList.add('map--material');
    }
    this.map = L.map(this._map, {
      attributionControl: false
    });

    this.map.addLayer(basemapLayer);
    this.map.addLayer(buildingsLayer);
    this.map.addControl(locateControl);

    if (mapbounds) {
      this.map.fitBounds(mapbounds);
    } else {
      this.map.setView([46.801111, 8.226667], 7);
    }

    if (geolocation) {
      locateControl.start();
    }

    this.map.on('moveend', this.updateMapView, this);
    markerLayer.on('click', this.onMarkerClick, this);
    buildingsLayer.on('click', this.onBuildingClick, this);
    buildingsLayer.on('dblclick', this.onBuildingDoubleClick, this);

    this.buildings = this.db.query(System).groupByRelation(Building).all();
    this.categories = this.db.query(RoomType).all();
    this.search.sort(this.map.getCenter());
  }

  onBuildingClick(e) {
    if (this.selection === e.layer.data && this.selection.systems.length === 1) {
      this.showInfo(this.selection.systems[0]);
    } else {
      this.selection = e.layer.data;
    }
  }

  onBuildingDoubleClick(e) {
    this.selection = e.layer.data;
    if (this.selection.systems.length === 1) {
      this.showInfo(this.selection.systems[0]);
    }
  }

  onMarkerClick(e) {
    if (this.selection && this.selection.systems.length === 1) {
      this.showInfo(this.selection.systems[0]);
    }
  }

  deselect() {
    this.selection = null;
  }

  selectionChanged(newValue, oldValue) {
    let marker = this.overlays.get('marker');
    let locateControl = this.controls.get('locate');
    if (oldValue) {
      this.map.removeLayer(marker);
    }
    if (newValue) {
      marker.setLatLng([newValue.lat, newValue.lng]);
      this.map.addLayer(marker);
      this._selectionList.scrollTop = 0;
      setTimeout(() => {
        this.map.invalidateSize({
          pan: false
        });
        if (!this.map.getBounds().contains(marker.getLatLng())) {
          locateControl._onDrag();
          this.map.setView(marker.getLatLng(), this.map.getZoom());
          marker._bringToFront();
        }
      }, 50);
    } else {
      setTimeout(() => {
        this.map.invalidateSize({
          pan: false
        });
      }, 50);
    }
  }

  set buildings(value) {
    let layer = this.overlays.get('buildings');
    layer.clearLayers();
    value.forEach(building => {
      let markerIcon;
      let buildingIcon = building.icon;
      if (buildingIcon) {
        markerIcon = L.divIcon({
          className: `leaflet-system-icon`,
          iconSize: 28,
          html: `<div style="background-color:${buildingIcon.color}"><span class="ons-icon ${buildingIcon.prefix} ${buildingIcon.prefix}-${buildingIcon.name}"></span></div>`
        });
      } else {
        markerIcon = L.divIcon({
          className: 'leaflet-system-icon',
          iconSize: 28,
          html: `<div>${building.systems.length}</div>`
        })
      }
      let marker = L.marker([building.lat, building.lng], {icon: markerIcon});
      marker.data = building;
      layer.addLayer(marker);
    });
  }

  get buildings() {
    let layer = this.overlays.get('buildings');
    return layer.getLayers().map(layer => layer.data);
  }

  updateMapView(evt) {
    let bounds = evt.target.getBounds();
    this.storage.setItem('mapbounds', [
      [bounds.getSouth(), bounds.getWest()],
      [bounds.getNorth(), bounds.getEast()]
    ]);
  }

  onLocateControlStart() {
    let locateControl = this.controls.get('locate');
    this.storage.setItem('geolocation', true);
    locateControl.isLocatingStart = true;
    locateControl._start();
  }

  onLocateControlStop() {
    let locateControl = this.controls.get('locate');
    this.storage.setItem('geolocation', false);
    locateControl._stop();
  }

  onLocateControlSetView() {
    let locateControl = this.controls.get('locate');
    if (locateControl.isLocatingStart) {
      locateControl.isLocatingStart = false;
      locateControl.options.keepCurrentZoomLevel = false;
      locateControl.options.locateOptions.maxZoom = this.map.getZoom() < 15 ? 15 : this.map.getZoom();
      locateControl._setView();
      locateControl.options.keepCurrentZoomLevel = true;
      locateControl.options.locateOptions.maxZoom = Infinity;
    } else {
      locateControl._setView();
    }
  }

  showMenu() {
    let menu = document.getElementById('menu');
    menu.open();
  }

  showSearch() {
    let center = this.map.getCenter();
    this.searchExec = false;
    this._search.show();
    this._searchinput.focus();
    this.search.sort(this.map.getCenter());
    this.currentSearchText = this.search.text;
    this.currentResults = this.search.results;
  }

  cancelSearch() {
    this._search.hide();
  }

  clearSearch() {
    this.search.reset();
    this.searchText = this.currentSearchText = this.search.text;
    this.buildings = this.db.query(System).groupByRelation(Building).all();
    this.selection = null;
  }

  showList() {
    this.router.navigateToRoute('list');
  }

  showInfo(system) {
    this.router.navigateToRoute('system', {id: system.id});
  }

  searchCategory(item) {
    this._search.hide().then(() => {
      let systems = this.db.query(System).filterBy('typID', item.id);
      this.search.isFiltered = true;
      this.search.text = item.typ;
      this.searchText = this.currentSearchText = this.search.text;
      this.buildings = systems.groupByRelation(Building).all();
      this.selection = null;
      this.zoomToNearest();

      let center = this.map.getCenter();
      this.search.filter(systems.all());
      this.search.sort(this.map.getCenter());
    });
  }

  zoomToNearest() {
    let center = this.map.getCenter();
    let layer = this.overlays.get('buildings');
    let locateControl = this.controls.get('locate');
    let closest = L.GeometryUtil.closestLayer(this.map, layer.getLayers(), center);
    if (!this.map.getBounds().contains(closest.layer.getLatLng())) {
      let bounds = L.latLngBounds(closest.layer.getLatLng(), center);
      locateControl._onDrag();
      this.map.fitBounds(bounds, {
        maxZoom: this.map.getZoom(),
        padding: [40, 40]
      });
    }
  }

  clearCurrentSearch() {
    this.currentSearchText = '';
    this.currentResults = {
      systems: [],
      locations: []
    };
    this._searchinput.focus();
  }

  onResultClick(system) {
    this._search.hide().then(() => {
      let query = this.db.query(System).groupByRelation(Building);
      if (!this.search.isFiltered) {
        this.buildings = query.all();
      }
      this.search.text = this.currentSearchText;
      this.search.results = this.currentResults;
      this.searchText = this.search.text ;
      this.results = this.currentResults;
      this.selection = null;
      this.map.once('moveend', () => {
        this.selection = query.getById(system.building.id);
      });
      this.locateControl._onDrag();
      this.map.setView([system.building.lat, system.building.lng], 17);
    });
  }

  onLocationResultClick(location) {
    this._search.hide().then(() => {
      this.buildings = this.db.query(System).groupByRelation(Building).all();
      this.search.text = this.currentSearchText;
      this.search.results = this.currentResults;
      this.searchText = this.currentSearchText;
      this.results = this.currentResults;
      this.selection = null;
      this.locateControl._onDrag();
      this.map.fitBounds(location.bounds);
    });
  }

  onSearch() {
    this.onSearchInput();
  }

  onSearchInput() {
    let value = this._searchinput.value;
    if (this.searchTimeout) {
      clearTimeout(this.searchTimeout);
    }
    this.searchTimeout = setTimeout(() => {
      if (this.search.isFiltered) {
        this.search.isFiltered = false;
        this.search.reset();
        this.search.sort(this.map.getCenter());
      }
      this.currentResults = this.search.execute(value);
      this.searchExec = true;
    }, 500);
  }

  createClusterIcon(cluster) {
    var childCount = cluster.getChildCount();

    var c = ' marker-cluster-';
    var size = 22;
    if (childCount < 10) {
      c += 'small';
    } else if (childCount < 100) {
      c += 'medium';
      size = 26;
    } else {
      c += 'large';
      size = 30;
    }

    return new L.DivIcon({
      html: '<div>' + childCount + '</div>',
      className: 'marker-cluster' + c,
      iconSize: size
    });
  }

  getMaxClusterRadius(zoom) {
    if (zoom < 13) {
      return 80;
    } else if (zoom < 15) {
      return 50;
    } else if (zoom < 17) {
      return 30;
    } else {
      return 20;
    }
  }
}
<|endoftext|>


<commit_before>/*global module:false*/
module.exports = function(grunt) {
    grunt.initConfig({
        watch: {
            reload: {
                files: ['src/*', 'src/js/*.js', 'src/css/*.css', 'grunt.js'],
                tasks: 'tinylr-reload'
            }
        }
    });

    grunt.registerTask('default', 'tinylr-start serve watch');
    grunt.registerTask('serve', 'Start server', function() {
        grunt.log.writeln('Surf to :8080/dev.html now!');
        require('./serve').listen(8080);
    });

    ['tiny-lr'].forEach(grunt.loadNpmTasks);
};
<commit_msg>Make utils to be watched<commit_after>/*global module:false*/
module.exports = function(grunt) {
    grunt.initConfig({
        watch: {
            reload: {
                files: ['src/*', 'src/js/*.js', 'src/js/utils/*.js', 'src/css/*.css', 'grunt.js'],
                tasks: 'tinylr-reload'
            }
        }
    });

    grunt.registerTask('default', 'tinylr-start serve watch');
    grunt.registerTask('serve', 'Start server', function() {
        grunt.log.writeln('Surf to :8080/dev.html now!');
        require('./serve').listen(8080);
    });

    ['tiny-lr'].forEach(grunt.loadNpmTasks);
};
<|endoftext|>