<commit_before>import {application} from 'nxus-core'
import {storage, HasModels} from 'nxus-storage'
import _ from 'underscore'
import Promise from 'bluebird'

import {router} from 'nxus-router'

import routes from 'routes'

import PermissionManager from './PermissionManager'

class UsersPermissions extends HasModels {
  constructor(opts={}) {
    opts.modelNames = {'users-role': 'Role', 'users-user': 'User'}
    super(opts)

    this._permissions = {}

    this._defaultRoles = {}

    this._routesPermissions = new routes()

    router.middleware(::this._userMiddleware)
    router.middleware(::this._checkMiddleware)

    // Create roles if they do not exist, adding missing perms
    this.__appListener = ::this._createRoles
    application.on('startup', this.__appListener)
    application.on('stop', () => {application.removeListener('startup', this.__appListener)})
  }

  _createRoles() {
    return Promise.map(_.keys(this._defaultRoles), async (role) => {
      let roleOb = await this.models.Role.createOrUpdate({role}, {role, systemDefined: true})
      this.log.info("Created role", role)
      roleObj.permissions = _.union(roleObj.permissions || [], this._defaultRoles[role])
      return roleObj.save()
    })
  }

  /*
   * Register a permission
   * @param {string} name Permission name
   * @param {string|array} [defaultRoles] Default role name(s) to contain this permission
   * @param {object} [objectModel] Collection of ObjectRoleModel for object permissions
   */
  register(name, defaultRoles=null, objectModel=null) {
    this._permissions[name] = {
      name,
      objectModel,
    }
    if(defaultRoles) {
      if (!_.isArray(defaultRoles)) {
        defaultRoles = [defaultRoles]
      }
      for (let role of defaultRoles) {
        if (!this._defaultRoles[role]) {
          this._defaultRoles[role] = []
        }
        this._defaultRoles[role].push(name)
      }
    }
  }

  /*
   * Guard a handler method or route a permission
   * @param {function|string} [handler|route] A handler or route to wrap with a permission check
   * @param {string} name Permission name
   * @param {object} [objectParam] URL param for object permissions object key
   */
  guard(handler, name, objectParam=null) {
    if (_.isString(handler)) {
      // Route
      this._routesPermissions.addRoute(handler, () => {return [name, objectParam]})
    } else {
      // Wrap handler
      return this._checkPermission(name, handler, objectParam)
    }
  }
  /*
   * Register a permission and guard a route handler in one
   * @param {string} name Permission name
   * @param {function|string} [handler|route] A handler or route to wrap with a permission check
   * @param {object} [objectParams] Mapping of req params to ObjectRoleModel identity
   * @param {string|array} [roleName] Default role name(s) to contain this permission
   */
  allow(name, handler = null, objectParams = null, roleName = null) {
    let coll, param
    if (objectParams) {
      coll = _.first(_.keys(objectParams))
      param = objectParams[coll]
    }
    this.register(name, roleName, coll)
    return this.guard(handler, name, param)
  }

  getPermissions() {
    return this._permissions
  }

  async getRoles() {
    let roles = await this.models.Role.find()
    let ret = {}
    for (let role of roles) {
      ret[role.role] = role
    }
    return ret
  }

  _checkPermission(name, handler, objectParam) {
    return (req, res, next) => {
      let promise = Promise.resolve()
      if (handler) {
        // Route handler, after middleware
        next = () => { handler(req, res) }
        promise = this._setObjectRoles(req.user, name, req.params[objectParam])
      }
      promise.then(() => {
        if (req.user.permissions.has(name)) {
          next()
        } else {
          res.status(403).send("Permission Denied")
        }
      })
    }
  }

  async _checkMiddleware(req, res, next) {
    let routePermission = this._routesPermissions.match(req.path)
    // TODO this probably needs to support nested/multiple matches
    if (req.user && routePermission) {
      let [permission, objectParam] = routePermission.fn()
      this.log.info("Checking route permission for ", req.path, permission, routePermission.params)
      await this._setObjectRoles(req.user, permission, routePermission.params[objectParam])
      this._checkPermission(permission, objectParam)(req, res, next)
    } else {
      next()
    }
  }

  async _userMiddleware(req, res, next) {
    if (req.user) {
      let u = await this.models.User.findOne(req.user.id).populate('roles').populate('team')
      req.user.permissions = new PermissionManager(u)
      next()
    } else {
      next()
    }
  }

  async _setObjectRoles(user, permission, objectId) {
    let objectModel = this._permissions[permission].objectModel
    if (!objectModel) return

    let model = await storage.getModel(objectModel)
    let roles = await model.find({user: user.id, object: objectId}).populate('role')
    user.permissions.addRoles(_.pluck(roles, 'role'), objectId)
  }

}

const permissions = UsersPermissions.getProxy()
export {UsersPermissions as default, permissions}
<commit_msg>Object permissions with a custom method for object role lookup<commit_after>import {application} from 'nxus-core'
import {storage, HasModels} from 'nxus-storage'
import _ from 'underscore'
import Promise from 'bluebird'

import {router} from 'nxus-router'

import routes from 'routes'

import PermissionManager from './PermissionManager'

class UsersPermissions extends HasModels {
  constructor(opts={}) {
    opts.modelNames = {'users-role': 'Role', 'users-user': 'User'}
    super(opts)

    this._permissions = {}

    this._defaultRoles = {}

    this._routesPermissions = new routes()

    router.middleware(::this._userMiddleware)
    router.middleware(::this._checkMiddleware)

    // Create roles if they do not exist, adding missing perms
    this.__appListener = ::this._createRoles
    application.on('startup', this.__appListener)
    application.on('stop', () => {application.removeListener('startup', this.__appListener)})
  }

  _createRoles() {
    return Promise.map(_.keys(this._defaultRoles), async (role) => {
      let roleOb = await this.models.Role.createOrUpdate({role}, {role, systemDefined: true})
      this.log.info("Created role", role)
      roleObj.permissions = _.union(roleObj.permissions || [], this._defaultRoles[role])
      return roleObj.save()
    })
  }

  /*
   * Register a permission
   * @param {string} name Permission name
   * @param {string|array} [defaultRoles] Default role name(s) to contain this permission
   * @param {object} [objectModel] Collection of ObjectRoleModel for object permissions, or function (objectId, user) to return the roles a user has for a given object
   */
  register(name, defaultRoles=null, objectModel=null) {
    this._permissions[name] = {
      name,
      objectModel,
    }
    if(defaultRoles) {
      if (!_.isArray(defaultRoles)) {
        defaultRoles = [defaultRoles]
      }
      for (let role of defaultRoles) {
        if (!this._defaultRoles[role]) {
          this._defaultRoles[role] = []
        }
        this._defaultRoles[role].push(name)
      }
    }
  }

  /*
   * Guard a handler method or route a permission
   * @param {function|string} [handler|route] A handler or route to wrap with a permission check
   * @param {string} name Permission name
   * @param {object} [objectParam] URL param for object permissions object key
   * @returns {function} Wrapped handler for method handlers
   */
  guard(handler, name, objectParam=null) {
    if (_.isString(handler)) {
      // Route
      this._routesPermissions.addRoute(handler, () => {return [name, objectParam]})
    } else {
      // Wrap handler
      return this._checkPermission(name, handler, objectParam)
    }
  }
  /*
   * Register a permission and guard a route handler in one
   * @param {string} name Permission name
   * @param {function|string} [handler|route] A handler or route to wrap with a permission check
   * @param {object} [objectParams] Mapping of req params to ObjectRoleModel identity
   * @param {string|array} [roleName] Default role name(s) to contain this permission
   * @returns {function} Wrapped handler for method handlers
   */
  allow(name, handler = null, objectParams = null, roleName = null) {
    let coll, param
    if (objectParams) {
      coll = _.first(_.keys(objectParams))
      param = objectParams[coll]
    }
    this.register(name, roleName, coll)
    return this.guard(handler, name, param)
  }

  getPermissions() {
    return this._permissions
  }

  async getRoles() {
    let roles = await this.models.Role.find()
    let ret = {}
    for (let role of roles) {
      ret[role.role] = role
    }
    return ret
  }

  _checkPermission(name, handler, objectParam) {
    return (req, res, next) => {
      let promise = Promise.resolve()
      if (handler) {
        // Route handler, after middleware
        next = () => { handler(req, res) }
        promise = this._setObjectRoles(req.user, name, req.params[objectParam])
      }
      promise.then(() => {
        if (req.user.permissions.has(name)) {
          next()
        } else {
          res.status(403).send("Permission Denied")
        }
      })
    }
  }

  async _checkMiddleware(req, res, next) {
    let routePermission = this._routesPermissions.match(req.path)
    // TODO this probably needs to support nested/multiple matches
    if (req.user && routePermission) {
      let [permission, objectParam] = routePermission.fn()
      this.log.info("Checking route permission for ", req.path, permission, routePermission.params)
      await this._setObjectRoles(req.user, permission, routePermission.params[objectParam])
      this._checkPermission(permission, objectParam)(req, res, next)
    } else {
      next()
    }
  }

  async _userMiddleware(req, res, next) {
    if (req.user) {
      let u = await this.models.User.findOne(req.user.id).populate('roles').populate('team')
      req.user.permissions = new PermissionManager(u)
      next()
    } else {
      next()
    }
  }

  async _setObjectRoles(user, permission, objectId) {
    let objectModel = this._permissions[permission].objectModel
    if (!objectModel) return
    let roles
    if (_.isString(objectModel)) {
      let model = await storage.getModel(objectModel)
      roles = await model.find({user: user.id, object: objectId}).populate('role')
    } else {
      roles = await objectModel(objectId, user)
    }
    user.permissions.addRoles(_.pluck(roles, 'role'), objectId)
  }

}

const permissions = UsersPermissions.getProxy()
export {UsersPermissions as default, permissions}
<|endoftext|>


<commit_before>var os = require('os');
var osRelease = parseFloat(os.release());

if (osRelease < 13  ) {
  module.exports = require('./legacy');
} else {
  module.exports = require('./mavericks');
}
<commit_msg>Use yosmite bindings if os release is 14.0.0<commit_after>var os = require('os');
var osRelease = parseFloat(os.release());

if (osRelease < 13  ) {
  module.exports = require('./legacy');
} else if (osRelease < 14) {
  module.exports = require('./mavericks');
} else {
  module.exports = require('./yosemite');
}
<|endoftext|>


<commit_before><commit_msg>add facebook image<commit_after><|endoftext|>


<commit_before>// TODO: switch to requireJS or AMD modules
// TODO: convert to backbone?

$(function(){
	mf.init()
	mf.load()
})

var mf = {}

mf.init = function() {
	// put in constructor
	mf.nav.skip    = new mf.controllers.button('#skip')
	mf.nav.discard = new mf.controllers.button('#discard')
	mf.nav.publish = new mf.controllers.button('#publish')
	mf.nav.inspect = new mf.controllers.button('#inspect')
	mf.nav.undo    = new mf.controllers.button('#undo')

	mf.nav.skip.bind('right').bind('j').bind('s')
	mf.nav.discard.bind('x').bind('d').bind('space')
	mf.nav.publish.bind('w').bind('p')
	mf.nav.inspect.bind('i')
	mf.nav.undo.bind('u').bind('ctrl+z')
	mf.nav.undo.disable()

	mf.display = new mf.controllers.display('article')
	mf.display.wait()

	mf.pending = new mf.controllers.counter('#pending')
	// queue refill should load article
	mf.pending.change(function(from, to){
		if (from == 0 && to > 0)
			mf.load()

		document.title =  '('+to+') Megafilter'
		console.log('change to',to,'from',from)
	})

	mf.nav.skip.action(mf.skip)
	mf.nav.discard.action(mf.discard)
	mf.nav.publish.action(mf.publish)
	mf.nav.inspect.action(mf.inspect)
	//mf.nav.undo.action(mf.undo)

	setInterval(mf.check_pending,5000)
}

// render the next article from cache and begin to use the
mf.next = function() {}

mf.controllers = {}

mf.controllers.display = function(selector) {
	var ele = $(selector)

	// currently displayed article, if any
	this.article = null

	// render a given node-feedparser article to the page
	this.render = function(article) {
		this.article = article
		$('#error').hide()
		$('#loading').hide()
		ele.css('visibility','visible')
		$('section.description',ele).html(article.description)
		$('> h1 a',ele).html(article.title).attr('href',article.origlink)
		$('time',ele).attr('datetime',article.pubdate)
		if (article.author) $('.note',ele).html(article.author).prepend(' by ')
		// also do link to source site homepage
		// open all article links in a new window
		$('a',ele),attr('target','_new')
		return this
	}

	var discard = this.discard = function() {
		this.article = null
		ele.css('visibility','hidden')
		return this
	}

	// show loading animation
	this.wait = function(){
		$('#loading').show()
		discard()
		$('#error').hide()
		return this
	}

	// show 'error' message
	this.error = function(msg) {
		$('#loading').hide()
		discard()
		$('#error').show().text(msg)
		return this
	}
}

// positive article counter
mf.controllers.counter = function(selector) {
	ele = $(selector)
	// count
	var value = " "

	// callback for when number changes
	var change = function(from,to) {}
	this.change = function(fn) {
		change = fn
	}

	this.set = function(number) {
		if (number == value) return;
		// from, to
		change(value,number)
		ele.text(number)
		value = number
		return this
	}

	// initialise to zero without triggering change()
	ele.text(value)

	this.get = function() {
		return value
	}

	this.decrement = function() {
		if (value > 0) {
			ele.text(--value)
			change(value+1,value)
		}

		return this
	}
}

// navigation buttons (sort of like a view controller)
mf.controllers.button = function(selector){
	var ele = $(selector)
	var enabled = true;

	// callback for when button is clicked or key is pressed
	var action = function() {}
	this.action = function(fn) {
		action = fn
	}

	ele.click(function() {
		if (enabled)
			action()
	})

	this.enable = function() {
		enabled = true
		ele.removeClass('disabled')
		return this
	}

	this.disable = function() {
		enabled = false
		ele.addClass('disabled')
		return this
	}

	// bind a key
	this.bind = function(key) {

		// press
		$(document).bind('keydown',key,function() {
			if (!enabled) return false

			ele.addClass('depressed')
			return false
		})
		// release
		$(document).bind('keyup',key,function() {
			if (!enabled) return false

			ele.removeClass('depressed')
			action()
			return false
		})
		return this
	}
}

// -------model?

// download and display the next article (or current on first load)
mf.load = mf.skip = function() {
	mf.display.wait()
	mf.nav.disable()
	$.ajax({
		url: mf.display.article?'/next':'/current',
		type:'GET',
		error:function() {
			mf.display.error('No more articles')
		},
		success:function(article) {
			if (!article.pending) {
				mf.display.error('None left in queue')
				ml.article = null
			} else {
				mf.display.render(article)
				mf.nav.enable()
			}

			mf.pending.set(article.pending)
		}

	})
}

mf.publish = function() {
	mf.pending.decrement()
	$.ajax({
		url:'/publish/'+mf.display.article.id,
		type:'GET',
		error:function() {
			mf.display.error("None left!")
		},
		success:function() {
			console.log('Published article')
		}

	})
	mf.load()
}

mf.discard = function() {
	mf.pending.decrement()
	$.ajax({
		url:'/'+mf.display.article.id,
		type:'DELETE',
		error:function() {
			mf.display.error("That's it!")
		},
		success:function() {
			console.log('Deleted article')
		}

	})
	mf.load()
}

mf.inspect = function() {
	window.open(mf.display.article.link)
}

mf.nav = {}
mf.nav.enable = function() {
	mf.nav.skip.enable()
	mf.nav.discard.enable()
	mf.nav.publish.enable()
	mf.nav.inspect.enable()
}

mf.nav.disable = function() {
	mf.nav.skip.disable()
	mf.nav.discard.disable()
	mf.nav.publish.disable()
	mf.nav.inspect.disable()
}

mf.check_pending = function () {
	$.ajax({
		url: '/pending',
		type: 'GET',
		success: function(d) {
			mf.pending.set(d.pending)
		}
	})
}
<commit_msg>pending: initialise to zero<commit_after>// TODO: switch to requireJS or AMD modules
// TODO: convert to backbone?

$(function(){
	mf.init()
	mf.load()
})

var mf = {}

mf.init = function() {
	// put in constructor
	mf.nav.skip    = new mf.controllers.button('#skip')
	mf.nav.discard = new mf.controllers.button('#discard')
	mf.nav.publish = new mf.controllers.button('#publish')
	mf.nav.inspect = new mf.controllers.button('#inspect')
	mf.nav.undo    = new mf.controllers.button('#undo')

	mf.nav.skip.bind('right').bind('j').bind('s')
	mf.nav.discard.bind('x').bind('d').bind('space')
	mf.nav.publish.bind('w').bind('p')
	mf.nav.inspect.bind('i')
	mf.nav.undo.bind('u').bind('ctrl+z')
	mf.nav.undo.disable()

	mf.display = new mf.controllers.display('article')
	mf.display.wait()

	mf.pending = new mf.controllers.counter('#pending')
	// queue refill should load article
	mf.pending.change(function(from, to){
		if (from == 0 && to > 0)
			mf.load()

		document.title =  '('+to+') Megafilter'
		console.log('change to',to,'from',from)
	})

	mf.nav.skip.action(mf.skip)
	mf.nav.discard.action(mf.discard)
	mf.nav.publish.action(mf.publish)
	mf.nav.inspect.action(mf.inspect)
	//mf.nav.undo.action(mf.undo)

	setInterval(mf.check_pending,5000)
}

// render the next article from cache and begin to use the
mf.next = function() {}

mf.controllers = {}

mf.controllers.display = function(selector) {
	var ele = $(selector)

	// currently displayed article, if any
	this.article = null

	// render a given node-feedparser article to the page
	this.render = function(article) {
		this.article = article
		$('#error').hide()
		$('#loading').hide()
		ele.css('visibility','visible')
		$('section.description',ele).html(article.description)
		$('> h1 a',ele).html(article.title).attr('href',article.origlink)
		$('time',ele).attr('datetime',article.pubdate)
		if (article.author) $('.note',ele).html(article.author).prepend(' by ')
		// also do link to source site homepage
		// open all article links in a new window
		$('a',ele),attr('target','_new')
		return this
	}

	var discard = this.discard = function() {
		this.article = null
		ele.css('visibility','hidden')
		return this
	}

	// show loading animation
	this.wait = function(){
		$('#loading').show()
		discard()
		$('#error').hide()
		return this
	}

	// show 'error' message
	this.error = function(msg) {
		$('#loading').hide()
		discard()
		$('#error').show().text(msg)
		return this
	}
}

// positive article counter
mf.controllers.counter = function(selector) {
	ele = $(selector)
	// count
	var value = " "

	// callback for when number changes
	var change = function(from,to) {}
	this.change = function(fn) {
		change = fn
	}

	this.set = function(number) {
		if (number == value) return;
		// from, to
		change(value,number)
		ele.text(number)
		value = number
		return this
	}

	// initialise to zero without triggering change()
	ele.text(0)

	this.get = function() {
		return value
	}

	this.decrement = function() {
		if (value > 0) {
			ele.text(--value)
			change(value+1,value)
		}

		return this
	}
}

// navigation buttons (sort of like a view controller)
mf.controllers.button = function(selector){
	var ele = $(selector)
	var enabled = true;

	// callback for when button is clicked or key is pressed
	var action = function() {}
	this.action = function(fn) {
		action = fn
	}

	ele.click(function() {
		if (enabled)
			action()
	})

	this.enable = function() {
		enabled = true
		ele.removeClass('disabled')
		return this
	}

	this.disable = function() {
		enabled = false
		ele.addClass('disabled')
		return this
	}

	// bind a key
	this.bind = function(key) {

		// press
		$(document).bind('keydown',key,function() {
			if (!enabled) return false

			ele.addClass('depressed')
			return false
		})
		// release
		$(document).bind('keyup',key,function() {
			if (!enabled) return false

			ele.removeClass('depressed')
			action()
			return false
		})
		return this
	}
}

// -------model?

// download and display the next article (or current on first load)
mf.load = mf.skip = function() {
	mf.display.wait()
	mf.nav.disable()
	$.ajax({
		url: mf.display.article?'/next':'/current',
		type:'GET',
		error:function() {
			mf.display.error('No more articles')
		},
		success:function(article) {
			if (!article.pending) {
				mf.display.error('None left in queue')
				ml.article = null
			} else {
				mf.display.render(article)
				mf.nav.enable()
			}

			mf.pending.set(article.pending)
		}

	})
}

mf.publish = function() {
	mf.pending.decrement()
	$.ajax({
		url:'/publish/'+mf.display.article.id,
		type:'GET',
		error:function() {
			mf.display.error("None left!")
		},
		success:function() {
			console.log('Published article')
		}

	})
	mf.load()
}

mf.discard = function() {
	mf.pending.decrement()
	$.ajax({
		url:'/'+mf.display.article.id,
		type:'DELETE',
		error:function() {
			mf.display.error("That's it!")
		},
		success:function() {
			console.log('Deleted article')
		}

	})
	mf.load()
}

mf.inspect = function() {
	window.open(mf.display.article.link)
}

mf.nav = {}
mf.nav.enable = function() {
	mf.nav.skip.enable()
	mf.nav.discard.enable()
	mf.nav.publish.enable()
	mf.nav.inspect.enable()
}

mf.nav.disable = function() {
	mf.nav.skip.disable()
	mf.nav.discard.disable()
	mf.nav.publish.disable()
	mf.nav.inspect.disable()
}

mf.check_pending = function () {
	$.ajax({
		url: '/pending',
		type: 'GET',
		success: function(d) {
			mf.pending.set(d.pending)
		}
	})
}
<|endoftext|>


<commit_before>//  ╦  ┌─┐┬ ┬┌─┐┬─┐╔╦╗┌─┐┌┬┐┌─┐┬
//  ║  ├─┤└┬┘├┤ ├┬┘║║║│ │ ││├┤ │
//  ╩═╝┴ ┴ ┴ └─┘┴└─╩ ╩└─┘─┴┘└─┘┴─┘

var LayerModel = function() {
  this.layers = {};
  this.layersSorted = [];
  this.Layer = function(name) {
    this.name = name;
    this.enabled = true;
    this.crashed = false;
    this.depth = this.getNextDepth();
  }
}
LayerModel.prototype.createLayer = function() {
  var name = string.genID();
  var l = new Layer(name);
  this.layers[name] = l;
  return l;
}
LayerModel.prototype.setVars = function(name, txt) {
  this.layers[name] = this.layers[name] || new Layer(name);
  eval("var obj = " + (txt || "{}"));
  this.layers[name].vars = obj;
}
LayerModel.prototype.setDraw = function(name, txt) {
  this.layers[name] = this.layers[name] || new Layer(name);
  eval("var f = function(d) { " + txt + " }");
  this.layers[name].draw = f;
  this.layers[name].crashed = false;
  this.sortLayers();
}
LayerModel.prototype.draw = function(err_cb) {
  var _this = this;
  this.layersSorted.forEach(function(name) {
    push();
    try {
      _this.layers[name].draw(_this.layers[name].vars);
    } catch(err) {
      _this.setCrashed(name);
      err_cb(name, err);
    }
    pop();
  });
}
LayerModel.prototype.remove = function(name) {
  delete this.layers[name];
  this.sortLayers();
}
LayerModel.prototype.setDepth = function(name, dep) {
  this.layers[name].depth = dep;
  this.sortLayers();
}
LayerModel.prototype.setEnabled = function(name, enabled) {
  this.layers[name].enabled = enabled;
  this.sortLayers();
}
LayerModel.prototype.setLayers = function(lyr) {
  this.layers = lyr;
  this.sortLayers();
}
LayerModel.prototype.getNextDepth = function() {
  var layers = this.layers;
  var depths = Object.keys(layers).map(function(name) {
    return layers[name].depth;
  });
  return Math.max.apply(Math, depths) + 2;
}
LayerModel.prototype.setCrashed = function(name) {
  this.layers[name].crashed = true;
  this.sortLayers();
}
LayerModel.prototype.sortLayers = function() {
  var layers = this.layers;
  var activeLayerNames = Object.keys(layers).filter(function(name) {
    return layers[name].enabled && !layers[name].crashed;
  });
  var sortedDepths = activeLayerNames.map(function(name) {
    return { name: name, depth: layers[name].depth }
  });
  sortedDepths.sort(function(a, b) { return a.depth - b.depth});
  this.layersSorted = sortedDepths.map(function(o) { return o.name; })
};

//   ╦┌─┐┬ ┬┬┌─┬┌─┬ ┬┌─┐
//   ║│ ││ │├┴┐├┴┐│ │├┤
//  ╚╝└─┘└─┘┴ ┴┴ ┴└─┘└─┘

var Joukkue = function() {
  this.socket = io();
  this.lastEditAreaId = undefined;
  this.lastEditSelection = undefined;
  this.animPlaying = true;
  this.reservedVSpace = 0;
  this.layerModel = new LayerModel();

  var _this = this;

  // Listen to socket events

  this.socket.on('connect', function() {
    _this.socket.emit(constants.CMD_ADD_USER, string.genRandomName());
  });

  this.socket.on(constants.CMD_SAY, function(username, msg){
    _this.addTextToChat(username + ': ' + msg);
  });

  this.socket.on(constants.CMD_SET_VARS, function(name, html) {
    var cell = $('#' + name + '_vars');
    cell.html(html);
    _this.layerModel.setVars(name, cell.text());
  });

  this.socket.on(constants.CMD_SET_DRAW, function(name, html) {
    var cell = $('#' + name + '_draw');
    cell.html(html);
    _this.layerModel.setDraw(name, cell.text());
  });

  this.socket.on(constants.CMD_REMOVE, function(name) {
    // if focused on disappearing layer, focus somewhere else
    if(cc.lastEditAreaId.attr('id').indexOf(name) == 0) {
      $('#but_help').focus();
    }

    _this.layerModel.remove(name);
    $('#' + name + '_draw').unbind();
    $('#' + name + '_vars').unbind();
    $('#' + name + '_depth').unbind();
    $('#' + name + '_draw').parent().remove();
  });

  this.socket.on(constants.CMD_SET_DEPTH, function(name, dep) {
    dep = parseFloat(dep) || 666;
    _this.layerModel.setDepth(name, dep);
    $('#' + name + '_depth').text(dep);
  });

  this.socket.on(constants.CMD_SET_ENABLED, function(name, enabled) {
    _this.layerModel.setEnabled(name, enabled);
    var tr = $('#' + name + '_draw').parent();
    if(enabled) {
      tr.removeClass('disabled');
    } else {
      tr.addClass('disabled');
    }
  });

  this.socket.on(constants.CMD_SET_LAYERS, function(lyr) {
    $('#grid tr.editable').remove();

    for(var l in lyr) {
      _this.addLayerToDOM(lyr[l]);

      var drawTxt = $('#' + lyr[l].name + '_draw').text();
      var varsTxt = $('#' + lyr[l].name + '_vars').text();

      // make real function/object out of strings
      eval("lyr[l].draw = function(d) { " + drawTxt + " }");
      eval("lyr[l].vars = " + (varsTxt || "{}"));
    };

    _this.layerModel.setLayers(lyr);
  });
};

//  ╔╦╗╔═╗╔╦╗   ┬┬ ┬┌─┐┌─┐┬  ┬┌┐┌┌─┐
//   ║║║ ║║║║   ││ ││ ┬│ ┬│  │││││ ┬
//  ═╩╝╚═╝╩ ╩  └┘└─┘└─┘└─┘┴─┘┴┘└┘└─┘

Joukkue.prototype.saveSelection = function() {
  if (window.getSelection) {
    sel = window.getSelection();
    if (sel.getRangeAt && sel.rangeCount) {
      return sel.getRangeAt(0);
    }
  } else if (document.selection && document.selection.createRange) {
    return document.selection.createRange();
  }
  return null;
}

Joukkue.prototype.restoreSelection = function(range) {
  if (range) {
    if (window.getSelection) {
      sel = window.getSelection();
      sel.removeAllRanges();
      sel.addRange(range);
    } else if (document.selection && range.select) {
      range.select();
    }
  }
}

Joukkue.prototype.addTextToChat = function(msg) {
  $('#row_chatView').append(msg + '
');
  $('#row_chatView').scrollTop($('#row_chatView')[0].scrollHeight);
};

Joukkue.prototype.addCrashToChat = function(name, err) {
  this.addTextToChat(string.fmt(txt.layerCrashed, name, err));
};

Joukkue.prototype.addLayerToDOM = function(l) {
  $('#grid').append(
    string.fmt('
', l.enabled ? '' : 'disabled')
    + string.fmt('%s	', l.name, l.vars || '')
    + string.fmt('%s	', l.name, l.draw || '')
    + string.fmt('%s	', l.name, l.depth || '')
    + '
'
  );

  $('#' + l.name + '_vars').focus(this.onFocusEditable).blur(this.onBlurEditable).mouseup(this.onMouseUpEditable);
  $('#' + l.name + '_draw').focus(this.onFocusEditable).blur(this.onBlurEditable).mouseup(this.onMouseUpEditable);
  $('#' + l.name + '_depth').focus(this.onFocusEditable).blur(this.onBlurEditable).mouseup(this.onMouseUpEditable);
  $('#' + l.name + '_draw').focus();
};

Joukkue.prototype.onBlurEditable = function(e) {
  var t = $(e.currentTarget);
  var isGridElement = t.closest($('#grid')).length > 0;
  t.parent('tr').removeClass('editing');
  if(isGridElement) {
    cc.lastEditAreaId.addClass('target');
  }
};

Joukkue.prototype.onFocusEditable = function(e) {
  var t = $(e.currentTarget);
  var isGridElement = t.closest($('#grid')).length > 0;
  t.parent('tr').addClass('editing');

  if(isGridElement) {
    cc.lastEditAreaId = t;
    $('#grid td.target').removeClass('target');

    // auto scroll up when clicking on last entry (if out of view)
    var offset = t.position().top + t.height() - $('#row_chatView').position().top + 12;
    if(offset > 0) {
      $('#row_grid').scrollTop(offset + $('#row_grid').scrollTop());
    }
  } else {
    // here we can tell the server NOT EDITING
  }
};

// A fix for the unexpected selection of text when
// click-on-last-cell auto scroll up
Joukkue.prototype.onMouseUpEditable = function() {
  var r = window.getSelection().getRangeAt(0);
  r.collapse();
}

Joukkue.prototype.onWindowResize = function() {
  $('#row_grid').height($(window).height() - this.reservedVSpace);
}

Joukkue.prototype.onPressEnter = function() {
  var cmd = $('#row_chatBox').text(),
      idParts,
      cmdParts;
  if(cmd.charAt(0) == '.' && cmd.length > 1) {
    cmdParts = cmd.split(' ');
    idParts = cc.lastEditAreaId.attr('id').split('_');
    switch(cmdParts[0].substr(1)) {
      case 'bottom':
        console.log('bottom', idParts[0]);
        break;
      case 'delete':
        console.log('delete', idParts[0]);
        break;
      case 'down':
        console.log('down', idParts[0]);
        break;
      case 'help':
        this.addTextToChat(txt.help.replace(/_/g, ' '));
        break;
      case 'name':
        break;
      case 'new':
        this.addLayerToDOM(this.layerModel.createLayer());
        break;
      case 'off':
        this.socket.emit(constants.CMD_SET_ENABLED, idParts[0], false);
        break;
      case 'on':
        this.socket.emit(constants.CMD_SET_ENABLED, idParts[0], true);
        break;
      case 'room':
        if(cmdParts[1].match(/\w+/)) {
          this.socket.emit(constants.CMD_JOIN_ROOM, cmdParts[1]);
        } else {
          this.addTextToChat(txt.roomHowto);
        }
        break;
      case 'rooms':
        break;
      case 'top':
        console.log('top', idParts[0]);
        break;
      case 'up':
        console.log('up', idParts[0]);
        break;
      case 'where':
      case 'who':
        this.socket.emit(constants.CMD_REQ_ROOM_INFO);
        break;
    }
  } else {
    cc.socket.emit(constants.CMD_SAY, cmd);
  }
}

//  ╔═╗╔═╕  ┬┌─┐
//  ╠═╝╚═╗  │└─┐
//  ╩  ╘═╝o└┘└─┘

function setup() {
  createCanvas(540, 540);
  background(0);
  var img = loadImage("/joukkue.png", function(i) {
    image(i, width/2-i.width/2, height/2-i.height/2)
  });
}

function draw() {
  cc.layerModel.draw(cc.addCrashToChat);
}

//  ╔╦╗╔═╗╔╦╗  ┌─┐┬  ┬┌─┐┌┐┌┬┐┌─┐   ┬   ┌┐ ┌─┐┌─┐┌┬┐
//   ║║║ ║║║║  ├┤ └┐┌┘├┤ ││││ └─┐  ┌┼─  ├┴┐│ ││ │ │
//  ═╩╝╚═╝╩ ╩  └─┘ └┘ └─┘┘└┘┴ └─┘  └┘   └─┘└─┘└─┘ ┴

$(function() {

  $('#but_help').val(txt.label_help);

  $('#but_play_pause').val(txt.label_pause);
  $('#but_play_pause').click(function() {
    cc.animPlaying = !cc.animPlaying;
    if(cc.animPlaying) {
      loop();
      $('#but_play_pause').val(txt.label_pause);
    } else {
      noLoop();
      $('#but_play_pause').val(txt.label_play);
    }
  });

  $('#but_new_layer').val(txt.label_new_layer);
  $('#but_new_layer').click(function() {
    cc.addLayerToDOM(cc.layerModel.createLayer());
  });

  $('#grid').keydown(function(e) {
    var idParts, layerName, varType, contentHTML,
        k = e.keyCode || e.charCode;

    if(k == 27) {
      // ESC
      cc.lastEditSelection = cc.saveSelection();
      $('#row_chatBox').focus();
    } else if(e.ctrlKey) {

      if(k == 10 || k == 13) {
        // CTRL + ENTER
        idParts = e.target.id.split('_');
        layerName = idParts[0];
        varType = idParts[1];
        contentHTML = $(e.target).html();
        cc.socket.emit(constants.GET_LAYER_SET_CMD[varType],
                       layerName, contentHTML);

      } else if(k == 8 || k == 46 ) {
        // CTRL + DEL
        idParts = e.target.id.split('_');
        layerName = idParts[0];
        cc.socket.emit(constants.CMD_REMOVE, layerName);
        return false;
      }
    }
  });

  $('#row_chatBox').focus(cc.onFocusEditable).blur(cc.onBlurEditable);
  $('#row_chatBox').keydown(function(e) {
    var k = e.keyCode || e.charCode;

    if(k == 10 || k == 13) {
      // ENTER
      cc.onPressEnter();
      $('#row_chatBox').text('');
      e.preventDefault();

    } else if(k == 27) {
      // ESC
      cc.lastEditAreaId.focus();
      cc.restoreSelection(cc.lastEditSelection);
    }
  });

  // resize grid matching window size
  cc.reservedVSpace = $('#row_menu').outerHeight(true) +
    $('#row_chatView').outerHeight(true) +
    $('#row_chatBox').outerHeight(true) + 8;
  cc.onWindowResize();

  $(window).resize(function() {
    cc.onWindowResize();
  });

  // show welcome
  cc.addTextToChat(txt.welcome);
});

var cc = new Joukkue();
<commit_msg>Fix layer creation (Layer class)<commit_after>//  ╦  ┌─┐┬ ┬┌─┐┬─┐╔╦╗┌─┐┌┬┐┌─┐┬
//  ║  ├─┤└┬┘├┤ ├┬┘║║║│ │ ││├┤ │
//  ╩═╝┴ ┴ ┴ └─┘┴└─╩ ╩└─┘─┴┘└─┘┴─┘

var LayerModel = function() {
  this.layers = {};
  this.layersSorted = [];

  var _this = this;
  this.Layer = function(name) {
    this.name = name;
    this.enabled = true;
    this.crashed = false;
    this.depth = _this.getNextDepth();
  }
}
LayerModel.prototype.createLayer = function() {
  var name = string.genID();
  var l = new this.Layer(name);
  this.layers[name] = l;
  return l;
}
LayerModel.prototype.setVars = function(name, txt) {
  this.layers[name] = this.layers[name] || new this.Layer(name);
  eval("var obj = " + (txt || "{}"));
  this.layers[name].vars = obj;
}
LayerModel.prototype.setDraw = function(name, txt) {
  this.layers[name] = this.layers[name] || new this.Layer(name);
  eval("var f = function(d) { " + txt + " }");
  this.layers[name].draw = f;
  this.layers[name].crashed = false;
  this.sortLayers();
}
LayerModel.prototype.draw = function(err_cb) {
  var _this = this;
  this.layersSorted.forEach(function(name) {
    push();
    try {
      _this.layers[name].draw(_this.layers[name].vars);
    } catch(err) {
      _this.setCrashed(name);
      err_cb(name, err);
    }
    pop();
  });
}
LayerModel.prototype.remove = function(name) {
  delete this.layers[name];
  this.sortLayers();
}
LayerModel.prototype.setDepth = function(name, dep) {
  this.layers[name].depth = dep;
  this.sortLayers();
}
LayerModel.prototype.setEnabled = function(name, enabled) {
  this.layers[name].enabled = enabled;
  this.sortLayers();
}
LayerModel.prototype.setLayers = function(lyr) {
  this.layers = lyr;
  this.sortLayers();
}
LayerModel.prototype.getNextDepth = function() {
  var layers = this.layers;
  var depths = Object.keys(layers).map(function(name) {
    return layers[name].depth;
  });
  return Math.max.apply(Math, depths) + 2;
}
LayerModel.prototype.setCrashed = function(name) {
  this.layers[name].crashed = true;
  this.sortLayers();
}
LayerModel.prototype.sortLayers = function() {
  var layers = this.layers;
  var activeLayerNames = Object.keys(layers).filter(function(name) {
    return layers[name].enabled && !layers[name].crashed;
  });
  var sortedDepths = activeLayerNames.map(function(name) {
    return { name: name, depth: layers[name].depth }
  });
  sortedDepths.sort(function(a, b) { return a.depth - b.depth});
  this.layersSorted = sortedDepths.map(function(o) { return o.name; })
};

//   ╦┌─┐┬ ┬┬┌─┬┌─┬ ┬┌─┐
//   ║│ ││ │├┴┐├┴┐│ │├┤
//  ╚╝└─┘└─┘┴ ┴┴ ┴└─┘└─┘

var Joukkue = function() {
  this.socket = io();
  this.lastEditAreaId = undefined;
  this.lastEditSelection = undefined;
  this.animPlaying = true;
  this.reservedVSpace = 0;
  this.layerModel = new LayerModel();

  var _this = this;

  // Listen to socket events

  this.socket.on('connect', function() {
    _this.socket.emit(constants.CMD_ADD_USER, string.genRandomName());
  });

  this.socket.on(constants.CMD_SAY, function(username, msg){
    _this.addTextToChat(username + ': ' + msg);
  });

  this.socket.on(constants.CMD_SET_VARS, function(name, html) {
    var cell = $('#' + name + '_vars');
    cell.html(html);
    _this.layerModel.setVars(name, cell.text());
  });

  this.socket.on(constants.CMD_SET_DRAW, function(name, html) {
    var cell = $('#' + name + '_draw');
    cell.html(html);
    _this.layerModel.setDraw(name, cell.text());
  });

  this.socket.on(constants.CMD_REMOVE, function(name) {
    // if focused on disappearing layer, focus somewhere else
    if(cc.lastEditAreaId.attr('id').indexOf(name) == 0) {
      $('#but_help').focus();
    }

    _this.layerModel.remove(name);
    $('#' + name + '_draw').unbind();
    $('#' + name + '_vars').unbind();
    $('#' + name + '_depth').unbind();
    $('#' + name + '_draw').parent().remove();
  });

  this.socket.on(constants.CMD_SET_DEPTH, function(name, dep) {
    dep = parseFloat(dep) || 666;
    _this.layerModel.setDepth(name, dep);
    $('#' + name + '_depth').text(dep);
  });

  this.socket.on(constants.CMD_SET_ENABLED, function(name, enabled) {
    _this.layerModel.setEnabled(name, enabled);
    var tr = $('#' + name + '_draw').parent();
    if(enabled) {
      tr.removeClass('disabled');
    } else {
      tr.addClass('disabled');
    }
  });

  this.socket.on(constants.CMD_SET_LAYERS, function(lyr) {
    $('#grid tr.editable').remove();

    for(var l in lyr) {
      _this.addLayerToDOM(lyr[l]);

      var drawTxt = $('#' + lyr[l].name + '_draw').text();
      var varsTxt = $('#' + lyr[l].name + '_vars').text();

      // make real function/object out of strings
      eval("lyr[l].draw = function(d) { " + drawTxt + " }");
      eval("lyr[l].vars = " + (varsTxt || "{}"));
    };

    _this.layerModel.setLayers(lyr);
  });
};

//  ╔╦╗╔═╗╔╦╗   ┬┬ ┬┌─┐┌─┐┬  ┬┌┐┌┌─┐
//   ║║║ ║║║║   ││ ││ ┬│ ┬│  │││││ ┬
//  ═╩╝╚═╝╩ ╩  └┘└─┘└─┘└─┘┴─┘┴┘└┘└─┘

Joukkue.prototype.saveSelection = function() {
  if (window.getSelection) {
    sel = window.getSelection();
    if (sel.getRangeAt && sel.rangeCount) {
      return sel.getRangeAt(0);
    }
  } else if (document.selection && document.selection.createRange) {
    return document.selection.createRange();
  }
  return null;
}

Joukkue.prototype.restoreSelection = function(range) {
  if (range) {
    if (window.getSelection) {
      sel = window.getSelection();
      sel.removeAllRanges();
      sel.addRange(range);
    } else if (document.selection && range.select) {
      range.select();
    }
  }
}

Joukkue.prototype.addTextToChat = function(msg) {
  $('#row_chatView').append(msg + '
');
  $('#row_chatView').scrollTop($('#row_chatView')[0].scrollHeight);
};

Joukkue.prototype.addCrashToChat = function(name, err) {
  this.addTextToChat(string.fmt(txt.layerCrashed, name, err));
};

Joukkue.prototype.addLayerToDOM = function(l) {
  $('#grid').append(
    string.fmt('
', l.enabled ? '' : 'disabled')
    + string.fmt('%s	', l.name, l.vars || '')
    + string.fmt('%s	', l.name, l.draw || '')
    + string.fmt('%s	', l.name, l.depth || '')
    + '
'
  );

  $('#' + l.name + '_vars').focus(this.onFocusEditable).blur(this.onBlurEditable).mouseup(this.onMouseUpEditable);
  $('#' + l.name + '_draw').focus(this.onFocusEditable).blur(this.onBlurEditable).mouseup(this.onMouseUpEditable);
  $('#' + l.name + '_depth').focus(this.onFocusEditable).blur(this.onBlurEditable).mouseup(this.onMouseUpEditable);
  $('#' + l.name + '_draw').focus();
};

Joukkue.prototype.onBlurEditable = function(e) {
  var t = $(e.currentTarget);
  var isGridElement = t.closest($('#grid')).length > 0;
  t.parent('tr').removeClass('editing');
  if(isGridElement) {
    cc.lastEditAreaId.addClass('target');
  }
};

Joukkue.prototype.onFocusEditable = function(e) {
  var t = $(e.currentTarget);
  var isGridElement = t.closest($('#grid')).length > 0;
  t.parent('tr').addClass('editing');

  if(isGridElement) {
    cc.lastEditAreaId = t;
    $('#grid td.target').removeClass('target');

    // auto scroll up when clicking on last entry (if out of view)
    var offset = t.position().top + t.height() - $('#row_chatView').position().top + 12;
    if(offset > 0) {
      $('#row_grid').scrollTop(offset + $('#row_grid').scrollTop());
    }
  } else {
    // here we can tell the server NOT EDITING
  }
};

// A fix for the unexpected selection of text when
// click-on-last-cell auto scroll up
Joukkue.prototype.onMouseUpEditable = function() {
  var r = window.getSelection().getRangeAt(0);
  r.collapse();
}

Joukkue.prototype.onWindowResize = function() {
  $('#row_grid').height($(window).height() - this.reservedVSpace);
}

Joukkue.prototype.onPressEnter = function() {
  var cmd = $('#row_chatBox').text(),
      idParts,
      cmdParts;
  if(cmd.charAt(0) == '.' && cmd.length > 1) {
    cmdParts = cmd.split(' ');
    idParts = cc.lastEditAreaId.attr('id').split('_');
    switch(cmdParts[0].substr(1)) {
      case 'bottom':
        console.log('bottom', idParts[0]);
        break;
      case 'delete':
        console.log('delete', idParts[0]);
        break;
      case 'down':
        console.log('down', idParts[0]);
        break;
      case 'help':
        this.addTextToChat(txt.help.replace(/_/g, ' '));
        break;
      case 'name':
        break;
      case 'new':
        this.addLayerToDOM(this.layerModel.createLayer());
        break;
      case 'off':
        this.socket.emit(constants.CMD_SET_ENABLED, idParts[0], false);
        break;
      case 'on':
        this.socket.emit(constants.CMD_SET_ENABLED, idParts[0], true);
        break;
      case 'room':
        if(cmdParts[1].match(/\w+/)) {
          this.socket.emit(constants.CMD_JOIN_ROOM, cmdParts[1]);
        } else {
          this.addTextToChat(txt.roomHowto);
        }
        break;
      case 'rooms':
        break;
      case 'top':
        console.log('top', idParts[0]);
        break;
      case 'up':
        console.log('up', idParts[0]);
        break;
      case 'where':
      case 'who':
        this.socket.emit(constants.CMD_REQ_ROOM_INFO);
        break;
    }
  } else {
    cc.socket.emit(constants.CMD_SAY, cmd);
  }
}

//  ╔═╗╔═╕  ┬┌─┐
//  ╠═╝╚═╗  │└─┐
//  ╩  ╘═╝o└┘└─┘

function setup() {
  createCanvas(540, 540);
  background(0);
  var img = loadImage("/joukkue.png", function(i) {
    image(i, width/2-i.width/2, height/2-i.height/2)
  });
}

function draw() {
  cc.layerModel.draw(cc.addCrashToChat);
}

//  ╔╦╗╔═╗╔╦╗  ┌─┐┬  ┬┌─┐┌┐┌┬┐┌─┐   ┬   ┌┐ ┌─┐┌─┐┌┬┐
//   ║║║ ║║║║  ├┤ └┐┌┘├┤ ││││ └─┐  ┌┼─  ├┴┐│ ││ │ │
//  ═╩╝╚═╝╩ ╩  └─┘ └┘ └─┘┘└┘┴ └─┘  └┘   └─┘└─┘└─┘ ┴

$(function() {

  $('#but_help').val(txt.label_help);

  $('#but_play_pause').val(txt.label_pause);
  $('#but_play_pause').click(function() {
    cc.animPlaying = !cc.animPlaying;
    if(cc.animPlaying) {
      loop();
      $('#but_play_pause').val(txt.label_pause);
    } else {
      noLoop();
      $('#but_play_pause').val(txt.label_play);
    }
  });

  $('#but_new_layer').val(txt.label_new_layer);
  $('#but_new_layer').click(function() {
    cc.addLayerToDOM(cc.layerModel.createLayer());
  });

  $('#grid').keydown(function(e) {
    var idParts, layerName, varType, contentHTML,
        k = e.keyCode || e.charCode;

    if(k == 27) {
      // ESC
      cc.lastEditSelection = cc.saveSelection();
      $('#row_chatBox').focus();
    } else if(e.ctrlKey) {

      if(k == 10 || k == 13) {
        // CTRL + ENTER
        idParts = e.target.id.split('_');
        layerName = idParts[0];
        varType = idParts[1];
        contentHTML = $(e.target).html();
        cc.socket.emit(constants.GET_LAYER_SET_CMD[varType],
                       layerName, contentHTML);

      } else if(k == 8 || k == 46 ) {
        // CTRL + DEL
        idParts = e.target.id.split('_');
        layerName = idParts[0];
        cc.socket.emit(constants.CMD_REMOVE, layerName);
        return false;
      }
    }
  });

  $('#row_chatBox').focus(cc.onFocusEditable).blur(cc.onBlurEditable);
  $('#row_chatBox').keydown(function(e) {
    var k = e.keyCode || e.charCode;

    if(k == 10 || k == 13) {
      // ENTER
      cc.onPressEnter();
      $('#row_chatBox').text('');
      e.preventDefault();

    } else if(k == 27) {
      // ESC
      cc.lastEditAreaId.focus();
      cc.restoreSelection(cc.lastEditSelection);
    }
  });

  // resize grid matching window size
  cc.reservedVSpace = $('#row_menu').outerHeight(true) +
    $('#row_chatView').outerHeight(true) +
    $('#row_chatBox').outerHeight(true) + 8;
  cc.onWindowResize();

  $(window).resize(function() {
    cc.onWindowResize();
  });

  // show welcome
  cc.addTextToChat(txt.welcome);
});

var cc = new Joukkue();
<|endoftext|>


<commit_before>var {DocumentBuilder, DocumentBuilderFactory} = javax.xml.parsers;
var fs = require('fs');

var slreader = require('./sldreader');
var {xmlFromPath, xmlToString} = require('./utils')

var attributeMapping = {
   // @@ enable/disable stroke with this
   "stroke": null,
   "color": "stroke",
   "weight": "stroke-width",
   "opacity": "fill-opacity",
   "fillOpacity": "fill-opacity",
   "fillColor": "fill",
   "strokeOpacity": "stroke-opacity",
   "strokeWidth": "stroke-width",
   // does not exist in mapnik: "strokeDashstyle": ""
   "dashArray": "stroke-dasharray",
   "lineJoin": "stroke-linejoin",
   "lineCap": "stroke-linecap"
};

/**
 * Produces mapnik.xml files given the JSON representation of FeatureTypeStyles as produced by sldreader.
 * @param {String} optional metadata information about about a map and its layers.
 */
var MapnikWriter = exports.MapnikWriter = function(mapMetadata) {

   // assuming mercator projection for all maps
   var attrs = {
      'srs': '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over',
      'background-color': 'transparent',
      'buffer-size': "128"
   }

   /**
    * Create a Filter tag based on the rule.
    * @param {Object} SLD rule object representation
    * @returns {org.w3c.dom.Node} a Filter tag
    */
   this.createFilter = function(filter) {
      var $filter = $doc.createElement('Filter');
      var isAnd = filter.operator == null || filter.operator == 'and';
      var filterString = "";
      filter.comparisions.forEach(function(comparision, idx) {
         filterString += '[' + comparision.property + '] ';
         filterString += comparision.operator;
         filterString += ' ' + comparision.literal;

         if (idx !== filter.comparisions.length-1) {
            if (true == isAnd) {
               filterString += ' and ';
            } else {
               filterString += ' or ';
            }
         }
      });
      var $filterText = $doc.createTextNode(filterString);
      $filter.appendChild($filterText);
      return $filter;
   }

   /**
    * Create Polygon- and LineSymbolizer tags for the given symbolizer representation
    * @param {symbolizer}
    */
   this.createSymbolizers = function(symbolizer) {
      var $polygon = $doc.createElement('PolygonSymbolizer');
      var $line = $doc.createElement('LineSymbolizer');

      Object.keys(symbolizer).forEach(function(key) {
         var attribute = attributeMapping[key];
         if (null == attribute) {
            //console.error('Unmapped attribute', key);
            return;
         }
         var val = symbolizer[key];
         if (val === null || val === undefined) {
            return;
         }
         if (attribute.substring(0, 6) == 'stroke') {
            $line.setAttribute(attribute, val);
         } else {
            $polygon.setAttribute(attribute, val);
         }
      });

      return [$polygon, $line];
   }

   /**
    * Adds a rule to an existing style element
    * @param {org.w3c.dom.Node} the mapnik "Style" tag below which the rule should be attached
    * @param {Object} rule information object
    */
   this.addRule = function($style, rule) {
      var $rule = $doc.createElement('Rule');

      var $filter = this.createFilter(rule.filter);
      var [$polygon, $line] = this.createSymbolizers(rule.symbolizer);

      $rule.appendChild($filter);
      $rule.appendChild($polygon);
      $rule.appendChild($line);

      $style.appendChild($rule);
      return $rule;
   };

   /**
    * Adds an array of FeatureTypeStyles to an existing map.
    * @param {Array} an array of FeatureTypeStyle object representations
    * @param {String} unique name of the style
    */
   this.addStyle = function(featureTypeStyles, name) {
      featureTypeStyles.forEach(function(rules) {
         var $style = $doc.createElement('Style');
         $style.setAttribute('name', name);

         rules.forEach(function(rule) {
            this.addRule($style, rule);
         }, this);

         $map.appendChild($style);
      }, this);
   };

   /**
    * Add a relatively referenced layer geojson to the map.
    *
    * @param {String} path to the geojson file relative to the mapnik.xml or absolute
    * @returns {String} unique name of the style for this layer
    */
   this.addLayer = function(geoJsonPath, name) {
      var $layer = $doc.createElement('Layer');
      $layer.setAttribute('name', name);
      $layer.setAttribute('status', 'on');
      $layer.setAttribute('srs', '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs');
      $layer.setAttribute('buffer-size', "128");

      var $styleName = $doc.createElement('StyleName');
      var styleName = java.util.UUID.randomUUID().toString()
      $styleName.setTextContent(styleName);
      $layer.appendChild($styleName);

      var $dataSource = $doc.createElement('Datasource');
      var $paramType = $doc.createElement('Parameter');
      $paramType.setAttribute('name', 'type');
      $paramType.setTextContent('ogr');
      $dataSource.appendChild($paramType);

      var $paramLayer = $doc.createElement('Parameter');
      $paramLayer.setAttribute('name', 'layer');
      $paramLayer.setTextContent('OGRGeoJSON');
      $dataSource.appendChild($paramLayer)

      //@@@ relative file and add name=base parameter

      var $paramFile = $doc.createElement('Parameter');
      $paramFile.setAttribute('name', 'file');
      var $cdata = $doc.createCDATASection(geoJsonPath);
      $paramFile.appendChild($cdata);
      $dataSource.appendChild($paramFile);
      $layer.appendChild($dataSource);

      $map.appendChild($layer);
      return styleName;
   }

   this.addMap = function(map) {
      map.layers.forEach(function(layer) {
         var geoJsonPath = fs.join(baseDirectory, layer.geojson);
         var sld = xmlFromPath(fs.join(baseDirectory, layer.sld));

         var styleName = this.addLayer(geoJsonPath, layer.title);
         var featureTypeStyles = SLDReader.parse(sld);
         this.addStyle(featureTypeStyles, styleName);
      }, this);
   }

   this.toString = function() {
      return xmlToString(this.$doc);
   }

   var docFactory = DocumentBuilderFactory.newInstance();
   var docBuilder = docFactory.newDocumentBuilder();
   var $doc = docBuilder.newDocument();
   this.$doc = $doc;
   var $map = $doc.createElement('Map');
   this.$map = $map;
   // set default attributes on map
   Object.keys(attrs).forEach(function(key) {
      $map.setAttribute(key, attrs[key]);
   });
   $doc.appendChild($map);

   if (mapMetadata !== undefined) {
      this.addMap(mapMetadata);
   }

   return this;
}
<commit_msg>string literals vs number literals<commit_after>var {DocumentBuilder, DocumentBuilderFactory} = javax.xml.parsers;
var fs = require('fs');

var slreader = require('./sldreader');
var {xmlFromPath, xmlToString} = require('./utils')

var attributeMapping = {
   // @@ enable/disable stroke with this
   "stroke": null,
   "color": "stroke",
   "weight": "stroke-width",
   "opacity": "fill-opacity",
   "fillOpacity": "fill-opacity",
   "fillColor": "fill",
   "strokeOpacity": "stroke-opacity",
   "strokeWidth": "stroke-width",
   // does not exist in mapnik: "strokeDashstyle": ""
   "dashArray": "stroke-dasharray",
   "lineJoin": "stroke-linejoin",
   "lineCap": "stroke-linecap"
};

/**
 * Produces mapnik.xml files given the JSON representation of FeatureTypeStyles as produced by sldreader.
 * @param {String} optional metadata information about about a map and its layers.
 */
var MapnikWriter = exports.MapnikWriter = function(mapMetadata) {

   // assuming mercator projection for all maps
   var attrs = {
      'srs': '+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over',
      'background-color': 'transparent',
      'buffer-size': "128"
   }

   /**
    * Create a Filter tag based on the rule.
    * @param {Object} SLD rule object representation
    * @returns {org.w3c.dom.Node} a Filter tag
    */
   this.createFilter = function(filter) {
      var $filter = $doc.createElement('Filter');
      var isAnd = filter.operator == null || filter.operator == 'and';
      var filterString = "";
      filter.comparisions.forEach(function(comparision, idx) {
         filterString += '[' + comparision.property + '] ';
         filterString += comparision.operator;
         if (typeof(comparision.literal) == 'string') {
            filterString += ' "' + comparision.literal + '"';
         } else {
            filterString += ' ' + comparision.literal;
         }

         if (idx !== filter.comparisions.length-1) {
            if (true == isAnd) {
               filterString += ' and ';
            } else {
               filterString += ' or ';
            }
         }
      });
      var $filterText = $doc.createTextNode(filterString);
      $filter.appendChild($filterText);
      return $filter;
   }

   /**
    * Create Polygon- and LineSymbolizer tags for the given symbolizer representation
    * @param {symbolizer}
    */
   this.createSymbolizers = function(symbolizer) {
      var $polygon = $doc.createElement('PolygonSymbolizer');
      var $line = $doc.createElement('LineSymbolizer');

      Object.keys(symbolizer).forEach(function(key) {
         var attribute = attributeMapping[key];
         if (null == attribute) {
            //console.error('Unmapped attribute', key);
            return;
         }
         var val = symbolizer[key];
         if (val === null || val === undefined) {
            return;
         }
         if (attribute.substring(0, 6) == 'stroke') {
            $line.setAttribute(attribute, val);
         } else {
            $polygon.setAttribute(attribute, val);
         }
      });

      return [$polygon, $line];
   }

   /**
    * Adds a rule to an existing style element
    * @param {org.w3c.dom.Node} the mapnik "Style" tag below which the rule should be attached
    * @param {Object} rule information object
    */
   this.addRule = function($style, rule) {
      var $rule = $doc.createElement('Rule');

      var $filter = this.createFilter(rule.filter);
      var [$polygon, $line] = this.createSymbolizers(rule.symbolizer);

      $rule.appendChild($filter);
      $rule.appendChild($polygon);
      $rule.appendChild($line);

      $style.appendChild($rule);
      return $rule;
   };

   /**
    * Adds an array of FeatureTypeStyles to an existing map.
    * @param {Array} an array of FeatureTypeStyle object representations
    * @param {String} unique name of the style
    */
   this.addStyle = function(featureTypeStyles, name) {
      featureTypeStyles.forEach(function(rules) {
         var $style = $doc.createElement('Style');
         $style.setAttribute('name', name);

         rules.forEach(function(rule) {
            this.addRule($style, rule);
         }, this);

         $map.appendChild($style);
      }, this);
   };

   /**
    * Add a relatively referenced layer geojson to the map.
    *
    * @param {String} path to the geojson file relative to the mapnik.xml or absolute
    * @returns {String} unique name of the style for this layer
    */
   this.addLayer = function(geoJsonPath, name) {
      var $layer = $doc.createElement('Layer');
      $layer.setAttribute('name', name);
      $layer.setAttribute('status', 'on');
      $layer.setAttribute('srs', '+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs');
      $layer.setAttribute('buffer-size', "128");

      var $styleName = $doc.createElement('StyleName');
      var styleName = java.util.UUID.randomUUID().toString()
      $styleName.setTextContent(styleName);
      $layer.appendChild($styleName);

      var $dataSource = $doc.createElement('Datasource');
      var $paramType = $doc.createElement('Parameter');
      $paramType.setAttribute('name', 'type');
      $paramType.setTextContent('ogr');
      $dataSource.appendChild($paramType);

      var $paramLayer = $doc.createElement('Parameter');
      $paramLayer.setAttribute('name', 'layer');
      $paramLayer.setTextContent('OGRGeoJSON');
      $dataSource.appendChild($paramLayer)

      //@@@ relative file and add name=base parameter

      var $paramFile = $doc.createElement('Parameter');
      $paramFile.setAttribute('name', 'file');
      var $cdata = $doc.createCDATASection(geoJsonPath);
      $paramFile.appendChild($cdata);
      $dataSource.appendChild($paramFile);
      $layer.appendChild($dataSource);

      $map.appendChild($layer);
      return styleName;
   }

   this.addMap = function(map) {
      map.layers.forEach(function(layer) {
         var geoJsonPath = fs.join(baseDirectory, layer.geojson);
         var sld = xmlFromPath(fs.join(baseDirectory, layer.sld));

         var styleName = this.addLayer(geoJsonPath, layer.title);
         var featureTypeStyles = SLDReader.parse(sld);
         this.addStyle(featureTypeStyles, styleName);
      }, this);
   }

   this.toString = function() {
      return xmlToString(this.$doc);
   }

   var docFactory = DocumentBuilderFactory.newInstance();
   var docBuilder = docFactory.newDocumentBuilder();
   var $doc = docBuilder.newDocument();
   this.$doc = $doc;
   var $map = $doc.createElement('Map');
   this.$map = $map;
   // set default attributes on map
   Object.keys(attrs).forEach(function(key) {
      $map.setAttribute(key, attrs[key]);
   });
   $doc.appendChild($map);

   if (mapMetadata !== undefined) {
      this.addMap(mapMetadata);
   }

   return this;
}
<|endoftext|>


<commit_before><commit_msg>bulid<commit_after><|endoftext|>


<commit_before>/** internal
 *  class Index
 *
 *  `Index` is a special cached version of [[Environment]].
 *
 *  The expection is that all of its file system methods are cached
 *  for the instances lifetime. This makes `Index` much faster. This
 *  behavior is ideal in production environments where the file system
 *  is immutable.
 *
 *  `Index` should not be initialized directly. Instead use
 *  [[Environment#index]].
 *
 *
 *  ##### SUBCLASS OF
 *
 *  [[Base]]
 **/

'use strict';

// internal
var Base            = require('./base');
var prop            = require('./common').prop;
var getter          = require('./common').getter;
//var cloneMimeTypes  = require('./common').cloneMimeTypes;

////////////////////////////////////////////////////////////////////////////////

/*:nodoc:*
 *  new Index(environment)
 **/
var Index = module.exports = function Index(environment) {
  Base.call(this);

  // some protected properties
  prop(this, 'environment',           environment);
  prop(this, 'ContextClass',          environment.ContextClass);

  // some private properties
  prop(this, '__trail__',             environment.__trail__.index);
  prop(this, '__cache__',             environment.__cache__);
  prop(this, '__engines__',           environment.getEngines());
  prop(this, '__mimeTypes__',         environment.registeredMimeTypes);
  prop(this, '__preProcessors__',     environment.getPreProcessors());
  prop(this, '__postProcessors__',    environment.getPostProcessors());
  prop(this, '__bundleProcessors__',  environment.getBundleProcessors());
  prop(this, '__compressors__',       environment.getCompressors());
  prop(this, '__configurations__',    environment.getConfigurations());

  // make some internal values immutable
  prop(this, '__digestAlgorithm__',   environment.digestAlgorithm);
  prop(this, '__version__',           environment.version);

  // internal cache
  prop(this, '__assets__',            {}, {writable:  true});
  prop(this, '__digests__',           {}, {writable:  true});
};

require('util').inherits(Index, Base);

/**
 *  Index#index -> Index
 *
 *  Self-reference to provide same interface as in [[Environment]].
 **/
getter(Index.prototype, 'index', function () {
  return this;
});

/**
 *  Index.getFileDigest(pathname) -> crypto.Hash
 *
 *  Cached version of [[Base#getFileDigest]].
 **/
Index.prototype.getFileDigest = function (pathname) {
  if (undefined === this.__digests__[pathname]) {
    this.__digests__[pathname] = Base.prototype.getFileDigest.call(this, pathname);
  }

  return this.__digests__[pathname];
};

var _findAsset = Base.prototype.findAsset;

/**
 *  Index#findAsset(pathname[, options]) -> Asset
 *
 *  Caches calls to [[Base#findAsset]].
 *  Pushes cache to the upstream environment as well.
 **/
Index.prototype.findAsset = function (pathname, options) {
  var asset, logical_cache_key, fullpath_cache_key;

  options           = options || {};
  options.bundle    = (undefined === options.bundle) ? true : options.bundle;
  logical_cache_key = this.cacheKeyFor(pathname, options);

  if (this.__assets__[logical_cache_key]) {
    return this.__assets__[logical_cache_key];
  }

  asset = _findAsset.call(this, pathname, options);

  if (asset) {
    fullpath_cache_key = this.cacheKeyFor(asset.pathname, options);

    // Cache on Index
    this.__assets__[logical_cache_key]  =
    this.__assets__[fullpath_cache_key] = asset;

    // Push cache upstream to Environment
    this.environment.__assets__[logical_cache_key]  =
    this.environment.__assets__[fullpath_cache_key] = asset;

    return asset;
  }
};

var _buildAsset = Base.prototype.buildAsset;

// See Base#buildAsset
Index.prototype.buildAsset = function (logicalPath, pathname, options) {
  var self = this, key = this.cacheKeyFor(pathname, options);

  if (!this.__assets__[key]) {
    this.__assets__[key] = this.cacheAsset(key, function () {
      return _buildAsset.call(self, logicalPath, pathname, options);
    });
  }

  return this.__assets__[key];
};

/** internal
 *  Index#expireIndex() -> Void
 *
 *  Throws an error. Kept for keeping same interface as in [[Environment]].
 **/
Index.prototype.expireIndex = function () {
  throw new Error("Can't modify immutable index");
};
<commit_msg>Set Environment's js/css compressors on Index<commit_after>/** internal
 *  class Index
 *
 *  `Index` is a special cached version of [[Environment]].
 *
 *  The expection is that all of its file system methods are cached
 *  for the instances lifetime. This makes `Index` much faster. This
 *  behavior is ideal in production environments where the file system
 *  is immutable.
 *
 *  `Index` should not be initialized directly. Instead use
 *  [[Environment#index]].
 *
 *
 *  ##### SUBCLASS OF
 *
 *  [[Base]]
 **/

'use strict';

// internal
var Base            = require('./base');
var prop            = require('./common').prop;
var getter          = require('./common').getter;
//var cloneMimeTypes  = require('./common').cloneMimeTypes;

////////////////////////////////////////////////////////////////////////////////

/*:nodoc:*
 *  new Index(environment)
 **/
var Index = module.exports = function Index(environment) {
  Base.call(this);

  // some protected properties
  prop(this, 'environment',           environment);
  prop(this, 'ContextClass',          environment.ContextClass);

  // some private properties
  prop(this, '__trail__',             environment.__trail__.index);
  prop(this, '__cache__',             environment.__cache__);
  prop(this, '__engines__',           environment.getEngines());
  prop(this, '__mimeTypes__',         environment.registeredMimeTypes);
  prop(this, '__preProcessors__',     environment.getPreProcessors());
  prop(this, '__postProcessors__',    environment.getPostProcessors());
  prop(this, '__bundleProcessors__',  environment.getBundleProcessors());
  prop(this, '__compressors__',       environment.getCompressors());
  prop(this, '__configurations__',    environment.getConfigurations());
  prop(this, '__jsCompressor__',      environment.__jsCompressor__);
  prop(this, '__cssCompressor__',     environment.__cssCompressor__);

  // make some internal values immutable
  prop(this, '__digestAlgorithm__',   environment.digestAlgorithm);
  prop(this, '__version__',           environment.version);

  // internal cache
  prop(this, '__assets__',            {}, {writable:  true});
  prop(this, '__digests__',           {}, {writable:  true});
};

require('util').inherits(Index, Base);

/**
 *  Index#index -> Index
 *
 *  Self-reference to provide same interface as in [[Environment]].
 **/
getter(Index.prototype, 'index', function () {
  return this;
});

/**
 *  Index.getFileDigest(pathname) -> crypto.Hash
 *
 *  Cached version of [[Base#getFileDigest]].
 **/
Index.prototype.getFileDigest = function (pathname) {
  if (undefined === this.__digests__[pathname]) {
    this.__digests__[pathname] = Base.prototype.getFileDigest.call(this, pathname);
  }

  return this.__digests__[pathname];
};

var _findAsset = Base.prototype.findAsset;

/**
 *  Index#findAsset(pathname[, options]) -> Asset
 *
 *  Caches calls to [[Base#findAsset]].
 *  Pushes cache to the upstream environment as well.
 **/
Index.prototype.findAsset = function (pathname, options) {
  var asset, logical_cache_key, fullpath_cache_key;

  options           = options || {};
  options.bundle    = (undefined === options.bundle) ? true : options.bundle;
  logical_cache_key = this.cacheKeyFor(pathname, options);

  if (this.__assets__[logical_cache_key]) {
    return this.__assets__[logical_cache_key];
  }

  asset = _findAsset.call(this, pathname, options);

  if (asset) {
    fullpath_cache_key = this.cacheKeyFor(asset.pathname, options);

    // Cache on Index
    this.__assets__[logical_cache_key]  =
    this.__assets__[fullpath_cache_key] = asset;

    // Push cache upstream to Environment
    this.environment.__assets__[logical_cache_key]  =
    this.environment.__assets__[fullpath_cache_key] = asset;

    return asset;
  }
};

var _buildAsset = Base.prototype.buildAsset;

// See Base#buildAsset
Index.prototype.buildAsset = function (logicalPath, pathname, options) {
  var self = this, key = this.cacheKeyFor(pathname, options);

  if (!this.__assets__[key]) {
    this.__assets__[key] = this.cacheAsset(key, function () {
      return _buildAsset.call(self, logicalPath, pathname, options);
    });
  }

  return this.__assets__[key];
};

/** internal
 *  Index#expireIndex() -> Void
 *
 *  Throws an error. Kept for keeping same interface as in [[Environment]].
 **/
Index.prototype.expireIndex = function () {
  throw new Error("Can't modify immutable index");
};
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');

module.exports = function(){

  return {
    auth:{
      attributes: function(attr){
        var template = {
          googleEmail: {
            type: 'string',
            unique: true
          },
          name:{
            type: 'string'
          }
        };

        _.merge(template, attr);
        _.merge(attr, template);
      }
    }
  };
};<commit_msg>reshuffle<commit_after>'use strict';

var _ = require('lodash');

module.exports = function(){

  return {
    auth:{
      attributes: function(attr){
        var template = {
          serializedData:{
      			type: 'STRING'
      		},

      		accessToken:{
      			type: 'STRING'
      		},

      		refreshToken:{
      			type: 'STRING'
      		}
        };

        _.merge(template, attr);
        _.merge(attr, template);
      }
    }
  };
};
<|endoftext|>


<commit_before>const request = require('request-promise');
const Discord = require('discord.js');
const revive = require('revive-stats.js')
const moment = require('moment');
module.exports = function (message) {
	var id = message.mentions.users.first() || message.author;
	id = id.id;
	let all = false;
	if (id === message.author.id) all = true;
   let arr = [];
	request("http://revive-bot-discord.revive.systems/v0/discord/userinfo/" + id).catch(err => { console.log(err); message.channel.sendMessage('api down') }).then(body => {
		try { body = JSON.parse(body) } catch (e) { console.log("error: " + body); }
		console.log(body);
		if (body.error)
		{ message.reply("The requested user hasnt linked his discord account with thier revive account"); return; }
		for (let i = 0; i < body.soldiers.length; i++) {
			let soldier = body.soldiers[i];
			if (!all) {
				if (soldier.nickname != body.username)
					continue;
			}
			let gameob = soldier.game == "stella" ? revive.bf2142 : revive.bf2;
			let ranklink = soldier.game == 'stella' ? 'https://github.com/ReviveNetwork/ReviveBot/raw/master/img/bf2142/rank_' : 'https://battlelog.co/img/ranks/rank_'
			gameob.getPlayer(soldier.pid).then(rank => {
				if (!rank) { throw new Error("Player" + soldier.nickname + " Doesnt have any stats") }
				let embed = new Discord.RichEmbed()
					.setTitle(soldier.nickname)
					.setThumbnail(ranklink + rank.rank + '.png')
					.addField("Game: ", (soldier.game == "stella" ? "Battlefield 2142" : "Battlefield 2"), true)
					.addField("Rank: ", (soldier.game == "stella" ? require('../../data/bf2142rank.json') : require('../../data/bf2rank.json'))[rank.rank], true)
					.addField("Online: ", (soldier.online == 1 ? "yes" : "no"), true)
					.addField("Last Active: ", moment(soldier.last_active, "YYYY-MM-DD HH:mm:ss").fromNow(), true)
					.addField("KDR: ", rank.kdr, true)
					.addField("Kills per Minute: ", rank.killsPM, true)
					.addField("Deaths per Minute: ", rank.deathsPM, true)
					.addField("Heals: ", rank.heals, true)
					.addField("Revives: ", rank.revives, true);
				((rank.topOpponentName) ? (embed.addField("Top Opponent: ", rank.topOpponentName, true).addField("Top Victim: ", rank.topVictimName, true)) : "");
				embed.setURL((soldier.game == "stella" ? "http://bl2142.co/bfhq.php?pid=" : "http://battlelog.co/bfhq.php?pid=") + soldier.pid)
					.setFooter("Created " + moment(soldier.time_created, "YYYY-MM-DD HH:mm:ss").fromNow())
					.setColor(soldier.game == "stella" ? "#0000FF" : "#ff0000");
				message.channel.sendEmbed(embed).catch(message.channel.sendMessage);
			});
		}
	});
}
<commit_msg>add usage on ~info<commit_after>const request = require('request-promise');
const Discord = require('discord.js');
const revive = require('revive-stats.js')
const moment = require('moment');
module.exports = function (message) {
	if(message.mentions.size ===0 && message.content.length>6)
	{
		message.reply("Usage:\n~info - shows your stats"+
		"\n~info <usermention> - shows stats of the user mentioned\n"
		+"(the user should have linked his forum account with his discord account)");
	}
	var id = message.mentions.users.first() || message.author;
	id = id.id;
	let all = false;
	if (id === message.author.id) all = true;
   let arr = [];
	request("http://revive-bot-discord.revive.systems/v0/discord/userinfo/" + id).catch(err => { console.log(err); message.channel.sendMessage('api down') }).then(body => {
		try { body = JSON.parse(body) } catch (e) { console.log("error: " + body); }
		console.log(body);
		if (body.error)
		{ message.reply("The requested user hasnt linked his discord account with thier revive account"); return; }
		for (let i = 0; i < body.soldiers.length; i++) {
			let soldier = body.soldiers[i];
			if (!all) {
				if (soldier.nickname != body.username)
					continue;
			}
			let gameob = soldier.game == "stella" ? revive.bf2142 : revive.bf2;
			let ranklink = soldier.game == 'stella' ? 'https://github.com/ReviveNetwork/ReviveBot/raw/master/img/bf2142/rank_' : 'https://battlelog.co/img/ranks/rank_'
			gameob.getPlayer(soldier.pid).then(rank => {
				if (!rank) { throw new Error("Player" + soldier.nickname + " Doesnt have any stats") }
				let embed = new Discord.RichEmbed()
					.setTitle(soldier.nickname)
					.setThumbnail(ranklink + rank.rank + '.png')
					.addField("Game: ", (soldier.game == "stella" ? "Battlefield 2142" : "Battlefield 2"), true)
					.addField("Rank: ", (soldier.game == "stella" ? require('../../data/bf2142rank.json') : require('../../data/bf2rank.json'))[rank.rank], true)
					.addField("Online: ", (soldier.online == 1 ? "yes" : "no"), true)
					.addField("Last Active: ", moment(soldier.last_active, "YYYY-MM-DD HH:mm:ss").fromNow(), true)
					.addField("KDR: ", rank.kdr, true)
					.addField("Kills per Minute: ", rank.killsPM, true)
					.addField("Deaths per Minute: ", rank.deathsPM, true)
					.addField("Heals: ", rank.heals, true)
					.addField("Revives: ", rank.revives, true);
				((rank.topOpponentName) ? (embed.addField("Top Opponent: ", rank.topOpponentName, true).addField("Top Victim: ", rank.topVictimName, true)) : "");
				embed.setURL((soldier.game == "stella" ? "http://bl2142.co/bfhq.php?pid=" : "http://battlelog.co/bfhq.php?pid=") + soldier.pid)
					.setFooter("Created " + moment(soldier.time_created, "YYYY-MM-DD HH:mm:ss").fromNow())
					.setColor(soldier.game == "stella" ? "#0000FF" : "#ff0000");
				message.channel.sendEmbed(embed).catch(message.channel.sendMessage);
			});
		}
	});
}
<|endoftext|>