<commit_before>
/* This file contains action evaluators used in combination with actor Goals to
 * implement more diverse computational intelligence for NPCs.
 * Each evaluator should return a desirability of given action, which is a
 * number between 0 and 1.
 */

const RG = require('./rg');
const Goal = require('./goals');
// const GoalsBattle = require('./goals-battle');

const Evaluator = {};

// Should be returned if evaluator is not applicable to current situation
Evaluator.NOT_POSSIBLE = -1;

// Should be returned if the case is always executed
Evaluator.ALWAYS = 10.0;

/* Base class for all evaluators. Provides only the basic constructor. */
class EvaluatorBase {

    constructor(actorBias) {
        this.actorBias = actorBias;
        this.type = 'Base';
    }

    calculateDesirability() {
        throw new Error('Pure virtual function');
    }

    setActorGoal() {
        throw new Error('Pure virtual function');
    }

    isOrder() {return false;}

    getType() {return this.type;}

    setBias(bias) {
        this.actorBias = bias;
    }

    toJSON() {
        return {
            type: this.getType(),
            bias: this.actorBias
        };
    }

}
Evaluator.Base = EvaluatorBase;

class EvaluatorAttackActor extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'AttackActor';
    }

    calculateDesirability(actor) {
        const brain = actor.getBrain();
        const seenCells = brain.getSeenCells();
        const enemyCell = brain.findEnemyCell(seenCells);
        if (enemyCell) {
            const result = 1;
            this.enemyActor = enemyCell.getActors()[0];
            return this.actorBias * result * 2;
        }
        return Evaluator.NOT_POSSIBLE;
    }

    setActorGoal(actor) {
        const topGoal = actor.getBrain().getGoal();
        const goal = new Goal.AttackActor(actor, this.enemyActor);
        topGoal.addGoal(goal);
    }

}
Evaluator.AttackActor = EvaluatorAttackActor;

/* Evaluator to check if an actor should resort to exploring the area. */
class EvaluatorExplore extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'Explore';
    }

    calculateDesirability(actor) {
        const enemyCells = RG.Brain.getEnemyCellsAround(actor);
        if (enemyCells.length > 0) {
            return 0.01;
        }
        return this.actorBias;
    }

    setActorGoal(actor) {
        const topGoal = actor.getBrain().getGoal();
        const goal = new Goal.Explore(actor);
        topGoal.addGoal(goal);
    }

}
Evaluator.Explore = EvaluatorExplore;

/* Evaluator to check if actor should flee from a fight. */
class EvaluatorFlee extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'Flee';
    }

    calculateDesirability(actor) {
        const enemyCells = RG.Brain.getEnemyCellsAround(actor);
        const health = actor.get('Health');
        const maxHP = health.getMaxHP();
        const HP = health.getHP();
        const propHP = HP / maxHP;
        if (enemyCells.length > 0) {
            if (propHP < this.actorBias) {
                this.enemyActor = enemyCells[0].getActors()[0];
                return this.actorBias * (1.0 - propHP) / Math.pow(propHP, 2);
            }
        }
        return Evaluator.NOT_POSSIBLE;
    }

    setActorGoal(actor) {
        if (this.enemyActor) {
            const topGoal = actor.getBrain().getGoal();
            const goal = new Goal.Flee(actor, this.enemyActor);
            topGoal.addGoal(goal);
        }
        else {
            RG.err('EvaluatorFlee', 'setActorGoal',
                'Enemy actor is null. Cannot flee.');
        }
    }

}
Evaluator.Flee = EvaluatorFlee;

/* Evaluator to check if actor should flee from a fight. */
class EvaluatorPatrol extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'Patrol';
        this.coords = [[2, 2], [40, 10], [20, 20]];
    }

    setCoords(coords) {
        this.coords = coords;
    }

    calculateDesirability() {
        return this.actorBias;
    }

    setActorGoal(actor) {
        const topGoal = actor.getBrain().getGoal();
        const coords = this.coords;
        const goal = new Goal.Patrol(actor, coords);
        topGoal.addGoal(goal);
    }
}
Evaluator.Patrol = EvaluatorPatrol;

/* Evaluator to check if actor should flee from a fight. */
class EvaluatorGuard extends EvaluatorBase {

    constructor(actorBias, xy) {
        super(actorBias);
        this.type = 'Guard';
        this.x = xy[0];
        this.y = xy[1];
    }

    setXY(xy) {
        this.x = xy[0];
        this.y = xy[1];
    }

    calculateDesirability() {
        return this.actorBias;
    }

    setActorGoal(actor) {
        const topGoal = actor.getBrain().getGoal();
        const goal = new Goal.Guard(actor, [this.x, this.y]);
        topGoal.addGoal(goal);
    }
}
Evaluator.Guard = EvaluatorGuard;

/* Evaluator to check if actor should flee from a fight. */
class EvaluatorOrders extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'Orders';
        this.goal = null;
    }

    /* Sets the arguments used for goal injection for commanded actor. */
    setArgs(args) {
        this.goal = args.goal;
        this.srcActor = args.srcActor;
    }

    calculateDesirability() {
        // TODO evaluate srcActor status
        // Evaluate difficulty of goal
        const commanderMult = 1.0;
        const goalCateg = this.goal.getCategory();
        let mult = goalCateg === Goal.Types.Kill ? 0.5 : 1.0;
        mult *= this.actorBias;
        if (this.acceptsOrdersFromSource()) {
            return mult * commanderMult;
        }
        return 0;
    }

    acceptsOrdersFromSource() {
        if (this.srcActor.has('Commander')) {
            return true;
        }
        else if (this.srcActor.isPlayer()) {
            return true;
        }
        return false;
    }

    setActorGoal(actor) {
        if (this.goal) {
            const topGoal = actor.getBrain().getGoal();
            topGoal.addGoal(this.goal);
        }
        else {
            RG.err('EvaluatorOrder', 'setActorGoal',
                'this.goal must not be null');
        }
    }

    setSubEvaluator(evaluator) {
        this.subEval = evaluator;
    }

    isOrder() {return true;}

}
Evaluator.Orders = EvaluatorOrders;

/* Calculates the desirability to cast a certain spell. */
class EvaluatorCastSpell extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'CastSpell';
        this._castingProb = 0.2;
    }

    setCastingProbability(prob) {
        this._castingProb = prob;
    }

    getCastingProbability() {
        return this._castingProb;
    }

    calculateDesirability(actor) {
        this.spell = this.getRandomSpell(actor);
        if (!this.spell) {return 0;}

        if (this.canCastSpell(actor)) {
            if (this.shouldCastSpell(actor)) {
                return this.actorBias;
            }
        }
        return 0;
    }

    setActorGoal(actor) {
        if (this.spell) {
            const topGoal = actor.getBrain().getGoal();
            const goal = new Goal.CastSpell(actor, this.spell, this.spellArgs);
            topGoal.addGoal(goal);
        }
        else {
            RG.err('EvaluatorFlee', 'setActorGoal',
                'Enemy actor is null. Cannot flee.');
        }
    }

    getRandomSpell(actor) {
        const book = actor.getBook();
        if (book && book.getSpells().length > 0) {
            const spell = RG.RAND.arrayGetRand(book.getSpells());
            return spell;
        }
        return null;
    }

    /* Returns true if spellcaster can cast a spell. */
    canCastSpell(actor) {
        if (actor.has('SpellPower')) {
            if (actor.get('SpellPower').getPP() >= this.spell.getPower()) {
                if (RG.RAND.getUniform() <= this._castingProb) {
                    return true;
                }
            }
        }
        return false;
    }

    /* Returns true if spellcaster should cast the spell. */
    shouldCastSpell(actor) {
        const brain = actor.getBrain();
        const seenCells = brain.getSeenCells();
        const enemyCell = brain.findEnemyCell(seenCells);
        const actorCellsAround = RG.Brain.getActorCellsAround(actor);
        if (enemyCell) {
            const enemy = enemyCell.getActors()[0];
            const args = {enemy, actor, actorCellsAround};
            return this.spell.aiShouldCastSpell(args, (actor, args) => {
                this.spellArgs = args;
            });
        }
        return false;
    }

}
Evaluator.CastSpell = EvaluatorCastSpell;

module.exports = Evaluator;
<commit_msg>Moved constants to RG.<commit_after>
/* This file contains action evaluators used in combination with actor Goals to
 * implement more diverse computational intelligence for NPCs.
 * Each evaluator should return a desirability of given action, which is a
 * number between 0 and 1.
 */

const RG = require('./rg');
const Goal = require('./goals');
// const GoalsBattle = require('./goals-battle');

const Evaluator = {};

// Should be returned if evaluator is not applicable to current situation
Evaluator.NOT_POSSIBLE = RG.BIAS.NOT_POSSIBLE;

// Should be returned if the case is always executed
Evaluator.ALWAYS = RG.BIAS.ALWAYS;

/* Base class for all evaluators. Provides only the basic constructor. */
class EvaluatorBase {

    constructor(actorBias) {
        this.actorBias = actorBias;
        this.type = 'Base';
    }

    calculateDesirability() {
        throw new Error('Pure virtual function');
    }

    setActorGoal() {
        throw new Error('Pure virtual function');
    }

    isOrder() {return false;}

    getType() {return this.type;}

    setBias(bias) {
        this.actorBias = bias;
    }

    toJSON() {
        return {
            type: this.getType(),
            bias: this.actorBias
        };
    }

}
Evaluator.Base = EvaluatorBase;

class EvaluatorAttackActor extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'AttackActor';
    }

    calculateDesirability(actor) {
        const brain = actor.getBrain();
        const seenCells = brain.getSeenCells();
        const enemyCell = brain.findEnemyCell(seenCells);
        if (enemyCell) {
            const result = 1;
            this.enemyActor = enemyCell.getActors()[0];
            return this.actorBias * result * 2;
        }
        return Evaluator.NOT_POSSIBLE;
    }

    setActorGoal(actor) {
        const topGoal = actor.getBrain().getGoal();
        const goal = new Goal.AttackActor(actor, this.enemyActor);
        topGoal.addGoal(goal);
    }

}
Evaluator.AttackActor = EvaluatorAttackActor;

/* Evaluator to check if an actor should resort to exploring the area. */
class EvaluatorExplore extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'Explore';
    }

    calculateDesirability(actor) {
        const enemyCells = RG.Brain.getEnemyCellsAround(actor);
        if (enemyCells.length > 0) {
            return 0.01;
        }
        return this.actorBias;
    }

    setActorGoal(actor) {
        const topGoal = actor.getBrain().getGoal();
        const goal = new Goal.Explore(actor);
        topGoal.addGoal(goal);
    }

}
Evaluator.Explore = EvaluatorExplore;

/* Evaluator to check if actor should flee from a fight. */
class EvaluatorFlee extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'Flee';
    }

    calculateDesirability(actor) {
        const enemyCells = RG.Brain.getEnemyCellsAround(actor);
        const health = actor.get('Health');
        const maxHP = health.getMaxHP();
        const HP = health.getHP();
        const propHP = HP / maxHP;
        if (enemyCells.length > 0) {
            if (propHP < this.actorBias) {
                this.enemyActor = enemyCells[0].getActors()[0];
                return this.actorBias * (1.0 - propHP) / Math.pow(propHP, 2);
            }
        }
        return Evaluator.NOT_POSSIBLE;
    }

    setActorGoal(actor) {
        if (this.enemyActor) {
            const topGoal = actor.getBrain().getGoal();
            const goal = new Goal.Flee(actor, this.enemyActor);
            topGoal.addGoal(goal);
        }
        else {
            RG.err('EvaluatorFlee', 'setActorGoal',
                'Enemy actor is null. Cannot flee.');
        }
    }

}
Evaluator.Flee = EvaluatorFlee;

/* Evaluator to check if actor should flee from a fight. */
class EvaluatorPatrol extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'Patrol';
        this.coords = [[2, 2], [40, 10], [20, 20]];
    }

    setCoords(coords) {
        this.coords = coords;
    }

    calculateDesirability() {
        return this.actorBias;
    }

    setActorGoal(actor) {
        const topGoal = actor.getBrain().getGoal();
        const coords = this.coords;
        const goal = new Goal.Patrol(actor, coords);
        topGoal.addGoal(goal);
    }
}
Evaluator.Patrol = EvaluatorPatrol;

/* Evaluator to check if actor should flee from a fight. */
class EvaluatorGuard extends EvaluatorBase {

    constructor(actorBias, xy) {
        super(actorBias);
        this.type = 'Guard';
        this.x = xy[0];
        this.y = xy[1];
    }

    setXY(xy) {
        this.x = xy[0];
        this.y = xy[1];
    }

    calculateDesirability() {
        return this.actorBias;
    }

    setActorGoal(actor) {
        const topGoal = actor.getBrain().getGoal();
        const goal = new Goal.Guard(actor, [this.x, this.y]);
        topGoal.addGoal(goal);
    }
}
Evaluator.Guard = EvaluatorGuard;

/* Evaluator to check if actor should flee from a fight. */
class EvaluatorOrders extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'Orders';
        this.goal = null;
    }

    /* Sets the arguments used for goal injection for commanded actor. */
    setArgs(args) {
        this.goal = args.goal;
        this.srcActor = args.srcActor;
    }

    calculateDesirability() {
        // TODO evaluate srcActor status
        // Evaluate difficulty of goal
        const commanderMult = 1.0;
        const goalCateg = this.goal.getCategory();
        let mult = goalCateg === Goal.Types.Kill ? 0.5 : 1.0;
        mult *= this.actorBias;
        if (this.acceptsOrdersFromSource()) {
            return mult * commanderMult;
        }
        return 0;
    }

    acceptsOrdersFromSource() {
        if (this.srcActor.has('Commander')) {
            return true;
        }
        else if (this.srcActor.isPlayer()) {
            return true;
        }
        return false;
    }

    setActorGoal(actor) {
        if (this.goal) {
            const topGoal = actor.getBrain().getGoal();
            topGoal.addGoal(this.goal);
        }
        else {
            RG.err('EvaluatorOrder', 'setActorGoal',
                'this.goal must not be null');
        }
    }

    setSubEvaluator(evaluator) {
        this.subEval = evaluator;
    }

    isOrder() {return true;}

}
Evaluator.Orders = EvaluatorOrders;

/* Calculates the desirability to cast a certain spell. */
class EvaluatorCastSpell extends EvaluatorBase {

    constructor(actorBias) {
        super(actorBias);
        this.type = 'CastSpell';
        this._castingProb = 0.2;
    }

    setCastingProbability(prob) {
        this._castingProb = prob;
    }

    getCastingProbability() {
        return this._castingProb;
    }

    calculateDesirability(actor) {
        this.spell = this.getRandomSpell(actor);
        if (!this.spell) {return 0;}

        if (this.canCastSpell(actor)) {
            if (this.shouldCastSpell(actor)) {
                return this.actorBias;
            }
        }
        return 0;
    }

    setActorGoal(actor) {
        if (this.spell) {
            const topGoal = actor.getBrain().getGoal();
            const goal = new Goal.CastSpell(actor, this.spell, this.spellArgs);
            topGoal.addGoal(goal);
        }
        else {
            RG.err('EvaluatorFlee', 'setActorGoal',
                'Enemy actor is null. Cannot flee.');
        }
    }

    getRandomSpell(actor) {
        const book = actor.getBook();
        if (book && book.getSpells().length > 0) {
            const spell = RG.RAND.arrayGetRand(book.getSpells());
            return spell;
        }
        return null;
    }

    /* Returns true if spellcaster can cast a spell. */
    canCastSpell(actor) {
        if (actor.has('SpellPower')) {
            if (actor.get('SpellPower').getPP() >= this.spell.getPower()) {
                if (RG.RAND.getUniform() <= this._castingProb) {
                    return true;
                }
            }
        }
        return false;
    }

    /* Returns true if spellcaster should cast the spell. */
    shouldCastSpell(actor) {
        const brain = actor.getBrain();
        const seenCells = brain.getSeenCells();
        const enemyCell = brain.findEnemyCell(seenCells);
        const actorCellsAround = RG.Brain.getActorCellsAround(actor);
        if (enemyCell) {
            const enemy = enemyCell.getActors()[0];
            const args = {enemy, actor, actorCellsAround};
            return this.spell.aiShouldCastSpell(args, (actor, args) => {
                this.spellArgs = args;
            });
        }
        return false;
    }

}
Evaluator.CastSpell = EvaluatorCastSpell;

module.exports = Evaluator;
<|endoftext|>


<commit_before>Seed({
		name : "Mold.Tools.Doc.HTML",
		dna : "class",
		include : [
			{ Ajax : "Mold.Lib.Ajax" }
		]
	},
	function(url){

		if(!url){
			throw new Error("Url is not defined!");
		}

		var _data = [];

		var Modul = function(conf){
			this.name = conf.name || false;
			this.description = conf.description || false;
			this.extend = conf.extend || false;
			this.snippets = [];
		}

		var Snippet = function(conf){
			this.description = conf.description || false;
			this.content = conf.content || '';
		}

		var _firstWord = function(value){
			value = value.toLowerCase()
			return value.substring(0, (~value.indexOf(' ')) ? value.indexOf(' ') : value.length );
		}

		var _extractText = function(value){
			return Mold.trim(value.substring((~value.indexOf(' ')) ? value.indexOf(' ') : value.length, value.length));
		}

		var _parseDoc = function(data){

			data = data.replace(/\n/g, "");
			var output = false;
			var dataParts = data.split(/\@([\s\S]*?)/g);

			for(var i = 0; i < dataParts.length; i++){
				var value = Mold.trim(dataParts[i]);

				switch(_firstWord(value)){
					case "modul":
						output = { type : "modul" };
						break;
					case "modul-end":
						output = { type : "modul-end" };
						break;
					case "snippet":
						output = { type : "snippet" };
						break;
					case "snippet-end":
						output = { type : "snippet-end" };
						break;
					case "name":
						console.log("name foudn",  _extractText(value))
						output.name = _extractText(value);
						break;
					case "description":
						output.description = _extractText(value);
						break;
					case "extends":
						output.extend = _extractText(value);
						break;
				}
			}
			return output;
		}

		var _parse = function(result){
			//console.log("data", result.data.data)
			var parts = result.data.data.split(/\<\!\-\-\/\/([\s\S]*?)\/\/\-\-\>/g);
			var parsed = false;
			var modul = false;
			var snippet = false;

			for(var i = 0; i < parts.length; i++){

				if((parsed = _parseDoc(parts[i]) )){
					//console.log("parsed", parsed.type)
					console.log(i, parts[i])
					switch(parsed.type){
						case "modul":
							modul = new Modul(parsed);
							_data.push(modul);
							break;
						case "snippet":
							if(!modul){
								throw new Error("A snippet has to be declared inside a modul!")
							}
							snippet = new Snippet(parsed);
							modul.snippets.push(snippet);
							break;
						case "modul-end":
							modul = false;
							break;
						case "snippet-end":
							snippet = false;
							break;
					}
				}else{
					if(snippet){
						snippet.content += parts[i];
					}
				}
			}

			console.log("data", _data)
			return _data
		}

		var request = new Ajax();

		request
			.get(url)
			.then(function(data){
				_parse(data);
			});

		this.publics = {
			getData : function(){
				return _data;
			}
		}
	}
)<commit_msg>Mold.Lib.Ajax replaced with Mold.Lib.File<commit_after>Seed({
		name : "Mold.Tools.Doc.HTML",
		dna : "class",
		include : [
			{ File : "Mold.Lib.File" },
			{ Promise : "Mold.Lib.Promise" }
		],
		test : "Mold.Test.Tools.Doc.HTML"
	},
	function(url){

		if(!url){
			throw new Error("Url is not defined!");
		}

		var _data = [];

		var Modul = function(conf){
			this.name = conf.name || false;
			this.description = conf.description || false;
			this.extend = conf.extend || false;
			this.snippets = [];
		}

		var Snippet = function(conf){
			this.description = conf.description || false;
			this.content = conf.content || '';
		}

		var _firstWord = function(value){
			value = value.toLowerCase();
			return value.substring(0, (~value.indexOf(' ')) ? value.indexOf(' ') : value.length );
		}

		var _extractText = function(value){
			return Mold.trim(value.substring((~value.indexOf(' ')) ? value.indexOf(' ') : value.length, value.length));
		}

		var _parseDoc = function(data){

			data = data.replace(/\n/g, "");
			var output = false;
			var dataParts = data.split(/\@([\s\S]*?)/g);

			for(var i = 0; i < dataParts.length; i++){
				var value = Mold.trim(dataParts[i]);

				switch(_firstWord(value)){
					case "modul":
						output = { type : "modul" };
						break;
					case "modul-end":
						output = { type : "modul-end" };
						break;
					case "snippet":
						output = { type : "snippet" };
						break;
					case "snippet-end":
						output = { type : "snippet-end" };
						break;
					case "name":
						console.log("name foudn",  _extractText(value))
						output.name = _extractText(value);
						break;
					case "description":
						output.description = _extractText(value);
						break;
					case "extends":
						output.extend = _extractText(value);
						break;
				}
			}
			return output;
		}

		var _parse = function(data){
			//console.log("data", result.data.data)
			var parts = data.split(/\<\!\-\-\/\/([\s\S]*?)\/\/\-\-\>/g);
			var parsed = false;
			var modul = false;
			var snippet = false;
			var output = [];

			for(var i = 0; i < parts.length; i++){

				if((parsed = _parseDoc(parts[i]) )){
					//console.log("parsed", parsed.type)
					console.log(i, parts[i])
					switch(parsed.type){
						case "modul":
							modul = new Modul(parsed);
							output.push(modul);
							break;
						case "snippet":
							if(!modul){
								throw new Error("A snippet has to be declared inside a modul!")
							}
							snippet = new Snippet(parsed);
							modul.snippets.push(snippet);
							break;
						case "modul-end":
							modul = false;
							break;
						case "snippet-end":
							snippet = false;
							break;
					}
				}else{
					if(snippet){
						snippet.content += parts[i];
					}
				}
			}
			return output;
		}

		var file = new File(url);

		this.publics = {
			get : function(callback){
				return new Promise(function(resolve, reject){
					file
						.content(function(data){
							resolve(_parse(data));
						})
						.error(function(error){
							reject(error);
						});
				});
			}
		}
	}
)<|endoftext|>


<commit_before>import Backbone from 'backbone';
import Clipboard from 'clipboard';
import $ from 'jquery';
import _ from 'underscore';
import Job from '../models/job';
import ResumeView from '../views/resume-view';

var JobView = Backbone.View.extend({
  jobTemplate: _.template($('#job-template').html()),
  metricTemplate: _.template($('#metric-template').html()),
  initialize: function(config) {
    this.jobID = config.jobID;
    this.model = new Job({id: this.jobID});
  },
  events: {
    'click #btn-metric': 'scoreAdjustment'
  },
  render: function() {
    var self = this;
    return this.model.fetch().then(function() {
      var clipboard = new Clipboard('#share-url', {
          text: function(trigger) { return $(location).attr('href'); }
      });

      clipboard.on('success', function(e) {
        var options = {
          placement: 'right',
          title: 'Copied URL to Clipboard!',
          trigger: 'click focus'
        };
        $('#share-url').tooltip(options).tooltip('show');
        setTimeout(function(){
            $('#share-url').tooltip(options).tooltip('hide');
        }, 2000);
      });
      var capitalize = function(string) {
          return string.charAt(0).toUpperCase() + string.slice(1);
      };
      var content = {
          jobTitle: self.model.get('jobTitle'),
          jobIndustry: self.model.get('jobIndustry'),
          jobExperience: self.model.get('jobExperience'),
          educationLevel: capitalize(self.model.get('educationLevel')),
          educationField: self.model.get('educationField'),
          languageSkills: self.model.get('languageSkills'),
          workSkills: self.model.get('languageSkills'),
          description: self.model.get('description')
      };

      self.multipliers = {
        multiplierJob: self.model.get('multiplierJob'),
        multiplierEdu: self.model.get('multiplierEdu'),
        multiplierLang: self.model.get('multiplierLang'),
        multiplierSkill: self.model.get('multiplierSkill'),
      };

      self.$el.html(self.jobTemplate(content));
      var view = new ResumeView({jobID: self.jobID});
      return view.render().then(function(rendered) {
        self.$el.append(rendered.el);
        self.$el.append(self.metricTemplate(self.multipliers));
        return self;
      });
    });
  },
  scoreAdjustment: function() {
    var requestedMultipliers = {
      multiplierJob: parseFloat($('#range-job').val()),
      multiplierEdu: parseFloat($('#range-edu').val()),
      multiplierLang: parseFloat($('#range-lang').val()),
      multiplierSkill: parseFloat($('#range-work').val()),
    };
    if(JSON.stringify(requestedMultipliers) !== JSON.stringify(this.multipliers)) {
      this.multipliers = requestedMultipliers;
      this.model.save(requestedMultipliers);
    }
  }
});

export default JobView;
<commit_msg>Fixed work skills not being displayed properly<commit_after>import Backbone from 'backbone';
import Clipboard from 'clipboard';
import $ from 'jquery';
import _ from 'underscore';
import Job from '../models/job';
import ResumeView from '../views/resume-view';

var JobView = Backbone.View.extend({
  jobTemplate: _.template($('#job-template').html()),
  metricTemplate: _.template($('#metric-template').html()),
  initialize: function(config) {
    this.jobID = config.jobID;
    this.model = new Job({id: this.jobID});
  },
  events: {
    'click #btn-metric': 'scoreAdjustment'
  },
  render: function() {
    var self = this;
    return this.model.fetch().then(function() {
      var clipboard = new Clipboard('#share-url', {
          text: function(trigger) { return $(location).attr('href'); }
      });

      clipboard.on('success', function(e) {
        var options = {
          placement: 'right',
          title: 'Copied URL to Clipboard!',
          trigger: 'click focus'
        };
        $('#share-url').tooltip(options).tooltip('show');
        setTimeout(function(){
            $('#share-url').tooltip(options).tooltip('hide');
        }, 2000);
      });
      var capitalize = function(string) {
          return string.charAt(0).toUpperCase() + string.slice(1);
      };
      var content = {
          jobTitle: self.model.get('jobTitle'),
          jobIndustry: self.model.get('jobIndustry'),
          jobExperience: self.model.get('jobExperience'),
          educationLevel: capitalize(self.model.get('educationLevel')),
          educationField: self.model.get('educationField'),
          languageSkills: self.model.get('languageSkills'),
          workSkills: self.model.get('workSkills'),
          description: self.model.get('description')
      };

      self.multipliers = {
        multiplierJob: self.model.get('multiplierJob'),
        multiplierEdu: self.model.get('multiplierEdu'),
        multiplierLang: self.model.get('multiplierLang'),
        multiplierSkill: self.model.get('multiplierSkill'),
      };

      self.$el.html(self.jobTemplate(content));
      var view = new ResumeView({jobID: self.jobID});
      return view.render().then(function(rendered) {
        self.$el.append(rendered.el);
        self.$el.append(self.metricTemplate(self.multipliers));
        return self;
      });
    });
  },
  scoreAdjustment: function() {
    var requestedMultipliers = {
      multiplierJob: parseFloat($('#range-job').val()),
      multiplierEdu: parseFloat($('#range-edu').val()),
      multiplierLang: parseFloat($('#range-lang').val()),
      multiplierSkill: parseFloat($('#range-work').val()),
    };
    if(JSON.stringify(requestedMultipliers) !== JSON.stringify(this.multipliers)) {
      this.multipliers = requestedMultipliers;
      this.model.save(requestedMultipliers);
    }
  }
});

export default JobView;
<|endoftext|>


<commit_before>var _ = require('underscore');

function InboxFeed(session, limit) {
    this.lastMaxId = null;
    this.moreAvailable = null;
    this.session = session;
    this.allThreads = [];
    this.limit = parseInt(limit) || null;
}

module.exports = InboxFeed;
var Thread = require('../thread');
var Request = require('../request');

InboxFeed.prototype.setMaxId = function (maxId) {
    this.lastMaxId = maxId;
};

InboxFeed.prototype.getMaxId = function () {
    return this.lastMaxId;
};

InboxFeed.prototype.isMoreAvailable = function () {
    return this.moreAvailable;
};

InboxFeed.prototype.get = function () {
    var that = this;
    return new Request(this.session)
        .setMethod('GET')
        .setResource('inbox', {
            maxId: this.getMaxId()
        })
        .send()
        .then(function(json) {
            that.moreAvailable = json.inbox.has_older;
            if (that.moreAvailable)
                that.setMaxId(json.inbox.oldest_cursor.toString());
            return _.map(json.inbox.threads, function (thread) {
                return new Thread(that.session, thread);
            })
        })
};

InboxFeed.prototype.all = function (useCache) {
    var that = this;
    if (useCache === undefined) useCache = true;
    return this.get()
        .then(function (threads) {
            that.allThreads = that.allThreads.concat(threads);
            var exceedLimit = false;
            if (that.limit && that.allThreads.length > that.limit)
                exceedLimit = true;
            if (that.moreAvailable && !exceedLimit) {
                return that.all();
            } else {
                return that.allThreads;
            }
        })
};
<commit_msg>getPendingRequestsTotal method to InboxFeed<commit_after>var _ = require('underscore');

function InboxFeed(session, limit) {
    this.lastMaxId = null;
    this.moreAvailable = null;
    this.session = session;
    this.allThreads = [];
    this.limit = parseInt(limit) || null;
    this.pendingRequestsTotal = null;
}

module.exports = InboxFeed;
var Thread = require('../thread');
var Request = require('../request');

InboxFeed.prototype.setMaxId = function (maxId) {
    this.lastMaxId = maxId;
};

InboxFeed.prototype.getMaxId = function () {
    return this.lastMaxId;
};

InboxFeed.prototype.isMoreAvailable = function () {
    return this.moreAvailable;
};

InboxFeed.prototype.getPendingRequestsTotal = function () {
    return this.pendingRequestsTotal;
};

InboxFeed.prototype.get = function () {
    var that = this;
    return new Request(this.session)
        .setMethod('GET')
        .setResource('inbox', {
            maxId: this.getMaxId()
        })
        .send()
        .then(function(json) {
            that.moreAvailable = json.inbox.has_older;
            that.pendingRequestsTotal = json.pending_requests_total;
            if (that.moreAvailable)
                that.setMaxId(json.inbox.oldest_cursor.toString());
            return _.map(json.inbox.threads, function (thread) {
                return new Thread(that.session, thread);
            })
        })
};

InboxFeed.prototype.all = function (useCache) {
    var that = this;
    if (useCache === undefined) useCache = true;
    return this.get()
        .then(function (threads) {
            that.allThreads = that.allThreads.concat(threads);
            var exceedLimit = false;
            if (that.limit && that.allThreads.length > that.limit)
                exceedLimit = true;
            if (that.moreAvailable && !exceedLimit) {
                return that.all();
            } else {
                return that.allThreads;
            }
        })
};
<|endoftext|>


<commit_before>const webpack = require('webpack')
const merge = require('webpack-merge')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

// build / run options
const PRODUCTION = (process.env.NODE_ENV === 'production')
const USEHOT = (!PRODUCTION && process.env.DEV_USEHOT === 'true')
const USESOURCEMAPS = true

const PATHS = {
  src: path.join(__dirname, 'src'),
  js: path.join(__dirname, 'src', 'js'),
  img: path.join(__dirname, 'src', 'img'),
  css: path.join(__dirname, 'src', 'css'),
  dist: path.join(__dirname, 'dist')
}

// common config
const common = {
  target: 'web',

  entry: [
      path.join(PATHS.js, 'main.js')
  ],

  output: {
    path: path.join(PATHS.dist, 'js/'),
    filename: 'bundle.js',
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel',
        include: PATHS.js,
        exclude: /node_modules/,
        query: {
          presets: ['es2015']
        }
      }
    ]
  },

  stats: { colors: true },

  plugins: [
  ]
}

var config = {} // get weird errors about block scope let

// Target specific config
if (PRODUCTION) {
  config = merge(common, {
    devtool: (USESOURCEMAPS) ? 'source-map' : common.devtool,
    module: {
      loaders: [{
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style', 'css'),
        include: PATHS.css
      }]
    },

    plugins: [
              new CopyWebpackPlugin([{from: path.join(PATHS.src, 'favicon.ico'), to: '..'},
                                     {from: path.join(PATHS.src, 'assistant.html'), to: '..'},
                                     {from: path.join(PATHS.src, 'media.json'), to: '..'},
                                     {from: path.join(PATHS.src, 'CNAME'), to: '..'},
                                     {from: path.join(PATHS.src, '404.html'), to: '..'},
                                     {from: path.join(PATHS.src, 'img'), to: '../img'}]), // abs paths to: don't work
              new HtmlWebpackPlugin({filename: path.join(PATHS.dist, 'assistant.html'),
                          template: path.join(PATHS.src, 'assistant.html'),
                          inject: true
                        }),
              new HtmlWebpackPlugin({filename: path.join(PATHS.dist, 'index.html'),
                template: path.join(PATHS.src, 'index.html'),
                inject: true
                }),
              new webpack.NoErrorsPlugin(),
              new ExtractTextPlugin('../css/[name].css'),
              new webpack.optimize.UglifyJsPlugin({minimize: true})
  ]
  })
} else {
  config = merge(common, {
    devtool: (USESOURCEMAPS) ? 'inline-source-map' : common.devtool,
    output: {
      pathinfo: true,
      publicPath: '/'
    },
    debug: true,
    devServer: {
      contentBase: PATHS.src,
      hot: USEHOT,
      inline: true,
      stats: 'errors-only',
      host: process.env.HOST || '0.0.0.0',
      port: process.env.PORT || '8080',
      historyApiFallback: {
        index: '/'
      }
    },
    module: {
      loaders: [
        {
          test: /\.css$/,
          loaders: ['style', 'css'],
          include: PATHS.css,
        }
      ]
    },

    plugins: [
      new HtmlWebpackPlugin({filename: 'index.html',
                              template: path.join(PATHS.src, 'index.html'),
                              inject: true
                            }),
      new HtmlWebpackPlugin({filename: 'assistant.html',
                              template: path.join(PATHS.src, 'assistant.html'),
                              inject: true
                            })
    ]
  })

  if (USEHOT) {
    config.plugins.push(new webpack.HotModuleReplacementPlugin())
  }
}

module.exports = config
<commit_msg>Add object rest spread plugin<commit_after>const webpack = require('webpack')
const merge = require('webpack-merge')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')

// build / run options
const PRODUCTION = (process.env.NODE_ENV === 'production')
const USEHOT = (!PRODUCTION && process.env.DEV_USEHOT === 'true')
const USESOURCEMAPS = true

const PATHS = {
  src: path.join(__dirname, 'src'),
  js: path.join(__dirname, 'src', 'js'),
  img: path.join(__dirname, 'src', 'img'),
  css: path.join(__dirname, 'src', 'css'),
  dist: path.join(__dirname, 'dist')
}

// common config
const common = {
  target: 'web',

  entry: [
    path.join(PATHS.js, 'main.js')
  ],

  output: {
    path: path.join(PATHS.dist, 'js/'),
    filename: 'bundle.js',
  },

  module: {
    loaders: [
      {
        test: /\.js$/,
        loader: 'babel',
        include: PATHS.js,
        exclude: /node_modules/,
        query: {
          presets: ['es2015'],
          plugins: ['transform-object-rest-spread']
        }
      }
    ]
  },

  stats: {colors: true},

  plugins: [
  ]
}

var config = {} // get weird errors about block scope let

// Target specific config
if (PRODUCTION) {
  config = merge(common, {
    devtool: (USESOURCEMAPS) ? 'source-map' : common.devtool,
    module: {
      loaders: [{
        test: /\.css$/,
        loader: ExtractTextPlugin.extract('style', 'css'),
        include: PATHS.css
      }]
    },

    plugins: [
              new CopyWebpackPlugin([{from: path.join(PATHS.src, 'favicon.ico'), to: '..'},
                                     {from: path.join(PATHS.src, 'assistant.html'), to: '..'},
                                     {from: path.join(PATHS.src, 'activity.html'), to: '..'},
                                     {from: path.join(PATHS.src, 'media.json'), to: '..'},
                                     {from: path.join(PATHS.src, 'CNAME'), to: '..'},
                                     {from: path.join(PATHS.src, '404.html'), to: '..'},
                                     {from: path.join(PATHS.src, 'img'), to: '../img'}]), // abs paths to: don't work
              new HtmlWebpackPlugin({filename: path.join(PATHS.dist, 'activity.html'),
                          template: path.join(PATHS.src, 'activity.html'),
                          inject: true
                        }),
              new HtmlWebpackPlugin({filename: path.join(PATHS.dist, 'assistant.html'),
                          template: path.join(PATHS.src, 'assistant.html'),
                          inject: true
                        }),
              new HtmlWebpackPlugin({filename: path.join(PATHS.dist, 'index.html'),
                template: path.join(PATHS.src, 'index.html'),
                inject: true
                }),
              new webpack.NoErrorsPlugin(),
              new ExtractTextPlugin('../css/[name].css'),
              new webpack.optimize.UglifyJsPlugin({minimize: true})
    ]
  })
} else {
  config = merge(common, {
    devtool: (USESOURCEMAPS) ? 'inline-source-map' : common.devtool,
    output: {
      pathinfo: true,
      publicPath: '/'
    },
    debug: true,
    devServer: {
      contentBase: PATHS.src,
      hot: USEHOT,
      inline: true,
      stats: 'errors-only',
      host: process.env.HOST || '0.0.0.0',
      port: process.env.PORT || '8080',
      historyApiFallback: {
        index: '/'
      }
    },
    module: {
      loaders: [
        {
          test: /\.css$/,
          loaders: ['style', 'css'],
          include: PATHS.css,
        }
      ]
    },

    plugins: [
      new HtmlWebpackPlugin({filename: 'index.html',
                              template: path.join(PATHS.src, 'index.html'),
                              inject: true
                            }),
      new HtmlWebpackPlugin({filename: 'assistant.html',
                              template: path.join(PATHS.src, 'assistant.html'),
                              inject: true
                            }),
      new HtmlWebpackPlugin({filename: 'activity.html',
                              template: path.join(PATHS.src, 'activity.html'),
                              inject: true
                            })
    ]
  })

  if (USEHOT) {
    config.plugins.push(new webpack.HotModuleReplacementPlugin())
  }
}

module.exports = config
<|endoftext|>


<commit_before>const webpack = require('webpack');
const path = require('path');

const nodeEnv = process.env.NODE_ENV || 'development';
const isProd = nodeEnv === 'production';

module.exports = {
  devtool: isProd ? 'hidden-source-map' : 'cheap-eval-source-map',
  entry: './index.js',
  output: {
    path: path.join(__dirname, './dist'),
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loaders: [
          'babel-loader'
        ]
      },
      {
        test: /\.json/,
        loader: 'json-loader'
      },
      {
        test: /\.css$/,
        loader: 'style-loader!css-loader'
      }
    ],
    plugins: [
      new webpack.optimize.OccurrenceOrderPlugin()
    ]
  }
};
<commit_msg>webpack: ignore electron, fix optimization<commit_after>const webpack = require('webpack');
const path = require('path');

const nodeEnv = process.env.NODE_ENV || 'development';
const isProd = nodeEnv === 'production';

module.exports = {
  devtool: isProd ? 'hidden-source-map' : 'cheap-eval-source-map',
  entry: './index.js',
  output: {
    path: path.join(__dirname, './dist'),
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.(js|jsx)$/,
        exclude: /node_modules/,
        loaders: [
          'babel-loader'
        ]
      },
      {
        test: /\.json/,
        loader: 'json-loader'
      },
      {
        test: /\.css$/,
        loader: 'style-loader!css-loader'
      }
    ]
  },
  plugins: [
    new webpack.optimize.OccurrenceOrderPlugin(),
    new webpack.ExternalsPlugin('commonjs', ['electron'])
  ]
};
<|endoftext|>


<commit_before>var path = require('path');

module.exports = {
  entry: path.resolve('./src/script/index.js'),
  devtool: 'eval',
  resolve: {
    extensions: ['.js', '.jsx', '.less', '.json'],
    alias: {
      'react': path.resolve('./node_modules/react'),
      'eth-lightwallet': path.resolve('./node_modules/eth-lightwallet/dist/lightwallet.min.js'),
    },
  },
  watchOptions: {
    poll: 5000,
    ignored: /node_modules/,
  },
  module : {
    loaders : [
      {
        test : /\.(js|jsx)$/,
        loader : 'babel',
        exclude: /node_modules/,
        query: {
          presets : ['es2015', 'react'],
          plugins: ['add-module-exports'],
        },
      },
      {
        test: /\.less$/,
        loader: 'style!css!less',
      },
      {
        test: /\.json$/,
        loader: 'json-loader',
      },
      {
        test: /\.(ttf|eot|svg|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9]|\?[0-9a-z#]+)?$/,
        loader: 'file-loader',
      },
    ],
  },
  output: {
    path: path.resolve('./public/build'),
    publicPath: '/build/',
    filename: 'app.js',
  },
}
<commit_msg>Remove broken reference to the 'add-module-exports' Babel plugin.<commit_after>var path = require('path');

module.exports = {
  entry: path.resolve('./src/script/index.js'),
  devtool: 'eval',
  resolve: {
    extensions: ['.js', '.jsx', '.less', '.json'],
    alias: {
      'react': path.resolve('./node_modules/react'),
      'eth-lightwallet': path.resolve('./node_modules/eth-lightwallet/dist/lightwallet.min.js'),
    },
  },
  watchOptions: {
    poll: 5000,
    ignored: /node_modules/,
  },
  module : {
    loaders : [
      {
        test : /\.(js|jsx)$/,
        loader : 'babel',
        exclude: /node_modules/,
        query: {
          presets : ['es2015', 'react'],
        },
      },
      {
        test: /\.less$/,
        loader: 'style!css!less',
      },
      {
        test: /\.json$/,
        loader: 'json-loader',
      },
      {
        test: /\.(ttf|eot|svg|woff|woff2)(\?v=[0-9]\.[0-9]\.[0-9]|\?[0-9a-z#]+)?$/,
        loader: 'file-loader',
      },
    ],
  },
  output: {
    path: path.resolve('./public/build'),
    publicPath: '/build/',
    filename: 'app.js',
  },
}
<|endoftext|>


<commit_before>// Generated by CoffeeScript 1.10.0
(function() {
  var _sync;

  if (document.location.href.match(/\/~[a-z.]+\//)) {
    arcs.baseURL += document.location.href.match(/\/~[a-z.]+\//);
    arcs.baseURL += BASE_URL;
  }
  else{
    arcs.baseURL = "/"+BASE_URL;
  }

  if (arcs.mode > 0) {
    arcs.dev = {};
    arcs.dev.reload = false;
    arcs.dev.reloadAt = 2000;
    _sync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
      arcs.log('Backbone.sync:', method, model, options);
      return _sync(method, model, options);
    };
    arcs.dev.reloadStylesheets = function() {
      var query;
      query = '?reload=' + new Date().getTime();
      return $('link[rel="stylesheet"]').each(function() {
        return this.href = this.href.replace(/\?.*|$/, query);
      });
    };
    if (arcs.dev.reload) {
      setInterval(arcs.dev.reloadStylesheets, arcs.dev.reloadAt);
    }
  }

  arcs.pagesSid = '738';

}).call(this);
<commit_msg>changed dev.js to be consistent for base url<commit_after>// Generated by CoffeeScript 1.10.0
(function() {
  var _sync;

  arcs.baseURL = "/"+BASE_URL;

  if (arcs.mode > 0) {
    arcs.dev = {};
    arcs.dev.reload = false;
    arcs.dev.reloadAt = 2000;
    _sync = Backbone.sync;
    Backbone.sync = function(method, model, options) {
      arcs.log('Backbone.sync:', method, model, options);
      return _sync(method, model, options);
    };
    arcs.dev.reloadStylesheets = function() {
      var query;
      query = '?reload=' + new Date().getTime();
      return $('link[rel="stylesheet"]').each(function() {
        return this.href = this.href.replace(/\?.*|$/, query);
      });
    };
    if (arcs.dev.reload) {
      setInterval(arcs.dev.reloadStylesheets, arcs.dev.reloadAt);
    }
  }

  arcs.pagesSid = '738';

}).call(this);
<|endoftext|>


<commit_before>//TODO wire protocol
//TODO wire protocol parser & handler

//define westfield namespace as wf
const wf = wf || {};

wf._Object = function (connection) {
    //--public functions--
    this.delete = function () {
        connection._objects.remove(this._id);
    };

    this.postError = function (errorCode, errorMsg) {
        //TODO send error on connection
    };

    //--constructor--
    const connection = connection;
};

//WIRE FORMAT proposal:

//example message format:
//corresponding wire message: 00 03 (id) 01 (opcode) 6e 3f 69 6f 61 00 00 00 14 00 (signature) 00 07 (arg0) 00 00 00 00 (arg1) 00 05 (arg2) fe 12 74 54 67 43 fa a8 ea b3 c8 93 75 36 8e 72 75 92 74 81 (arg3)
// message = {
//     id: 3, //used to find the object with id 3: uint16
//     opcode: 1, //used find the function of object that corresponds to opcode 1: uin8
//     signature: "n?ioa", //used to define the type of the arguments (n= new object with id: uin16, ? = optional, i = integer: sint32, o = existing object with id: uin16, a = array followed by uint32 for size): null terminated char array
//     argsArray: [7, undefined, 5, new ArrayBuffer(20)] // to be used with js' "apply" call.
// };

//example generated object:
// wf.Foo = function (connection) {
//
//     this.__1 = function (argsArray) {
//         this.bar.apply(this, argsArray);
//     };
//
//     //--constructor--
//     wf._Object.call(this, connection);
// };
// wf.Foo.prototype = Object.create(wf._Object);

//TODO we probably want to set a group of functions (an implemented interface)?
//example user implementation:
//foo.bar = myBar;

//example invocation:
// function dispatch(message) {
//     this._objects[message.id]["__"+message.opcode](message.argsArray);
// }

wf.Connection = function (webSocket) {

    //--public properties--
    this._objects = new Map();

    //--private functions--
    const parse = function (blob) {
        //TODO convert blob to message;

    };

    const dispatch = function (message) {
        //TODO interpret message => find object & invoke it's function
    };

    const onSocketOpen = function (event) {
        //TODO send back-end minimal required browser info (we start with screen size)
    };

    const onSocketClose = function (event) {

    };

    const onSocketError = function (event) {

    };

    const onSocketMessage = function (event) {
        const message = parse(event);
        dispatch(message);
    };

    const setupSocket = function (socket) {
        socket.onopen = onSocketOpen;
        socket.onclose = onSocketClose;
        socket.onerror = onSocketError;
        socket.onmessage = onSocketMessage;

        return socket;
    };

    //--public functions--
    this.send = function (data) {
        socket.send(data);
    };

    this.close = function () {
        socket.close();
    };

    this._registerObject = function (object) {
        //find unused id.
        var id = 1;
        while (this._objects.has(id)) {
            id++;
        }
        object._id = id;
        this._objects.set(object._id, object);
    };

    //--constructor--
    const socket = setupSocket(webSocket);
    this._registerObject(this.registry);
};

wf.connect = function (socketUrl) {
    const socket = new WebSocket(socketUrl, "westfield");
    const connection = new wf.Connection(socket);

    //registry will be defined by the protocol generator
    const registry = new wf.Registry();
    connection._registerObject(registry);
    connection.registry = registry;

    return connection;
};
<commit_msg>experiment with marshall function<commit_after>//TODO wire protocol
//TODO wire protocol parser & handler

//define westfield namespace as wf
const wf = wf || {};

wf._Object = function (connection) {
    //--public functions--
    this.delete = function () {
        this.objects.remove(this._id);
        connection.marshall(this._id, 0, "o", [object._id]);
    };

    this.postError = function (errorCode, errorMsg) {
        //TODO send error on connection
    };

    //--constructor--
    const connection = connection;
};

//WIRE FORMAT proposal:

//example message format from client to server:
//corresponding wire message: 00 03 (id) 01 (opcode) 6e 3f 69 6f 61 00 (signature) 00 07 (arg0) 00 00 00 00 (arg1) 00 05 (arg2) 00 00 00 14 fe 12 74 54 67 43 fa a8 ea b3 c8 93 75 36 8e 72 75 92 74 81 (arg3)
// message = {
//     id: 3, //used to find the object with id 3: uint16
//     opcode: 1, //used find the function of object that corresponds to opcode 1. Opcode 0 is reserved: uint8
//     signature: "n?ioa", //used to define the type of the arguments (n= new object with id: uin16, ? = optional, i = integer: sint32, o = existing object with id: uin16, a = array): null terminated char array
//     argsArray: [7, undefined, 5, new ArrayBuffer(20)] // to be used with js' "apply" call.
// };

//example generated object:
// wf.Foo = function (connection) {
//
//     this.1 = function (argsArray) {
//         this.bar.apply(this, argsArray);
//     };
//
//     //--constructor--
//     wf._Object.call(this, connection);
// };
// wf.Foo.prototype = Object.create(wf._Object);

wf.Connection = function (webSocket) {

    //--private properties--
    this.objects = new Map();

    //--private functions--
    const unmarshall = function (blob) {
        //TODO convert blob to message;

    };

    const dispatch = function (message) {
        //TODO interpret message => find object & invoke it's function
    };

    const onSocketOpen = function (event) {
        //TODO send back-end minimal required browser info (we start with screen size)
    };

    const onSocketClose = function (event) {

    };

    const onSocketError = function (event) {

    };

    const onSocketMessage = function (event) {
        const message = unmarshall(event);
        dispatch(message);
    };

    const setupSocket = function (socket) {
        socket.onopen = onSocketOpen;
        socket.onclose = onSocketClose;
        socket.onerror = onSocketError;
        socket.onmessage = onSocketMessage;

        return socket;
    };

    //--public functions--
    this.marshall = function (id, opcode, signature, argsArray) {

        //TODO make this function great again.

        //determine length
        //id(2)+opcode(1)
        var size = 3;
        //signature.length+null byte
        size += signature.length + 1;

        const wireCharsAscii = [];
        var argi = 0;
        //first pass, determine size
        var optional = false;
        for (var i = 0; i < signature.length; i++) {
            var signatureChar = signature[i];
            wireCharsAscii[i] = signatureChar.charCodeAt(i);
            switch (signatureChar) {
                case "i": //integer, sint32 -> 4
                case "f": //fixed, uint32 -> 4
                    size += 4;
                    argi++;
                    break;
                case "o": //object, uint16 -> 2
                case "n": //new object, uint16 -> 2
                    size += 2;
                    argi++;
                    break;
                case "s": //string, 4+data length (in bytes)
                case "a": //array, 4+data length (in bytes)

                    const arg = argsArray[argi];
                    if (optional && arg == undefined) {
                        size += 4;
                    }
                    else if (arg instanceof ArrayBuffer || arg instanceof String) {
                        size += 4;
                        size += arg.length;
                    }
                    else {
                        throw new TypeError("Argument #" + argi + " is not of type ArrayBuffer or String.");
                    }

                    argi++;
                    break;
                case "?": //optional -> 0
                    optional = true;
                    break;
                default:
                //TODO more types
            }
        }
        wireCharsAscii[wireCharsAscii.length] = 0;

        const wireMsg = new ArrayBuffer(size);
        const wireMsgView = new DataView(wireMsg);
        var offset = 0;

        wireMsgView.setInt16(offset, id, true);//id
        offset += 2;

        wireMsgView.setInt8(offset, opcode);//opcode
        offset += 1;

        wireCharsAscii.forEach(function (asciiChar) {
            wireMsg.setInt8(offset, asciiChar);
            offset += 1;
        });

        //second pass, fill in buffer
        argi = 0;
        optional = false;
        for (i = 0; i < signature.length; i++) {
            signatureChar = signature[i];
            const arg = argsArray[argi];
            switch (signatureChar) {
                case "i":
                case "f":
                    if (optional && arg == undefined) {
                        wireMsgView.setInt32(offset, 0, true);
                        optional = false;
                    } else {
                        wireMsgView.setInt32(offset, arg, true);
                    }
                    offset += 4;

                    argi++;
                    break;
                case "o":
                case "n":
                    if (optional && arg == undefined) {
                        wireMsgView.setUint16(offset, 0, true);
                        optional = false;
                    } else {
                        wireMsgView.setUint16(offset, arg, true);
                    }
                    offset += 2;

                    argi++;
                    break;
                case "s":
                case "a":
                    if (optional && arg == undefined) {
                        wireMsgView.setInt32(offset, 0, true);
                        offset += 4;
                        optional = false;
                    } else {
                        wireMsgView.setInt32(offset, arg.length, true);
                        offset += 4;
                        arg.forEach(new function (byte) {
                            wireMsg.setInt8(offset, byte);
                            offset += 1;
                        });
                    }

                    argi++;
                    break;
                case "?":
                    optional = true;
                    break;
                default:
                    throw new TypeError("Unrecognized type " + signatureChar + " in signature for arg #" + argi);
                //TODO more types
            }
        }

        socket.send(wireMsg);
    };

    this.close = function () {
        this.objects.values().slice().forEach(function (object) {
            object.delete();
        });
        socket.close();
    };

    this._registerObject = function (object) {
        //find unused id.
        var id = 1;
        while (this._objects.has(id)) {
            id++;
        }
        object._id = id;
        this.objects.set(object._id, object);
    };

    //--constructor--
    const socket = setupSocket(webSocket);
};

wf.connect = function (socketUrl) {
    const socket = new WebSocket(socketUrl, "westfield");
    const connection = new wf.Connection(socket);

    //registry will be defined by the protocol generator
    const registry = new wf.Registry();
    connection._registerObject(registry);
    connection.registry = registry;

    return connection;
};
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   MySystem.PropertyEditorPane
// Copyright: ©2010 Concord Consortium
// under the MIT License (see LICENSE file for more info)
// ==========================================================================
/*globals MySystem LinkIt SCUI Forms */

/** @class

  (Document Your View Here)

  @extends SC.Pane
*/
sc_require('core');

MySystem.PropertyEditorPane = SC.PalettePane.extend(
{
  acceptsFirstResponder: YES,
  layout: {
      top: 150,
      right: 5,
      width: 250,
      height: 240
  },
  classNames: 'property-editor'.w(),

  displayProperties: 'objectToEdit isSelected'.w(),
  objectToEdit: null,
  isSelected: false,

  childViews: ''.w(),

  propertiesForm: Forms.FormView.create({
    fields: "".w(),
    findField: function(key) {
      var rightField = null;
      this.fields.forEach( function (item, index, enumerable) {
        if (item.get('fieldKey') == key) {
          rightField = item;
        }
      });
      return rightField;
    }
  }),

  // returns the index of the first occurrence of element in array, -1 if it's not there
  indexOf: function(element, array) {
    for (var i = 0; i < array.length; i += 1) {
      if (element == array[i]) return i;
    }
    return -1;
  },

  update_everything: function() {
    var form = this.get('propertiesForm');
    var baseObject = this.get('objectToEdit');
    if (baseObject === null) {
      // Clear fields
      if (form.parentView !== null) {
        form.set('fields', []);
        form.removeAllChildren();
      }
    } else {
      // Add the form if it doesn't exist
      if (form.parentView === null) {
        this.appendChild(form);
      }
      form.set('content', baseObject);
      // Clear fields before we start
      form.set('fields', []);
      form.removeAllChildren();
      // Append form rows
      form.set('fields', baseObject.get('formFields'));
      if (baseObject.kindOf(MySystem.Link)) {
        var startNode = baseObject.get('startNode');
        var endNode = baseObject.get('endNode');
        var colors = startNode.intersection(startNode.acceptableOutLinkColors(), endNode.acceptableInLinkColors());
        var radioButtons = form.get('_displayFields').objectAt(0).get('_displayFields').objectAt(0).get('field');
        // if (!startNode.get('transformer')) {
        //   // TODO: Figure out a more elegant way to do this
        //   form.get('_displayFields').objectAt(0).get('_displayFields').objectAt(0).get('field').set('isEnabled', false);
        // }
        var items = radioButtons.get('items');
        for (var i = 0; i < items.get('length'); i += 1) {
          var item = items.objectAt(i);
          if (colors === null) {
            item.enabled = true;
          } else {
            if (this.indexOf(item.value, colors) >= 0) {
              item.enabled = true;
            } else {
              item.enabled = false;
            }
          }
        }
      }
    }
  }.observes('objectToEdit'),

  fieldChanged: function(target, key, value, revision) {// note value will always be null
    var field = target;
    var newValue = field.get('value');
    this.get('objectToEdit').set(key, newValue);
  },

  keyDown: function(evt) {
    return this.interpretKeyEvents(evt) ? YES : NO;
  },

  deleteBackward: function() {
    MySystem.canvasView.deleteSelection();
    // this.get('objectToEdit').destroy();
    return YES;
  },

  deleteForward: function() {
    MySystem.canvasView.deleteSelection();
    // this.get('objectToEdit').destroy();
    return YES;
  }
});
<commit_msg>Simplifying the link type form.<commit_after>// ==========================================================================
// Project:   MySystem.PropertyEditorPane
// Copyright: ©2010 Concord Consortium
// under the MIT License (see LICENSE file for more info)
// ==========================================================================
/*globals MySystem LinkIt SCUI Forms */

/** @class

  (Document Your View Here)

  @extends SC.Pane
*/
sc_require('core');

MySystem.PropertyEditorPane = SC.PalettePane.extend(
{
  acceptsFirstResponder: YES,
  layout: {
      top: 150,
      right: 5,
      width: 250,
      height: 240
  },
  classNames: 'property-editor'.w(),

  displayProperties: 'objectToEdit isSelected'.w(),
  objectToEdit: null,
  isSelected: false,

  childViews: ''.w(),

  propertiesForm: Forms.FormView.create({
    fields: "".w(),
    findField: function(key) {
      var rightField = null;
      this.fields.forEach( function (item, index, enumerable) {
        if (item.get('fieldKey') == key) {
          rightField = item;
        }
      });
      return rightField;
    }
  }),

  // returns the index of the first occurrence of element in array, -1 if it's not there
  indexOf: function(element, array) {
    for (var i = 0; i < array.length; i += 1) {
      if (element == array[i]) return i;
    }
    return -1;
  },

  update_everything: function() {
    var form = this.get('propertiesForm');
    var baseObject = this.get('objectToEdit');
    if (baseObject === null) {
      // Clear fields
      if (form.parentView !== null) {
        form.set('fields', []);
        form.removeAllChildren();
      }
    } else {
      // Add the form if it doesn't exist
      if (form.parentView === null) {
        this.appendChild(form);
      }
      form.set('content', baseObject);
      // Clear fields before we start
      form.set('fields', []);
      form.removeAllChildren();
      // Append form rows
      form.set('fields', baseObject.get('formFields'));
      /* Temporarily removed for Berkeley 0.1 release */
      // if (baseObject.kindOf(MySystem.Link)) {
        // var startNode = baseObject.get('startNode');
        // var endNode = baseObject.get('endNode');
        // var colors = startNode.intersection(startNode.acceptableOutLinkColors(), endNode.acceptableInLinkColors());
        // FIXME: Need to work on values here
        // var radioButtons = form.get('_displayFields').objectAt(0).get('_displayFields').objectAt(0).get('field');
        // if (!startNode.get('transformer')) {
        //   // TODO: Figure out a more elegant way to do this
        //   form.get('_displayFields').objectAt(0).get('_displayFields').objectAt(0).get('field').set('isEnabled', false);
        // }
        // var items = radioButtons.get('items');
        // for (var i = 0; i < items.get('length'); i += 1) {
        //   var item = items.objectAt(i);
        //   if (true) { // (colors === null) {
        //     item.enabled = true;
        //   } else {
        //     if (this.indexOf(item.value, colors) >= 0) {
        //       item.enabled = true;
        //     } else {
        //       item.enabled = false;
        //     }
        //   }
        // }
      // }
    }
  }.observes('objectToEdit'),

  fieldChanged: function(target, key, value, revision) {// note value will always be null
    var field = target;
    var newValue = field.get('value');
    this.get('objectToEdit').set(key, newValue);
  },

  keyDown: function(evt) {
    return this.interpretKeyEvents(evt) ? YES : NO;
  },

  deleteBackward: function() {
    MySystem.canvasView.deleteSelection();
    // this.get('objectToEdit').destroy();
    return YES;
  },

  deleteForward: function() {
    MySystem.canvasView.deleteSelection();
    // this.get('objectToEdit').destroy();
    return YES;
  }
});
<|endoftext|>


<commit_before>/**
 * Maskable
 *
 * @mixin
 *
 * Creates an input mask that is
 * generated from a masked str
 *
 * Example: mask="#### #### #### ####"
 */

import {
  isMaskDelimiter,
  maskText,
  unmaskText
} from '../util/mask'

export default {
  data: () => ({
    selection: 0,
    preDefined: {
      'credit-card': '#### - #### - #### - ####',
      'date': '##/##/####',
      'date-with-time': '##/##/#### ##:##',
      'phone': '(###) ### - ####',
      'social': '###-##-####',
      'time': '##:##',
      'time-with-seconds': '##:##:##'
    }
  }),

  props: {
    dontFillMaskBlanks: Boolean,
    mask: {
      type: [Object, String],
      default: null
    },
    returnMaskedValue: Boolean
  },

  computed: {
    masked () {
      const preDefined = this.preDefined[this.mask]
      const mask = preDefined || this.mask || ''

      return mask.split('')
    }
  },

  watch: {
    /**
     * Make sure the cursor is in the correct
     * location when the mask changes
     */
    mask () {
      if (!this.$refs.input) return

      const oldText = this.$refs.input.value || ''
      const newText = this.maskText(this.lazyValue || '')
      let position = 0
      let selection = this.selection

      for (const char of oldText.substr(0, selection)) {
        isMaskDelimiter(char) || position++
      }

      selection = 0
      for (const char of newText) {
        isMaskDelimiter(char) || position--
        selection++
        if (position <= 0) break
      }

      this.setCaretPosition(selection)
    }
  },

  methods: {
    setCaretPosition (selection) {
      this.selection = selection
      window.setTimeout(() => {
        this.$refs.input.setSelectionRange(selection, selection)
      }, 0)
    },
    updateRange () {
      if (!this.$refs.input) return

      const newValue = this.maskText(this.lazyValue)
      let selection = 0

      this.$refs.input.value = newValue
      for (const char of newValue) {
        if (this.lazySelection <= 0) break
        isMaskDelimiter(char) || this.lazySelection--
        selection++
      }

      this.setCaretPosition(selection)
    },
    maskText (text) {
      if (!this.mask) return text

      return maskText(text, this.masked, this.dontFillMaskBlanks)
    },
    unmaskText (text) {
      if (this.returnMaskedValue || !this.mask) return text

      return unmaskText(text)
    },
    // When the input changes and is
    // re-created, ensure that the
    // caret location is correct
    setSelectionRange () {
      this.$nextTick(this.updateRange)
    }
  }
}
<commit_msg>Fix cursor position in masked inputs when the framerate is low<commit_after>/**
 * Maskable
 *
 * @mixin
 *
 * Creates an input mask that is
 * generated from a masked str
 *
 * Example: mask="#### #### #### ####"
 */

import {
  isMaskDelimiter,
  maskText,
  unmaskText
} from '../util/mask'

export default {
  data: () => ({
    selection: 0,
    preDefined: {
      'credit-card': '#### - #### - #### - ####',
      'date': '##/##/####',
      'date-with-time': '##/##/#### ##:##',
      'phone': '(###) ### - ####',
      'social': '###-##-####',
      'time': '##:##',
      'time-with-seconds': '##:##:##'
    }
  }),

  props: {
    dontFillMaskBlanks: Boolean,
    mask: {
      type: [Object, String],
      default: null
    },
    returnMaskedValue: Boolean
  },

  computed: {
    masked () {
      const preDefined = this.preDefined[this.mask]
      const mask = preDefined || this.mask || ''

      return mask.split('')
    }
  },

  watch: {
    /**
     * Make sure the cursor is in the correct
     * location when the mask changes
     */
    mask () {
      if (!this.$refs.input) return

      const oldText = this.$refs.input.value || ''
      const newText = this.maskText(this.lazyValue || '')
      let position = 0
      let selection = this.selection

      for (const char of oldText.substr(0, selection)) {
        isMaskDelimiter(char) || position++
      }

      selection = 0
      for (const char of newText) {
        isMaskDelimiter(char) || position--
        selection++
        if (position <= 0) break
      }

      this.setCaretPosition(selection)
    }
  },

  methods: {
    setCaretPosition (selection) {
      this.selection = selection
      window.setTimeout(() => {
        this.$refs.input.setSelectionRange(this.selection, this.selection)
      }, 0)
    },
    updateRange () {
      if (!this.$refs.input) return

      const newValue = this.maskText(this.lazyValue)
      let selection = 0

      this.$refs.input.value = newValue
      for (const char of newValue) {
        if (this.lazySelection <= 0) break
        isMaskDelimiter(char) || this.lazySelection--
        selection++
      }

      this.setCaretPosition(selection)
    },
    maskText (text) {
      if (!this.mask) return text

      return maskText(text, this.masked, this.dontFillMaskBlanks)
    },
    unmaskText (text) {
      if (this.returnMaskedValue || !this.mask) return text

      return unmaskText(text)
    },
    // When the input changes and is
    // re-created, ensure that the
    // caret location is correct
    setSelectionRange () {
      this.$nextTick(this.updateRange)
    }
  }
}
<|endoftext|>


<commit_before>'use strict';

const Joi = require('joi'),
  handlers = require('./controllers/handler');

module.exports = function(server) {
  server.route({
    method: 'GET',
    path: '/deck/{id}',
    handler: handlers.getDeck,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
      },
      tags: ['api'],
      description: 'Get metadata of a deck'
    }
  });

  server.route({
    method: 'POST',
    path: '/deck/new',
    handler: handlers.newDeck,
    config: {
      validate: {
        payload: Joi.object().keys({
          description: Joi.string(),
          language: Joi.string(),
          translation: Joi.string().alphanum().lowercase(),
          tags: Joi.array().items(Joi.string()).default([]),
          title: Joi.string(),
          user: Joi.string().alphanum().lowercase(),
          root_deck: Joi.string().alphanum().lowercase(),
          parent_deck: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          //position: Joi.string().alphanum().lowercase().min(0),
          license: Joi.string().valid('CC0', 'CC BY', 'CC BY-SA')
        }).requiredKeys('user', 'license'),
      },
      tags: ['api'],
      description: 'Create a new deck'
    }
  });

  server.route({
    method: 'PUT',
    path: '/deck/{id}',
    handler: handlers.updateDeckRevision,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
        payload: Joi.object().keys({
          description: Joi.string(),
          language: Joi.string(),
          translation: Joi.string().alphanum().lowercase(),
          tags: Joi.array().items(Joi.string()).default([]),
          title: Joi.string(),
          user: Joi.string().alphanum().lowercase(),
          root_deck: Joi.string(),
          parent_deck: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          content_items: Joi.array(),
          license: Joi.string().valid('CC0', 'CC BY', 'CC BY-SA')
        }).requiredKeys('user', 'license'),
      },
      tags: ['api'],
      description: 'Replace a deck by creating a new revision'
    }
  });

  server.route({
    method: 'POST',
    path: '/deck/revert/{id}',
    handler: handlers.revertDeckRevision,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
        payload: Joi.object().keys({
          revision_id: Joi.string().alphanum().lowercase()
        }).requiredKeys('revision_id'),
      },
      tags: ['api'],
      description: 'Revert a deck to an old revision'
    }
  });

  //slides
  server.route({
    method: 'GET',
    path: '/slide/{id}',
    handler: handlers.getSlide,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
      },
      tags: ['api'],
      description: 'Get a slide'
    }
  });

  server.route({
    method: 'GET',
    path: '/allslide',
    handler: handlers.getAllSlides,
    config: {
      validate: {
        params: {
        },
      },
      tags: ['api'],
      description: 'Get all slide'
    }
  });

  server.route({
    method: 'GET',
    path: '/deck/{id}/slides',
    handler: handlers.getFlatSlides,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
      },
      tags: ['api'],
      description: 'Get all slide'
    }
  });

  server.route({
    method: 'POST',
    path: '/slide/new',
    handler: handlers.newSlide,
    config: {
      validate: {
        payload: Joi.object().keys({
          title: Joi.string(),
          content: Joi.string(),
          speakernotes: Joi.string(),
          user: Joi.string().alphanum().lowercase(),
          root_deck: Joi.string().alphanum().lowercase(),
          parent_deck: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
		  //add a field for deck revision?
		  /* root_deck : Joi.object().keys({
            id: Joi.string().alphanum().lowercase(), //id of the root deck
            revision: Joi.string().alphanum().lowercase() //revision number of the root deck revision
          }), */
          parent_slide: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          position: Joi.string().alphanum().lowercase().min(0),
          language: Joi.string(),
          license: Joi.string().valid('CC0', 'CC BY', 'CC BY-SA')
        }).requiredKeys('user', 'content', 'root_deck', 'license'),
      },
      tags: ['api'],
      description: 'Create a new slide'
    }
  });

  // TODO Altered API from Alis proposal
  server.route({
    method: 'PUT',
    path: '/slide/{id}',
    //for now, no new revision on replace
    handler: handlers.updateNoRevisionSlide,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
        payload: Joi.object().keys({
          title: Joi.string(),
          content: Joi.string(),
          speakernotes: Joi.string(),
          user: Joi.string().alphanum().lowercase(),
          root_deck: Joi.string(),
          parent_deck: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          parent_slide: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          position: Joi.string().alphanum().lowercase().min(0),
          language: Joi.string(),
          license: Joi.string().valid('CC0', 'CC BY', 'CC BY-SA')
        }).requiredKeys('user', 'content', 'root_deck', 'license'),
      },
      tags: ['api'],
      description: 'Replace a slide with a new revision'
    }
  });

  server.route({
    method: 'POST',
    path: '/slide/revert/{id}',
    handler: handlers.revertSlideRevision,
    config: {
      validate: {
        params: {
          id: Joi.string().alphanum().lowercase()
        },
        payload: Joi.object().keys({
          revision_id: Joi.string().alphanum().lowercase()
        }).requiredKeys('revision_id'),
      },
      tags: ['api'],
      description: 'Revert a slide to an old revision'
    }
  });

  //------------decktree APIs----------------
  server.route({
    method: 'GET',
    path: '/decktree/{id}',
    handler: handlers.getDeckTree,
    config: {
      validate: {
        params: {
          id: Joi.string()
        }
      },
      tags: ['api'],
      description: 'Get the deck tree'
    }
  });

  server.route({
    method: 'POST',
    path: '/decktree/node/create',
    handler: handlers.createDeckTreeNode,
    config: {
      validate: {
        payload: Joi.object().keys({
          selector: Joi.object().keys({
            id: Joi.string(), //id of the root deck
            spath: Joi.string(),
            stype: Joi.string(),
            sid: Joi.string()
          }),
          nodeSpec: Joi.object().keys({
            id: Joi.string(),
            type: Joi.string()
          }),
          user: Joi.string().alphanum().lowercase()
        }).requiredKeys('selector', 'user'),
      },
      tags: ['api'],
      description: 'Create a new node (slide/deck) in the deck tree'
    }
  });

  server.route({
    method: 'PUT',
    path: '/decktree/node/rename',
    handler: handlers.renameDeckTreeNode,
    config: {
      validate: {
        payload: Joi.object().keys({
          selector: Joi.object().keys({
            id: Joi.string(), //id of the root deck
            spath: Joi.string(),
            stype: Joi.string(),
            sid: Joi.string()
          }),
          name: Joi.string(),
          user: Joi.string().alphanum().lowercase()
        }).requiredKeys('selector', 'user'),
      },
      tags: ['api'],
      description: 'Rename a node (slide/deck) in the deck tree'
    }
  });

  server.route({
    method: 'DELETE',
    path: '/decktree/node/delete',
    handler: handlers.deleteDeckTreeNode,
    config: {
      validate: {
        payload: Joi.object().keys({
          selector: Joi.object().keys({
            id: Joi.string(), //id of the root deck
            spath: Joi.string(),
            stype: Joi.string(),
            sid: Joi.string()
          }),
          user: Joi.string().alphanum().lowercase()
        }).requiredKeys('selector', 'user'),
      },
      tags: ['api'],
      description: 'Delete a node (slide/deck) from the deck tree'
    }
  });
};
<commit_msg>Fixed bug with translation object in deck/new parameters<commit_after>'use strict';

const Joi = require('joi'),
  handlers = require('./controllers/handler');

module.exports = function(server) {
  server.route({
    method: 'GET',
    path: '/deck/{id}',
    handler: handlers.getDeck,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
      },
      tags: ['api'],
      description: 'Get metadata of a deck'
    }
  });

  server.route({
    method: 'POST',
    path: '/deck/new',
    handler: handlers.newDeck,
    config: {
      validate: {
        payload: Joi.object().keys({
          description: Joi.string(),
          language: Joi.string(),
          translation: Joi.object().keys({
            status: Joi.string().valid('original', 'google', 'revised')
          }),
          tags: Joi.array().items(Joi.string()).default([]),
          title: Joi.string(),
          user: Joi.string().alphanum().lowercase(),
          root_deck: Joi.string().alphanum().lowercase(),
          parent_deck: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          //position: Joi.string().alphanum().lowercase().min(0),
          license: Joi.string().valid('CC0', 'CC BY', 'CC BY-SA')
        }).requiredKeys('user', 'license'),
      },
      tags: ['api'],
      description: 'Create a new deck'
    }
  });

  server.route({
    method: 'PUT',
    path: '/deck/{id}',
    handler: handlers.updateDeckRevision,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
        payload: Joi.object().keys({
          description: Joi.string(),
          language: Joi.string(),
          translation: Joi.string().alphanum().lowercase(),
          tags: Joi.array().items(Joi.string()).default([]),
          title: Joi.string(),
          user: Joi.string().alphanum().lowercase(),
          root_deck: Joi.string(),
          parent_deck: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          content_items: Joi.array(),
          license: Joi.string().valid('CC0', 'CC BY', 'CC BY-SA')
        }).requiredKeys('user', 'license'),
      },
      tags: ['api'],
      description: 'Replace a deck by creating a new revision'
    }
  });

  server.route({
    method: 'POST',
    path: '/deck/revert/{id}',
    handler: handlers.revertDeckRevision,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
        payload: Joi.object().keys({
          revision_id: Joi.string().alphanum().lowercase()
        }).requiredKeys('revision_id'),
      },
      tags: ['api'],
      description: 'Revert a deck to an old revision'
    }
  });

  //slides
  server.route({
    method: 'GET',
    path: '/slide/{id}',
    handler: handlers.getSlide,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
      },
      tags: ['api'],
      description: 'Get a slide'
    }
  });

  server.route({
    method: 'GET',
    path: '/allslide',
    handler: handlers.getAllSlides,
    config: {
      validate: {
        params: {
        },
      },
      tags: ['api'],
      description: 'Get all slide'
    }
  });

  server.route({
    method: 'GET',
    path: '/deck/{id}/slides',
    handler: handlers.getFlatSlides,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
      },
      tags: ['api'],
      description: 'Get all slide'
    }
  });

  server.route({
    method: 'POST',
    path: '/slide/new',
    handler: handlers.newSlide,
    config: {
      validate: {
        payload: Joi.object().keys({
          title: Joi.string(),
          content: Joi.string(),
          speakernotes: Joi.string(),
          user: Joi.string().alphanum().lowercase(),
          root_deck: Joi.string().alphanum().lowercase(),
          parent_deck: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
		  //add a field for deck revision?
		  /* root_deck : Joi.object().keys({
            id: Joi.string().alphanum().lowercase(), //id of the root deck
            revision: Joi.string().alphanum().lowercase() //revision number of the root deck revision
          }), */
          parent_slide: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          position: Joi.string().alphanum().lowercase().min(0),
          language: Joi.string(),
          license: Joi.string().valid('CC0', 'CC BY', 'CC BY-SA')
        }).requiredKeys('user', 'content', 'root_deck', 'license'),
      },
      tags: ['api'],
      description: 'Create a new slide'
    }
  });

  // TODO Altered API from Alis proposal
  server.route({
    method: 'PUT',
    path: '/slide/{id}',
    //for now, no new revision on replace
    handler: handlers.updateNoRevisionSlide,
    config: {
      validate: {
        params: {
          id: Joi.string()
        },
        payload: Joi.object().keys({
          title: Joi.string(),
          content: Joi.string(),
          speakernotes: Joi.string(),
          user: Joi.string().alphanum().lowercase(),
          root_deck: Joi.string(),
          parent_deck: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          parent_slide: Joi.object().keys({
            id: Joi.string().alphanum().lowercase(),
            revision: Joi.string().alphanum().lowercase()
          }),
          position: Joi.string().alphanum().lowercase().min(0),
          language: Joi.string(),
          license: Joi.string().valid('CC0', 'CC BY', 'CC BY-SA')
        }).requiredKeys('user', 'content', 'root_deck', 'license'),
      },
      tags: ['api'],
      description: 'Replace a slide with a new revision'
    }
  });

  server.route({
    method: 'POST',
    path: '/slide/revert/{id}',
    handler: handlers.revertSlideRevision,
    config: {
      validate: {
        params: {
          id: Joi.string().alphanum().lowercase()
        },
        payload: Joi.object().keys({
          revision_id: Joi.string().alphanum().lowercase()
        }).requiredKeys('revision_id'),
      },
      tags: ['api'],
      description: 'Revert a slide to an old revision'
    }
  });

  //------------decktree APIs----------------
  server.route({
    method: 'GET',
    path: '/decktree/{id}',
    handler: handlers.getDeckTree,
    config: {
      validate: {
        params: {
          id: Joi.string()
        }
      },
      tags: ['api'],
      description: 'Get the deck tree'
    }
  });

  server.route({
    method: 'POST',
    path: '/decktree/node/create',
    handler: handlers.createDeckTreeNode,
    config: {
      validate: {
        payload: Joi.object().keys({
          selector: Joi.object().keys({
            id: Joi.string(), //id of the root deck
            spath: Joi.string(),
            stype: Joi.string(),
            sid: Joi.string()
          }),
          nodeSpec: Joi.object().keys({
            id: Joi.string(),
            type: Joi.string()
          }),
          user: Joi.string().alphanum().lowercase()
        }).requiredKeys('selector', 'user'),
      },
      tags: ['api'],
      description: 'Create a new node (slide/deck) in the deck tree'
    }
  });

  server.route({
    method: 'PUT',
    path: '/decktree/node/rename',
    handler: handlers.renameDeckTreeNode,
    config: {
      validate: {
        payload: Joi.object().keys({
          selector: Joi.object().keys({
            id: Joi.string(), //id of the root deck
            spath: Joi.string(),
            stype: Joi.string(),
            sid: Joi.string()
          }),
          name: Joi.string(),
          user: Joi.string().alphanum().lowercase()
        }).requiredKeys('selector', 'user'),
      },
      tags: ['api'],
      description: 'Rename a node (slide/deck) in the deck tree'
    }
  });

  server.route({
    method: 'DELETE',
    path: '/decktree/node/delete',
    handler: handlers.deleteDeckTreeNode,
    config: {
      validate: {
        payload: Joi.object().keys({
          selector: Joi.object().keys({
            id: Joi.string(), //id of the root deck
            spath: Joi.string(),
            stype: Joi.string(),
            sid: Joi.string()
          }),
          user: Joi.string().alphanum().lowercase()
        }).requiredKeys('selector', 'user'),
      },
      tags: ['api'],
      description: 'Delete a node (slide/deck) from the deck tree'
    }
  });
};
<|endoftext|>


<commit_before>var randomstring = require("randomstring");
var Immutable = require('seamless-immutable');
var actions = require('../state/actions/actions');
var stateStore = undefined;
var deepEqual = require('deep-equal');
var ddiff = require('deep-diff');

if (process.type !== 'browser') {
  stateStore = require('../rendererStore');
  var firebaseService = require('electron').remote.getGlobal('firebaseService');
} else {
  stateStore = require('../mainStore');
}

module.exports = {
  Document,
  updateOnCMChange,
  emitChanges,
  getRemoteFileDiff,
  setAsCurrentDoc,
  upateCursorLocation
}

function Document(id, title, scriptType) {
  if (!id) {
    id = randomstring.generate(20)
  }

  var doc = Immutable({
    id: id,
    title: title || null,
    createdOn: Date.now(),
    modifiedOn: Date.now(),
    author: null,
    content: '',
    sync: false,
    type: scriptType,
    history: [],
    collaborators: {},
    related: [],
    cursor: null,
    deleted: false,
    history: []
  })

  if (firebaseService) {
    doc = Immutable.set(doc, 'author', firebaseService.firebaseUser.id);
    firebaseService.addFileToUser(doc.id);
    firebaseService.writeRemoteFile(doc);
  }
  return doc;
};

function updateOnCMChange(doc, c, change) {
  var updated = Immutable.merge(doc, {
    // history: doc.history.concat(doc.modifiedOn),
    content: c.getValue(),
    modifiedOn: Date.now(),
  });

  if (doc.title === 'Untitled' || doc.title.length < 10) {
    updated = Immutable.set(updated, 'title', updated.content.substring(0,10));
  }

  stateStore.dispatch(actions.updateDoc(updated));
  firebaseService.updateRemoteFile(updated);
  return updated;
};

function emitChanges(updated) {
  stateStore.dispatch(actions.updateDoc(updated));
  firebaseService.writeRemoteFile(updated);
}

function getRemoteFileDiff(local, remote) {
  if (local && remote && !deepEqual(local, remote)) {
    var diff = ddiff(local, remote),
        changes = diff.map(function(d) {
          var c = [];
          for (var p in d.path) {
            c.push(d.path[p]);
          }
          return c;
        });

    return [].concat.apply([], changes);
  }
  return [];
}

function setAsCurrentDoc(docID, cm) {
  firebaseService.updateUserCurrentFile(docID);
  firebaseService.getCurrentCollaboratorCursors(docID);
  stateStore.dispatch(actions.changeCurrentDoc(docID));
  if (cm) {
    upateCursorLocation(cm, docID);
  }
}

function upateCursorLocation(cm, docID) {
  var rawCursor = cm.getCursor();
  console.log(rawCursor)
  var cursor = {
        line: rawCursor.line,
        ch: rawCursor.ch
      };
  firebaseService.updateUserCursor(cursor);
  stateStore.dispatch(actions.userCursorUpdate(cursor, docID));
}
<commit_msg>fixing weird document update bug, moving cursors when it shouldn't<commit_after>var randomstring = require("randomstring");
var Immutable = require('seamless-immutable');
var actions = require('../state/actions/actions');
var stateStore = undefined;
var deepEqual = require('deep-equal');
var ddiff = require('deep-diff');

if (process.type !== 'browser') {
  stateStore = require('../rendererStore');
  var firebaseService = require('electron').remote.getGlobal('firebaseService');
} else {
  stateStore = require('../mainStore');
}

module.exports = {
  Document,
  updateOnCMChange,
  emitChanges,
  getRemoteFileDiff,
  setAsCurrentDoc,
  upateCursorLocation
}

function Document(id, title, scriptType) {
  if (!id) {
    id = randomstring.generate(20)
  }

  var doc = Immutable({
    id: id,
    title: title || null,
    createdOn: Date.now(),
    modifiedOn: Date.now(),
    author: null,
    content: '',
    sync: false,
    type: scriptType,
    history: [],
    collaborators: {},
    related: [],
    cursor: null,
    deleted: false,
    history: []
  })

  if (firebaseService) {
    doc = Immutable.set(doc, 'author', firebaseService.firebaseUser.id);
    firebaseService.addFileToUser(doc.id);
    firebaseService.writeRemoteFile(doc);
  }
  return doc;
};

function updateOnCMChange(doc, c, change) {
  var updated = Immutable.merge(doc, {
    // history: doc.history.concat(doc.modifiedOn),
    content: c.getValue(),
    modifiedOn: Date.now(),
  });

  if (doc.title === 'Untitled' || doc.title.length < 10) {
    updated = Immutable.set(updated, 'title', updated.content.substring(0,10));
  }

  return updated;
};

function emitChanges(updated) {
  stateStore.dispatch(actions.updateDoc(updated));
  firebaseService.writeRemoteFile(updated);
}

function getRemoteFileDiff(local, remote) {
  if (local && remote && !deepEqual(local, remote)) {
    var diff = ddiff(local, remote),
        changes = diff.map(function(d) {
          var c = [];
          for (var p in d.path) {
            c.push(d.path[p]);
          }
          return c;
        });

    return [].concat.apply([], changes);
  }
  return [];
}

function setAsCurrentDoc(docID, cm) {
  firebaseService.updateUserCurrentFile(docID);
  firebaseService.getCurrentCollaboratorCursors(docID);
  stateStore.dispatch(actions.changeCurrentDoc(docID));
  if (cm) {
    upateCursorLocation(cm, docID);
  }
}

function upateCursorLocation(cm, docID) {
  var rawCursor = cm.getCursor();
  console.log(rawCursor)
  var cursor = {
        line: rawCursor.line,
        ch: rawCursor.ch
      };
  firebaseService.updateUserCursor(cursor);
  stateStore.dispatch(actions.userCursorUpdate(cursor, docID));
}
<|endoftext|>