<commit_before>
var ref = require('ref');
var q = require('q');
var async = require('async');
var driver_const = require('ljswitchboard-ljm_driver_constants');
var data_parser = require('ljswitchboard-data_parser');
var modbus_map = require('ljswitchboard-modbus_map').getConstants();
// var modbus_map = data_parser.getConstants();
var ljm_ffi = require('ljm-ffi');
var ljm = ljm_ffi.load();

function parseIPAddress(ipInt) {
	var ipAddr = new Buffer(4);
	ipAddr.writeUInt32LE(ipInt, 0);

	var ipStr = "";
	ipStr += ipAddr.readUInt8(3).toString();
	ipStr += ".";
	ipStr += ipAddr.readUInt8(2).toString();
	ipStr += ".";
	ipStr += ipAddr.readUInt8(1).toString();
	ipStr += ".";
	ipStr += ipAddr.readUInt8(0).toString();
	return ipStr;
}
module.exports.parseIPAddress = parseIPAddress;

function getHandleInfo(handle, cb) {
	function handleInfoReporter(data) {
		// console.log('Handle Info', data);
		var ipStr = parseIPAddress(data.IPAddress);
		var deviceData = {
			'H': handle,
			'DT': data.DeviceType,
			'CT': data.ConnectionType,
			'SN': data.SerialNumber,
			'IP': ipStr,
			'P': data.Port,
			'ljmError': data.ljmError,
		};
		cb(deviceData);
	}
	var res = ljm.LJM_GetHandleInfo.async(
		handle, // Handle
		0, // DeviceType
		0, // ConnectionType
		0, // SerialNumber
		0, // IPAddress
		0, // Port
		0, // MaxBytesPerMB
		handleInfoReporter
	);
}
module.exports.getHandleInfo = getHandleInfo;

function readDeviceRegister(handle, deviceType, register, cb) {
	// console.log('VCT - ', handle, register);
	var info = modbus_map.getAddressInfo(register, 0);
	if(info.typeString !== 'STRING') {
		// data_parser.parseResult
		ljm.LJM_eReadAddress.async(
			handle, // Handle
			info.address,
			info.type,
			0,
			function(results) {
				if(results.ljmError === 0) {
					var pRes = data_parser.parseResult(
						info.address,
						results.Value,
						deviceType
					);
					cb(pRes);
				} else {
					var pErr = data_parser.parseError(
						info.address,
						results.ljmError,
						deviceType
					);
					var keys = Object.keys(pErr.defaultValue);
					keys.forEach(function(key) {
						pErr[key] = pErr.defaultValue[key];
					});
					cb(pErr);
				}
			}
		);
	} else {
		// data_parser.parseResult
		ljm.LJM_eReadAddressString.async(
			handle, // Handle
			info.address,
			'',
			function(results) {
				if(results.ljmError === 0) {
					var pRes = data_parser.parseResult(
						info.address,
						results.String,
						deviceType
					);
					cb(pRes);
				} else {
					var pErr = data_parser.parseError(
						info.address,
						results.ljmError,
						deviceType
					);
					cb(pErr);
				}
			}
		);
	}
}

function readAndParseRegisters(handle, deviceType, registers, cb) {
	var data = {};
	function getData(register, innerCB) {
		readDeviceRegister(handle, deviceType, register, function(regData) {
			data[regData.name] = regData;
			innerCB();
		});
	}
	function returnResults(err) {
		cb(data);
	}
	async.eachSeries(registers, getData, returnResults);
}

function getProductType(deviceInfo) {
	if(deviceInfo.dt === 7) {
		return deviceInfo.HARDWARE_INSTALLED.productType;
	} else if(deviceInfo.dt === 4) {
		// return deviceInfo.HARDWARE_INSTALLED.productType;
		return 'T4';
	} else if(deviceInfo.dt === 5) {
		// return deviceInfo.HARDWARE_INSTALLED.productType;
		return 'T5';
	} else if(deviceInfo.dt === 200) {
		return deviceInfo.DGT_INSTALLED_OPTIONS.productType;
	} else {
		console.log('Failed to get product type', deviceInfo.dt);
		return deviceInfo.deviceTypeName;
	}
}
function getModelType(deviceInfo) {
	var pt = deviceInfo.deviceTypeName;
	var sc = '';
	if(deviceInfo.dt === 7) {
		pt = deviceInfo.HARDWARE_INSTALLED.productType;
	} else if(deviceInfo.dt === 4) {
		// pt = deviceInfo.HARDWARE_INSTALLED.productType;
		pt = 'T4';
	} else if(deviceInfo.dt === 5) {
		// pt = deviceInfo.HARDWARE_INSTALLED.productType;
		pt = 'T5';
	} else if(deviceInfo.dt === 200) {
		pt = deviceInfo.DGT_INSTALLED_OPTIONS.productType;
	} else {
		console.log('Failed to get model type');
	}
	return pt;
}
function getDeviceInfo(device, handle, registers, cb) {
	console.log('getDeviceInfo DEVICE', device);
	var deviceInfo = {};
	function handleReadData(results) {
		var isError = false;
		var keys = Object.keys(results);
		keys.forEach(function(key) {
			deviceInfo[key] = results[key];
			if(results[key].errorCode) {
				isError = true;
			}
		});
		deviceInfo.acquiredRequiredData = !isError;
		deviceInfo.productType = getProductType(deviceInfo);
		deviceInfo.modelType = getModelType(deviceInfo);

		// console.log('Device Info', deviceInfo);
		cb(deviceInfo);
	}

	function handleGetHandleInfo(handleInfo) {
		deviceInfo.handle = handle;

		var dt = handleInfo.DeviceType;
		deviceInfo.dt = dt;
		deviceInfo.deviceType = dt;
		deviceInfo.deviceTypeStr = driver_const.DRIVER_DEVICE_TYPE_NAMES[dt];
		deviceInfo.deviceTypeString = driver_const.DRIVER_DEVICE_TYPE_NAMES[dt];
		deviceInfo.deviceTypeName = driver_const.DEVICE_TYPE_NAMES[dt];

		var ct = handleInfo.ConnectionType;
		deviceInfo.handleConnectionType = ct;
		deviceInfo.handleConnectionTypeStr = driver_const.DRIVER_CONNECTION_TYPE_NAMES[ct];
		deviceInfo.handleConnectionTypeName = driver_const.CONNECTION_TYPE_NAMES[ct];

		var liveCT = driver_const.CONNECTION_MEDIUM[ct];
		deviceInfo.ct = liveCT;
		deviceInfo.connectionType = liveCT;
		deviceInfo.connectionTypeStr = driver_const.DRIVER_CONNECTION_TYPE_NAMES[liveCT];
		deviceInfo.connectionTypeName = driver_const.CONNECTION_TYPE_NAMES[liveCT];

		deviceInfo.serialNumber = handleInfo.SerialNumber;
		deviceInfo.ip = parseIPAddress(handleInfo.IPAddress);
		deviceInfo.port = handleInfo.Port;
		deviceInfo.maxBytesPerMB = handleInfo.MaxBytesPerMB;
		readAndParseRegisters(handle, dt, registers, handleReadData);
	}

	var res = ljm.LJM_GetHandleInfo.async(
		handle, // Handle
		0, // DeviceType
		0, // ConnectionType
		0, // SerialNumber
		0, // IPAddress
		0, // Port
		0, // MaxBytesPerMB
		handleGetHandleInfo
	);
}
module.exports.getDeviceInfo = getDeviceInfo;

function getDeviceInfoSync(handle) {
	var handleInfo = ljm.LJM_GetHandleInfo(
		handle, // Handle
		0, // DeviceType
		0, // ConnectionType
		0, // SerialNumber
		0, // IPAddress
		0, // Port
		0 // MaxBytesPerMB
	);
	var ipStr = parseIPAddress(handleInfo.IPAddress);

	var deviceNameData = ljm.LJM_eReadNameString(handle, 'DEVICE_NAME_DEFAULT', '');
	var deviceName = deviceNameData.String;

	var wifiIPData = ljm.LJM_eReadName(handle, 'WIFI_IP', 0);
	var wifiIP = parseIPAddress(wifiIPData.Value);

	var ethernetIPData = ljm.LJM_eReadName(handle, 'ETHERNET_IP', 0);
	var ethernetIP = parseIPAddress(ethernetIPData.Value);

	var firmwareVersionData = ljm.LJM_eReadName(handle, 'FIRMWARE_VERSION', 0);
	var firmwareVersion = parseFloat(firmwareVersionData.Value.toFixed(4));

	console.log('DN', deviceName);
	console.log('WI', wifiIP);
	console.log('EI', ethernetIP);
	console.log('FV', firmwareVersion);

	var deviceData = {
		'H': handle,
		'DT': handleInfo.DeviceType,
		'CT': handleInfo.ConnectionType,
		'SN': handleInfo.SerialNumber,
		'IP': ipStr,
		'P': handleInfo.Port,
		'DN': deviceName,
		'EIP': ethernetIP,
		'WIP': wifiIP,
		'FV': firmwareVersion,
	};
	return deviceData;
}
module.exports.getDeviceInfoSync = getDeviceInfoSync;

var DEBUG_VERIFY_DEVICE_CONNECTION = false;
function verifyDeviceConnection(dt, ct, id, cb) {
	var deviceOpened = false;
	var openError = 0;
	var deviceHandle = 0;
	var deviceClosed = false;
	var closeError = 0;
	var isVerified = false;
	var ljmHandleInfo = {};
	function handleDeviceClose(closeInfo) {
		if(DEBUG_VERIFY_DEVICE_CONNECTION) {
			console.log('VCT - in handleDeviceClose', deviceHandle, closeInfo.ljmError, ct, id);
		}
		closeError = closeInfo.ljmError;
		if(closeInfo.ljmError === 0) {
			deviceClosed = true;
		} else {
			deviceClosed = false;
		}
		isVerified = deviceOpened && deviceClosed;
		// isVerified = deviceOpened;
		if(deviceOpened) {
			if(!deviceClosed) {
				console.error(
					'Error Closing Opened Device.... Uh... WEIRD! device_scanner, ljm_utils',
					dt, ct, id, closeError);
			}
		}
		cb({
			deviceOpened: deviceOpened,
			openError: openError,
			deviceClosed: deviceClosed,
			closeError: closeError,
			isVerified: isVerified,
			handleInfo: ljmHandleInfo,
		});
	}
	function handleGetHandleInfo(handleInfo) {
		if(DEBUG_VERIFY_DEVICE_CONNECTION) {
			console.log('VCT - in handleGetHandleInfo', deviceHandle, handleInfo.ljmError, ct, id);
		}
		ljmHandleInfo = handleInfo;
		ljm.LJM_Close.async(deviceHandle, handleDeviceClose);
	}
	function handleDeviceOpen(openInfo) {
		deviceHandle = openInfo.handle;
		if(DEBUG_VERIFY_DEVICE_CONNECTION) {
			console.log('VCT - in handleDeviceOpen', deviceHandle, openInfo.ljmError, ct, id);
		}
		openError = openInfo.ljmError;
		if(openInfo.ljmError === 0) {
			deviceOpened = true;
			//
			getHandleInfo(deviceHandle, handleGetHandleInfo);
		} else {
			ljm.LJM_Close.async(deviceHandle, handleDeviceClose);
		}
	}
	if(DEBUG_VERIFY_DEVICE_CONNECTION) {
		console.log('VCT - Opening Device', ct, id);
	}
	ljm.LJM_Open.async(
		dt,
		ct,
		id,
		0, // Handle
		handleDeviceOpen
	);
}
module.exports.verifyDeviceConnection = verifyDeviceConnection;

function closeDevice (handle, cb) {
	function handleDeviceClose(closeInfo) {
		var deviceClosed = false;
		var closeError = closeInfo.ljmError;
		if(closeInfo.ljmError === 0) {
			deviceClosed = true;
		} else {
			deviceClosed = false;
		}

		cb({
			deviceClosed: deviceClosed,
			closeError: closeError,
		});
	}
	ljm.LJM_Close.async(
		handle,
		handleDeviceClose
	);
}
module.exports.closeDevice = closeDevice;
<commit_msg>'another'<commit_after>
var ref = require('ref');
var q = require('q');
var async = require('async');
var driver_const = require('ljswitchboard-ljm_driver_constants');
var data_parser = require('ljswitchboard-data_parser');
var modbus_map = require('ljswitchboard-modbus_map').getConstants();
// var modbus_map = data_parser.getConstants();
var ljm_ffi = require('ljm-ffi');
var ljm = ljm_ffi.load();

function parseIPAddress(ipInt) {
	var ipAddr = new Buffer(4);
	ipAddr.writeUInt32LE(ipInt, 0);

	var ipStr = "";
	ipStr += ipAddr.readUInt8(3).toString();
	ipStr += ".";
	ipStr += ipAddr.readUInt8(2).toString();
	ipStr += ".";
	ipStr += ipAddr.readUInt8(1).toString();
	ipStr += ".";
	ipStr += ipAddr.readUInt8(0).toString();
	return ipStr;
}
module.exports.parseIPAddress = parseIPAddress;

function getHandleInfo(handle, cb) {
	function handleInfoReporter(data) {
		// console.log('Handle Info', data);
		var ipStr = parseIPAddress(data.IPAddress);
		var deviceData = {
			'H': handle,
			'DT': data.DeviceType,
			'CT': data.ConnectionType,
			'SN': data.SerialNumber,
			'IP': ipStr,
			'P': data.Port,
			'ljmError': data.ljmError,
		};
		cb(deviceData);
	}
	var res = ljm.LJM_GetHandleInfo.async(
		handle, // Handle
		0, // DeviceType
		0, // ConnectionType
		0, // SerialNumber
		0, // IPAddress
		0, // Port
		0, // MaxBytesPerMB
		handleInfoReporter
	);
}
module.exports.getHandleInfo = getHandleInfo;

function readDeviceRegister(handle, deviceType, register, cb) {
	// console.log('VCT - ', handle, register);
	var info = modbus_map.getAddressInfo(register, 0);
	if(info.typeString !== 'STRING') {
		// data_parser.parseResult
		ljm.LJM_eReadAddress.async(
			handle, // Handle
			info.address,
			info.type,
			0,
			function(results) {
				if(results.ljmError === 0) {
					var pRes = data_parser.parseResult(
						info.address,
						results.Value,
						deviceType
					);
					cb(pRes);
				} else {
					var pErr = data_parser.parseError(
						info.address,
						results.ljmError,
						deviceType
					);
					var keys = Object.keys(pErr.defaultValue);
					keys.forEach(function(key) {
						pErr[key] = pErr.defaultValue[key];
					});
					cb(pErr);
				}
			}
		);
	} else {
		// data_parser.parseResult
		ljm.LJM_eReadAddressString.async(
			handle, // Handle
			info.address,
			'',
			function(results) {
				if(results.ljmError === 0) {
					var pRes = data_parser.parseResult(
						info.address,
						results.String,
						deviceType
					);
					cb(pRes);
				} else {
					var pErr = data_parser.parseError(
						info.address,
						results.ljmError,
						deviceType
					);
					cb(pErr);
				}
			}
		);
	}
}

function readAndParseRegisters(handle, deviceType, registers, cb) {
	var data = {};
	function getData(register, innerCB) {
		readDeviceRegister(handle, deviceType, register, function(regData) {
			data[regData.name] = regData;
			innerCB();
		});
	}
	function returnResults(err) {
		cb(data);
	}
	async.eachSeries(registers, getData, returnResults);
}

function getProductType(deviceInfo) {
	if(deviceInfo.dt === 7) {
		return deviceInfo.HARDWARE_INSTALLED.productType;
	} else if(deviceInfo.dt === 4) {
		// return deviceInfo.HARDWARE_INSTALLED.productType;
		return 'T4';
	} else if(deviceInfo.dt === 5) {
		// return deviceInfo.HARDWARE_INSTALLED.productType;
		return 'T5';
	} else if(deviceInfo.dt === 200) {
		return deviceInfo.DGT_INSTALLED_OPTIONS.productType;
	} else {
		console.log('Failed to get product type', deviceInfo.dt);
		return deviceInfo.deviceTypeName;
	}
}
function getModelType(deviceInfo) {
	var pt = deviceInfo.deviceTypeName;
	var sc = '';
	if(deviceInfo.dt === 7) {
		pt = deviceInfo.HARDWARE_INSTALLED.productType;
	} else if(deviceInfo.dt === 4) {
		// pt = deviceInfo.HARDWARE_INSTALLED.productType;
		pt = 'T4';
	} else if(deviceInfo.dt === 5) {
		// pt = deviceInfo.HARDWARE_INSTALLED.productType;
		pt = 'T5';
	} else if(deviceInfo.dt === 200) {
		pt = deviceInfo.DGT_INSTALLED_OPTIONS.productType;
	} else {
		console.log('Failed to get model type');
	}
	return pt;
}
function getDeviceInfo(device, handle, registers, cb) {
	// console.log('getDeviceInfo DEVICE', device);
	console.log('TODO: search for .isActive, and do similar things for device.savedAttributes.isConnected??')
	var deviceInfo = {};
	function handleReadData(results) {
		var isError = false;
		var keys = Object.keys(results);
		keys.forEach(function(key) {
			deviceInfo[key] = results[key];
			if(results[key].errorCode) {
				isError = true;
			}
		});
		deviceInfo.acquiredRequiredData = !isError;
		deviceInfo.productType = getProductType(deviceInfo);
		deviceInfo.modelType = getModelType(deviceInfo);

		// console.log('Device Info', deviceInfo);
		cb(deviceInfo);
	}

	function handleGetHandleInfo(handleInfo) {
		deviceInfo.handle = handle;

		var dt = handleInfo.DeviceType;
		deviceInfo.dt = dt;
		deviceInfo.deviceType = dt;
		deviceInfo.deviceTypeStr = driver_const.DRIVER_DEVICE_TYPE_NAMES[dt];
		deviceInfo.deviceTypeString = driver_const.DRIVER_DEVICE_TYPE_NAMES[dt];
		deviceInfo.deviceTypeName = driver_const.DEVICE_TYPE_NAMES[dt];

		var ct = handleInfo.ConnectionType;
		deviceInfo.handleConnectionType = ct;
		deviceInfo.handleConnectionTypeStr = driver_const.DRIVER_CONNECTION_TYPE_NAMES[ct];
		deviceInfo.handleConnectionTypeName = driver_const.CONNECTION_TYPE_NAMES[ct];

		var liveCT = driver_const.CONNECTION_MEDIUM[ct];
		deviceInfo.ct = liveCT;
		deviceInfo.connectionType = liveCT;
		deviceInfo.connectionTypeStr = driver_const.DRIVER_CONNECTION_TYPE_NAMES[liveCT];
		deviceInfo.connectionTypeName = driver_const.CONNECTION_TYPE_NAMES[liveCT];

		deviceInfo.serialNumber = handleInfo.SerialNumber;
		deviceInfo.ip = parseIPAddress(handleInfo.IPAddress);
		deviceInfo.port = handleInfo.Port;
		deviceInfo.maxBytesPerMB = handleInfo.MaxBytesPerMB;
		readAndParseRegisters(handle, dt, registers, handleReadData);
	}

	var res = ljm.LJM_GetHandleInfo.async(
		handle, // Handle
		0, // DeviceType
		0, // ConnectionType
		0, // SerialNumber
		0, // IPAddress
		0, // Port
		0, // MaxBytesPerMB
		handleGetHandleInfo
	);
}
module.exports.getDeviceInfo = getDeviceInfo;

function getDeviceInfoSync(handle) {
	var handleInfo = ljm.LJM_GetHandleInfo(
		handle, // Handle
		0, // DeviceType
		0, // ConnectionType
		0, // SerialNumber
		0, // IPAddress
		0, // Port
		0 // MaxBytesPerMB
	);
	var ipStr = parseIPAddress(handleInfo.IPAddress);

	var deviceNameData = ljm.LJM_eReadNameString(handle, 'DEVICE_NAME_DEFAULT', '');
	var deviceName = deviceNameData.String;

	var wifiIPData = ljm.LJM_eReadName(handle, 'WIFI_IP', 0);
	var wifiIP = parseIPAddress(wifiIPData.Value);

	var ethernetIPData = ljm.LJM_eReadName(handle, 'ETHERNET_IP', 0);
	var ethernetIP = parseIPAddress(ethernetIPData.Value);

	var firmwareVersionData = ljm.LJM_eReadName(handle, 'FIRMWARE_VERSION', 0);
	var firmwareVersion = parseFloat(firmwareVersionData.Value.toFixed(4));

	console.log('DN', deviceName);
	console.log('WI', wifiIP);
	console.log('EI', ethernetIP);
	console.log('FV', firmwareVersion);

	var deviceData = {
		'H': handle,
		'DT': handleInfo.DeviceType,
		'CT': handleInfo.ConnectionType,
		'SN': handleInfo.SerialNumber,
		'IP': ipStr,
		'P': handleInfo.Port,
		'DN': deviceName,
		'EIP': ethernetIP,
		'WIP': wifiIP,
		'FV': firmwareVersion,
	};
	return deviceData;
}
module.exports.getDeviceInfoSync = getDeviceInfoSync;

var DEBUG_VERIFY_DEVICE_CONNECTION = false;
function verifyDeviceConnection(dt, ct, id, cb) {
	var deviceOpened = false;
	var openError = 0;
	var deviceHandle = 0;
	var deviceClosed = false;
	var closeError = 0;
	var isVerified = false;
	var ljmHandleInfo = {};
	function handleDeviceClose(closeInfo) {
		if(DEBUG_VERIFY_DEVICE_CONNECTION) {
			console.log('VCT - in handleDeviceClose', deviceHandle, closeInfo.ljmError, ct, id);
		}
		closeError = closeInfo.ljmError;
		if(closeInfo.ljmError === 0) {
			deviceClosed = true;
		} else {
			deviceClosed = false;
		}
		isVerified = deviceOpened && deviceClosed;
		// isVerified = deviceOpened;
		if(deviceOpened) {
			if(!deviceClosed) {
				console.error(
					'Error Closing Opened Device.... Uh... WEIRD! device_scanner, ljm_utils',
					dt, ct, id, closeError);
			}
		}
		cb({
			deviceOpened: deviceOpened,
			openError: openError,
			deviceClosed: deviceClosed,
			closeError: closeError,
			isVerified: isVerified,
			handleInfo: ljmHandleInfo,
		});
	}
	function handleGetHandleInfo(handleInfo) {
		if(DEBUG_VERIFY_DEVICE_CONNECTION) {
			console.log('VCT - in handleGetHandleInfo', deviceHandle, handleInfo.ljmError, ct, id);
		}
		ljmHandleInfo = handleInfo;
		ljm.LJM_Close.async(deviceHandle, handleDeviceClose);
	}
	function handleDeviceOpen(openInfo) {
		deviceHandle = openInfo.handle;
		if(DEBUG_VERIFY_DEVICE_CONNECTION) {
			console.log('VCT - in handleDeviceOpen', deviceHandle, openInfo.ljmError, ct, id);
		}
		openError = openInfo.ljmError;
		if(openInfo.ljmError === 0) {
			deviceOpened = true;
			//
			getHandleInfo(deviceHandle, handleGetHandleInfo);
		} else {
			ljm.LJM_Close.async(deviceHandle, handleDeviceClose);
		}
	}
	if(DEBUG_VERIFY_DEVICE_CONNECTION) {
		console.log('VCT - Opening Device', ct, id);
	}
	ljm.LJM_Open.async(
		dt,
		ct,
		id,
		0, // Handle
		handleDeviceOpen
	);
}
module.exports.verifyDeviceConnection = verifyDeviceConnection;

function closeDevice (handle, cb) {
	function handleDeviceClose(closeInfo) {
		var deviceClosed = false;
		var closeError = closeInfo.ljmError;
		if(closeInfo.ljmError === 0) {
			deviceClosed = true;
		} else {
			deviceClosed = false;
		}

		cb({
			deviceClosed: deviceClosed,
			closeError: closeError,
		});
	}
	ljm.LJM_Close.async(
		handle,
		handleDeviceClose
	);
}
module.exports.closeDevice = closeDevice;
<|endoftext|>


<commit_before>import md5 from 'MD5'
import atomifyCSS from 'atomify-css'
import browserify from 'browserify'
import path from 'path'
import fs from 'fs'
import versions from './versions.json'

const staticPath = path.join(__dirname, 'static')
const versionsPath = path.join(__dirname, 'versions.json')

const writeVersions = () => fs.writeFileSync(versionsPath, JSON.stringify(versions, null, 2))

const buildJs = function buildJs (callback) {
  console.info(['info', 'http', 'bundle', 'js'], 'started')
  const b = browserify({
    debug: true
    , extensions: ['.js', '.json', '.jsx']
  })

  b.add(path.join(staticPath, 'entry.js'))

  b.transform('babelify')
  b.plugin('minifyify', {map: '/static/index.js.map'})

  b.bundle((...args) => {
    console.info(['info', 'http', 'bundle', 'js'], 'finished')
    callback.apply(null, args)
  })
}
buildJs(function bundled (err, js, map) {
  if (err) throw err

  versions.js = md5(js)
  fs.writeFileSync(path.join(staticPath, 'index.js'), js)
  fs.writeFileSync(path.join(staticPath, 'index.js.map'), map)
  writeVersions()
})

const buildCss = function buildCss (callback) {
  console.info(['info', 'http', 'bundle', 'css'], 'started')
  atomifyCSS({
    entry: path.join(__dirname, 'components', '_routes', 'index.css')
    , compress: true
    , autoprefixer: true
  }, (...args) => {
    console.info(['info', 'http', 'bundle', 'css'], 'finished')
    callback.apply(null, args)
  })
}
buildCss(function builtCss (err, css) {
  if (err) throw err
  versions.css = md5(css)
  fs.writeFileSync(path.join(staticPath, 'entry.css'), css)
  writeVersions()
})
<commit_msg>build script now uses browserify-incremental<commit_after>const BUILD_TIMER = 'build'
console.time(BUILD_TIMER)

import md5 from 'MD5'
import atomifyCSS from 'atomify-css'
import browserify from 'browserify'
import browserifyIncremental from 'browserify-incremental'
import assign from 'lodash/object/assign'
import path from 'path'
import fs from 'fs'
import versions from './versions.json'

const staticPath = path.join(__dirname, 'static')
const versionsPath = path.join(__dirname, 'versions.json')

const writeVersions = () => fs.writeFile(versionsPath, JSON.stringify(versions, null, 2))

const buildJs = function buildJs (callback) {
  console.info(['info', 'http', 'bundle', 'js'], 'started')
  const b = browserify(assign({
    debug: true
    , extensions: ['.js', '.json', '.jsx']
    , cacheFile: path.join('/tmp', `${path.basename(__dirname)}-browserify-cache.json`)
  }, browserifyIncremental.args))

  b.add(path.join(staticPath, 'entry.js'))

  b.transform('babelify')
  b.plugin('minifyify', {map: '/static/index.js.map'})

  browserifyIncremental(b)

  b.bundle((...args) => {
    console.info(['info', 'http', 'bundle', 'js'], 'finished')
    callback.apply(null, args)
  })
}
buildJs(function bundled (err, js, map) {
  if (err) throw err

  versions.js = md5(js)
  fs.writeFile(path.join(staticPath, 'index.js'), js)
  fs.writeFile(path.join(staticPath, 'index.js.map'), map)
  writeVersions()
})

const buildCss = function buildCss (callback) {
  console.info(['info', 'http', 'bundle', 'css'], 'started')
  atomifyCSS({
    entry: path.join(__dirname, 'components', '_routes', 'index.css')
    , compress: true
    , autoprefixer: true
  }, (...args) => {
    console.info(['info', 'http', 'bundle', 'css'], 'finished')
    callback.apply(null, args)
  })
}
buildCss(function builtCss (err, css) {
  if (err) throw err
  versions.css = md5(css)
  fs.writeFile(path.join(staticPath, 'entry.css'), css)
  writeVersions()
})

process.on('exit', () => console.timeEnd(BUILD_TIMER))
<|endoftext|>


<commit_before>/*!
 * Copyright 2012 Sakai Foundation (SF) Licensed under the
 * Educational Community 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.osedu.org/licenses/ECL-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.
 */

var _ = require('underscore');
var express = require('express');
var RedisStore = require('connect-redis')(express);

var TelemetryAPI = require('oae-telemetry');
var log = require('oae-logger').logger('oae-server');

// Maintains a list of paths that are safe from CSRF attacks
var safePathPrefixes = [];

/**
 * Starts an express server on the specified port. This will be done for the global admin server, as well
 * as for the tenant server.
 *
 * @param  {Number}     port        The port on which the express server should be started
 * @param  {Object}     config      JSON object containing configuration values for Cassandra, Redis, logging and telemetry
 * @return {Express}                The created express server
 */
module.exports.setupServer = function(port, config) {
    // Create the express server
    var server = express();
    // Make it listen for requests on the specified port
    server.listen(port);

    // Don't output pretty JSON,
    server.set('json spaces', 0);

    // We'll be using cookies to hash the principalId.
    // Signing of the cookie will be done by the session middleware.
    server.use(express.cookieParser());

    // The bodyParser will parse the following type of requests:
    // * application/json
    // * urlencoded (regular POST requests)
    // * multipart (file uploads)
    // We pass in the config.files hash so we can configure where
    // the uploaded files will be temporarily stored.
    server.use(express.bodyParser(config.files));

    // This needs to come BEFORE passport and AFTER cookieParser.
    // The secret will be used to sign the cookie
    // We'll use Redis as a store for our sessions.
    var redisStore = new RedisStore({
        'host': config.redis.host,
        'port': config.redis.port,
        'pass': config.redis.pass,
        'db': config.redis.dbIndex
    });
    server.use(express.session({'secret': config.cookie.secret, 'store': redisStore}));

    // Add telemetry before we do anything else.
    server.use(function(req, res, next) {
        TelemetryAPI.request(req, res);
        next();
    });

    /*!
     * Referer-based CSRF protection. If the request is not safe (e.g., POST, DELETE) and the origin of the request (as
     * specified by the HTTP Referer header) does not match the target host of the request (as specified by the HTTP
     * Host header), then the request will result in a 500 error.
     *
     * While referer-based protection is not highly recommended due to spoofing possibilities in insecure environments,
     * it currently offers the best trade-off between ease of use (e.g., for cURL interoperability), effort and security
     * against CSRF attacks.
     *
     * If using a utility such as `curl` to POST requests to the API, you can bypass this by just setting the referer
     * header to "/":
     *
     * curl -X POST -e / http://my.oae.com/api/auth/login
     *
     * More information about CSRF attacks: http://en.wikipedia.org/wiki/Cross-site_request_forgery
     */
    server.use(function(req, res, next) {
        if (!_isSafeMethod(req.method) && !_isSafePath(req) && !_isSameOrigin(req)) {
            log().warn({
                'method': req.method,
                'host': req.headers.host,
                'referer': req.headers.referer,
                'targetPath': req.path
            }, 'CSRF validation failed: attempted to execute unsafe operation from untrusted origin.');
            return _abort(res, 500, 'CSRF validation failed: attempted to execute unsafe method from untrusted origin.');
        }

        next();
    });

    return server;
};

/**
 * Add a path to the list of safe paths. Paths added here will not be protected against CSRF
 * attacks. This is common for endpoints that have other verification mechanisms such as Shibboleth.
 *
 * @param  {String}     pathPrefix  A path prefix that will not be validated against CSRF attacks
 */
var addSafePathPrefix = module.exports.addSafePathPrefix = function(pathPrefix) {
    log().info('Adding %s to list of paths that are not CSRF-protected.', pathPrefix);
    safePathPrefixes.push(pathPrefix);
};

/**
 * This method is used to bind server functionality after all modules have had an opportunity to do so. This can be useful for things such
 * as:
 *
 *  * Response code logging / telemetry
 *  * Default "catch-all" error handling
 *
 * @param  {Express}    server      The express server for which the initialized should be finalized
 */
module.exports.postInitializeServer = function(server) {

    // Explicitly apply the routes to the end
    server.use(server.router);

    // Catch-all error handler
    var serverTelemetry = TelemetryAPI.telemetry('server');
    server.use(function(err, req, res, next) {
        serverTelemetry.incr('error');
        log(req.ctx).error({
            err: err,
            req: req,
            res: res
        }, 'Unhandled error in the request chain, caught at the default error handler.');
        res.send(500, 'An unexpected error occurred.');
    });
};

/**
 * Abort a request with a given code and response message.
 *
 * @param  {Response}   res     The express response object
 * @param  {Number}     code    The HTTP response code
 * @param  {String}     message The message body to provide as a reason for aborting the request
 * @api private
 */
var _abort = function(res, code, message) {
    res.setHeader('Connection', 'Close');
    return res.send(code, message);
};

/**
 * Determines if the target path for a request is considered "safe" from CSRF attacks.
 *
 * @param  {Request}    req     The express request object
 * @return {Boolean}            `true` if the path is safe from CSRF attacks, `false` otherwise
 * @api private
 */
var _isSafePath = function(req) {
    var path = req.path;
    var matchingPaths = _.filter(safePathPrefixes, function(safePathPrefix) {
        return (path.indexOf(safePathPrefix) === 0);
    });
    return (matchingPaths.length > 0);
};

/**
 * Determine whether or not the given request method is considered "safe"
 *
 * @param  {String}     method  The request method
 * @return {Boolean}            `true` if the request method is safe (e.g., GET, HEAD), `false` otherwise
 * @api private
 */
var _isSafeMethod = function(method) {
    return (method === 'GET' || method === 'HEAD');
};

/**
 * Determine whether or not the origin host of the given request is the same as the target host.
 *
 * @param  {Request}    req     The express request object to test
 * @return {Boolean}            `true` if the request is of the same origin as the target host, `false` otherwise
 * @api private
 */
var _isSameOrigin = function(req) {
    var host = req.headers.host;
    var referer = req.headers.referer;

    if (!referer) {
        return false;
    }

    if (referer.indexOf('/') !== 0) {
        // Verify the host portion against the host header
        referer = referer.split('://')[1];
        if (!referer || referer.split('/')[0] !== host) {
            // If there is nothing after the protocol (e.g., "http://") or the host before the first slash does not match
            // we deem it not to be the same origin.
            return false;
        } else {
            return true;
        }
    } else {
        // If the referer is a relative uri, it must be from same origin.
        return true;
    }
};
<commit_msg>Store authenticated userid on cookie, not redis<commit_after>/*!
 * Copyright 2012 Sakai Foundation (SF) Licensed under the
 * Educational Community 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.osedu.org/licenses/ECL-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.
 */

var _ = require('underscore');
var express = require('express');

var log = require('oae-logger').logger('oae-server');
var TelemetryAPI = require('oae-telemetry');

// Maintains a list of paths that are safe from CSRF attacks
var safePathPrefixes = [];

/**
 * Starts an express server on the specified port. This will be done for the global admin server, as well
 * as for the tenant server.
 *
 * @param  {Number}     port        The port on which the express server should be started
 * @param  {Object}     config      JSON object containing configuration values for Cassandra, Redis, logging and telemetry
 * @return {Express}                The created express server
 */
module.exports.setupServer = function(port, config) {
    // Create the express server
    var server = express();
    // Make it listen for requests on the specified port
    server.listen(port);

    // Don't output pretty JSON,
    server.set('json spaces', 0);

    // We'll be using cookies to hash the principalId.
    // Signing of the cookie will be done by the session middleware.
    server.use(express.cookieParser());

    // The bodyParser will parse the following type of requests:
    // * application/json
    // * urlencoded (regular POST requests)
    // * multipart (file uploads)
    // We pass in the config.files hash so we can configure where
    // the uploaded files will be temporarily stored.
    server.use(express.bodyParser(config.files));

    // This needs to come BEFORE passport and AFTER cookieParser.
    // The secret will be used to sign the cookie
    server.use(express.cookieSession({'secret': config.cookie.secret}));

    // Add telemetry before we do anything else.
    server.use(function(req, res, next) {
        TelemetryAPI.request(req, res);
        next();
    });

    /*!
     * Referer-based CSRF protection. If the request is not safe (e.g., POST, DELETE) and the origin of the request (as
     * specified by the HTTP Referer header) does not match the target host of the request (as specified by the HTTP
     * Host header), then the request will result in a 500 error.
     *
     * While referer-based protection is not highly recommended due to spoofing possibilities in insecure environments,
     * it currently offers the best trade-off between ease of use (e.g., for cURL interoperability), effort and security
     * against CSRF attacks.
     *
     * If using a utility such as `curl` to POST requests to the API, you can bypass this by just setting the referer
     * header to "/":
     *
     * curl -X POST -e / http://my.oae.com/api/auth/login
     *
     * More information about CSRF attacks: http://en.wikipedia.org/wiki/Cross-site_request_forgery
     */
    server.use(function(req, res, next) {
        if (!_isSafeMethod(req.method) && !_isSafePath(req) && !_isSameOrigin(req)) {
            log().warn({
                'method': req.method,
                'host': req.headers.host,
                'referer': req.headers.referer,
                'targetPath': req.path
            }, 'CSRF validation failed: attempted to execute unsafe operation from untrusted origin.');
            return _abort(res, 500, 'CSRF validation failed: attempted to execute unsafe method from untrusted origin.');
        }

        next();
    });

    return server;
};

/**
 * Add a path to the list of safe paths. Paths added here will not be protected against CSRF
 * attacks. This is common for endpoints that have other verification mechanisms such as Shibboleth.
 *
 * @param  {String}     pathPrefix  A path prefix that will not be validated against CSRF attacks
 */
var addSafePathPrefix = module.exports.addSafePathPrefix = function(pathPrefix) {
    log().info('Adding %s to list of paths that are not CSRF-protected.', pathPrefix);
    safePathPrefixes.push(pathPrefix);
};

/**
 * This method is used to bind server functionality after all modules have had an opportunity to do so. This can be useful for things such
 * as:
 *
 *  * Response code logging / telemetry
 *  * Default "catch-all" error handling
 *
 * @param  {Express}    server      The express server for which the initialized should be finalized
 */
module.exports.postInitializeServer = function(server) {

    // Explicitly apply the routes to the end
    server.use(server.router);

    // Catch-all error handler
    var serverTelemetry = TelemetryAPI.telemetry('server');
    server.use(function(err, req, res, next) {
        serverTelemetry.incr('error');
        log(req.ctx).error({
            err: err,
            req: req,
            res: res
        }, 'Unhandled error in the request chain, caught at the default error handler.');
        res.send(500, 'An unexpected error occurred.');
    });
};

/**
 * Abort a request with a given code and response message.
 *
 * @param  {Response}   res     The express response object
 * @param  {Number}     code    The HTTP response code
 * @param  {String}     message The message body to provide as a reason for aborting the request
 * @api private
 */
var _abort = function(res, code, message) {
    res.setHeader('Connection', 'Close');
    return res.send(code, message);
};

/**
 * Determines if the target path for a request is considered "safe" from CSRF attacks.
 *
 * @param  {Request}    req     The express request object
 * @return {Boolean}            `true` if the path is safe from CSRF attacks, `false` otherwise
 * @api private
 */
var _isSafePath = function(req) {
    var path = req.path;
    var matchingPaths = _.filter(safePathPrefixes, function(safePathPrefix) {
        return (path.indexOf(safePathPrefix) === 0);
    });
    return (matchingPaths.length > 0);
};

/**
 * Determine whether or not the given request method is considered "safe"
 *
 * @param  {String}     method  The request method
 * @return {Boolean}            `true` if the request method is safe (e.g., GET, HEAD), `false` otherwise
 * @api private
 */
var _isSafeMethod = function(method) {
    return (method === 'GET' || method === 'HEAD');
};

/**
 * Determine whether or not the origin host of the given request is the same as the target host.
 *
 * @param  {Request}    req     The express request object to test
 * @return {Boolean}            `true` if the request is of the same origin as the target host, `false` otherwise
 * @api private
 */
var _isSameOrigin = function(req) {
    var host = req.headers.host;
    var referer = req.headers.referer;

    if (!referer) {
        return false;
    }

    if (referer.indexOf('/') !== 0) {
        // Verify the host portion against the host header
        referer = referer.split('://')[1];
        if (!referer || referer.split('/')[0] !== host) {
            // If there is nothing after the protocol (e.g., "http://") or the host before the first slash does not match
            // we deem it not to be the same origin.
            return false;
        } else {
            return true;
        }
    } else {
        // If the referer is a relative uri, it must be from same origin.
        return true;
    }
};
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';

import Splash from './components/Splash';
import Join from './components/Join';
import Lobby from './components/Lobby';

const App = ({ context }) => {
  switch (context) {
    case 'SPLASH': {
      return <Splash />;
    }
    case 'JOIN': {
      return <Join />;
    }
    case 'LOBBY': {
      return <Lobby />;
    }
  }
}

const mapStateToProps = (state) => ({
  context: state.context
})

export default connect(mapStateToProps)(App);
<commit_msg>Added default to make fn travis happy<commit_after>import React from 'react';
import { connect } from 'react-redux';

import Splash from './components/Splash';
import Join from './components/Join';
import Lobby from './components/Lobby';

const App = ({ context }) => {
  switch (context) {
    case 'SPLASH': {
      return <Splash />;
    }
    case 'JOIN': {
      return <Join />;
    }
    case 'LOBBY': {
      return <Lobby />;
    }
    default: {
      return null;
    }
  }
}

const mapStateToProps = (state) => ({
  context: state.context
})

export default connect(mapStateToProps)(App);
<|endoftext|>


<commit_before>// @flow
import * as TrackerGen from '../actions/tracker-gen'
import * as Types from '../constants/types/tracker'
import * as Constants from '../constants/tracker'

function updateUserState(
  state: Types.State,
  username: string,
  sub: (state: ?Types.TrackerState) => ?Types.TrackerState
): Types.State {
  if (!username) {
    return state
  }
  const subState = sub(state.userTrackers[username])
  return {
    ...state,
    userTrackers: {
      ...state.userTrackers,
      [username]: subState,
    },
  }
}

function updateNonUserState(
  state: Types.State,
  username: string,
  sub: (state: ?Types.NonUserState) => ?Types.NonUserState
): Types.State {
  if (!username) {
    return state
  }
  const subState = sub(state.nonUserTrackers[username])
  return {
    ...state,
    nonUserTrackers: {
      ...state.nonUserTrackers,
      [username]: subState,
    },
  }
}

export default function(
  state: Types.State = Constants.initialState,
  action: TrackerGen.Actions
): Types.State {
  switch (action.type) {
    case TrackerGen.resetStore:
      return {
        ...state,
        trackers: {},
        nonUserTrackers: {},
      }
    case TrackerGen.cacheIdentify: {
      const {goodTill, uid} = action.payload
      return {
        ...state,
        cachedIdentifies: {
          ...state.cachedIdentifies,
          [uid]: goodTill,
        },
      }
    }
    case TrackerGen.pendingIdentify: {
      const {username, pending} = action.payload
      return {
        ...state,
        pendingIdentifies: {
          ...state.pendingIdentifies,
          [username]: pending ? true : undefined,
        },
      }
    }
    case TrackerGen.setRegisterIdentifyUi: {
      const {started} = action.payload
      return {
        ...state,
        serverStarted: started,
      }
    }

    case TrackerGen.showNonUser: {
      const {nonUser} = action.payload
      return updateNonUserState(state, action.payload.username, s => {
        return {
          ...s,
          closed: false,
          hidden: false,
          inviteLink: nonUser.throttled ? null : nonUser.inviteLink,
          isPrivate: nonUser.isPrivate,
          name: nonUser.assertion,
          reason: `You opened ${nonUser.folderName}`,
          serviceName: nonUser.socialAssertion.service,
        }
      })
    }
    case TrackerGen.onClose: {
      const {username} = action.payload
      const isUser = state.userTrackers[username]
      if (isUser) {
        return updateUserState(state, username, s => ({
          ...s,
          closed: true,
          hidden: false,
          lastAction: null,
          needTrackTokenDismiss: !!s && !s.trackToken, // did we have a track token at this time?
          shouldFollow: false, // don't follow if they close x out the window
        }))
      }
      const isNonUser = state.nonUserTrackers[username]
      if (isNonUser) {
        return updateNonUserState(state, username, s => ({
          ...s,
          closed: true,
          hidden: false,
        }))
      }
      return state
    }
    case TrackerGen.updateUsername: {
      const {username} = action.payload
      return updateUserState(state, username, s => s || Constants.initialTrackerState(username))
    }
    case TrackerGen.identifyStarted:
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        error: null,
      }))
    case TrackerGen.updateSelectedTeam: {
      const {selectedTeam, username} = action.payload
      return updateUserState(state, username, s => ({
        ...s,
        selectedTeam,
      }))
    }
    case TrackerGen.updateReason:
      // In case the reason is null, let's use our existing reason
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        reason: (action.payload && action.payload.reason) || (s && s.reason),
      }))
    case TrackerGen.updateTrackToken: {
      const {trackToken} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        trackToken: trackToken,
      }))
    }
    case TrackerGen.setNeedTrackTokenDismiss: {
      const {needTrackTokenDismiss} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        needTrackTokenDismiss,
      }))
    }
    case TrackerGen.waiting: {
      const {waiting} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        waiting,
      }))
    }
    case TrackerGen.setOnFollow: {
      const {username} = action.payload
      return updateUserState(state, username, s => ({
        ...s,
        currentlyFollowing: true,
        lastAction: 'followed',
        reason: `You have followed ${username}.`,
      }))
    }
    case TrackerGen.setOnRefollow: {
      const {username} = action.payload
      return updateUserState(state, username, s => ({
        ...s,
        lastAction: 'refollowed',
        reason: `You have re-followed ${username}.`,
        trackerState: 'normal',
        eldestKidChanged: false,
      }))
    }
    case TrackerGen.setOnUnfollow: {
      const {username} = action.payload
      return updateUserState(state, username, s => ({
        ...s,
        currentlyFollowing: false,
        lastAction: 'unfollowed',
        reason: `You have unfollowed ${username}.`,
      }))
    }
    case TrackerGen.onError: {
      let error = 'There was an error updating your follow status.'
      if (action.payload && action.payload.extraText) {
        error = `There was an error: ${action.payload.extraText}`
      }
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        error,
      }))
    }
    case TrackerGen.updateEldestKidChanged: {
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        eldestKidChanged: true,
      }))
    }
    case TrackerGen.updateProofState: {
      const {username} = action.payload
      return updateUserState(state, username, s => {
        if (!s) {
          return s
        }
        const proofsGeneralState = Constants.overviewStateOfProofs(s.proofs)
        const trackerMessage = Constants.deriveTrackerMessage(
          username,
          s.currentlyFollowing,
          proofsGeneralState
        )
        const reason = trackerMessage || s.reason
        return {
          ...s,
          changed: proofsGeneralState.anyChanged,
          reason,
          shouldFollow: Constants.deriveShouldFollow(proofsGeneralState),
          trackerState: Constants.deriveSimpleProofState(s.eldestKidChanged, proofsGeneralState),
        }
      })
    }
    case TrackerGen.resetProofs:
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        proofs: [],
      }))
    case TrackerGen.setProofs: {
      const {identity, username} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        proofs: Constants.dedupeProofs([
          ...(s ? s.proofs : []),
          ...(identity.revokedDetails || []).map(rv => Constants.revokedProofToProof(rv)),
          ...(identity.proofs || [])
            .map(rp => Constants.remoteProofToProof(username, Constants.checking, rp.proof)),
        ]),
      }))
    }
    case TrackerGen.updatePGPKey: {
      const {pgpFingerprint, kid} = action.payload
      const fingerPrint = Constants.bufferToNiceHexString(pgpFingerprint)
      return updateUserState(state, action.payload.username, s => {
        const url = `https://keybase.io/${s ? s.username : ''}/sigchain`
        const proof = {
          color: 'green',
          // TODO: We don't currently get the sigID so we can't link to the actual sigChain statement. See https://keybase.atlassian.net/browse/CORE-3529
          humanUrl: url,
          id: kid,
          isTracked: s ? s.currentlyFollowing : false,
          mTime: 0,
          meta: null,
          name: fingerPrint,
          profileUrl: url,
          state: 'normal',
          type: 'pgp',
        }

        return {
          ...s,
          proofs: Constants.dedupeProofs(s ? s.proofs.concat([proof]) : [proof]),
        }
      })
    }
    case TrackerGen.updateZcash: {
      const {sigID, address} = action.payload
      return updateUserState(state, action.payload.username, s => {
        const url = `https://keybase.io/${s ? s.username : ''}/sigchain#${sigID}`
        const proof = {
          color: 'green',
          humanUrl: url,
          id: sigID,
          isTracked: s ? s.currentlyFollowing : false,
          mTime: 0,
          meta: null,
          name: address,
          profileUrl: url,
          state: 'normal',
          type: 'zcash',
        }

        return {
          ...s,
          proofs: Constants.dedupeProofs(s ? s.proofs.concat([proof]) : [proof]),
        }
      })
    }
    case TrackerGen.updateBTC: {
      const {sigID, address} = action.payload
      return updateUserState(state, action.payload.username, s => {
        const url = `https://keybase.io/${s ? s.username : ''}/sigchain#${sigID}`
        const proof = {
          color: 'green',
          humanUrl: url,
          id: sigID,
          isTracked: s ? s.currentlyFollowing : false,
          mTime: 0,
          meta: null,
          name: address,
          profileUrl: url,
          state: 'normal',
          type: 'btc',
        }

        return {
          ...s,
          proofs: Constants.dedupeProofs(s ? s.proofs.concat([proof]) : [proof]),
        }
      })
    }
    case TrackerGen.updateProof: {
      const {remoteProof, linkCheckResult, username} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        proofs: Constants.updateProof(username, s ? s.proofs : [], remoteProof, linkCheckResult),
      }))
    }
    case TrackerGen.updateUserInfo: {
      const {userCard, username} = action.payload
      const userInfo = {
        fullname: userCard.fullName,
        followersCount: userCard.followers,
        followingCount: userCard.following,
        followsYou: userCard.theyFollowYou,
        uid: userCard.uid,
        bio: userCard.bio,
        avatar: `https://keybase.io/${username}/picture`,
        location: userCard.location,
        showcasedTeams: userCard.teamShowcase || [],
      }
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        userInfo,
      }))
    }
    case TrackerGen.markActiveIdentifyUi: {
      const {active} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        serverActive: active,
      }))
    }
    case TrackerGen.reportLastTrack: {
      const {tracking} = action.payload
      return updateUserState(state, action.payload.username, s => {
        const proofs = (s ? s.proofs : []).map(
          p => (['btc', 'pgp'].includes(p.type) ? {...p, isTracked: tracking} : p)
        )
        return {
          ...s,
          currentlyFollowing: tracking,
          proofs,
        }
      })
    }
    case TrackerGen.showTracker:
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        closed: false,
        hidden: false,
      }))
    case TrackerGen.remoteDismiss:
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        closed: true,
      }))
    case TrackerGen.setUpdateTrackers: {
      const {trackers, tracking} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        trackersLoaded: true,
        trackers,
        tracking,
      }))
    }
    case TrackerGen.updateFolders: {
      const {tlfs} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        tlfs,
      }))
    }
    case TrackerGen.identifyFinished: {
      if (action.error) {
        const {error} = action.payload
        return updateUserState(state, action.payload.username, s => ({
          ...s,
          error,
          serverActive: false,
        }))
      } else {
        return updateUserState(state, action.payload.username, s => ({
          ...s,
          error: null,
        }))
      }
    }
    // Saga only actions
    case TrackerGen.follow:
    case TrackerGen.getMyProfile:
    case TrackerGen.getProfile:
    case TrackerGen.ignore:
    case TrackerGen.openProofUrl:
    case TrackerGen.parseFriendship:
    case TrackerGen.refollow:
    case TrackerGen.setupTrackerHandlers:
    case TrackerGen.unfollow:
    case TrackerGen.updateTrackers:
      return state
    default:
      // eslint-disable-next-line no-unused-expressions
      (action: empty) // if you get a flow error here it means there's an action you claim to handle but didn't
      return state
  }
}
<commit_msg>Sort showcased teams by team name on profile and tracker popup (#9944)<commit_after>// @flow
import * as TrackerGen from '../actions/tracker-gen'
import * as Types from '../constants/types/tracker'
import * as Constants from '../constants/tracker'

const sortByTeamName = (a, b) => a.fqName.localeCompare(b.fqName)

function updateUserState(
  state: Types.State,
  username: string,
  sub: (state: ?Types.TrackerState) => ?Types.TrackerState
): Types.State {
  if (!username) {
    return state
  }
  const subState = sub(state.userTrackers[username])
  return {
    ...state,
    userTrackers: {
      ...state.userTrackers,
      [username]: subState,
    },
  }
}

function updateNonUserState(
  state: Types.State,
  username: string,
  sub: (state: ?Types.NonUserState) => ?Types.NonUserState
): Types.State {
  if (!username) {
    return state
  }
  const subState = sub(state.nonUserTrackers[username])
  return {
    ...state,
    nonUserTrackers: {
      ...state.nonUserTrackers,
      [username]: subState,
    },
  }
}

export default function(
  state: Types.State = Constants.initialState,
  action: TrackerGen.Actions
): Types.State {
  switch (action.type) {
    case TrackerGen.resetStore:
      return {
        ...state,
        trackers: {},
        nonUserTrackers: {},
      }
    case TrackerGen.cacheIdentify: {
      const {goodTill, uid} = action.payload
      return {
        ...state,
        cachedIdentifies: {
          ...state.cachedIdentifies,
          [uid]: goodTill,
        },
      }
    }
    case TrackerGen.pendingIdentify: {
      const {username, pending} = action.payload
      return {
        ...state,
        pendingIdentifies: {
          ...state.pendingIdentifies,
          [username]: pending ? true : undefined,
        },
      }
    }
    case TrackerGen.setRegisterIdentifyUi: {
      const {started} = action.payload
      return {
        ...state,
        serverStarted: started,
      }
    }

    case TrackerGen.showNonUser: {
      const {nonUser} = action.payload
      return updateNonUserState(state, action.payload.username, s => {
        return {
          ...s,
          closed: false,
          hidden: false,
          inviteLink: nonUser.throttled ? null : nonUser.inviteLink,
          isPrivate: nonUser.isPrivate,
          name: nonUser.assertion,
          reason: `You opened ${nonUser.folderName}`,
          serviceName: nonUser.socialAssertion.service,
        }
      })
    }
    case TrackerGen.onClose: {
      const {username} = action.payload
      const isUser = state.userTrackers[username]
      if (isUser) {
        return updateUserState(state, username, s => ({
          ...s,
          closed: true,
          hidden: false,
          lastAction: null,
          needTrackTokenDismiss: !!s && !s.trackToken, // did we have a track token at this time?
          shouldFollow: false, // don't follow if they close x out the window
        }))
      }
      const isNonUser = state.nonUserTrackers[username]
      if (isNonUser) {
        return updateNonUserState(state, username, s => ({
          ...s,
          closed: true,
          hidden: false,
        }))
      }
      return state
    }
    case TrackerGen.updateUsername: {
      const {username} = action.payload
      return updateUserState(state, username, s => s || Constants.initialTrackerState(username))
    }
    case TrackerGen.identifyStarted:
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        error: null,
      }))
    case TrackerGen.updateSelectedTeam: {
      const {selectedTeam, username} = action.payload
      return updateUserState(state, username, s => ({
        ...s,
        selectedTeam,
      }))
    }
    case TrackerGen.updateReason:
      // In case the reason is null, let's use our existing reason
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        reason: (action.payload && action.payload.reason) || (s && s.reason),
      }))
    case TrackerGen.updateTrackToken: {
      const {trackToken} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        trackToken: trackToken,
      }))
    }
    case TrackerGen.setNeedTrackTokenDismiss: {
      const {needTrackTokenDismiss} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        needTrackTokenDismiss,
      }))
    }
    case TrackerGen.waiting: {
      const {waiting} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        waiting,
      }))
    }
    case TrackerGen.setOnFollow: {
      const {username} = action.payload
      return updateUserState(state, username, s => ({
        ...s,
        currentlyFollowing: true,
        lastAction: 'followed',
        reason: `You have followed ${username}.`,
      }))
    }
    case TrackerGen.setOnRefollow: {
      const {username} = action.payload
      return updateUserState(state, username, s => ({
        ...s,
        lastAction: 'refollowed',
        reason: `You have re-followed ${username}.`,
        trackerState: 'normal',
        eldestKidChanged: false,
      }))
    }
    case TrackerGen.setOnUnfollow: {
      const {username} = action.payload
      return updateUserState(state, username, s => ({
        ...s,
        currentlyFollowing: false,
        lastAction: 'unfollowed',
        reason: `You have unfollowed ${username}.`,
      }))
    }
    case TrackerGen.onError: {
      let error = 'There was an error updating your follow status.'
      if (action.payload && action.payload.extraText) {
        error = `There was an error: ${action.payload.extraText}`
      }
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        error,
      }))
    }
    case TrackerGen.updateEldestKidChanged: {
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        eldestKidChanged: true,
      }))
    }
    case TrackerGen.updateProofState: {
      const {username} = action.payload
      return updateUserState(state, username, s => {
        if (!s) {
          return s
        }
        const proofsGeneralState = Constants.overviewStateOfProofs(s.proofs)
        const trackerMessage = Constants.deriveTrackerMessage(
          username,
          s.currentlyFollowing,
          proofsGeneralState
        )
        const reason = trackerMessage || s.reason
        return {
          ...s,
          changed: proofsGeneralState.anyChanged,
          reason,
          shouldFollow: Constants.deriveShouldFollow(proofsGeneralState),
          trackerState: Constants.deriveSimpleProofState(s.eldestKidChanged, proofsGeneralState),
        }
      })
    }
    case TrackerGen.resetProofs:
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        proofs: [],
      }))
    case TrackerGen.setProofs: {
      const {identity, username} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        proofs: Constants.dedupeProofs([
          ...(s ? s.proofs : []),
          ...(identity.revokedDetails || []).map(rv => Constants.revokedProofToProof(rv)),
          ...(identity.proofs || [])
            .map(rp => Constants.remoteProofToProof(username, Constants.checking, rp.proof)),
        ]),
      }))
    }
    case TrackerGen.updatePGPKey: {
      const {pgpFingerprint, kid} = action.payload
      const fingerPrint = Constants.bufferToNiceHexString(pgpFingerprint)
      return updateUserState(state, action.payload.username, s => {
        const url = `https://keybase.io/${s ? s.username : ''}/sigchain`
        const proof = {
          color: 'green',
          // TODO: We don't currently get the sigID so we can't link to the actual sigChain statement. See https://keybase.atlassian.net/browse/CORE-3529
          humanUrl: url,
          id: kid,
          isTracked: s ? s.currentlyFollowing : false,
          mTime: 0,
          meta: null,
          name: fingerPrint,
          profileUrl: url,
          state: 'normal',
          type: 'pgp',
        }

        return {
          ...s,
          proofs: Constants.dedupeProofs(s ? s.proofs.concat([proof]) : [proof]),
        }
      })
    }
    case TrackerGen.updateZcash: {
      const {sigID, address} = action.payload
      return updateUserState(state, action.payload.username, s => {
        const url = `https://keybase.io/${s ? s.username : ''}/sigchain#${sigID}`
        const proof = {
          color: 'green',
          humanUrl: url,
          id: sigID,
          isTracked: s ? s.currentlyFollowing : false,
          mTime: 0,
          meta: null,
          name: address,
          profileUrl: url,
          state: 'normal',
          type: 'zcash',
        }

        return {
          ...s,
          proofs: Constants.dedupeProofs(s ? s.proofs.concat([proof]) : [proof]),
        }
      })
    }
    case TrackerGen.updateBTC: {
      const {sigID, address} = action.payload
      return updateUserState(state, action.payload.username, s => {
        const url = `https://keybase.io/${s ? s.username : ''}/sigchain#${sigID}`
        const proof = {
          color: 'green',
          humanUrl: url,
          id: sigID,
          isTracked: s ? s.currentlyFollowing : false,
          mTime: 0,
          meta: null,
          name: address,
          profileUrl: url,
          state: 'normal',
          type: 'btc',
        }

        return {
          ...s,
          proofs: Constants.dedupeProofs(s ? s.proofs.concat([proof]) : [proof]),
        }
      })
    }
    case TrackerGen.updateProof: {
      const {remoteProof, linkCheckResult, username} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        proofs: Constants.updateProof(username, s ? s.proofs : [], remoteProof, linkCheckResult),
      }))
    }
    case TrackerGen.updateUserInfo: {
      const {userCard, username} = action.payload
      const userInfo = {
        fullname: userCard.fullName,
        followersCount: userCard.followers,
        followingCount: userCard.following,
        followsYou: userCard.theyFollowYou,
        uid: userCard.uid,
        bio: userCard.bio,
        avatar: `https://keybase.io/${username}/picture`,
        location: userCard.location,
        showcasedTeams: (userCard.teamShowcase || []).sort(sortByTeamName),
      }
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        userInfo,
      }))
    }
    case TrackerGen.markActiveIdentifyUi: {
      const {active} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        serverActive: active,
      }))
    }
    case TrackerGen.reportLastTrack: {
      const {tracking} = action.payload
      return updateUserState(state, action.payload.username, s => {
        const proofs = (s ? s.proofs : []).map(
          p => (['btc', 'pgp'].includes(p.type) ? {...p, isTracked: tracking} : p)
        )
        return {
          ...s,
          currentlyFollowing: tracking,
          proofs,
        }
      })
    }
    case TrackerGen.showTracker:
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        closed: false,
        hidden: false,
      }))
    case TrackerGen.remoteDismiss:
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        closed: true,
      }))
    case TrackerGen.setUpdateTrackers: {
      const {trackers, tracking} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        trackersLoaded: true,
        trackers,
        tracking,
      }))
    }
    case TrackerGen.updateFolders: {
      const {tlfs} = action.payload
      return updateUserState(state, action.payload.username, s => ({
        ...s,
        tlfs,
      }))
    }
    case TrackerGen.identifyFinished: {
      if (action.error) {
        const {error} = action.payload
        return updateUserState(state, action.payload.username, s => ({
          ...s,
          error,
          serverActive: false,
        }))
      } else {
        return updateUserState(state, action.payload.username, s => ({
          ...s,
          error: null,
        }))
      }
    }
    // Saga only actions
    case TrackerGen.follow:
    case TrackerGen.getMyProfile:
    case TrackerGen.getProfile:
    case TrackerGen.ignore:
    case TrackerGen.openProofUrl:
    case TrackerGen.parseFriendship:
    case TrackerGen.refollow:
    case TrackerGen.setupTrackerHandlers:
    case TrackerGen.unfollow:
    case TrackerGen.updateTrackers:
      return state
    default:
      // eslint-disable-next-line no-unused-expressions
      (action: empty) // if you get a flow error here it means there's an action you claim to handle but didn't
      return state
  }
}
<|endoftext|>


<commit_before>angular.module('users').controller('UserController', ['$scope', '$http', '$routeParams', 'Authentication', function($scope, $http, $routeParams, Authentication) {

    $scope.collectUserDetails = function() {
    $http.get('/users/' + $routeParams.user_id).success(function(data) {
      $scope.data = data;
    });
  };
}]);
<commit_msg>Send connection request re-added<commit_after>angular.module('users').controller('UserController', ['$scope', '$http', '$routeParams', 'Authentication', function($scope, $http, $routeParams, Authentication) {

    $scope.authentication = Authentication;
    var userRecv = $routeParams.user_id;
    var userSender = $scope.authentication.user.id;

    $scope.collectUserDetails = function() {
    $http.get('/users/' + $routeParams.user_id).success(function(data) {
      $scope.data = data;
    });
  };

  $scope.sendConnection = function() {
    $http.post('user_connection/' + userSender + '/' + userRecv).success(function(data) {
      console.log(data);
      console.log('connection added');
    });
  };
}]);
<|endoftext|>


<commit_before>module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        browserify: {
            dist: {
                files: {
                    'public/js/generated/formathandlers.js': ['clientjs/formathandlers.js'],
                    'public/js/generated/templates.js': ['clientjs/templates.js'],
                },
                options: { }
            }
        },
        less: {
            dist: {
                files: {
                    'public/css/style.css': 'public/css/style.less',
                }
            },
            dist_min: {
                files: {
                    'public/css/style.min.css': 'public/css/style.less',
                },
                options: { yuicompress: true }
            },
        },
        jshint: {
            files: [
                'server.js',
                'routes/*.js',
                'models/*.js',
                'bin/**/*.js',
                'lib/**/*.js',
                'tests/*.js'
            ],
            options: {
                "loopfunc": true,
                "unused": true,
                "sub": true,
                global: {
                    module: true
                }
            }
        },
        mochaTest: {
            test: {
                options: { reporter: 'spec' }
            },
            src: [
                'tests/*.js',
            ]
        },
        coverage: {
            options: {
                reporter: 'html-cov',
                quiet: true,
                captureFile: 'coverage.html'
            },
            src: [ 'tests/*.js' ]
        }
    });

    grunt.loadNpmTasks('grunt-browserify');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');

    grunt.registerTask('default', [ 'browserify', 'less' ]);
};
<commit_msg>Add test task for grunt<commit_after>module.exports = function(grunt) {
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        browserify: {
            dist: {
                files: {
                    'public/js/generated/formathandlers.js': ['clientjs/formathandlers.js'],
                    'public/js/generated/templates.js': ['clientjs/templates.js'],
                },
                options: { }
            }
        },
        less: {
            dist: {
                files: {
                    'public/css/style.css': 'public/css/style.less',
                }
            },
            dist_min: {
                files: {
                    'public/css/style.min.css': 'public/css/style.less',
                },
                options: { yuicompress: true }
            },
        },
        jshint: {
            files: [
                'server.js',
                'routes/*.js',
                'models/*.js',
                'bin/**/*.js',
                'lib/**/*.js',
                'tests/*.js'
            ],
            options: {
                "loopfunc": true,
                "unused": true,
                "sub": true,
                global: {
                    module: true
                }
            }
        },
        mochaTest: {
            test: {
                options: { reporter: 'spec' }
            },
            src: [
                'tests/*.js',
            ]
        },
        coverage: {
            options: {
                reporter: 'html-cov',
                quiet: true,
                captureFile: 'coverage.html'
            },
            src: [ 'tests/*.js' ]
        }
    });

    grunt.loadNpmTasks('grunt-browserify');
    grunt.loadNpmTasks('grunt-contrib-less');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-mocha-test');

    grunt.registerTask('test', [ 'mochaTest' ])
    grunt.registerTask('default', [ 'browserify', 'less' ]);
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        concat: {
            options: {
                separator: '\n\n'
            },
            libs: {
                src: [
                    'public/assets/js/libs/jquery.min.js',
                    'public/assets/js/libs/velocity.min.js',
                    'public/assets/js/libs/bootstrap.min.js',
                    'public/assets/js/libs/select2.min.js',
                    'public/assets/js/libs/autosize.min.js',
                    'public/assets/js/libs/spin.min.js',
                    'public/assets/js/libs/jquery.cropit.js',
                    'public/assets/js/libs/add-to-any.min.js'
                ],
                dest: 'public/assets/dist/js/libs.js'
            },
            linken: {
                src: [
                    'public/assets/js/common.js',
                    'public/assets/js/add-pane.js',
                    'public/assets/js/control-pane.js',
                    'public/assets/js/item-pane.js',
                    'public/assets/js/discover.js'
                ],
                dest: 'public/assets/dist/js/linken.js'
            },
            dist: {
                src: ['public/assets/dist/js/libs.js', 'public/assets/dist/js/linken.js'],
                dest: 'public/assets/dist/js/linken-dist.js'
            }
        },
        uglify: {
            options: {
                banner: '/*! Linken <%= grunt.template.today("yyyy-mm-dd") %> */\n'
            },
            build: {
                src: [
                    'public/assets/dist/js/linken-dist.js'
                ],
                dest: 'public/assets/dist/js/linken.min.js'
            }
        },
        watch: {
            scripts: {
                files: ['resources/assets/sass/*.scss'],
                tasks: ['sass'],
                options: {
                    spawn: false,
                    interval: 3007
                }
            }
        },
        sass: {
            options: {
                sourceMap: false
            },
            dist: {
                files: {
                    'public/assets/css/base.css': 'resources/assets/sass/base.scss'
                }
            }
        },
        processhtml: {
            options: {},
            dist: {
                files: {
                    'resources/views/layouts/layoutDist.blade.php': ['resources/views/layouts/layout.blade.php']
                }
            }
        },
        replace: {
            dist: {
                src: ['public/assets/dist/css/linken.min.css'],
                overwrite: true,
                replacements: [
                    {
                        from: '../images',
                        to: '../../images'
                    },
                    {
                        from: '../fonts',
                        to: '../../fonts'
                    }
                ]
            }
        },
        cssmin: {
            options: {
                shorthandCompacting: false,
                roundingPrecision: -1
            },
            target: {
                files: {
                    'public/assets/dist/css/linken.min.css': [
                        'public/assets/css/google-fonts-Montserrat.css',
                        'public/assets/css/bootstrap.min.css',
                        'public/assets/css/select2.min.css',
                        'public/assets/css/base.css'
                    ]
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-sass');
    grunt.loadNpmTasks('grunt-processhtml');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-text-replace');

    grunt.registerTask('default', ['sass']);
    grunt.registerTask('dist', ['concat:libs', 'concat:linken', 'concat:dist', 'uglify', 'sass', 'processhtml', 'cssmin', 'replace']);

};
<commit_msg>forgot to add welcome.js to grunt<commit_after>module.exports = function(grunt) {

    // Project configuration.
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        concat: {
            options: {
                separator: '\n\n'
            },
            libs: {
                src: [
                    'public/assets/js/libs/jquery.min.js',
                    'public/assets/js/libs/velocity.min.js',
                    'public/assets/js/libs/bootstrap.min.js',
                    'public/assets/js/libs/select2.min.js',
                    'public/assets/js/libs/autosize.min.js',
                    'public/assets/js/libs/spin.min.js',
                    'public/assets/js/libs/jquery.cropit.js',
                    'public/assets/js/libs/add-to-any.min.js'
                ],
                dest: 'public/assets/dist/js/libs.js'
            },
            linken: {
                src: [
                    'public/assets/js/common.js',
                    'public/assets/js/add-pane.js',
                    'public/assets/js/control-pane.js',
                    'public/assets/js/item-pane.js',
                    'public/assets/js/discover.js',
                    'public/assets/js/welcome.js'
                ],
                dest: 'public/assets/dist/js/linken.js'
            },
            dist: {
                src: ['public/assets/dist/js/libs.js', 'public/assets/dist/js/linken.js'],
                dest: 'public/assets/dist/js/linken-dist.js'
            }
        },
        uglify: {
            options: {
                banner: '/*! Linken <%= grunt.template.today("yyyy-mm-dd") %> */\n'
            },
            build: {
                src: [
                    'public/assets/dist/js/linken-dist.js'
                ],
                dest: 'public/assets/dist/js/linken.min.js'
            }
        },
        watch: {
            scripts: {
                files: ['resources/assets/sass/*.scss'],
                tasks: ['sass'],
                options: {
                    spawn: false,
                    interval: 3007
                }
            }
        },
        sass: {
            options: {
                sourceMap: false
            },
            dist: {
                files: {
                    'public/assets/css/base.css': 'resources/assets/sass/base.scss'
                }
            }
        },
        processhtml: {
            options: {},
            dist: {
                files: {
                    'resources/views/layouts/layoutDist.blade.php': ['resources/views/layouts/layout.blade.php']
                }
            }
        },
        replace: {
            dist: {
                src: ['public/assets/dist/css/linken.min.css'],
                overwrite: true,
                replacements: [
                    {
                        from: '../images',
                        to: '../../images'
                    },
                    {
                        from: '../fonts',
                        to: '../../fonts'
                    }
                ]
            }
        },
        cssmin: {
            options: {
                shorthandCompacting: false,
                roundingPrecision: -1
            },
            target: {
                files: {
                    'public/assets/dist/css/linken.min.css': [
                        'public/assets/css/google-fonts-Montserrat.css',
                        'public/assets/css/bootstrap.min.css',
                        'public/assets/css/select2.min.css',
                        'public/assets/css/base.css'
                    ]
                }
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-sass');
    grunt.loadNpmTasks('grunt-processhtml');
    grunt.loadNpmTasks('grunt-contrib-cssmin');
    grunt.loadNpmTasks('grunt-text-replace');

    grunt.registerTask('default', ['sass']);
    grunt.registerTask('dist', ['concat:libs', 'concat:linken', 'concat:dist', 'uglify', 'sass', 'processhtml', 'cssmin', 'replace']);

};
<|endoftext|>