<commit_before>var ZonaLocation    = require('../app/models/zonaLocation');
var Zona            = require('../app/models/zona');
var mongoose = require('mongoose');

module.exports = function(app, passport) {

    app.get('/api/posts', isLoggedIn, function(req, res) {
        ZonaLocation.find({}, function(err, posts) {
            if (err)
                return res.status(400).send(err);
            res.send(posts);
        }).sort({createDate: 1});
    });

    app.post('/api/post', isLoggedIn, function(req, res) {
        // create the user
        var newPost         = new ZonaLocation();
        Zona.findOne({name:req.body.zonaName}, function(err, zona) {
            if (err)
                return res.status(400).send(err);
            if (zona) {
                // si la zona ya existe
                newPost.zoneId      = zona._id;
                newPost.zoneName    = req.body.zonaName;
                newPost.description = req.body.description;
                newPost.user        = req.body.user;
                newPost.images      = req.body.images;
                newPost.status      = req.body.status;
                newPost.save(function(err) {
                    if (err)
                        return res.status(400).send(err);
                    var update = {};
                    if(newPost.status){
                        update = { $inc: { ranking: 1 }};
                    } else{
                        update = { $inc: { ranking: -1 }};
                    }
                    Zona.update({ _id: zona._id }, update, {}, function(err, posts) {
                        if (err)
                            return res.status(400).send(err);
                        //console.log(posts)
                    });
                    return res.status(201).send(newPost);
                });
            } else {
                // esto si es una nueva zona
                var newZona            = new Zona();
                newZona.name    = req.body.zonaName;
                if(newPost.status){
                    newZona.ranking = 1;
                } else{
                    newZona.ranking = 0;
                }
                newZona.save(function(err) {
                    if (err)
                        return res.status(400).send(err);
                    newPost.zoneId      = newZona._id;
                    newPost.zoneName    = req.body.zonaName;
                    newPost.description = req.body.description;
                    newPost.user        = req.body.user;
                    newPost.images      = req.body.images;
                    newPost.status      = req.body.status;
                    newPost.save(function(err) {
                        if (err)
                            return res.status(400).send(err);
                        return res.status(201).send(newPost);
                    });
                });
                // if there is a user id already but no token (user was linked at one point and then removed)
            }
        });
    });

    app.get('/api/search/:zoneName', isLoggedIn, function(req, res) {
        ZonaLocation.find({zoneName:req.params.zoneName}, function(err, posts) {
            if (err)
                return res.status(400).send(err);
                // si la zona ya existe
            return res.status(200).send(posts);
        });
    });
};

// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
    if (req.isAuthenticated())
        return next();

    //res.redirect('/');
    return next();
}
<commit_msg>fix in name zona<commit_after>var ZonaLocation    = require('../app/models/zonaLocation');
var Zona            = require('../app/models/zona');
var mongoose = require('mongoose');

module.exports = function(app, passport) {

    app.get('/api/posts', isLoggedIn, function(req, res) {
        ZonaLocation.find({}, function(err, posts) {
            if (err)
                return res.status(400).send(err);
            res.send(posts);
        }).sort({createDate: 1});
    });

    app.post('/api/post', isLoggedIn, function(req, res) {
        // create the user
        var newPost         = new ZonaLocation();
        Zona.findOne({name:req.body.zoneName}, function(err, zona) {
            if (err)
                return res.status(400).send(err);
            if (zona) {
                // si la zona ya existe
                newPost.zoneId      = zona._id;
                newPost.zoneName    = req.body.zoneName;
                newPost.description = req.body.description;
                newPost.user        = req.body.user;
                newPost.images      = req.body.images;
                newPost.status      = req.body.status;
                newPost.save(function(err) {
                    if (err)
                        return res.status(400).send(err);
                    var update = {};
                    if(newPost.status){
                        update = { $inc: { ranking: 1 }};
                    } else{
                        update = { $inc: { ranking: -1 }};
                    }
                    Zona.update({ _id: zona._id }, update, {}, function(err, posts) {
                        if (err)
                            return res.status(400).send(err);
                        //console.log(posts)
                    });
                    return res.status(201).send(newPost);
                });
            } else {
                // esto si es una nueva zona
                var newZona            = new Zona();
                newZona.name    = req.body.zoneName;
                if(newPost.status){
                    newZona.ranking = 1;
                } else{
                    newZona.ranking = 0;
                }
                newZona.save(function(err) {
                    if (err)
                        return res.status(400).send(err);
                    newPost.zoneId      = newZona._id;
                    newPost.zoneName    = req.body.zoneName;
                    newPost.description = req.body.description;
                    newPost.user        = req.body.user;
                    newPost.images      = req.body.images;
                    newPost.status      = req.body.status;
                    newPost.save(function(err) {
                        if (err)
                            return res.status(400).send(err);
                        return res.status(201).send(newPost);
                    });
                });
                // if there is a user id already but no token (user was linked at one point and then removed)
            }
        });
    });

    app.get('/api/search/:zoneName', isLoggedIn, function(req, res) {
        ZonaLocation.find({zoneName:req.params.zoneName}, function(err, posts) {
            if (err)
                return res.status(400).send(err);
                // si la zona ya existe
            return res.status(200).send(posts);
        });
    });
};

// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
    if (req.isAuthenticated())
        return next();

    //res.redirect('/');
    return next();
}
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

'use strict'

only support node 6+
const verCompare = require('compare-versions')
if( verCompare(process.versions.node, '6.0.0') < 0 ) throw new Error('jade-press only support nodejs version 6.0.0+, please update your nodejs')

//imports
const
koa = require('koa')
,compress = require('koa-compress')
,serve = require('koa-static')
,conditional = require('koa-conditional-get')
,etag = require('koa-etag')
,Jade = require('koa-jade')
,bodyParser = require('koa-bodyparser')
,mount = require('koa-mount')
,router = require('koa-router')
,MongoStore = require('koa-generic-session-mongo')
,session = require('koa-generic-session')
,path = require('path')
,fs = require('fs')
,_ = require('lodash')
,tools = require('../lib/tools')
,oneYear = 1000 * 60 * 60 * 24 * 365
,plugins = require('../lib/plugins').plugins
,pack = require('../package.json')

exports.publicExports = {
	tools: tools
}

//middlewares
exports.middlewares = [

	conditional()

	// parse application/x-www-form-urlencoded
	,bodyParser()

	,etag()

	,compress({
		threshold: 2048
		,flush: require('zlib').Z_SYNC_FLUSH
	})

	,serve( path.resolve(__dirname, '../public'), {
		maxAge: oneYear
	})

	,serve( process.cwd() + '/bower_components', {
		maxAge: oneYear
	})

]

exports.start = function() {

	let

	setting = require('./setting')
	,local = require('./local')
	,port = local.port
	,routes = require('../route/')

	// all environments
	,app = koa()
	,middlewares = exports.middlewares

	//middleware
	app.keys = [setting.secret]

	//load theme res
	let themeResPath = setting.theme.path?setting.theme.path + '/public'
											:
											process.cwd() + '/node_modules/' + setting.theme + '/public'
	try {
		let themeRes = fs.accessSync(themeResPath)
		let op = serve( themeResPath, {
			maxAge: oneYear
		})
		middlewares.push( mount('/' + (setting.theme.staticAlias || setting.theme.name || setting.theme), op) )
	} catch(e) {
		console.warn(setting.theme, 'has no public')
	}

	//view engine
	var jade = new Jade({
		viewPath: path.resolve(__dirname, '..')
		,debug: false
		,pretty: false
		,compileDebug: local.env !== 'production'
		,locals: { _:_ }
		//basedir: 'path/for/jade/extends',
		,noCache: local.env !== 'production'
	})

	middlewares.push(jade.middleware)

	//session
	middlewares.push(session({
		key: setting.sessionName
		,rolling: true
		,store: new MongoStore(setting.mongoStoreOptions)
	}))

	//routes
	middlewares = middlewares.concat(routes.middlewares)

	//exntend
	exports.publicExports.middlewares = middlewares
	exports.middlewares = middlewares
	tools.extendLib(__filename, exports, plugins)

	//now use middlewares
	for(let i = 0, len = exports.middlewares.length;i < len;i ++) {
		app.use(exports.middlewares[i])
	}

	return app
}

exports.init = function* (config) {

	let
	setting = require('./setting')
	,local = require('./local')
	Object.assign(setting, config.setting)
	Object.assign(local, config.local)

	let
	tools = require('../lib/tools')
	,log = tools.log
	,err = tools.err
	,dbRef = require('../lib/db')
	,plugins = require('../lib/plugins')
	,mail = require('../lib/mail')

	//load db
	yield dbRef.init()

	var db = dbRef.db

	var hasMeta = yield db.collection('meta').findOne()

	tools.loadTheme404500()

	setting.mailServiceReady = yield mail.checkMailService()

	if(!hasMeta) yield require('../lib/init').init(config.init)

	yield require('../lib/update').check()

	local.themeVersion = setting.theme.version?setting.theme.version:(setting.plugins[setting.theme] || '*')

	plugins.loadPlugins()

	let app = exports.start()

	log('jade-press', 'version', pack.version)

	return Promise.resolve(app)

}

<commit_msg>fix typo<commit_after>
/**
 * Module dependencies.
 */

'use strict'

//only support node 6+
const verCompare = require('compare-versions')
if( verCompare(process.versions.node, '6.0.0') < 0 ) throw new Error('jade-press only support nodejs version 6.0.0+, please update your nodejs')

//imports
const
koa = require('koa')
,compress = require('koa-compress')
,serve = require('koa-static')
,conditional = require('koa-conditional-get')
,etag = require('koa-etag')
,Jade = require('koa-jade')
,bodyParser = require('koa-bodyparser')
,mount = require('koa-mount')
,router = require('koa-router')
,MongoStore = require('koa-generic-session-mongo')
,session = require('koa-generic-session')
,path = require('path')
,fs = require('fs')
,_ = require('lodash')
,tools = require('../lib/tools')
,oneYear = 1000 * 60 * 60 * 24 * 365
,plugins = require('../lib/plugins').plugins
,pack = require('../package.json')

exports.publicExports = {
	tools: tools
}

//middlewares
exports.middlewares = [

	conditional()

	// parse application/x-www-form-urlencoded
	,bodyParser()

	,etag()

	,compress({
		threshold: 2048
		,flush: require('zlib').Z_SYNC_FLUSH
	})

	,serve( path.resolve(__dirname, '../public'), {
		maxAge: oneYear
	})

	,serve( process.cwd() + '/bower_components', {
		maxAge: oneYear
	})

]

exports.start = function() {

	let

	setting = require('./setting')
	,local = require('./local')
	,port = local.port
	,routes = require('../route/')

	// all environments
	,app = koa()
	,middlewares = exports.middlewares

	//middleware
	app.keys = [setting.secret]

	//load theme res
	let themeResPath = setting.theme.path?setting.theme.path + '/public'
											:
											process.cwd() + '/node_modules/' + setting.theme + '/public'
	try {
		let themeRes = fs.accessSync(themeResPath)
		let op = serve( themeResPath, {
			maxAge: oneYear
		})
		middlewares.push( mount('/' + (setting.theme.staticAlias || setting.theme.name || setting.theme), op) )
	} catch(e) {
		console.warn(setting.theme, 'has no public')
	}

	//view engine
	var jade = new Jade({
		viewPath: path.resolve(__dirname, '..')
		,debug: false
		,pretty: false
		,compileDebug: local.env !== 'production'
		,locals: { _:_ }
		//basedir: 'path/for/jade/extends',
		,noCache: local.env !== 'production'
	})

	middlewares.push(jade.middleware)

	//session
	middlewares.push(session({
		key: setting.sessionName
		,rolling: true
		,store: new MongoStore(setting.mongoStoreOptions)
	}))

	//routes
	middlewares = middlewares.concat(routes.middlewares)

	//exntend
	exports.publicExports.middlewares = middlewares
	exports.middlewares = middlewares
	tools.extendLib(__filename, exports, plugins)

	//now use middlewares
	for(let i = 0, len = exports.middlewares.length;i < len;i ++) {
		app.use(exports.middlewares[i])
	}

	return app
}

exports.init = function* (config) {

	let
	setting = require('./setting')
	,local = require('./local')
	Object.assign(setting, config.setting)
	Object.assign(local, config.local)

	let
	tools = require('../lib/tools')
	,log = tools.log
	,err = tools.err
	,dbRef = require('../lib/db')
	,plugins = require('../lib/plugins')
	,mail = require('../lib/mail')

	//load db
	yield dbRef.init()

	var db = dbRef.db

	var hasMeta = yield db.collection('meta').findOne()

	tools.loadTheme404500()

	setting.mailServiceReady = yield mail.checkMailService()

	if(!hasMeta) yield require('../lib/init').init(config.init)

	yield require('../lib/update').check()

	local.themeVersion = setting.theme.version?setting.theme.version:(setting.plugins[setting.theme] || '*')

	plugins.loadPlugins()

	let app = exports.start()

	log('jade-press', 'version', pack.version)

	return Promise.resolve(app)

}

<|endoftext|>


<commit_before>const routes = require('./routes')

module.exports = {
  routes,
  currentModal: '',
  modalConfig: {},
  message: 'Welcome to Front-Vue!',
  messages: {}
}
<commit_msg>Changes home page subtitle.<commit_after>const routes = require('./routes')

module.exports = {
  routes,
  currentModal: '',
  modalConfig: {},
  message: 'Welcome to Feathers-Vue',
  messages: {}
}
<|endoftext|>


<commit_before>var AVALON_NANO_VENDOR_ID = 10737; //0x29f1;
var AVALON_NANO_PRODUCT_ID = 13297; //0x33f1;
var FILTERS = {
	filters: [{
		vendorId: AVALON_NANO_VENDOR_ID,
		productId: AVALON_NANO_PRODUCT_ID
	}]};

var P_DETECT = 0x0a;
var P_REQUIRE = 0x12;
var P_WORK = 0x1c;
var P_ACKDETECT = 0x19;
var P_NONCE = 0x17;

var CANAAN_HEAD1 = 0x41;
var CANAAN_HEAD2 = 0x56;

var CRC16_TABLE = [
	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
];

var LOG1_STYLE = 'color: green';
var LOG2_STYLE = 'color: blue';
var DEBUG_STYLE = 'color: black';

var check_version = function(version) {
	return version.slice(0, 15) === '3U1410-82418d6+';
};

var crc16 = function(arraybuffer) {
	var data = new Uint8Array(arraybuffer);
	var crc = 0;
	var i = 0;
	var len = data.byteLength;

	while (len-- > 0)
		crc = CRC16_TABLE[((crc >>> 8) ^ data[i++]) & 0xff] ^ (crc << 8);

	return crc;
};

var ab2str = function(arraybuffer) {
	var view = new Uint8Array(arraybuffer);
	var str = '';
	for (var v of view)
		str += ('0' + v.toString(16)).slice(-2);
	return str;
};

var mm_encode = function(type, idx, cnt, data) {
	var pkg = new ArrayBuffer(39);
	var view = new Uint8Array(pkg);
	var view_data = new Uint8Array(data);

	view[0] = CANAAN_HEAD1;
	view[1] = CANAAN_HEAD2;
	view[2] = type;
	view[3] = idx;
	view[4] = cnt;

	for (var i = 0; i < 32; i++)
		view[i + 5] = view_data[i] || 0;
	var crc = crc16(pkg.slice(5, 37));
	view[37] = (crc & 0xff00) >>> 8;
	view[38] = crc & 0x00ff;

	return pkg;
};

var mm_decode = function(pkg) {
	var view = new Uint8Array(pkg);

	var head1 = view[0];
	var head2 = view[1];
	if (head1 !== CANAAN_HEAD1 || head2 !== CANAAN_HEAD2) {
		console.warn("Wrong head.");
		return false;
	}
	var cmd = view[2];
	var idx = view[3];
	var cnt = view[4];

	var data = pkg.slice(5, 37);
	var crc_l = view[37];
	var crc_h = view[38];
	var crc = crc16(data);
	if (crc_l !== ((crc & 0xff00) >>> 8) || crc_h !== (crc & 0x00ff)) {
		console.warn("Wrong CRC.");
		return false;
	}

	switch (cmd) {
		case P_ACKDETECT:
			var version = '';
			for (var c of new Uint8Array(data))
				version += String.fromCharCode(c);
			return {type: P_ACKDETECT, version: version};
		case P_NONCE:
			var nonce = new DataView(data).getUint32(0, false);
			return {type: P_NONCE, nonce: nonce};
		default:
			return data;
	}
};
<commit_msg>APP: Add getwork pool data converter<commit_after>var AVALON_NANO_VENDOR_ID = 10737; //0x29f1;
var AVALON_NANO_PRODUCT_ID = 13297; //0x33f1;
var FILTERS = {
	filters: [{
		vendorId: AVALON_NANO_VENDOR_ID,
		productId: AVALON_NANO_PRODUCT_ID
	}]};

var P_DETECT = 0x0a;
var P_REQUIRE = 0x12;
var P_WORK = 0x1c;
var P_ACKDETECT = 0x19;
var P_NONCE = 0x17;

var CANAAN_HEAD1 = 0x41;
var CANAAN_HEAD2 = 0x56;

var CRC16_TABLE = [
	0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
	0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
	0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
	0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
	0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
	0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
	0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
	0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
	0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
	0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
	0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
	0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
	0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
	0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
	0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
	0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
	0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
	0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
	0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
	0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
	0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
	0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
	0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
	0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
	0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
	0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
	0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
	0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
	0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
	0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
	0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
	0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
];

var LOG1_STYLE = 'color: green';
var LOG2_STYLE = 'color: blue';
var DEBUG_STYLE = 'color: black';

var check_version = function(version) {
	return version.slice(0, 15) === '3U1410-82418d6+';
};

var crc16 = function(arraybuffer) {
	var data = new Uint8Array(arraybuffer);
	var crc = 0;
	var i = 0;
	var len = data.byteLength;

	while (len-- > 0)
		crc = CRC16_TABLE[((crc >>> 8) ^ data[i++]) & 0xff] ^ (crc << 8);

	return crc;
};

var ab2str = function(arraybuffer) {
	var view = new Uint8Array(arraybuffer);
	var str = '';
	for (var v of view)
		str += ('0' + v.toString(16)).slice(-2);
	return str;
};

var mm_encode = function(type, idx, cnt, data) {
	var pkg = new ArrayBuffer(39);
	var view = new Uint8Array(pkg);
	var view_data = new Uint8Array(data);

	view[0] = CANAAN_HEAD1;
	view[1] = CANAAN_HEAD2;
	view[2] = type;
	view[3] = idx;
	view[4] = cnt;

	for (var i = 0; i < 32; i++)
		view[i + 5] = view_data[i] || 0;
	var crc = crc16(pkg.slice(5, 37));
	view[37] = (crc & 0xff00) >>> 8;
	view[38] = crc & 0x00ff;

	return pkg;
};

var mm_decode = function(pkg) {
	var view = new Uint8Array(pkg);

	var head1 = view[0];
	var head2 = view[1];
	if (head1 !== CANAAN_HEAD1 || head2 !== CANAAN_HEAD2) {
		console.warn("Wrong head.");
		return false;
	}
	var cmd = view[2];
	var idx = view[3];
	var cnt = view[4];

	var data = pkg.slice(5, 37);
	var crc_l = view[37];
	var crc_h = view[38];
	var crc = crc16(data);
	if (crc_l !== ((crc & 0xff00) >>> 8) || crc_h !== (crc & 0x00ff)) {
		console.warn("Wrong CRC.");
		return false;
	}

	switch (cmd) {
		case P_ACKDETECT:
			var version = '';
			for (var c of new Uint8Array(data))
				version += String.fromCharCode(c);
			return {type: P_ACKDETECT, version: version};
		case P_NONCE:
			var nonce = new DataView(data).getUint32(0, false);
			return {type: P_NONCE, nonce: nonce};
		default:
			return data;
	}
};

var gw_pool2raw = function(midstat, data) {
	var raw = new ArrayBuffer(64);
	var view = new DataView(raw);
	var i;

	data = data.slice(128, 128 + 24);
	for (i = 0; i < 32; i++)
		view.setUint8(31 - i, parseInt(midstat.slice(i * 2, i * 2 + 2), 16), false);
	for (i = 0; i < 12; i++)
		view.setUint8(63 - i, parseInt(data.slice(i * 2, i * 2 + 2), 16), false);
	return raw;
};
<|endoftext|>


<commit_before>import assignSafe from '../util/assign-safe';
import data from '../util/data';
import events from '../lifecycle/events';
import properties from '../lifecycle/properties';
import protos from '../util/protos';
import registry from '../global/registry';
import walkTree from '../util/walk-tree';

let elProto = window.Element.prototype;
let oldSetAttribute = elProto.setAttribute;
let oldRemoveAttribute = elProto.removeAttribute;

function applyPrototype (proto) {
  let prototypes = protos(proto);
  return function () {
    prototypes.forEach(proto => {
      if (!proto.isPrototypeOf(this)) {
        assignSafe(this, proto);
      }
    });
  };
}

function patchAttributeMethods (elem) {
  elem.setAttribute = function (name, newValue) {
    let oldValue = this.getAttribute(name);
    oldSetAttribute.call(elem, name, newValue);
    elem.attributeChangedCallback(name, oldValue, String(newValue));
  };

  elem.removeAttribute = function (name) {
    let oldValue = this.getAttribute(name);
    oldRemoveAttribute.call(elem, name);
    elem.attributeChangedCallback(name, oldValue, null);
  };
}

function callCreatedOnDescendants (elem, id) {
  walkTree(elem.childNodes, function (child) {
    registry.find(child).forEach(Ctor => Ctor.prototype.createdCallback.call(child));
  }, function (child) {
    return !data(child, id).created;
  });
}

function callUpdateOnProperties (opts) {
  let props = opts.properties || {};
  let names = Object.keys(props);
  return function (elem) {
    names.forEach(function (name) {
      let update = props[name].update;
      update && update.call(elem, elem[name]);
    });
  };
}

function markAsResolved (elem, resolvedAttribute, unresolvedAttribute) {
  elem.removeAttribute(unresolvedAttribute);
  elem.setAttribute(resolvedAttribute, '');
}

export default function (opts) {
  let created = opts.created;
  let isNative = opts.isNative;
  let initProps = callUpdateOnProperties(opts);
  let prototype = applyPrototype(opts.prototype);
  let ready = opts.ready;

  return function () {
    let info = data(this, opts.id);
    let isResolved = this.hasAttribute(opts.resolvedAttribute);

    if (info.created) return;
    info.created = true;

    isNative || patchAttributeMethods(this);
    isNative || prototype.call(this);
    properties.call(this, opts.properties);
    events.call(this, opts.events);
    opts.created && created.call(this);
    callCreatedOnDescendants(this, opts.id);
    initProps(this);
    opts.ready && ready.call(this);
    isResolved || markAsResolved(this, opts.resolvedAttribute, opts.unresolvedAttribute);
  };
}
<commit_msg>Better name for calling update on props. Fix breaking test where no args are passed to the prop.<commit_after>import assignSafe from '../util/assign-safe';
import data from '../util/data';
import events from '../lifecycle/events';
import properties from '../lifecycle/properties';
import protos from '../util/protos';
import registry from '../global/registry';
import walkTree from '../util/walk-tree';

let elProto = window.Element.prototype;
let oldSetAttribute = elProto.setAttribute;
let oldRemoveAttribute = elProto.removeAttribute;

function applyPrototype (proto) {
  let prototypes = protos(proto);
  return function () {
    prototypes.forEach(proto => {
      if (!proto.isPrototypeOf(this)) {
        assignSafe(this, proto);
      }
    });
  };
}

function patchAttributeMethods (elem) {
  elem.setAttribute = function (name, newValue) {
    let oldValue = this.getAttribute(name);
    oldSetAttribute.call(elem, name, newValue);
    elem.attributeChangedCallback(name, oldValue, String(newValue));
  };

  elem.removeAttribute = function (name) {
    let oldValue = this.getAttribute(name);
    oldRemoveAttribute.call(elem, name);
    elem.attributeChangedCallback(name, oldValue, null);
  };
}

function callCreatedOnDescendants (elem, id) {
  walkTree(elem.childNodes, function (child) {
    registry.find(child).forEach(Ctor => Ctor.prototype.createdCallback.call(child));
  }, function (child) {
    return !data(child, id).created;
  });
}

function createCallUpdateOnProperties (opts) {
  let props = opts.properties || {};
  let names = Object.keys(props);
  return function (elem) {
    names.forEach(function (name) {
      let prop = props[name];
      let update = prop && prop.update;
      update && update.call(elem, elem[name]);
    });
  };
}

function markAsResolved (elem, resolvedAttribute, unresolvedAttribute) {
  elem.removeAttribute(unresolvedAttribute);
  elem.setAttribute(resolvedAttribute, '');
}

export default function (opts) {
  let created = opts.created;
  let isNative = opts.isNative;
  let callUpdateOnProperties = createCallUpdateOnProperties(opts);
  let prototype = applyPrototype(opts.prototype);
  let ready = opts.ready;

  return function () {
    let info = data(this, opts.id);
    let isResolved = this.hasAttribute(opts.resolvedAttribute);

    if (info.created) return;
    info.created = true;

    isNative || patchAttributeMethods(this);
    isNative || prototype.call(this);
    properties.call(this, opts.properties);
    events.call(this, opts.events);
    opts.created && created.call(this);
    callCreatedOnDescendants(this, opts.id);
    callUpdateOnProperties(this);
    opts.ready && ready.call(this);
    isResolved || markAsResolved(this, opts.resolvedAttribute, opts.unresolvedAttribute);
  };
}
<|endoftext|>


<commit_before>'use strict'
var ErrorStackParser = require('error-stack-parser')
var TRACE_SIZE = 7
var rejectionStack = null
var context = {stack: null, previousStack: null}
var asapRoot = require('path').dirname(require.resolve('asap'))

exports.init = function () {
	var Promise = require('./promise')

	// Captures the current stack info and pushes it onto the stack trace.
	// Optionally trims a certain number of lines from the stack info.
	Promise.prototype._addStackTrace = _addStackTrace
}

// Used before an asynchronous callback.
exports.setContext = function (promise, deferred) {
	context.stack = deferred.promise._trace
	context.previousStack = promise._trace
}
// Used after an asynchronous callback.
exports.releaseContext = function () {
	context.stack = null
	context.previousStack = null
}

// Upgrades a function returned by Promise#_rejector(), so that the rejected
// promise receives the stack trace of the promise that handled its rejection.
// Rejector functions are not allowed to throw, so if something goes wrong, we
// reject the promise with a FatalError.
exports.upgradeRejector = function (rej) {
	return function (err) {
		if (!context.previousStack) {
			err = new SyntaxError('This rejector can only be used within an asynchronous callback.')
			err.name = 'FatalError'
		} else {
			try {
				exports.setRejectionStack(context.previousStack)
			} catch (e) {
				err = e
				err.name = 'FatalError'
			}
		}
		return rej(err)
	}
}

// By setting this, the next promise that is rejected will have this stack.
exports.setRejectionStack = function (stack) {
	if (!(stack instanceof _Stack)) {
		throw new TypeError('Expected argument to be a Stack object.')
	}
	if (rejectionStack) {
		throw new SyntaxError('Invoked .setRejectionStack() twice before a promise was rejected.')
	}
	rejectionStack = stack
}
// Returns whether there is a rejection stack to use.
exports.useRejectionStack = function () {
	var temp = rejectionStack
	rejectionStack = null
	return temp
}

function _addStackTrace(trim) {
	var stackPoint = captureStackPoint(_addStackTrace)
	this._trace = new _Stack(stackPoint, this._trace, trim)
	if (context.stack) {
		var end = this._trace
		while (end.parent) {end = end.parent}
		end.parent = context.stack
	}
	if (this._trace.parent) {
		cleanStackTrace(this._trace)
	}
}

function _Stack(stackPoint, parent, trim) {
	setNonEnumerable(this, 'stackPoint', stackPoint)
	setNonEnumerable(this, 'parent', parent)
	setNonEnumerable(this, 'trim', trim >>> 0)
}
_Stack.prototype.getTrace = function () {
	var point = this
	var stacks = []
	do {
		stacks.push(point)
		point = point.parent
	} while (point)
	return stacks.map(formatStack, {count: 0})
		.filter(function (str) {return !!str})
		.join('\nFrom previous event:\n') + '\n'
}

function setNonEnumerable(obj, prop, value) {
	Object.defineProperty(obj, prop, {
		value: value,
		enumerable: false,
		configurable: true,
		writable: true
	})
}

if (typeof Error.captureStackTrace === 'function') {
	var captureStackPoint = function (caller) {
		var temp = {}
		Error.captureStackTrace(temp, caller)
		return temp.stack.replace(/^.*\n?/, '')
	}
} else {
	var captureStackPoint = function () {
		try {
			throw new Error('YOU SHOULD NEVER SEE THIS')
		} catch (err) {
			if (!err.stack || typeof err.stack !== 'string') {
				throw new Error('Could not generate stack trace.')
			}
			var message = String(err)
			var indexOfMessage = err.stack.indexOf(message)
			if (indexOfMessage === -1) {
				return err.stack
			}
			return err.stack.slice(indexOfMessage + message.length)
				.replace(/^\n*/, '')
				.replace(/^.*\n?.*\n?/, '')
		}
	}
}

function cleanStackTrace(point) {
	var stacks = 0
	var maxPoints = TRACE_SIZE * 2
	while (point) {
		if (++stacks === maxPoints) {
			point.parent = undefined
			break
		}
		point = point.parent
	}
}

function formatStack(stack, index, allStacks) {
	if (!stack.stackPoint || this.count === TRACE_SIZE) {
		return ''
	}

	var processed = []
	var parsedLines = ErrorStackParser.parse({stack: stack.stackPoint})
	var lines = stack.stackPoint.split('\n')
	var lineCount = lines.length
	if (lineCount !== parsedLines.length) {
		this.count += 1
		return '[Failed to parse stack trace]'
	}

	for (var i=stack.trim; i<lineCount; ++i) {
		var parsedLine = parsedLines[i]
		var fullPath = parsedLine.fileName || ''
		if (fullPath.indexOf(asapRoot) === 0) {
			break
		}
		if (fullPath.indexOf(__dirname) !== 0) {
			processed.push(shrinkPath(lines[i], fullPath))
		}
	}

	if (processed.length) {
		this.count += 1
		return processed.join('\n')
	}
	return ''
}

function shrinkPath(line, fullPath) {
	if (fullPath && line.length > 80) {
		var parts = fullPath.split(/[/\\]/)
		var originalLine = line
		var tries = 0
		do {
			line = originalLine.replace(fullPath, '...' + parts.slice(++tries).join('/'))
		} while (line.length > 80 && parts.length - tries > 2)
	}
	return line
}
<commit_msg>tweaked edge case<commit_after>'use strict'
var ErrorStackParser = require('error-stack-parser')
var TRACE_SIZE = 7
var rejectionStack = null
var context = {stack: null, previousStack: null}
var asapRoot = require('path').dirname(require.resolve('asap'))

exports.init = function () {
	var Promise = require('./promise')

	// Captures the current stack info and pushes it onto the stack trace.
	// Optionally trims a certain number of lines from the stack info.
	Promise.prototype._addStackTrace = _addStackTrace
}

// Used before an asynchronous callback.
exports.setContext = function (promise, deferred) {
	context.stack = deferred.promise._trace
	context.previousStack = promise._trace
}
// Used after an asynchronous callback.
exports.releaseContext = function () {
	context.stack = null
	context.previousStack = null
}

// Upgrades a function returned by Promise#_rejector(), so that the rejected
// promise receives the stack trace of the promise that handled its rejection.
// Rejector functions are not allowed to throw, so if something goes wrong, we
// reject the promise with a FatalError.
exports.upgradeRejector = function (rej) {
	return function (err) {
		if (!context.previousStack) {
			err = new SyntaxError('This rejector can only be used within an asynchronous callback.')
			err.name = 'FatalError'
		} else {
			try {
				exports.setRejectionStack(context.previousStack)
			} catch (e) {
				err = e
				err.name = 'FatalError'
			}
		}
		return rej(err)
	}
}

// By setting this, the next promise that is rejected will have this stack.
exports.setRejectionStack = function (stack) {
	if (!(stack instanceof _Stack)) {
		throw new TypeError('Expected argument to be a Stack object.')
	}
	if (rejectionStack) {
		throw new SyntaxError('Invoked .setRejectionStack() twice before a promise was rejected.')
	}
	rejectionStack = stack
}
// Returns whether there is a rejection stack to use.
exports.useRejectionStack = function () {
	var temp = rejectionStack
	rejectionStack = null
	return temp
}

function _addStackTrace(trim) {
	var stackPoint = captureStackPoint(_addStackTrace)
	this._trace = new _Stack(stackPoint, this._trace, trim)
	if (context.stack) {
		var end = this._trace
		while (end.parent) {end = end.parent}
		end.parent = context.stack
	}
	if (this._trace.parent) {
		cleanStackTrace(this._trace)
	}
}

function _Stack(stackPoint, parent, trim) {
	setNonEnumerable(this, 'stackPoint', stackPoint)
	setNonEnumerable(this, 'parent', parent)
	setNonEnumerable(this, 'trim', trim >>> 0)
}
_Stack.prototype.getTrace = function () {
	var point = this
	var stacks = []
	do {
		stacks.push(point)
		point = point.parent
	} while (point)
	return stacks.map(formatStack, {count: 0})
		.filter(function (str) {return !!str})
		.join('\nFrom previous event:\n') + '\n'
}

function setNonEnumerable(obj, prop, value) {
	Object.defineProperty(obj, prop, {
		value: value,
		enumerable: false,
		configurable: true,
		writable: true
	})
}

if (typeof Error.captureStackTrace === 'function') {
	var captureStackPoint = function (caller) {
		var temp = {}
		Error.captureStackTrace(temp, caller)
		return temp.stack.replace(/^.*\n?/, '')
	}
} else {
	var captureStackPoint = function () {
		try {
			throw new Error('YOU SHOULD NEVER SEE THIS')
		} catch (err) {
			if (!err.stack || typeof err.stack !== 'string') {
				throw new Error('Could not generate stack trace.')
			}
			var message = String(err)
			var indexOfMessage = err.stack.indexOf(message)
			if (indexOfMessage === -1) {
				return err.stack
			}
			return err.stack.slice(indexOfMessage + message.length)
				.replace(/^\n*/, '')
				.replace(/^.*\n?.*\n?/, '')
		}
	}
}

function cleanStackTrace(point) {
	var stacks = 0
	var maxPoints = TRACE_SIZE * 2
	while (point) {
		if (++stacks === maxPoints) {
			point.parent = undefined
			break
		}
		point = point.parent
	}
}

function formatStack(stack, index, allStacks) {
	if (!stack.stackPoint || this.count === TRACE_SIZE) {
		return ''
	}

	var processed = []
	var parsedLines = ErrorStackParser.parse({stack: stack.stackPoint})
	var lines = stack.stackPoint.split('\n')
	var lineCount = lines.length
	if (lineCount !== parsedLines.length) {
		this.count += 1
		return '    [Failed to parse stack trace]'
	}

	for (var i=stack.trim; i<lineCount; ++i) {
		var parsedLine = parsedLines[i]
		var fullPath = parsedLine.fileName || ''
		if (fullPath.indexOf(asapRoot) === 0) {
			break
		}
		if (fullPath.indexOf(__dirname) !== 0) {
			processed.push(shrinkPath(lines[i], fullPath))
		}
	}

	if (processed.length) {
		this.count += 1
		return processed.join('\n')
	}
	return ''
}

function shrinkPath(line, fullPath) {
	if (fullPath && line.length > 80) {
		var parts = fullPath.split(/[/\\]/)
		var originalLine = line
		var tries = 0
		do {
			line = originalLine.replace(fullPath, '...' + parts.slice(++tries).join('/'))
		} while (line.length > 80 && parts.length - tries > 2)
	}
	return line
}
<|endoftext|>


<commit_before>import { isObject } from 'lodash';

const mewApiError = 'Websocket connection failed';

export const knownErrors = {
  'Can\'t assign to property "request"': mewApiError,
  "Cannot create property 'request'": mewApiError,
  'GATT Server is disconnected. Cannot perform GATT operations.': mewApiError,
  "'CONNECTION ERROR: Couldn't connect to node on WS.'": mewApiError,
  'Interaction timeout': 'Please unlock your deveice',
  "CONNECTION ERROR: Couldn't connect to node on WS":
    "Couldn't connect to WS node. Please refresh and try again.",
  'connection not open on send': mewApiError,
  'Ledger device: Condition of use not satisfied': mewApiError,
  'Provided address null is invalid': 'No address provided',
  'transaction underpriced': 'Transaction gas price too low',
  'invalid remainder': 'invalid remainder',
  'Internal JSON-RPC error': 'Internal JSON-RPC error. Execution Reverted',
  'Transaction has been reverted by the EVM':
    'Transaction has been reverted by the EVM',
  'TypeError: Failed to fetch': 'Request Failed. Please refresh and try again.',
  "TypeError: Cannot read properties of null (reading 'errorHandler')":
    'There was an error signing transaction with this wallet',
  "Returned values aren't valid, did it run Out of Gas?":
    "Returned values aren't valid, did it run Out of Gas?" +
    'You might also see this error if you are not using the ' +
    'correct ABI for the contract you are retrieving data from, ' +
    'requesting data from a block number that does not exist, ' +
    'or querying a node which is not fully synced.',
  'ENS is not supported': 'ENS is not supported on network private',
  '未能完成该操作。无效的自变量':
    'The operation could not be completed. Invalid argument.',
  'AbortError: The user aborted a request':
    'Request was aborted. Please try again.',
  'JsonRpcEngine: Response has no error or result for request':
    'Unexpected response from request. Please try again.',
  'Error: TypeError: Origin https://www.myetherwallet.com is not allowed by Access-Control-Allow-Origin.':
    'CORS Request cannot be made due to security reasons',
  "Cannot read properties of undefined (reading 'click')": ''
};

const handleError = err => {
  const errorValues = Object.keys(knownErrors);
  const foundError = errorValues.find(item => {
    const message =
      err && err.message
        ? isObject(err.message)
          ? err.message.message
          : err.message
        : err;
    if (!message) return false;
    return message.includes(item);
  });
  return foundError ? true : false;
};

export default handleError;
<commit_msg>fix: 🐛 permission denied error<commit_after>import { isObject } from 'lodash';

const mewApiError = 'Websocket connection failed';

export const knownErrors = {
  'Can\'t assign to property "request"': mewApiError,
  "Cannot create property 'request'": mewApiError,
  'GATT Server is disconnected. Cannot perform GATT operations.': mewApiError,
  "'CONNECTION ERROR: Couldn't connect to node on WS.'": mewApiError,
  'Interaction timeout': 'Please unlock your deveice',
  "CONNECTION ERROR: Couldn't connect to node on WS":
    "Couldn't connect to WS node. Please refresh and try again.",
  'connection not open on send': mewApiError,
  'Ledger device: Condition of use not satisfied': mewApiError,
  'Provided address null is invalid': 'No address provided',
  'transaction underpriced': 'Transaction gas price too low',
  'invalid remainder': 'invalid remainder',
  'Internal JSON-RPC error': 'Internal JSON-RPC error. Execution Reverted',
  'Transaction has been reverted by the EVM':
    'Transaction has been reverted by the EVM',
  'TypeError: Failed to fetch': 'Request Failed. Please refresh and try again.',
  "TypeError: Cannot read properties of null (reading 'errorHandler')":
    'There was an error signing transaction with this wallet',
  "Returned values aren't valid, did it run Out of Gas?":
    "Returned values aren't valid, did it run Out of Gas?" +
    'You might also see this error if you are not using the ' +
    'correct ABI for the contract you are retrieving data from, ' +
    'requesting data from a block number that does not exist, ' +
    'or querying a node which is not fully synced.',
  'ENS is not supported': 'ENS is not supported on network private',
  '未能完成该操作。无效的自变量':
    'The operation could not be completed. Invalid argument.',
  'AbortError: The user aborted a request':
    'Request was aborted. Please try again.',
  'JsonRpcEngine: Response has no error or result for request':
    'Unexpected response from request. Please try again.',
  'Error: TypeError: Origin https://www.myetherwallet.com is not allowed by Access-Control-Allow-Origin.':
    'CORS Request cannot be made due to security reasons',
  "Cannot read properties of undefined (reading 'click')": '',
  'Permission denied.': 'Permission denied. Please try again.'
};

const handleError = err => {
  const errorValues = Object.keys(knownErrors);
  const foundError = errorValues.find(item => {
    const message =
      err && err.message
        ? isObject(err.message)
          ? err.message.message
          : err.message
        : err;
    if (!message) return false;
    return message.includes(item);
  });
  return foundError ? true : false;
};

export default handleError;
<|endoftext|>


<commit_before>var exports,console,$finished,process$,$empty;//IGNORE
function Comparison(x){}//IGNORE
function ArraySequence(x){}//IGNORE
function Entry(a,b){}//IGNORE
function Singleton(x){}//IGNORE
function SequenceBuilder(){}//IGNORE
function Integer(x){}//IGNORE
function String$(f,x){}//IGNORE

function print(line) { process$.writeLine(line.getString()); }
exports.print=print;

var larger = Comparison("larger");
function getLarger() { return larger }
var smaller = Comparison("smaller");
function getSmaller() { return smaller }
var equal = Comparison("equal");
function getEqual() { return equal }
function largest(x, y) { return x.compare(y) === larger ? x : y }
function smallest(x, y) { return x.compare(y) === smaller ? x : y }

exports.getLarger=getLarger;
exports.getSmaller=getSmaller;
exports.getEqual=getEqual;
exports.largest=largest;
exports.smallest=smallest;

//receives ArraySequence, returns element
function min(seq) {
    var v = seq.getFirst();
    if (v === null) return null;
    var iter = seq.getRest().getIterator();
    var e; while ((e = iter.next()) !== $finished) {
        v = smallest(v, e);
    }
    return v;
}
//receives ArraySequence, returns element
function max(/*ContainerWithFirstElement*/seq) {
    var v = seq.getFirst();
    if (v === null) return null;
    var iter = seq.getRest().getIterator();
    var e; while ((e = iter.next()) !== $finished) {
        v = largest(v, e);
    }
    return v;
}
function sum(seq) {
    var v = seq.getFirst();
    var iter = seq.getRest().getIterator();
    var e; while ((e = iter.next()) !== $finished) {
        v = v.plus(e);
    }
    return v;
}

//receives ArraySequence of ArraySequences, returns flat ArraySequence
function join(seqs) {
    if (seqs === undefined) return $empty;
    var builder = [];
    var it = seqs.getIterator();
    var seq;
    while ((seq = it.next()) !== $finished) {
        var it2 = seq.getIterator();
        var elem;
        while ((elem = it2.next()) != $finished) {builder.push(elem);}
    }
    return ArraySequence(builder);
}
//receives ArraySequences, returns ArraySequence
function zip(keys, items) {
    var entries = []
    var numEntries = Math.min(keys.value.length, items.value.length);
    for (var i = 0; i < numEntries; i++) {
        entries[i] = Entry(keys.value[i], items.value[i]);
    }
    return ArraySequence(entries);
}
//receives and returns ArraySequence
function coalesce(seq) {
    if (seq === undefined) {return $empty}
    return seq.getCoalesced();
}

//receives ArraySequence and CeylonObject, returns new ArraySequence
function append(seq, elem) {
    return ArraySequence(seq.value.concat(elem));
}
function prepend(seq, elem) {
    if (seq.getEmpty()) {
        return Singleton(elem);
    } else {
        var sb = SequenceBuilder();
        sb.append(elem);
        sb.appendAll(seq);
        return sb.getSequence();
    }
}

//Receives Iterable, returns ArraySequence (with Entries)
function entries(seq) {
    if (seq === undefined) return $empty;
    return seq.getIndexed();
}

function any(/*Boolean...*/ values) {
    if (values === undefined) return false;
    var it = values.getIterator();
    var v;
    while ((v = it.next()) !== $finished) {
        if (v) {return true;}
    }
    return false;
}
function every(/*Boolean...*/ values) {
    if (values === undefined) return false;
    var it = values.getIterator();
    var v;
    while ((v = it.next()) !== $finished) {
        if (!v) {return false;}
    }
    return true;
}

function first(/*Element...*/ elements) {
    if (elements === undefined) return null;
    var e = elements.getIterator().next();
    return (e !== $finished) ? e : null;
}

exports.min=min;
exports.max=max;
exports.sum=sum;
exports.join=join;
exports.zip=zip;
exports.coalesce=coalesce;
exports.append=append;
exports.prepend=prepend;
exports.entries=entries;
exports.any=any;
exports.every=every;
exports.first=first;

//These are operators for handling nulls
function exists(value) {
    return value !== null && value !== undefined;
}
function nonempty(value) {
    return value !== null && value !== undefined && !value.getEmpty();
}

function isOfType(obj, typeName) {
    if (obj === null) {
        return typeName==="ceylon.language.Nothing" || typeName==="ceylon.language.Void";
    }
    return obj.getT$all && typeName in obj.getT$all();
}
function isOfTypes(obj, types) {
    if (obj===null) {
        return types.l.indexOf('ceylon.language.Nothing')>=0 || types.l.indexOf('ceylon.language.Void')>=0;
    }
    var unions = false;
    var inters = true;
    var _ints=false;
    var objTypes = obj.getT$all();
    for (var i = 0; i < types.l.length; i++) {
        var t = types.l[i];
        var partial = false;
        if (typeof t === 'string') {
            partial = t in objTypes;
        } else {
            partial = isOfTypes(obj, t);
        }
        if (types.t==='u') {
            unions = partial || unions;
        } else {
            inters = partial && inters;
            _ints=true;
        }
    }
    return _ints ? inters||unions : unions;
}

function className(obj) {
    if (obj === null) return String$('ceylon.language.Nothing');
    return String$(obj.getT$name());
}

function identityHash(obj) {
    return obj.identifiableObjectID;
}

//This is just so that you can pass a comprehension and return it as iterable
function elements(iter) {
    return iter;
}
exports.elements=elements;
exports.exists=exists;
exports.nonempty=nonempty;
exports.isOfType=isOfType;
exports.isOfTypes=isOfTypes;
exports.className=className;
exports.identityHash=identityHash;
<commit_msg>Remove append() and prepend()<commit_after>var exports,console,$finished,process$,$empty;//IGNORE
function Comparison(x){}//IGNORE
function ArraySequence(x){}//IGNORE
function Entry(a,b){}//IGNORE
function Singleton(x){}//IGNORE
function SequenceBuilder(){}//IGNORE
function Integer(x){}//IGNORE
function String$(f,x){}//IGNORE

function print(line) { process$.writeLine(line.getString()); }
exports.print=print;

var larger = Comparison("larger");
function getLarger() { return larger }
var smaller = Comparison("smaller");
function getSmaller() { return smaller }
var equal = Comparison("equal");
function getEqual() { return equal }
function largest(x, y) { return x.compare(y) === larger ? x : y }
function smallest(x, y) { return x.compare(y) === smaller ? x : y }

exports.getLarger=getLarger;
exports.getSmaller=getSmaller;
exports.getEqual=getEqual;
exports.largest=largest;
exports.smallest=smallest;

//receives ArraySequence, returns element
function min(seq) {
    var v = seq.getFirst();
    if (v === null) return null;
    var iter = seq.getRest().getIterator();
    var e; while ((e = iter.next()) !== $finished) {
        v = smallest(v, e);
    }
    return v;
}
//receives ArraySequence, returns element
function max(/*ContainerWithFirstElement*/seq) {
    var v = seq.getFirst();
    if (v === null) return null;
    var iter = seq.getRest().getIterator();
    var e; while ((e = iter.next()) !== $finished) {
        v = largest(v, e);
    }
    return v;
}
function sum(seq) {
    var v = seq.getFirst();
    var iter = seq.getRest().getIterator();
    var e; while ((e = iter.next()) !== $finished) {
        v = v.plus(e);
    }
    return v;
}

//receives ArraySequence of ArraySequences, returns flat ArraySequence
function join(seqs) {
    if (seqs === undefined) return $empty;
    var builder = [];
    var it = seqs.getIterator();
    var seq;
    while ((seq = it.next()) !== $finished) {
        var it2 = seq.getIterator();
        var elem;
        while ((elem = it2.next()) != $finished) {builder.push(elem);}
    }
    return ArraySequence(builder);
}
//receives ArraySequences, returns ArraySequence
function zip(keys, items) {
    var entries = []
    var numEntries = Math.min(keys.value.length, items.value.length);
    for (var i = 0; i < numEntries; i++) {
        entries[i] = Entry(keys.value[i], items.value[i]);
    }
    return ArraySequence(entries);
}
//receives and returns ArraySequence
function coalesce(seq) {
    if (seq === undefined) {return $empty}
    return seq.getCoalesced();
}

//Receives Iterable, returns ArraySequence (with Entries)
function entries(seq) {
    if (seq === undefined) return $empty;
    return seq.getIndexed();
}

function any(/*Boolean...*/ values) {
    if (values === undefined) return false;
    var it = values.getIterator();
    var v;
    while ((v = it.next()) !== $finished) {
        if (v) {return true;}
    }
    return false;
}
function every(/*Boolean...*/ values) {
    if (values === undefined) return false;
    var it = values.getIterator();
    var v;
    while ((v = it.next()) !== $finished) {
        if (!v) {return false;}
    }
    return true;
}

function first(/*Element...*/ elements) {
    if (elements === undefined) return null;
    var e = elements.getIterator().next();
    return (e !== $finished) ? e : null;
}

exports.min=min;
exports.max=max;
exports.sum=sum;
exports.join=join;
exports.zip=zip;
exports.coalesce=coalesce;
exports.entries=entries;
exports.any=any;
exports.every=every;
exports.first=first;

//These are operators for handling nulls
function exists(value) {
    return value !== null && value !== undefined;
}
function nonempty(value) {
    return value !== null && value !== undefined && !value.getEmpty();
}

function isOfType(obj, typeName) {
    if (obj === null) {
        return typeName==="ceylon.language.Nothing" || typeName==="ceylon.language.Void";
    }
    return obj.getT$all && typeName in obj.getT$all();
}
function isOfTypes(obj, types) {
    if (obj===null) {
        return types.l.indexOf('ceylon.language.Nothing')>=0 || types.l.indexOf('ceylon.language.Void')>=0;
    }
    var unions = false;
    var inters = true;
    var _ints=false;
    var objTypes = obj.getT$all();
    for (var i = 0; i < types.l.length; i++) {
        var t = types.l[i];
        var partial = false;
        if (typeof t === 'string') {
            partial = t in objTypes;
        } else {
            partial = isOfTypes(obj, t);
        }
        if (types.t==='u') {
            unions = partial || unions;
        } else {
            inters = partial && inters;
            _ints=true;
        }
    }
    return _ints ? inters||unions : unions;
}

function className(obj) {
    if (obj === null) return String$('ceylon.language.Nothing');
    return String$(obj.getT$name());
}

function identityHash(obj) {
    return obj.identifiableObjectID;
}

//This is just so that you can pass a comprehension and return it as iterable
function elements(iter) {
    return iter;
}
exports.elements=elements;
exports.exists=exists;
exports.nonempty=nonempty;
exports.isOfType=isOfType;
exports.isOfTypes=isOfTypes;
exports.className=className;
exports.identityHash=identityHash;
<|endoftext|>


<commit_before>class Modal {
  constructor(id, blocking) {
    this.container = document.getElementById(id);

    this.blockingDiv = null;
    if (blocking) {
      this.blockingDiv = this.addBlockingBackgroundDiv();
    }

    this.header = this.createAndAddDiv('modal-header');
    this.body = this.createAndAddDiv('modal-body');
    this.footer = this.createAndAddDiv('modal-footer');

    this.isVisible = false;
    this.hide();
  }

  addBlockingBackgroundDiv() {
    let blockingDiv = document.createElement('div');
    blockingDiv.classList.add('blocking');

    let modalParent = this.container.parentNode;
    modalParent.replaceChild(blockingDiv, this.container);
    blockingDiv.appendChild(this.container);

    return blockingDiv
  }

  setHeader(text) {
    this.header.innerHTML = "";

    let closeBtn = document.createElement('button');
    closeBtn.innerText = "X";
    closeBtn.classList.add('modal-close-btn');
    closeBtn.onclick = () => {this.hide()};

    let heading = document.createElement('h1');
    heading.innerText = text;

    this.header.appendChild(closeBtn);
    this.header.appendChild(heading);

    this.center();
  }

  setBody(elements) {
    this.body.innerHTML = "";

    for (let element of elements) {
      this.body.appendChild(element);
    }

    this.center();
  }

  center() {
    const width = this.container.clientWidth;
    const height = this.container.clientHeight;

    this.container.style['margin-left'] = -1 * width/2 + 'px';
    this.container.style['margin-top'] = -1 * height/2 + 'px';
  }

  show() {
    if (this.blockingDiv != null) {
      this.blockingDiv.classList.remove('hidden');
    }
    this.container.classList.remove('hidden');

    this.center();

    this.isVisible = true;
  }

  hide() {
    if (this.blockingDiv != null) {
      this.blockingDiv.classList.add('hidden');
    }
    this.container.classList.add('hidden');

    this.isVisible = false;
  }

  createAndAddDiv(className) {
    let div = document.createElement('div');
    div.classList.add(className);
    this.container.appendChild(div);

    return div;
  }

}
<commit_msg>Change 'X' used and replace double quotes with single quotes<commit_after>class Modal {
  constructor(id, blocking) {
    this.container = document.getElementById(id);

    this.blockingDiv = null;
    if (blocking) {
      this.blockingDiv = this.addBlockingBackgroundDiv();
    }

    this.header = this.createAndAddDiv('modal-header');
    this.body = this.createAndAddDiv('modal-body');
    this.footer = this.createAndAddDiv('modal-footer');

    this.isVisible = false;
    this.hide();
  }

  addBlockingBackgroundDiv() {
    let blockingDiv = document.createElement('div');
    blockingDiv.classList.add('blocking');

    let modalParent = this.container.parentNode;
    modalParent.replaceChild(blockingDiv, this.container);
    blockingDiv.appendChild(this.container);

    return blockingDiv
  }

  setHeader(text) {
    this.header.innerHTML = '';

    let closeBtn = document.createElement('button');
    closeBtn.innerText = '✕';
    closeBtn.classList.add('modal-close-btn');
    closeBtn.onclick = () => {this.hide()};

    let heading = document.createElement('h1');
    heading.innerText = text;

    this.header.appendChild(closeBtn);
    this.header.appendChild(heading);

    this.center();
  }

  setBody(elements) {
    this.body.innerHTML = '';

    for (let element of elements) {
      this.body.appendChild(element);
    }

    this.center();
  }

  center() {
    const width = this.container.clientWidth;
    const height = this.container.clientHeight;

    this.container.style['margin-left'] = -1 * width/2 + 'px';
    this.container.style['margin-top'] = -1 * height/2 + 'px';
  }

  show() {
    if (this.blockingDiv != null) {
      this.blockingDiv.classList.remove('hidden');
    }
    this.container.classList.remove('hidden');

    this.center();

    this.isVisible = true;
  }

  hide() {
    if (this.blockingDiv != null) {
      this.blockingDiv.classList.add('hidden');
    }
    this.container.classList.add('hidden');

    this.isVisible = false;
  }

  createAndAddDiv(className) {
    let div = document.createElement('div');
    div.classList.add(className);
    this.container.appendChild(div);

    return div;
  }

}
<|endoftext|>


<commit_before>var Connection = require( './connection' ),
  events = require( 'events' ),
  pckg = require( '../package.json' ),
  util = require( 'util' )

/**
 * MessageConnector that uses Redis' pub-sub capabilities for deepstream
 * messaging.
 *
 * Due to the forever blocking "subscriber only" nature of Redis this
 * establishes two connections to the redis server, one for up and one for
 * downstream
 *
 * @param {Object} options Redis connection options. See connection.js for details
 *
 * @constructor
 */
var MessageConnector = function( options ) {
  Connection.call( this, options )

  this.name = pckg.name
  this.version = pckg.version

  this._senderId = options.serverName || ( Math.random() * 10000000000000000000 ).toString( 36 )
  this._eventEmitter = new events.EventEmitter()
  this._publishConnection = new Connection( options )
  this.client.on( 'message', this._onMessage.bind( this ) )
}

util.inherits( MessageConnector, Connection )

/**
 * Removes <callback> as a listener and notifies the server
 * that the client is no longer interested in messages for <topic>
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
MessageConnector.prototype.unsubscribe = function( topic, callback ) {
  this._eventEmitter.removeListener( topic, callback )
  if ( this._hasNoListeners( topic ) ) {
    this.client.unsubscribe( topic )
  }
}

/**
 * Subscribe as a listener to <topic>. Multiple subscriptions
 * to the same topic are allowed. It's up to this class
 * to ensure that <callback> won't receive any messages published
 * by itself
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
MessageConnector.prototype.subscribe = function( topic, callback ) {
  if ( this._hasNoListeners( topic ) ) {
    this.client.subscribe( topic )
  }
  this._eventEmitter.on( topic, callback )
}

/**
 * Publish messages on a topic.
 *
 * This implementation will add the server name to the message to make sure
 * that the client doesn't receive messages that where send by itself
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
MessageConnector.prototype.publish = function( topic, message ) {
  message._s = this._senderId
  this._publishConnection.client.publish( topic, JSON.stringify( message ) )
}

/**
 * Makes sure that no listeners are left for a given topic.
 * This might be replaced by the more performant listenerCount( topic ) in the near
 * future (listeners() creates a copy of the listeners array), but for the moment
 * we prefer to maintain backwards compatibility with Node 0.x versions.
 *
 * @param   {String}  topic [description]
 *
 * @returns {Boolean} hasNoListeners
 */
MessageConnector.prototype._hasNoListeners = function( topic ) {
  return this._eventEmitter.listeners( topic ).length === 0
}

/**
 * Callback for incoming messages. Parses the JSON stringified message,
 * checks that it hasn't been send by itself and is meant for a topic
 * that the client is subscribed to and - if so - notifies the callbacks
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @private
 * @returns {void}
 */
MessageConnector.prototype._onMessage = function( topic, message ) {
  var parsedMessage

  try{
    parsedMessage = JSON.parse( message )
  } catch ( e ) {
    this._onError( 'Error parsing message ' + e.toString() )
    return
  }

  if( parsedMessage._s === this._senderId ) {
    return
  }

  delete parsedMessage._s

  if( this._hasNoListeners( topic ) ) {
    this._onError( 'Received message for unknown topic ' + topic )
    return
  }

  this._eventEmitter.emit( topic, parsedMessage )
}

module.exports = MessageConnector<commit_msg>added close method to allow connections to be closed gracefully when deepstream quits<commit_after>var Connection = require( './connection' ),
  events = require( 'events' ),
  pckg = require( '../package.json' ),
  util = require( 'util' )

/**
 * MessageConnector that uses Redis' pub-sub capabilities for deepstream
 * messaging.
 *
 * Due to the forever blocking "subscriber only" nature of Redis this
 * establishes two connections to the redis server, one for up and one for
 * downstream
 *
 * @param {Object} options Redis connection options. See connection.js for details
 *
 * @constructor
 */
var MessageConnector = function( options ) {
  Connection.call( this, options )

  this.name = pckg.name
  this.version = pckg.version

  this._senderId = options.serverName || ( Math.random() * 10000000000000000000 ).toString( 36 )
  this._eventEmitter = new events.EventEmitter()
  this._publishConnection = new Connection( options )
  this.client.on( 'message', this._onMessage.bind( this ) )
}

util.inherits( MessageConnector, Connection )

/**
 * Gracefully close the connection to redis
 *
 * Called when deepstream.close() is invoked.
 * Emits 'close' event to notify deepstream of clean closure.
 *
 * @public
 * @returns {void}
 */
MessageConnector.prototype.close = function(){
  this.client.removeAllListeners( 'end' )
  this.client.once( 'end', this.emit.bind( this, 'close' ) )
  this.client.quit()
}

/**
 * Removes <callback> as a listener and notifies the server
 * that the client is no longer interested in messages for <topic>
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
MessageConnector.prototype.unsubscribe = function( topic, callback ) {
  this._eventEmitter.removeListener( topic, callback )
  if ( this._hasNoListeners( topic ) ) {
    this.client.unsubscribe( topic )
  }
}

/**
 * Subscribe as a listener to <topic>. Multiple subscriptions
 * to the same topic are allowed. It's up to this class
 * to ensure that <callback> won't receive any messages published
 * by itself
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
MessageConnector.prototype.subscribe = function( topic, callback ) {
  if ( this._hasNoListeners( topic ) ) {
    this.client.subscribe( topic )
  }
  this._eventEmitter.on( topic, callback )
}

/**
 * Publish messages on a topic.
 *
 * This implementation will add the server name to the message to make sure
 * that the client doesn't receive messages that where send by itself
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @public
 * @returns {void}
 */
MessageConnector.prototype.publish = function( topic, message ) {
  message._s = this._senderId
  this._publishConnection.client.publish( topic, JSON.stringify( message ) )
}

/**
 * Makes sure that no listeners are left for a given topic.
 * This might be replaced by the more performant listenerCount( topic ) in the near
 * future (listeners() creates a copy of the listeners array), but for the moment
 * we prefer to maintain backwards compatibility with Node 0.x versions.
 *
 * @param   {String}  topic [description]
 *
 * @returns {Boolean} hasNoListeners
 */
MessageConnector.prototype._hasNoListeners = function( topic ) {
  return this._eventEmitter.listeners( topic ).length === 0
}

/**
 * Callback for incoming messages. Parses the JSON stringified message,
 * checks that it hasn't been send by itself and is meant for a topic
 * that the client is subscribed to and - if so - notifies the callbacks
 *
 * @param   {String}   topic
 * @param   {Function} callback
 *
 * @private
 * @returns {void}
 */
MessageConnector.prototype._onMessage = function( topic, message ) {
  var parsedMessage

  try{
    parsedMessage = JSON.parse( message )
  } catch ( e ) {
    this._onError( 'Error parsing message ' + e.toString() )
    return
  }

  if( parsedMessage._s === this._senderId ) {
    return
  }

  delete parsedMessage._s

  if( this._hasNoListeners( topic ) ) {
    this._onError( 'Received message for unknown topic ' + topic )
    return
  }

  this._eventEmitter.emit( topic, parsedMessage )
}

module.exports = MessageConnector
<|endoftext|>


<commit_before>'use strict';

const Firebase = require('firebase');
const rest = require('../rest');

const version = 1;
const noop = () => undefined;

const Upgrader = exports.Upgrader = class Upgrader {

  constructor(ref, token, opts) {
    const root = ref.root();

    this.baseUri = root.toString();

    this.dest = root.child('singpath');
    this.taskDest = root.child('singpath/queues/default/tasks');
    this.client = rest.client(this.baseUri, token);

    opts = opts || {};
    this.queryLog = opts.queryLog || noop;
    this.logger = opts.logger || {
      debug: noop,
      info: noop,
      error: noop
    };

    this.logger.debug('Upgrader targeting "%s"', this.baseUri);
  }

  start() {
    return this.migratePaths().then(() => version);
  }

  solution(payload, resolution) {
    const solution = {
      meta: {
        startedAt: resolution.startedAt,
        endedAt: resolution.endedAt || null,
        verified: resolution.output !== undefined,
        solved: resolution.output && resolution.output.solved || false
      },
      payload: payload
    };

    if (solution.meta.verified) {
      solution.meta.taskId = 'migrate-version-1';
      solution.results = {
        'migrate-version-1': resolution.output
      };
    }

    if (solution.meta.solved) {
      solution.meta.history = {
        [solution.meta.startedAt]: solution.meta.endedAt - solution.meta.startedAt
      };
    }

    return Promise.resolve(solution);
  }

  task(pathId, levelId, problemId, publicId, solution) {
    return this.client.get(`auth/publicIds/${publicId}`).then(uid => {
      return {
        owner: uid,
        payload: solution.payload,
        createdAt: Firebase.ServerValue.TIMESTAMP,
        started: false,
        completed: false,
        consumed: false,
        solutionRef: `singpath/queuedSolutions/${pathId}/${levelId}/${problemId}/${publicId}/default`
      };
    });
  }

  solutionRef(solution) {
    const ref = {
      startedAt: solution.meta.startedAt,
      language: solution.payload.language,
      solved: solution.meta.solved
    };

    if (solution.meta.solved) {
      ref.duration = solution.meta.history[solution.meta.startedAt];
    }

    return ref;
  }

  saveSolution(pathId, levelId, problemId, publicId, solution) {
    this.logger.debug(
      'Saving queued solution at /singpath/queuedSolutions/%s/%s/%s/%s/default',
      pathId, levelId, problemId, publicId
    );

    if (solution.meta.verified) {
      return this.saveVerifiedSolution(pathId, levelId, problemId, publicId, solution);
    } else {
      return this.saveSolutionAndTask(pathId, levelId, problemId, publicId, solution);
    }
  }

  saveVerifiedSolution(pathId, levelId, problemId, publicId, solution) {
    return new Promise((resolve, reject) => {
      const data = {
        [`queuedSolutions/${pathId}/${levelId}/${problemId}/${publicId}/default`]: solution,
        [`userProfiles/${publicId}/queuedSolutions/${pathId}/${levelId}/${problemId}/default`]: this.solutionRef(solution)
      };

      this.dest.update(data, err => {
        let success;

        if (err) {
          success = false;
          reject(err);
        } else {
          success = true;
          resolve();
        }

        this.queryLog({data, success, baseUri: this.baseUri, path: '/singpath'});
      });
    });
  }

  saveSolutionAndTask(pathId, levelId, problemId, publicId, solution) {
    return this.task(pathId, levelId, problemId, publicId, solution).then(task => {
      const taskId = solution.meta.taskId = this.taskDest.push();
      return new Promise((resolve, reject) => {
        const data = {
          [`queuedSolutions/${pathId}/${levelId}/${problemId}/${publicId}/default`]: solution,
          [`userProfiles/${publicId}/queuedSolutions/${pathId}/${levelId}/${problemId}/default`]: this.solutionRef(solution),
          [`queues/default/tasks/${taskId}`]: task
        };

        this.dest.update(data, err => {
          let success;

          if (err) {
            reject(err);
          } else {
            resolve();
          }

          this.queryLog({data, success, baseUri: this.baseUri, path: '/singpath'});
        });
      });
    });
  }

  migratePaths() {
    this.logger.info('migrating solutions...');

    return this.pathIds().then(ids => {
      this.logger.debug('Paths to handle: %j', ids);

      return ids.reduce((chain, pathId) => {
        return chain.then(() => this.migrateLevels(pathId));
      }, Promise.resolve());
    });
  }

  migrateLevels(pathId) {
    this.logger.info('migrating solutions at /singpath/solutions/%s ...', pathId);

    return this.levelIds(pathId).then(ids => {
      this.logger.debug('Levels to handle (path id: %s): %j', pathId, ids);

      return ids.reduce((chain, levelId) => {
        return chain.then(() => this.migrateProblems(pathId, levelId));
      }, Promise.resolve());
    });
  }

  migrateProblems(pathId, levelId) {
    this.logger.info('migrating solutions at /singpath/solutions/%s/%s ...', pathId, levelId);

    return this.problemIds(pathId, levelId).then(ids => {
      this.logger.debug('Problems to handle (path id: %s, level id: %s): %j', pathId, levelId, ids);

      return ids.reduce((chain, problemId) => {
        return chain.then(() => this.migrateSolutions(pathId, levelId, problemId));
      }, Promise.resolve());
    });
  }

  migrateSolutions(pathId, levelId, problemId) {
    this.logger.info('migrating solutions at /singpath/solutions/%s/%s/%s ...', pathId, levelId, problemId);
    return Promise.all([
      this.solutions(pathId, levelId, problemId),
      this.resolutions(pathId, levelId, problemId)
    ]).then(data => {
      const solutions = data[0] || {};
      const resolutions = data[1] || {};
      const publicIds = Object.keys(solutions);

      this.logger.debug(
        'Solutions to handle (path id: %s, level id: %s, problem id: %s): %j',
        pathId, levelId, problemId, publicIds
      );

      return publicIds.reduce((chain, publicId) => {
        const payload = solutions[publicId];
        const resolution = resolutions[publicId];

        return chain.then(
          () => this.solution(payload, resolution)
        ).then(
          solution => this.saveSolution(pathId, levelId, problemId, publicId, solution)
        );
      }, Promise.resolve());
    });
  }

  pathIds() {
    return this.client.get('singpath/paths', true).then(ids => {
      return ids !== null ? Object.keys(ids) : [];
    });
  }

  levelIds(pathId) {
    return this.client.get(`singpath/levels/${pathId}`, true).then(ids => {
      return ids !== null ? Object.keys(ids) : [];
    });
  }

  problemIds(pathId, levelId) {
    return this.client.get(`singpath/problems/${pathId}/${levelId}`, true).then(ids => {
      return ids !== null ? Object.keys(ids) : [];
    });
  }

  solutions(pathId, levelId, problemId) {
    const path = `singpath/solutions/${pathId}/${levelId}/${problemId}`;

    return this.client.get(path).then(solutions => solutions || {});
  }

  resolutions(pathId, levelId, problemId) {
    const path = `singpath/resolutions/${pathId}/${levelId}/${problemId}`;

    return this.client.get(path).then(resolutions => resolutions || {});
  }
};

// New version after migration
exports.version = version;
exports.description = 'Convert solutions and resolutions to queuedSolutions';

// Transform the solutions and resolutions into queuedSolutions
// (and optionally tasks).
exports.upgrade = (src, token, opts) => new Upgrader(src, token, opts).start();

// Nothing to do when reverting (maybe deleted queued solutions)
exports.revert = () => Promise.resolve(version - 1);
<commit_msg>Fix solution migration process<commit_after>'use strict';

const Firebase = require('firebase');
const rest = require('../rest');

const version = 1;
const noop = () => undefined;

const Upgrader = exports.Upgrader = class Upgrader {

  constructor(ref, token, opts) {
    const root = ref.root();

    this.baseUri = root.toString();

    this.dest = root.child('singpath');
    this.taskDest = root.child('singpath/queues/default/tasks');
    this.client = rest.client(this.baseUri, token);

    opts = opts || {};
    this.queryLog = opts.queryLog || noop;
    this.logger = opts.logger || {
      debug: noop,
      info: noop,
      error: noop
    };

    this.logger.debug('Upgrader targeting "%s"', this.baseUri);
  }

  start() {
    return this.migratePaths().then(() => version);
  }

  solution(payload, resolution) {
    const solution = {
      meta: {
        startedAt: resolution.startedAt,
        endedAt: resolution.endedAt || null,
        verified: resolution.output !== undefined,
        solved: resolution.output && resolution.output.solved || false
      },
      payload: payload
    };

    if (solution.meta.verified) {
      solution.meta.taskId = 'migrate-version-1';
      solution.results = {
        'migrate-version-1': resolution.output
      };
    }

    if (solution.meta.solved) {
      solution.meta.history = {
        [solution.meta.startedAt]: solution.meta.endedAt - solution.meta.startedAt
      };
    }

    return Promise.resolve(solution);
  }

  task(pathId, levelId, problemId, publicId, solution) {
    return this.client.get(`auth/publicIds/${publicId}`).then(uid => {
      return {
        owner: uid,
        payload: solution.payload,
        createdAt: Firebase.ServerValue.TIMESTAMP,
        started: false,
        completed: false,
        consumed: false,
        solutionRef: `singpath/queuedSolutions/${pathId}/${levelId}/${problemId}/${publicId}/default`
      };
    });
  }

  solutionRef(solution) {
    const ref = {
      startedAt: solution.meta.startedAt,
      language: solution.payload.language,
      solved: solution.meta.solved
    };

    if (solution.meta.solved) {
      ref.duration = solution.meta.history[solution.meta.startedAt];
    }

    return ref;
  }

  saveSolution(pathId, levelId, problemId, publicId, solution) {
    this.logger.debug(
      'Saving queued solution at /singpath/queuedSolutions/%s/%s/%s/%s/default',
      pathId, levelId, problemId, publicId
    );

    if (
      !solution ||
      !solution.meta ||
      !solution.payload ||
      !solution.meta.endedAt ||
      !solution.meta.startedAt ||
      solution.meta.verified == null ||
      solution.meta.solved == null
    ) {
      this.logger.debug('Dropping solution; it is missing some attribute');
      return Promise.resolve();
    }

    if (solution.meta.verified) {
      return this.saveVerifiedSolution(pathId, levelId, problemId, publicId, solution);
    } else {
      return this.saveSolutionAndTask(pathId, levelId, problemId, publicId, solution);
    }
  }

  saveVerifiedSolution(pathId, levelId, problemId, publicId, solution) {
    return new Promise((resolve, reject) => {
      const data = {
        [`queuedSolutions/${pathId}/${levelId}/${problemId}/${publicId}/default`]: solution,
        [`userProfiles/${publicId}/queuedSolutions/${pathId}/${levelId}/${problemId}/default`]: this.solutionRef(solution)
      };

      this.dest.update(data, err => {
        let success;

        if (err) {
          success = false;
          reject(err);
        } else {
          success = true;
          resolve();
        }

        this.queryLog({data, success, baseUri: this.baseUri, path: '/singpath'});
      });
    });
  }

  saveSolutionAndTask(pathId, levelId, problemId, publicId, solution) {
    return this.task(pathId, levelId, problemId, publicId, solution).then(task => {
      const taskId = solution.meta.taskId = this.taskDest.push().key();

      return new Promise((resolve, reject) => {
        const data = {
          [`queuedSolutions/${pathId}/${levelId}/${problemId}/${publicId}/default`]: solution,
          [`userProfiles/${publicId}/queuedSolutions/${pathId}/${levelId}/${problemId}/default`]: this.solutionRef(solution),
          [`queues/default/tasks/${taskId}`]: task
        };

        this.dest.update(data, err => {
          let success;

          if (err) {
            reject(err);
          } else {
            resolve();
          }

          this.queryLog({data, success, baseUri: this.baseUri, path: '/singpath'});
        });
      });
    });
  }

  migratePaths() {
    this.logger.info('migrating solutions...');

    return this.pathIds().then(ids => {
      this.logger.debug('Paths to handle: %j', ids);

      return ids.reduce((chain, pathId) => {
        return chain.then(() => this.migrateLevels(pathId));
      }, Promise.resolve());
    });
  }

  migrateLevels(pathId) {
    this.logger.info('migrating solutions at /singpath/solutions/%s ...', pathId);

    return this.levelIds(pathId).then(ids => {
      this.logger.debug('Levels to handle (path id: %s): %j', pathId, ids);

      return ids.reduce((chain, levelId) => {
        return chain.then(() => this.migrateProblems(pathId, levelId));
      }, Promise.resolve());
    });
  }

  migrateProblems(pathId, levelId) {
    this.logger.info('migrating solutions at /singpath/solutions/%s/%s ...', pathId, levelId);

    return this.problemIds(pathId, levelId).then(ids => {
      this.logger.debug('Problems to handle (path id: %s, level id: %s): %j', pathId, levelId, ids);

      return ids.reduce((chain, problemId) => {
        return chain.then(() => this.migrateSolutions(pathId, levelId, problemId));
      }, Promise.resolve());
    });
  }

  migrateSolutions(pathId, levelId, problemId) {
    this.logger.info('migrating solutions at /singpath/solutions/%s/%s/%s ...', pathId, levelId, problemId);
    return Promise.all([
      this.solutions(pathId, levelId, problemId),
      this.resolutions(pathId, levelId, problemId)
    ]).then(data => {
      const solutions = data[0] || {};
      const resolutions = data[1] || {};
      const publicIds = Object.keys(solutions);

      this.logger.debug(
        'Solutions to handle (path id: %s, level id: %s, problem id: %s): %j',
        pathId, levelId, problemId, publicIds
      );

      return publicIds.reduce((chain, publicId) => {
        const payload = solutions[publicId];
        const resolution = resolutions[publicId];

        return chain.then(
          () => this.solution(payload, resolution)
        ).then(
          solution => this.saveSolution(pathId, levelId, problemId, publicId, solution)
        );
      }, Promise.resolve());
    });
  }

  pathIds() {
    return this.client.get('singpath/paths', true).then(ids => {
      return ids !== null ? Object.keys(ids) : [];
    });
  }

  levelIds(pathId) {
    return this.client.get(`singpath/levels/${pathId}`, true).then(ids => {
      return ids !== null ? Object.keys(ids) : [];
    });
  }

  problemIds(pathId, levelId) {
    return this.client.get(`singpath/problems/${pathId}/${levelId}`, true).then(ids => {
      return ids !== null ? Object.keys(ids) : [];
    });
  }

  solutions(pathId, levelId, problemId) {
    const path = `singpath/solutions/${pathId}/${levelId}/${problemId}`;

    return this.client.get(path).then(solutions => solutions || {});
  }

  resolutions(pathId, levelId, problemId) {
    const path = `singpath/resolutions/${pathId}/${levelId}/${problemId}`;

    return this.client.get(path).then(resolutions => resolutions || {});
  }
};

// New version after migration
exports.version = version;
exports.description = 'Convert solutions and resolutions to queuedSolutions';

// Transform the solutions and resolutions into queuedSolutions
// (and optionally tasks).
exports.upgrade = (src, token, opts) => new Upgrader(src, token, opts).start();

// Nothing to do when reverting (maybe deleted queued solutions)
exports.revert = () => Promise.resolve(version - 1);
<|endoftext|>


<commit_before>import _ from 'underscore';
import Marionette from 'backbone.marionette';

const ClassOptions = [
  'childApps',
  'childAppOptions'
];

 /**
 * This provides methods used for "App Manager" functionality - the adding and removing child `App`s. It's not meant to
 * be used directly.
 *
 * @mixin
 */
export default {

  /**
   * @private
   * @method _initChildApps
   * @constructs ChildApps
   * @param {Object} [options] - Settings for the ChildApps.
   * @param {Object} [options.childApps] - Hash for setting up child apps.
   * @param {Object} [options.childAppOptions] - Hash of options passed to every child app.
   *
   * ```js
   * childApps: {
   *   appName: {
   *     AppClass: MyChildAppClass,
   *     fooOption: true,
   *     startWithParent: true
   *   },
   *   barApp: MyOtherChildAppClass
   * }
   * ```
   */
  _initChildApps(options = {}) {
    this._childApps = {};

    this.mergeOptions(options, ClassOptions);

    let childApps = this.childApps;

    if(childApps) {
      if(_.isFunction(childApps)) {
        childApps = childApps.call(this, options);
      }

      this.addChildApps(childApps);
    }

    this._initListeners();
  },

  /**
   * The child apps should be handled while the app is running;
   * After start, before stop, and before destroy.
   *
   * @private
   * @method _initListeners
   */
  _initListeners() {
    this.on({
      'start': this._startChildApps,
      'before:stop': this._stopChildApps,
      'before:destroy': this._destroyChildApps
    });
  },

  /**
   * Starts `childApps` if allowed by child
   *
   * @private
   * @method _startChildApps
   */
  _startChildApps() {
    _.each(this._childApps, function(childApp) {
      if(_.result(childApp, 'startWithParent')) {
        childApp.start();
      }
    });
  },

  /**
   * Stops `childApps` if allowed by child
   *
   * @private
   * @method _stopChildApps
   */
  _stopChildApps() {
    _.each(this._childApps, function(childApp) {
      if(_.result(childApp, 'stopWithParent')) {
        childApp.stop();
      }
    });
  },

  /**
   * Starts `childApp`
   *
   * @param {String} appName - Name of childApp to start
   * @param {object} options - Start options for app
   * @public
   * @method startChildApp
   */
  startChildApp(appName, options) {
    this.getChildApp(appName).start(options);

    return this;
  },

  /**
   * Stops `childApp`
   *
   * @param {String} appName - Name of childApp to stop
   * @public
   * @method stopChildApp
   */
  stopChildApp(appName) {
    this.getChildApp(appName).stop();

    return this;
  },

  /**
   * Destroys `childApps` if allowed by child
   *
   * @private
   * @method _destroyChildApps
   */
  _destroyChildApps() {
    _.each(this._childApps, function(childApp) {
      if(!_.result(childApp, 'preventDestroy')) {
        childApp.destroy();
      }
    });
  },

  /**
   * Internal helper to instantiate and `App` from on `Object`
   *
   * @private
   * @method _buildAppFromObject
   * @param {Object} appConfig - `AppClass` and any other option for the `App`
   * @returns {App}
   */
  _buildAppFromObject(appConfig) {
    const AppClass = appConfig.AppClass;
    const options = _.omit(appConfig, 'AppClass');

    return this.buildApp(AppClass, options);
  },

  /**
   * Helper for building an App and return it
   *
   * @private
   * @method _buildApp
   * @param {App} AppClass - An App Class
   * @param {Object} AppClass - Optionally passed as an appConfig Object
   * @param {Object} [options] - options for the AppClass
   * @returns {App}
   */
  _buildApp(AppClass, options) {
    if(_.isFunction(AppClass)) {
      return this.buildApp(AppClass, options);
    }
    if(_.isObject(AppClass)) {
      return this._buildAppFromObject(AppClass);
    }
  },

  /**
   * Build an App and return it
   * Override for dynamic App building
   *
   * @public
   * @method buildApp
   * @param {App} [AppClass] - An App Class
   * @param {Object} [options] - options for the AppClass
   * @returns {App}
   */
  buildApp(AppClass, options) {
    // options on childApp definition supersede childAppOptions
    options = _.extend({}, this.childAppOptions, options);

    return new AppClass(options);
  },

  /**
   * Internal helper to verify `appName` is unique and not in use
   *
   * @private
   * @method _ensureAppIsUnique
   * @param {String} appName - Name of app to test
   * @throws DuplicateChildAppError - Thrown if `App` already has an `appName` registered
   */
  _ensureAppIsUnique(appName) {
    if(this._childApps[appName]) {
      throw new Marionette.Error({
        name: 'DuplicateChildAppError',
        message: `A child App with name "${ appName }" has already been added.`
      });
    }
  },

  /**
   * Add child `App`s to this `App`
   *
   * @public
   * @method addChildApps
   * @param {Object} childApps - Hash of names and `AppClass` or `appConfig`
   */
  addChildApps(childApps) {
    _.each(childApps, function(childApp, appName) {
      this.addChildApp(appName, childApp);
    }, this);
  },

  /**
   * Build's childApp and registers it with this App
   * Starts the childApp, if this app is running and child is `startWithParent`
   *
   * @public
   * @method addChildApp
   * @param {String} appName - Name of App to register
   * @param {App} AppClass - An App Class
   * @param {Object} AppClass - Optionally passed as an appConfig Object
   * @param {Object} [options] - options for the AppClass
   * @throws AddChildAppError - Thrown if no childApp could be built from params
   * @returns {App}
   */
  addChildApp(appName, AppClass, options) {
    this._ensureAppIsUnique(appName);

    const childApp = this._buildApp(AppClass, options);

    if(!childApp) {
      throw new Marionette.Error({
        name: 'AddChildAppError',
        message: 'App build failed.  Incorrect configuration.'
      });
    }

    childApp._name = appName;

    this._childApps[appName] = childApp;

    // When the app is destroyed remove the cached app.
    childApp.on('destroy', _.partial(this._removeChildApp, appName), this);

    if(this.isRunning() && _.result(childApp, 'startWithParent')) {
      childApp.start();
    }

    return childApp;
  },

  /**
   * Returns registered child `App`s name
   *
   * @public
   * @method getName
   * @returns {String}
   */
  getName() {
    return this._name;
  },

  /**
   * Returns registered child `App`s array
   *
   * @public
   * @method getChildApps
   * @returns {Array}
   */
  getChildApps() {
    return _.clone(this._childApps);
  },

  /**
   * Returns registered child `App`
   *
   * @public
   * @method getChildApp
   * @param {String} appName - Name of App to retrieve
   * @returns {App}
   */
  getChildApp(appName) {
    return this._childApps[appName];
  },

  /**
   * Internal helper.  Unregisters child `App`
   *
   * @private
   * @method _removeChildApp
   * @param {String} appName - Name of App to unregister
   * @returns {App}
   */
  _removeChildApp(appName) {
    delete this._childApps[appName]._name;
    delete this._childApps[appName];
  },

  /**
   * Removes all childApps and returns them.
   * The return is useful if any app is using `preventDestroy`
   *
   * @public
   * @method removeChildApps
   * @returns {Array}
   */
  removeChildApps() {
    const childApps = this.getChildApps();

    _.each(this._childApps, function(childApp, appName) {
      this.removeChildApp(appName);
    }, this);

    return childApps;
  },

  /**
   * Destroys or removes registered child `App` by name
   * depending on `preventDestroy`
   *
   * @public
   * @method removeChildApp
   * @param {String} appName - Name of App to destroy
   * @param {Object} [options.preventDestroy] - Flag to remove but prevent App destroy
   * @returns {App}
   */
  removeChildApp(appName, options) {
    options = _.extend({}, options);

    const childApp = this.getChildApp(appName);

    if(!childApp) {
      return;
    }

    // if preventDestroy simply unregister the child app
    if(options.preventDestroy || _.result(childApp, 'preventDestroy')) {
      this._removeChildApp(appName);
    } else {
      childApp.destroy();
    }

    return childApp;
  }
};
<commit_msg>Fix child-app jsdoc param<commit_after>import _ from 'underscore';
import Marionette from 'backbone.marionette';

const ClassOptions = [
  'childApps',
  'childAppOptions'
];

 /**
 * This provides methods used for "App Manager" functionality - the adding and removing child `App`s. It's not meant to
 * be used directly.
 *
 * @mixin
 */
export default {

  /**
   * @private
   * @method _initChildApps
   * @constructs ChildApps
   * @param {Object} [options] - Settings for the ChildApps.
   * @param {Object} [options.childApps] - Hash for setting up child apps.
   * @param {Object} [options.childAppOptions] - Hash of options passed to every child app.
   *
   * ```js
   * childApps: {
   *   appName: {
   *     AppClass: MyChildAppClass,
   *     fooOption: true,
   *     startWithParent: true
   *   },
   *   barApp: MyOtherChildAppClass
   * }
   * ```
   */
  _initChildApps(options = {}) {
    this._childApps = {};

    this.mergeOptions(options, ClassOptions);

    let childApps = this.childApps;

    if(childApps) {
      if(_.isFunction(childApps)) {
        childApps = childApps.call(this, options);
      }

      this.addChildApps(childApps);
    }

    this._initListeners();
  },

  /**
   * The child apps should be handled while the app is running;
   * After start, before stop, and before destroy.
   *
   * @private
   * @method _initListeners
   */
  _initListeners() {
    this.on({
      'start': this._startChildApps,
      'before:stop': this._stopChildApps,
      'before:destroy': this._destroyChildApps
    });
  },

  /**
   * Starts `childApps` if allowed by child
   *
   * @private
   * @method _startChildApps
   */
  _startChildApps() {
    _.each(this._childApps, function(childApp) {
      if(_.result(childApp, 'startWithParent')) {
        childApp.start();
      }
    });
  },

  /**
   * Stops `childApps` if allowed by child
   *
   * @private
   * @method _stopChildApps
   */
  _stopChildApps() {
    _.each(this._childApps, function(childApp) {
      if(_.result(childApp, 'stopWithParent')) {
        childApp.stop();
      }
    });
  },

  /**
   * Starts `childApp`
   *
   * @param {String} appName - Name of childApp to start
   * @param {Object} options - Start options for app
   * @public
   * @method startChildApp
   */
  startChildApp(appName, options) {
    this.getChildApp(appName).start(options);

    return this;
  },

  /**
   * Stops `childApp`
   *
   * @param {String} appName - Name of childApp to stop
   * @public
   * @method stopChildApp
   */
  stopChildApp(appName) {
    this.getChildApp(appName).stop();

    return this;
  },

  /**
   * Destroys `childApps` if allowed by child
   *
   * @private
   * @method _destroyChildApps
   */
  _destroyChildApps() {
    _.each(this._childApps, function(childApp) {
      if(!_.result(childApp, 'preventDestroy')) {
        childApp.destroy();
      }
    });
  },

  /**
   * Internal helper to instantiate and `App` from on `Object`
   *
   * @private
   * @method _buildAppFromObject
   * @param {Object} appConfig - `AppClass` and any other option for the `App`
   * @returns {App}
   */
  _buildAppFromObject(appConfig) {
    const AppClass = appConfig.AppClass;
    const options = _.omit(appConfig, 'AppClass');

    return this.buildApp(AppClass, options);
  },

  /**
   * Helper for building an App and return it
   *
   * @private
   * @method _buildApp
   * @param {App} AppClass - An App Class
   * @param {Object} AppClass - Optionally passed as an appConfig Object
   * @param {Object} [options] - options for the AppClass
   * @returns {App}
   */
  _buildApp(AppClass, options) {
    if(_.isFunction(AppClass)) {
      return this.buildApp(AppClass, options);
    }
    if(_.isObject(AppClass)) {
      return this._buildAppFromObject(AppClass);
    }
  },

  /**
   * Build an App and return it
   * Override for dynamic App building
   *
   * @public
   * @method buildApp
   * @param {App} [AppClass] - An App Class
   * @param {Object} [options] - options for the AppClass
   * @returns {App}
   */
  buildApp(AppClass, options) {
    // options on childApp definition supersede childAppOptions
    options = _.extend({}, this.childAppOptions, options);

    return new AppClass(options);
  },

  /**
   * Internal helper to verify `appName` is unique and not in use
   *
   * @private
   * @method _ensureAppIsUnique
   * @param {String} appName - Name of app to test
   * @throws DuplicateChildAppError - Thrown if `App` already has an `appName` registered
   */
  _ensureAppIsUnique(appName) {
    if(this._childApps[appName]) {
      throw new Marionette.Error({
        name: 'DuplicateChildAppError',
        message: `A child App with name "${ appName }" has already been added.`
      });
    }
  },

  /**
   * Add child `App`s to this `App`
   *
   * @public
   * @method addChildApps
   * @param {Object} childApps - Hash of names and `AppClass` or `appConfig`
   */
  addChildApps(childApps) {
    _.each(childApps, function(childApp, appName) {
      this.addChildApp(appName, childApp);
    }, this);
  },

  /**
   * Build's childApp and registers it with this App
   * Starts the childApp, if this app is running and child is `startWithParent`
   *
   * @public
   * @method addChildApp
   * @param {String} appName - Name of App to register
   * @param {App} AppClass - An App Class
   * @param {Object} AppClass - Optionally passed as an appConfig Object
   * @param {Object} [options] - options for the AppClass
   * @throws AddChildAppError - Thrown if no childApp could be built from params
   * @returns {App}
   */
  addChildApp(appName, AppClass, options) {
    this._ensureAppIsUnique(appName);

    const childApp = this._buildApp(AppClass, options);

    if(!childApp) {
      throw new Marionette.Error({
        name: 'AddChildAppError',
        message: 'App build failed.  Incorrect configuration.'
      });
    }

    childApp._name = appName;

    this._childApps[appName] = childApp;

    // When the app is destroyed remove the cached app.
    childApp.on('destroy', _.partial(this._removeChildApp, appName), this);

    if(this.isRunning() && _.result(childApp, 'startWithParent')) {
      childApp.start();
    }

    return childApp;
  },

  /**
   * Returns registered child `App`s name
   *
   * @public
   * @method getName
   * @returns {String}
   */
  getName() {
    return this._name;
  },

  /**
   * Returns registered child `App`s array
   *
   * @public
   * @method getChildApps
   * @returns {Array}
   */
  getChildApps() {
    return _.clone(this._childApps);
  },

  /**
   * Returns registered child `App`
   *
   * @public
   * @method getChildApp
   * @param {String} appName - Name of App to retrieve
   * @returns {App}
   */
  getChildApp(appName) {
    return this._childApps[appName];
  },

  /**
   * Internal helper.  Unregisters child `App`
   *
   * @private
   * @method _removeChildApp
   * @param {String} appName - Name of App to unregister
   * @returns {App}
   */
  _removeChildApp(appName) {
    delete this._childApps[appName]._name;
    delete this._childApps[appName];
  },

  /**
   * Removes all childApps and returns them.
   * The return is useful if any app is using `preventDestroy`
   *
   * @public
   * @method removeChildApps
   * @returns {Array}
   */
  removeChildApps() {
    const childApps = this.getChildApps();

    _.each(this._childApps, function(childApp, appName) {
      this.removeChildApp(appName);
    }, this);

    return childApps;
  },

  /**
   * Destroys or removes registered child `App` by name
   * depending on `preventDestroy`
   *
   * @public
   * @method removeChildApp
   * @param {String} appName - Name of App to destroy
   * @param {Object} [options.preventDestroy] - Flag to remove but prevent App destroy
   * @returns {App}
   */
  removeChildApp(appName, options) {
    options = _.extend({}, options);

    const childApp = this.getChildApp(appName);

    if(!childApp) {
      return;
    }

    // if preventDestroy simply unregister the child app
    if(options.preventDestroy || _.result(childApp, 'preventDestroy')) {
      this._removeChildApp(appName);
    } else {
      childApp.destroy();
    }

    return childApp;
  }
};
<|endoftext|>