<commit_before>function Player(army, hqPos) {
	this.army = army;
  this.gold = 500;
  this.active = false; // boolean to be used to determine which players turn it is
  this.hqPos = hqPos;
};

Player.prototype.update = function(map, myTurn) {
	this.army.update(map);
};

Player.prototype.unitPositions = function() {
  return this.army.units.map(function(unit) {
    return unit.pos;
  });
};

Player.prototype.onTurnStart = function(map, myPlayerID) {
  this.army.units.forEach(function(unit) {
    var tile = map.getTileAtPos(unit.pos);
    if(tile.owner !== undefined && tile.owner === myPlayerID) {
      var prevDamageTaken = unit.damageTaken;
      unit.damageTaken -= Math.floor(unit.health / 5);
      if(unit.damageTaken < 0) {
        unit.damageTaken = 0;
      }
      var healthGained = prevDamageTaken - unit.damageTaken ;
      console.log(healthGained);
      if(healthGained > 0){
        var style = { font: "12px Arial", backgroundColor: "green", fill: "#ffffff", strokeThickness: 3, align: "center" };
        var text = game.add.text(unit.pos.canvasX() + 16, unit.pos.canvasY(), ("+" + healthGained), style);
        text.anchor.set(0.5);
        text.alpha = 1;
        var tween = game.add.tween(text).to( { alpha: 0, y: unit.pos.canvasY() - 20 }, 1500, "Linear", true);
      }
    }
  });
}

Player.prototype.openMenu = function() {
  //TODO: Opens menu and presents player options
};

Player.prototype.endTurn = function() {
  // Allows player to end their turn
  this.army.units.forEach(function(unit) {
    unit.resetUnit();
  });
};

Player.prototype.quitGame = function() {
  //TODO: Allows player to end the battle
  // When this function is called it will start the "VictoryState" Game State
};
<commit_msg>remove console log<commit_after>function Player(army, hqPos) {
	this.army = army;
  this.gold = 500;
  this.active = false; // boolean to be used to determine which players turn it is
  this.hqPos = hqPos;
};

Player.prototype.update = function(map, myTurn) {
	this.army.update(map);
};

Player.prototype.unitPositions = function() {
  return this.army.units.map(function(unit) {
    return unit.pos;
  });
};

Player.prototype.onTurnStart = function(map, myPlayerID) {
  this.army.units.forEach(function(unit) {
    var tile = map.getTileAtPos(unit.pos);
    if(tile.owner !== undefined && tile.owner === myPlayerID) {
      var prevDamageTaken = unit.damageTaken;
      unit.damageTaken -= Math.floor(unit.health / 5);
      if(unit.damageTaken < 0) {
        unit.damageTaken = 0;
      }
      var healthGained = prevDamageTaken - unit.damageTaken ;

      if(healthGained > 0){
        var style = { font: "12px Arial", backgroundColor: "green", fill: "#ffffff", strokeThickness: 3, align: "center" };
        var text = game.add.text(unit.pos.canvasX() + 16, unit.pos.canvasY(), ("+" + healthGained), style);
        text.anchor.set(0.5);
        text.alpha = 1;
        var tween = game.add.tween(text).to( { alpha: 0, y: unit.pos.canvasY() - 20 }, 1500, "Linear", true);
      }
    }
  });
}

Player.prototype.openMenu = function() {
  //TODO: Opens menu and presents player options
};

Player.prototype.endTurn = function() {
  // Allows player to end their turn
  this.army.units.forEach(function(unit) {
    unit.resetUnit();
  });
};

Player.prototype.quitGame = function() {
  //TODO: Allows player to end the battle
  // When this function is called it will start the "VictoryState" Game State
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 FOAM Bootstrap

 FOAM uses Models to specify class definitions.
 The FOAM Model class is itself specified with a FOAM model, meaning
 that Model is defined in the same language which it defines.
 This self-modeling system requires some care to bootstrap, but results
 in a very compact, uniform, and powerful system.

 FObject -> FObject Class                     Prototype
    ^                        +-.prototype---------^
    |                        |                    |
  Model  -> buildClass()  -> Class -> create() -> instance

  FObject is the root model/class of all other classes, including Model.
  Abstract Class is the prototype of FObject's Class, which makes it the root of all Classes.
  From a Model we call buildClass() to create a Class (or the previously created Class) object.
  From the Class we call create() to create new instances of that class.
  New instances extend the classes prototype object, which is stored on the class as .prototype.

  instance ---> .cls_   -> Object's Class
       |
       +------> .model_ -> Object's Model

  All descendents of FObject have references to both their Model and Class.
    - obj.cls_ refers to an Object's Class
    - obj.model_ refers to an Object's Model

  Classes also refer to their Model with .model_.

  Model is its own definition:

    Model.buildClass().create(Model) == Model
    Model.model_ === Model

  Models are defined as a collection of Axioms.
  It is the responsibility of Axioms to install itself onto a Model's Class and/or Prototype.

  Axioms are defined with the following psedo-interface:

    public interface Axiom {
      optional installInClass(cls)
      optional installInProto(proto)
    }

  Ex. of a Model with one Axiom:

  foam.CLASS({
    name: 'Sample',

    axioms: [
      {
        name: 'axiom1',
        installInClass: function(cls) { ... },
        installInProto: function(proto) { ... }
      }
    ]
  });

  Axioms can be added either during the initial creation of a class and prototype,
  or anytime after.  This allows classes to be extended with new functionality,
  and this is very important to the bootstrap process because it allows us to
  start out with very simple definitions of Model and FObject, and then build
  them up until they're fully bootstrapped.

  However, raw axioms are rarely used directly. Instead we model higher-level
  axiom types, including:

Requires   - Require other classes

Imports    - Context imports

Exports    - Context exports

Implements - Declare interfaces implemented / mix-ins mixed-in

Constants  - Add constants to the prototype and class

Properties - High-level instance variable definitions

Methods    - Prototype methods

Topics     - Publish/sub topics

Listeners  - Like methods, but with extra features for use as callbacks

*/

/**
 Bootstrap support.

 Is discarded after use.
*/
foam.LIB({
  name: 'foam.boot',

  constants: {
    startTime: Date.now(),
  },

  methods: [
    /**
      Create or Update a Prototype from a Model definition.

      This will be added as a method on the Model class
      when it is eventually built.

      (Model is 'this').
    */
    function buildClass() {
      var context = this.__context__ || foam.__context__;
      var cls;

      if ( this.refines ) {
        cls = context.lookup(this.refines);
        foam.assert(cls, 'Unknown refinement class: ' + this.refines);
      } else {
        foam.assert(this.id, 'Missing id name.', this.name);
        foam.assert(this.name, 'Missing class name.');

        var parent = this.extends      ?
          context.lookup(this.extends) :
          foam.core.FObject            ;

        cls                  = parent.createSubClass_();
        cls.prototype.cls_   = cls;
        cls.prototype.model_ = this;
        cls.count_           = 0;            // Number of instances created
        cls.id               = this.id;
        cls.package          = this.package;
        cls.name             = this.name;
        cls.model_           = this;

        // Install an FObject on the class that we can use as a pub/sub hub.
        // We have to do this because classes aren't FObjects.
        // This is used to publish 'installAxiom' events to, so that descendents
        // properties know when they need to be re-installed.
        if ( cls !== foam.core.FObject ) {
          cls.pubsub_ = foam.core.FObject.create();

          // Relay 'installAxiom' events from parent class.
          parent.pubsub_ && parent.pubsub_.sub(
            'installAxiom',
            function(_, a1, a2, a3) { cls.pubsub_.pub(a1, a2, a3); });
        }
      }

      cls.installModel(this);

      return cls;
    },

    function start() {
      /* Start the bootstrap process. */

      var buildClass = this.buildClass;

      // Will be replaced in phase2.
      foam.CLASS = function(m) {
        m.id = m.package + '.' + m.name;
        var cls = buildClass.call(m);

        foam.assert(
          ! m.refines,
          'Refines is not supported in early bootstrap');

        foam.register(cls);

        // Register the class in the global package path.
        foam.package.registerClass(cls);

        return cls;
      };
    },

    /** Start second phase of bootstrap process. */
    function phase2() {
      // Upgrade to final CLASS() definition.
      /* Creates a Foam class from a plain-old-object definition:
          (1) Determine the class of model for the new class's model;
          (2) Construct and validate the new class's model;
          (3) Construct and validate the new class.
          @method CLASS
          @memberof module:foam */
      foam.CLASS = function(m, skipRegistration) {
        var cls   = m.class ? foam.lookup(m.class) : foam.core.Model;
        var model = cls.create(m);
        model.validate();
        // cls was: class-for-model-construction;
        // cls is: class-constructed-from-model.
        cls = model.buildClass();
        cls.validate();

        if ( skipRegistration ) return cls;

        if ( ! m.refines ) {
          // Register class in global context.
          foam.register(cls);

          // Register the class in the global package path.
          foam.package.registerClass(cls);
        } else {
          // Register refinement id in global context.
          // If duplicate names are being registered and the system complains,
          // find the offending refinement and give it a package and name.
          foam.register(cls, model.id);
        }

        return cls;
      };

      // Upgrade existing classes to real classes.
      for ( var key in foam.core ) {
        var m = foam.lookup(key).model_;

        // classModel.buildClass() expects 'refines' if we are upgrading an
        // existing class.
        m.refines = m.id;

        foam.CLASS(m, true);
      }
    },

    function phase3() {
      // Substitute foam.core.installModel() with simpler axiom-only version.
      foam.core.FObject.installModel = function installModel(m) {
        if ( m.source ) m.axioms_.forEach(function(a) { a.source = m.source; });
        this.installAxioms(m.axioms_);
      };
    },

    /** Finish the bootstrap process, deleting foam.boot when done. */
    function end() {
      var Model = foam.core.Model;

      // Update psedo-Models to real Models
      for ( var key in foam.core ) {
        var c = foam.core[key];
        c.prototype.model_ = c.model_ = Model.create(c.model_);
      }

      delete foam.boot;

      console.log('core boot time: ', Date.now() - this.startTime);
    }
  ]
});

foam.boot.start();
<commit_msg>Clear the axiomCache when the parent has axioms installed on it.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 FOAM Bootstrap

 FOAM uses Models to specify class definitions.
 The FOAM Model class is itself specified with a FOAM model, meaning
 that Model is defined in the same language which it defines.
 This self-modeling system requires some care to bootstrap, but results
 in a very compact, uniform, and powerful system.

 FObject -> FObject Class                     Prototype
    ^                        +-.prototype---------^
    |                        |                    |
  Model  -> buildClass()  -> Class -> create() -> instance

  FObject is the root model/class of all other classes, including Model.
  Abstract Class is the prototype of FObject's Class, which makes it the root of all Classes.
  From a Model we call buildClass() to create a Class (or the previously created Class) object.
  From the Class we call create() to create new instances of that class.
  New instances extend the classes prototype object, which is stored on the class as .prototype.

  instance ---> .cls_   -> Object's Class
       |
       +------> .model_ -> Object's Model

  All descendents of FObject have references to both their Model and Class.
    - obj.cls_ refers to an Object's Class
    - obj.model_ refers to an Object's Model

  Classes also refer to their Model with .model_.

  Model is its own definition:

    Model.buildClass().create(Model) == Model
    Model.model_ === Model

  Models are defined as a collection of Axioms.
  It is the responsibility of Axioms to install itself onto a Model's Class and/or Prototype.

  Axioms are defined with the following psedo-interface:

    public interface Axiom {
      optional installInClass(cls)
      optional installInProto(proto)
    }

  Ex. of a Model with one Axiom:

  foam.CLASS({
    name: 'Sample',

    axioms: [
      {
        name: 'axiom1',
        installInClass: function(cls) { ... },
        installInProto: function(proto) { ... }
      }
    ]
  });

  Axioms can be added either during the initial creation of a class and prototype,
  or anytime after.  This allows classes to be extended with new functionality,
  and this is very important to the bootstrap process because it allows us to
  start out with very simple definitions of Model and FObject, and then build
  them up until they're fully bootstrapped.

  However, raw axioms are rarely used directly. Instead we model higher-level
  axiom types, including:

Requires   - Require other classes

Imports    - Context imports

Exports    - Context exports

Implements - Declare interfaces implemented / mix-ins mixed-in

Constants  - Add constants to the prototype and class

Properties - High-level instance variable definitions

Methods    - Prototype methods

Topics     - Publish/sub topics

Listeners  - Like methods, but with extra features for use as callbacks

*/

/**
 Bootstrap support.

 Is discarded after use.
*/
foam.LIB({
  name: 'foam.boot',

  constants: {
    startTime: Date.now(),
  },

  methods: [
    /**
      Create or Update a Prototype from a Model definition.

      This will be added as a method on the Model class
      when it is eventually built.

      (Model is 'this').
    */
    function buildClass() {
      var context = this.__context__ || foam.__context__;
      var cls;

      if ( this.refines ) {
        cls = context.lookup(this.refines);
        foam.assert(cls, 'Unknown refinement class: ' + this.refines);
      } else {
        foam.assert(this.id, 'Missing id name.', this.name);
        foam.assert(this.name, 'Missing class name.');

        var parent = this.extends      ?
          context.lookup(this.extends) :
          foam.core.FObject            ;

        cls                  = parent.createSubClass_();
        cls.prototype.cls_   = cls;
        cls.prototype.model_ = this;
        cls.count_           = 0;            // Number of instances created
        cls.id               = this.id;
        cls.package          = this.package;
        cls.name             = this.name;
        cls.model_           = this;

        // Install an FObject on the class that we can use as a pub/sub hub.
        // We have to do this because classes aren't FObjects.
        // This is used to publish 'installAxiom' events to, so that descendents
        // properties know when they need to be re-installed.
        if ( cls !== foam.core.FObject ) {
          cls.pubsub_ = foam.core.FObject.create();

          // Relay 'installAxiom' events from parent class.
          parent.pubsub_ && parent.pubsub_.sub(
            'installAxiom',
            function(_, a1, a2, a3) {
              cls.private_.axiomCache = {};
              cls.pubsub_.pub(a1, a2, a3);
            });
        }
      }

      cls.installModel(this);

      return cls;
    },

    function start() {
      /* Start the bootstrap process. */

      var buildClass = this.buildClass;

      // Will be replaced in phase2.
      foam.CLASS = function(m) {
        m.id = m.package + '.' + m.name;
        var cls = buildClass.call(m);

        foam.assert(
          ! m.refines,
          'Refines is not supported in early bootstrap');

        foam.register(cls);

        // Register the class in the global package path.
        foam.package.registerClass(cls);

        return cls;
      };
    },

    /** Start second phase of bootstrap process. */
    function phase2() {
      // Upgrade to final CLASS() definition.
      /* Creates a Foam class from a plain-old-object definition:
          (1) Determine the class of model for the new class's model;
          (2) Construct and validate the new class's model;
          (3) Construct and validate the new class.
          @method CLASS
          @memberof module:foam */
      foam.CLASS = function(m, skipRegistration) {
        var cls   = m.class ? foam.lookup(m.class) : foam.core.Model;
        var model = cls.create(m);
        model.validate();
        // cls was: class-for-model-construction;
        // cls is: class-constructed-from-model.
        cls = model.buildClass();
        cls.validate();

        if ( skipRegistration ) return cls;

        if ( ! m.refines ) {
          // Register class in global context.
          foam.register(cls);

          // Register the class in the global package path.
          foam.package.registerClass(cls);
        } else {
          // Register refinement id in global context.
          // If duplicate names are being registered and the system complains,
          // find the offending refinement and give it a package and name.
          foam.register(cls, model.id);
        }

        return cls;
      };

      // Upgrade existing classes to real classes.
      for ( var key in foam.core ) {
        var m = foam.lookup(key).model_;

        // classModel.buildClass() expects 'refines' if we are upgrading an
        // existing class.
        m.refines = m.id;

        foam.CLASS(m, true);
      }
    },

    function phase3() {
      // Substitute foam.core.installModel() with simpler axiom-only version.
      foam.core.FObject.installModel = function installModel(m) {
        if ( m.source ) m.axioms_.forEach(function(a) { a.source = m.source; });
        this.installAxioms(m.axioms_);
      };
    },

    /** Finish the bootstrap process, deleting foam.boot when done. */
    function end() {
      var Model = foam.core.Model;

      // Update psedo-Models to real Models
      for ( var key in foam.core ) {
        var c = foam.core[key];
        c.prototype.model_ = c.model_ = Model.create(c.model_);
      }

      delete foam.boot;

      console.log('core boot time: ', Date.now() - this.startTime);
    }
  ]
});

foam.boot.start();
<|endoftext|>


<commit_before>var querystring = require('querystring')
var underscore = require('underscore')
var wreck = require('wreck')

var DB = require('./database')
var Queue = require('./queue')
var Wallet = require('./wallet')

var profile = process.env.NODE_ENV || 'development'
var config = require('../config/config.' + profile + '.js')

underscore.keys(config).forEach((key) => {
  var m = config[key]
  if (typeof m === 'undefined') return

  underscore.keys(m).forEach((k) => {
    if (typeof m[k] === 'undefined') throw new Error('config.' + key + '.' + k + ': undefined')

    if ((typeof m[k] !== 'number') && (typeof m[k] !== 'boolean') && (!m[k])) {
      throw new Error('config.' + key + '.' + k + ': empty')
    }
  })
})

var runtime = {
  config: config,
  db: new DB(config),
  login: config.login,
  queue: new Queue(config)
}
runtime.wallet = new Wallet(config, runtime)

runtime.notify = (debug, payload) => {
  var opts
  var params = runtime.config.slack

  debug('notify', payload)
  if (!(params && params.webhook && params.channel)) return debug('notify', 'slack webhook not configured')

  underscore.defaults(payload, { channel: params.channel,
                                 username: params.username || 'webhookbot',
                                 icon_emoji: params.icon_emoji || ':ghost:',
                                 text: 'ping.' })
  opts = { headers: { 'content-type': 'application/x-www-form-url-encoded' },
           payload: querystring.stringify(payload)
         }
  wreck.post(params.webhook, opts, (err, response, body) => {
    if (err) return debug('notify', { payload: payload, reason: err.toString() })

    debug('notify', payload)
  })
}

module.exports = runtime
<commit_msg>not happy<commit_after>var querystring = require('querystring')
var underscore = require('underscore')
var wreck = require('wreck')

var DB = require('./database')
var Queue = require('./queue')
var Wallet = require('./wallet')

var profile = process.env.NODE_ENV || 'development'
var config = require('../config/config.' + profile + '.js')

underscore.keys(config).forEach((key) => {
  var m = config[key]
  if (typeof m === 'undefined') return

  underscore.keys(m).forEach((k) => {
    if (typeof m[k] === 'undefined') throw new Error('config.' + key + '.' + k + ': undefined')

    if ((typeof m[k] !== 'number') && (typeof m[k] !== 'boolean') && (!m[k])) {
      throw new Error('config.' + key + '.' + k + ': empty')
    }
  })
})

var runtime = {
  config: config,
  db: new DB(config),
  login: config.login,
  queue: new Queue(config)
}
runtime.wallet = new Wallet(config, runtime)

runtime.notify = (debug, payload) => {
  var opts
  var params = runtime.config.slack

try {
  debug('notify', payload)
  if (!(params && params.webhook && params.channel)) return debug('notify', 'slack webhook not configured')

  underscore.defaults(payload, { channel: params.channel,
                                 username: params.username || 'webhookbot',
                                 icon_emoji: params.icon_emoji || ':ghost:',
                                 text: 'ping.' })
  opts = { headers: { 'content-type': 'application/x-www-form-url-encoded' },
           payload: querystring.stringify(payload)
         }
  wreck.post(params.webhook, opts, (err, response, body) => {
    if (err) return debug('notify', { payload: payload, reason: err.toString() })

    debug('notify', payload)
  })
} catch (ex) { console.log('notify', ex) }
}

module.exports = runtime
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 FOAM Bootstrap

 FOAM uses Models to specify class definitions.
 The FOAM Model class is itself specified with a FOAM model, meaning
 that Model is defined in the same language which it defines.
 This self-modeling system requires some care to bootstrap, but results
 in a very compact, uniform, and powerful system.

 FObject -> FObject Class                     Prototype
    ^                        +-.prototype---------^
    |                        |                    |
  Model  -> buildClass()  -> Class -> create() -> instance

  FObject is the root model/class of all other classes, including Model.
  Abstract Class is the prototype of FObject's Class, which makes it the root of all Classes.
  From a Model we call buildClass() to create a Class (or the previously created Class) object.
  From the Class we call create() to create new instances of that class.
  New instances extend the classes prototype object, which is stored on the class as .prototype.

  instance ---> .cls_   -> Object's Class
       |
       +------> .model_ -> Object's Model

  All descendents of FObject have references to both their Model and Class.
    - obj.cls_ refers to an Object's Class
    - obj.model_ refers to an Object's Model

  Classes also refer to their Model with .model_.

  Model is its own definition:

    Model.buildClass().create(Model) == Model
    Model.model_ === Model

  Models are defined as a collection of Axioms.
  It is the responsibility of Axioms to install itself onto a Model's Class and/or Prototype.

  Axioms are defined with the following psedo-interface:

    public interface Axiom {
      optional installInClass(cls)
      optional installInProto(proto)
    }

  Ex. of a Model with one Axiom:

  foam.CLASS({
    name: 'Sample',

    axioms: [
      {
        name: 'axiom1',
        installInClass: function(cls) { ... },
        installInProto: function(proto) { ... }
      }
    ]
  });

  Axioms can be added either during the initial creation of a class and prototype,
  or anytime after.  This allows classes to be extended with new functionality,
  and this is very important to the bootstrap process because it allows us to
  start out with very simple definitions of Model and FObject, and then build
  them up until they're fully bootstrapped.

  However, raw axioms are rarely used directly. Instead we model higher-level
  axiom types, including:

Requires   - Require other classes

Imports    - Context imports

Exports    - Context exports

Implements - Declare interfaces implemented / mix-ins mixed-in

Constants  - Add constants to the prototype and class

Properties - High-level instance variable definitions

Methods    - Prototype methods

Topics     - Publish/sub topics

Listeners  - Like methods, but with extra features for use as callbacks

*/

/**
 Bootstrap support.

 Is discarded after use.
*/
foam.LIB({
  name: 'foam.boot',

  constants: {
    startTime: Date.now(),
  },

  methods: [
    /**
      Create or Update a Prototype from a Model definition.

      This will be added as a method on the Model class
      when it is eventually built.

      (Model is 'this').
    */
    function buildClass() {
      var context = this.__context__ || foam.__context__;
      var cls;

      if ( this.refines ) {
        cls = context.lookup(this.refines);
        foam.assert(cls, 'Unknown refinement class: ' + this.refines);
      } else {
        foam.assert(this.id, 'Missing id name.', this.name);
        foam.assert(this.name, 'Missing class name.');

        var parent = this.extends      ?
          context.lookup(this.extends) :
          foam.core.FObject            ;

        cls                  = parent.createSubClass_();
        cls.prototype.cls_   = cls;
        cls.prototype.model_ = this;
        cls.count_           = 0;            // Number of instances created
        cls.id               = this.id;
        cls.package          = this.package;
        cls.name             = this.name;
        cls.model_           = this;

        // Install an FObject on the class that we can use as a pub/sub hub.
        // We have to do this because classes aren't FObjects.
        // This is used to publish 'installAxiom' events to, so that descendents
        // properties know when they need to be re-installed.
        if ( cls !== foam.core.FObject ) {
          cls.pubsub_ = foam.core.FObject.create();

          // Relay 'installAxiom' events from parent class.
          parent.pubsub_ && parent.pubsub_.sub(
            'installAxiom',
            function(_, a1, a2, a3) { cls.pubsub_.pub(a1, a2, a3); });
        }
      }

      cls.installModel(this);

      return cls;
    },

    function start() {
      /* Start the bootstrap process. */

      var buildClass = this.buildClass;

      // Will be replaced in phase2.
      foam.CLASS = function(m) {
        m.id = m.package + '.' + m.name;
        var cls = buildClass.call(m);

        foam.assert(
          ! m.refines,
          'Refines is not supported in early bootstrap');

        foam.register(cls);

        // Register the class in the global package path.
        foam.package.registerClass(cls);

        return cls;
      };
    },

    /** Start second phase of bootstrap process. */
    function phase2() {
      // Upgrade to final CLASS() definition.
      /* Creates a Foam class from a plain-old-object definition:
          (1) Determine the class of model for the new class's model;
          (2) Construct and validate the new class's model;
          (3) Construct and validate the new class.
          @method CLASS
          @memberof module:foam */
      foam.CLASS = function(m, skipRegistration) {
        var cls   = m.class ? foam.lookup(m.class) : foam.core.Model;
        var model = cls.create(m);
        model.validate();
        // cls was: class-for-model-construction;
        // cls is: class-constructed-from-model.
        cls = model.buildClass();
        cls.validate();

        if ( skipRegistration ) return cls;

        if ( ! m.refines ) {
          // Register class in global context.
          foam.register(cls);

          // Register the class in the global package path.
          foam.package.registerClass(cls);
        } else if ( m.name ) {
          // Register refinement id in global context.
          foam.register(cls, ( m.package || 'foam.core' ) + '.' + m.name);
        }
        // TODO(markdittmer): Identify and name anonymous refinements with:
        // else {
        //   console.warn('Refinement without unique id', cls);
        //   debugger;
        // }

        return cls;
      };

      // Upgrade existing classes to real classes.
      for ( var key in foam.core ) {
        var m = foam.lookup(key).model_;

        // classModel.buildClass() expects 'refines' if we are upgrading an
        // existing class.
        m.refines = m.id;

        foam.CLASS(m, true);
      }
    },

    function phase3() {
      // Substitute foam.core.installModel() with simpler axiom-only version.
      foam.core.FObject.installModel = function installModel(m) {
        this.installAxioms(m.axioms_);
      };
    },

    /** Finish the bootstrap process, deleting foam.boot when done. */
    function end() {
      var Model = foam.core.Model;

      // Update psedo-Models to real Models
      for ( var key in foam.core ) {
        var c = foam.core[key];
        c.prototype.model_ = c.model_ = Model.create(c.model_);
      }

      delete foam.boot;

      console.log('core boot time: ', Date.now() - this.startTime);
    }
  ]
});

foam.boot.start();
<commit_msg>Fix bug in Boot.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 FOAM Bootstrap

 FOAM uses Models to specify class definitions.
 The FOAM Model class is itself specified with a FOAM model, meaning
 that Model is defined in the same language which it defines.
 This self-modeling system requires some care to bootstrap, but results
 in a very compact, uniform, and powerful system.

 FObject -> FObject Class                     Prototype
    ^                        +-.prototype---------^
    |                        |                    |
  Model  -> buildClass()  -> Class -> create() -> instance

  FObject is the root model/class of all other classes, including Model.
  Abstract Class is the prototype of FObject's Class, which makes it the root of all Classes.
  From a Model we call buildClass() to create a Class (or the previously created Class) object.
  From the Class we call create() to create new instances of that class.
  New instances extend the classes prototype object, which is stored on the class as .prototype.

  instance ---> .cls_   -> Object's Class
       |
       +------> .model_ -> Object's Model

  All descendents of FObject have references to both their Model and Class.
    - obj.cls_ refers to an Object's Class
    - obj.model_ refers to an Object's Model

  Classes also refer to their Model with .model_.

  Model is its own definition:

    Model.buildClass().create(Model) == Model
    Model.model_ === Model

  Models are defined as a collection of Axioms.
  It is the responsibility of Axioms to install itself onto a Model's Class and/or Prototype.

  Axioms are defined with the following psedo-interface:

    public interface Axiom {
      optional installInClass(cls)
      optional installInProto(proto)
    }

  Ex. of a Model with one Axiom:

  foam.CLASS({
    name: 'Sample',

    axioms: [
      {
        name: 'axiom1',
        installInClass: function(cls) { ... },
        installInProto: function(proto) { ... }
      }
    ]
  });

  Axioms can be added either during the initial creation of a class and prototype,
  or anytime after.  This allows classes to be extended with new functionality,
  and this is very important to the bootstrap process because it allows us to
  start out with very simple definitions of Model and FObject, and then build
  them up until they're fully bootstrapped.

  However, raw axioms are rarely used directly. Instead we model higher-level
  axiom types, including:

Requires   - Require other classes

Imports    - Context imports

Exports    - Context exports

Implements - Declare interfaces implemented / mix-ins mixed-in

Constants  - Add constants to the prototype and class

Properties - High-level instance variable definitions

Methods    - Prototype methods

Topics     - Publish/sub topics

Listeners  - Like methods, but with extra features for use as callbacks

*/

/**
 Bootstrap support.

 Is discarded after use.
*/
foam.LIB({
  name: 'foam.boot',

  constants: {
    startTime: Date.now(),
  },

  methods: [
    /**
      Create or Update a Prototype from a Model definition.

      This will be added as a method on the Model class
      when it is eventually built.

      (Model is 'this').
    */
    function buildClass() {
      var context = this.__context__ || foam.__context__;
      var cls;

      if ( this.refines ) {
        cls = context.lookup(this.refines);
        foam.assert(cls, 'Unknown refinement class: ' + this.refines);
      } else {
        foam.assert(this.id, 'Missing id name.', this.name);
        foam.assert(this.name, 'Missing class name.');

        var parent = this.extends      ?
          context.lookup(this.extends) :
          foam.core.FObject            ;

        cls                  = parent.createSubClass_();
        cls.prototype.cls_   = cls;
        cls.prototype.model_ = this;
        cls.count_           = 0;            // Number of instances created
        cls.id               = this.id;
        cls.package          = this.package;
        cls.name             = this.name;
        cls.model_           = this;

        // Install an FObject on the class that we can use as a pub/sub hub.
        // We have to do this because classes aren't FObjects.
        // This is used to publish 'installAxiom' events to, so that descendents
        // properties know when they need to be re-installed.
        if ( cls !== foam.core.FObject ) {
          cls.pubsub_ = foam.core.FObject.create();

          // Relay 'installAxiom' events from parent class.
          parent.pubsub_ && parent.pubsub_.sub(
            'installAxiom',
            function(_, a1, a2, a3) { cls.pubsub_.pub(a1, a2, a3); });
        }
      }

      cls.installModel(this);

      return cls;
    },

    function start() {
      /* Start the bootstrap process. */

      var buildClass = this.buildClass;

      // Will be replaced in phase2.
      foam.CLASS = function(m) {
        if ( ! m.source && global.document && global.document.currentScript ) {
          m.source = global.document.currentScript.src;
        }

        m.id = m.package + '.' + m.name;
        var cls = buildClass.call(m);

        foam.assert(
          ! m.refines,
          'Refines is not supported in early bootstrap');

        foam.register(cls);

        // Register the class in the global package path.
        foam.package.registerClass(cls);

        return cls;
      };
    },

    /** Start second phase of bootstrap process. */
    function phase2() {
      // Upgrade to final CLASS() definition.
      /* Creates a Foam class from a plain-old-object definition:
          (1) Determine the class of model for the new class's model;
          (2) Construct and validate the new class's model;
          (3) Construct and validate the new class.
          @method CLASS
          @memberof module:foam */
      foam.CLASS = function(m, skipRegistration) {
        if ( ! m.source && global.document && global.document.currentScript ) {
          m.source = global.document.currentScript.src;
        }

        var cls   = m.class ? foam.lookup(m.class) : foam.core.Model;
        var model = cls.create(m);
        model.validate();
        // cls was: class-for-model-construction;
        // cls is: class-constructed-from-model.
        cls = model.buildClass();
        cls.validate();

        if ( skipRegistration ) return cls;

        if ( ! m.refines ) {
          // Register class in global context.
          foam.register(cls);

          // Register the class in the global package path.
          foam.package.registerClass(cls);
        } else if ( m.name ) {
          // Register refinement id in global context.
          foam.register(cls, ( m.package || 'foam.core' ) + '.' + m.name);
        }
        // TODO(markdittmer): Identify and name anonymous refinements with:
        // else {
        //   console.warn('Refinement without unique id', cls);
        //   debugger;
        // }

        return cls;
      };

      // Upgrade existing classes to real classes.
      for ( var key in foam.core ) {
        var m = foam.lookup(key).model_;

        // classModel.buildClass() expects 'refines' if we are upgrading an
        // existing class.
        m.refines = m.id;

        foam.CLASS(m, true);
      }
    },

    function phase3() {
      // Substitute foam.core.installModel() with simpler axiom-only version.
      foam.core.FObject.installModel = function installModel(m) {
        if ( m.source ) m.axioms_.forEach(function(a) { a.source = m.source; });
        this.installAxioms(m.axioms_);
      };
    },

    /** Finish the bootstrap process, deleting foam.boot when done. */
    function end() {
      var Model = foam.core.Model;

      // Update psedo-Models to real Models
      for ( var key in foam.core ) {
        var c = foam.core[key];
        c.prototype.model_ = c.model_ = Model.create(c.model_);
      }

      delete foam.boot;

      console.log('core boot time: ', Date.now() - this.startTime);
    }
  ]
});

foam.boot.start();
<|endoftext|>


<commit_before>/* eslint-disable camelcase, key-spacing */

const ffi = require('ffi');
const ref = require('ref');

const lib = new ffi.Library(null, {
  dlopen: ['pointer', ['string', 'int']]
});

const libobjc = new ffi.Library('libobjc', {
  // Selectors
  sel_getUid : ['pointer', ['string']],
  sel_getName: ['string', ['pointer']],

  // Classes
  objc_getClass          : ['pointer', ['string']],
  object_getClass        : ['pointer', ['pointer']],
  class_getName          : ['string', ['pointer']],
  class_getClassMethod   : ['pointer', ['pointer', 'pointer']],
  class_getInstanceMethod: ['pointer', ['pointer', 'pointer']],

  // Methods
  method_copyReturnType      : ['string', ['pointer']],
  method_copyArgumentType    : ['string', ['pointer', 'int']],
  method_getNumberOfArguments: ['int', ['pointer']]
});

libobjc.objc_msgSend = ffi.DynamicLibrary().get('objc_msgSend'); // eslint-disable-line new-cap

const importFramework = name => {
  const handle = lib.dlopen(`/System/Library/Frameworks/${name}.framework/${name}`, 1); // 1: RTLD_LAZY
  return !handle.isNull();
};

importFramework('Foundation');

const getSymbol = name => new ffi.DynamicLibrary().get(name);

// NSString* constants require special handling
// We have to adjust the symbol's type, in order to dereference it
const getSymbolAsId = name => {
  try {
    const symbol = getSymbol(name);
    symbol.type = ref.refType(ref.refType(ref.types.void));
    return symbol.deref();
  } catch (err) {
    return null;
  }
};

const msgSend = (returnType, argumentTypes) => {
  return ffi.ForeignFunction(libobjc.objc_msgSend, returnType, argumentTypes); // eslint-disable-line new-cap
};

const classExists = classname => {
  return !libobjc.objc_getClass(classname).isNull();
};

module.exports = libobjc;
module.exports.msgSend = msgSend;
module.exports.import = importFramework;
module.exports.classExists = classExists;
module.exports.getSymbol = getSymbol;
module.exports.getSymbolAsId = getSymbolAsId;
<commit_msg>cache imported frameworks<commit_after>/* eslint-disable camelcase, key-spacing */

const ffi = require('ffi');
const ref = require('ref');

const lib = new ffi.Library(null, {
  dlopen: ['pointer', ['string', 'int']]
});

const libobjc = new ffi.Library('libobjc', {
  // Selectors
  sel_getUid : ['pointer', ['string']],
  sel_getName: ['string', ['pointer']],

  // Classes
  objc_getClass          : ['pointer', ['string']],
  object_getClass        : ['pointer', ['pointer']],
  class_getName          : ['string', ['pointer']],
  class_getClassMethod   : ['pointer', ['pointer', 'pointer']],
  class_getInstanceMethod: ['pointer', ['pointer', 'pointer']],

  // Methods
  method_copyReturnType      : ['string', ['pointer']],
  method_copyArgumentType    : ['string', ['pointer', 'int']],
  method_getNumberOfArguments: ['int', ['pointer']]
});

libobjc.objc_msgSend = ffi.DynamicLibrary().get('objc_msgSend'); // eslint-disable-line new-cap

const importList = [];

const importFramework = name => {
  if (importList.includes(name)) return true; // eslint-disable-line curly

  const handle = lib.dlopen(`/System/Library/Frameworks/${name}.framework/${name}`, ffi.DynamicLibrary.FLAGS.RTLD_LAZY);
  const success = !handle.isNull();
  if (success) importList.push(name); // eslint-disable-line curly
  return success;
};

importFramework('Foundation');

const getSymbol = name => new ffi.DynamicLibrary().get(name);

// NSString* constants require special handling
// We have to adjust the symbol's type, in order to dereference it
const getSymbolAsId = name => {
  try {
    const symbol = getSymbol(name);
    symbol.type = ref.refType(ref.refType(ref.types.void));
    return symbol.deref();
  } catch (err) {
    return null;
  }
};

const msgSend = (returnType, argumentTypes) => {
  return ffi.ForeignFunction(libobjc.objc_msgSend, returnType, argumentTypes); // eslint-disable-line new-cap
};

const classExists = classname => {
  return !libobjc.objc_getClass(classname).isNull();
};

module.exports = libobjc;
module.exports.msgSend = msgSend;
module.exports.import = importFramework;
module.exports.classExists = classExists;
module.exports.getSymbol = getSymbol;
module.exports.getSymbolAsId = getSymbolAsId;
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * For those familiar with Java, FOAM Enums are very similar to Java enums in
 * design.
 *
 * An Enum is essentially a class with a fixed number of named instances.
 * The instances are frequently referred to as Enum Values, or the 'values'
 * of an Enum.
 *
 * Enums have most of the features available to FOAM classes, including
 * properties, methods, constants, templates, and listeners.
 *
 * Enums extend from FObject, so they inherit FObject features such as
 * pub/sub events, diffing, hashCode, etc.
 *
 * Enums also have a few built-in properties by default. Every Enum has an
 * 'ordinal' property, which is a integer unique to all the Enum Values of a
 * particular Enum. Each enum also has a 'name' property, which is the name
 * given to each Enum Value.
 *
 * Example usage:
 *

 * // To define an enum we use the foam.ENUM() function.
 * foam.ENUM({
 *   name: 'IssueStatus',
 *
 *   // Enums share many features with regular classes, the properties
 *   // and methods we want our enums to have are defined as follows.
 *   properties: [
 *     {
 *       class: 'Boolean',
 *       name: 'consideredOpen',
 *       value: true
 *     }
 *   ],
 *
 *   methods: [
 *     function foo() {
 *       return this.label + ( this.consideredOpen ? ' is' : ' is not' ) +
 *           ' considered open.';
 *     }
 *   ],
 *
 *   // Use the values: key to define the actual Enum Values that we
 *   // want to exist.
 *   values: [
 *     {
 *       name: 'OPEN'
 *     },
 *     {
 *       // The ordinal can be specified explicitly.
 *       name: 'CLOSED',
 *       ordinal: 100
 *     },
 *     {
 *       // If the ordinal isn't given explicitly it is auto assigned as
 *       // the previous ordinal + 1
 *       name: 'ASSIGNED'
 *     },
 *     {
 *       // You can specify the label, which will be used when rendering in a
 *       // combo box or similar
 *       name: 'UNVERIFIED',
 *       label: 'Unverified'
 *     },
 *     {
 *       // Values for additional properties to your enum are also defined
 *       // inline.
 *       name: 'FIXED',
 *       label: 'Fixed',
 *       consideredOpen: false
 *     }
 *   ]
 * });
 *
 * console.log(IssueStatus.OPEN.name); // outputs "OPEN"
 * console.log(IssueStatus.ASSIGNED.consideredOpen); // outputs "true"
 *
 * // Enum value ordinals can be specified.
 * console.log(IssueStatus.CLOSED.ordinal); // outputs 100
 * // values without specified ordinals get auto assigned.
 * console.log(IssueStatus.ASSIGNED.ordinal); // outputs 101
 *
 * // Methods can be called on the enum values.
 * // outputs "Fixed is not considered open."
 * console.log(IssueStatus.FIXED.foo());
 *
 * // To store enums on a class, it is recommended to use the Enum property
 * // type.
 * foam.CLASS({
 *   name: 'Issue',
 *   properties: [
 *     {
 *       class: 'Enum',
 *       of: 'IssueStatus',
 *       name: 'status'
 *     }
 *   ]
 * });
 *
 * var issue = Issue.create({ status: IssueStatus.UNVERIFIED });
 * console.log(issue.status.label); // outputs "Unverified"
 *
 * // Enum properties give you some convenient adapting.
 * // You can set the property to the ordinal or the
 * // name of an enum, and it will set the property
 * // to the correct Enum value.
 *
 * issue.status = 100;
 *
 * issue.status === IssueStatus.CLOSED; // is true
 *
 * // Enum properties also allow you to assign them via the name
 * // of the enum.
 *
 * issue.status = "ASSIGNED"
 *
 * issue.status === IssueStatus.ASSIGNED; // is true
 *
 * The extent of all Enum values can be accessed from either the collection or from any
 * individual Enum value:
 * console.log(IssueStatus.VALUES, IssueStatus.CLOSED.VALUES);
 *
 * Values can be specified as just Strings if you don't want to explicitly set the label
 * or ordinal. Ex.:
 *
 * foam.ENUM({
 *  name: 'DaysOfWeek',
 *  values: [
 *    'SUNDAY',
 *    'MONDAY',
 *    'TUESDAY',
 *    'WEDNESDAY',
 *    'THURSDAY',
 *    'FRIDAY',
 *    'SATURDAY'
 *  ]
 * });
 *
 *

 */
// TODO: Make extend Model so can override methods (or do some other way).
foam.CLASS({
  package: 'foam.core.internal',
  name: 'EnumValueAxiom',

  documentation: 'The definition of a single Enum value.',

  properties: [
    {
      name: 'ordinal',
      getter: function() { return this.definition.ordinal; },
      setter: function(o) { this.definition.ordinal = o; }
    },
    {
      name: 'name',
      getter: function() { return this.definition.name; }
    },
    'definition'
  ],

  methods: [
    function installInClass(cls) {
      var e = cls.create(this.definition);
      cls.installConstant(this.name, e);
      cls.VALUES.push(e);
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'EnumModel',
  extends: 'Model',

  documentation: 'Model for defining Enum(erations).',

  properties: [
    [ 'extends', 'foam.core.AbstractEnum' ],
    {
      class: 'AxiomArray',
      of: 'foam.core.internal.EnumValueAxiom',
      name: 'values',
      adapt: function(_, v) {
        var used = {}; // map of ordinals used to check for duplicates

        var next = 0;
        for ( var i = 0 ; i < v.length ; i++ ) {
          var def = v[i];

          if ( foam.String.isInstance(def) ) {
            def = { label: def, name: foam.String.constantize(def) };
          }

          if ( def.ordinal || def.ordinal === 0 ) {
            next = def.ordinal + 1;
          } else {
            def.ordinal = next++;
          }

          if ( ! foam.core.internal.EnumValueAxiom.isInstance(def) ) {
            v[i] = def = foam.core.internal.EnumValueAxiom.create({definition: def});
          }

          if ( used[def.ordinal] ) {
            throw this.id +
                ' Enum error: duplicate ordinal found ' + def.name + ' ' +
                used[def.ordinal] + ' both have an ordinal of ' + def.ordinal;
          }

          used[def.ordinal] = def.name;
        }

        return v;
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'AbstractEnum',

  documentation: 'Abstract base class for all Enum classes.',

  axioms: [
    foam.pattern.Multiton.create({property: 'ordinal'}),
    {
      installInClass: function(cls) {
        // Each sub-class of AbstractEnum gets it's own VALUES array.
        Object.defineProperty(cls, 'VALUES', {
          get: function() {
            return this.private_.VALUES || ( this.private_.VALUES = [] );
          },
          configurable: true,
          enumerable: false
        });
      },
      installInProto: function(p) {
        Object.defineProperty(p, 'VALUES', {
          get: function() { return this.cls_.VALUES; },
          configurable: true,
          enumerable: false
        });
      }
    }
  ],

  properties: [
    {
      class: 'Int',
      name: 'ordinal',
      final: true
    },
    {
      class: 'String',
      name: 'name',
      final: true
    },
    {
      class: 'String',
      name: 'label',
      final: true
    }
  ],

  methods: [
    function toString() { return this.name; }
  ]
});

// TODO(adamvy): Support default values.
foam.CLASS({
  package: 'foam.core',
  name: 'Enum',
  extends: 'Property',

  documentation: 'A Property type for storing enum values.',

  properties: [
    {
      class: 'Class',
      name: 'of',
      required: true
    },
    [
      'adapt',
      function(o, n, prop) {
        var of = prop.of;

        if ( n && n.cls_ === of ) return n;

        var type = foam.typeOf(n), ret;

        if ( type === foam.String ) {
          ret = of[foam.String.constantize(n)];
        } else if ( type === foam.Number ) {
          ret = of.create({ordinal: n}, foam.__context__);
        }

        if ( ret ) return ret;

        throw 'Attempt to set invalid Enum value. Enum: ' + of.id + ', value: ' + n;
      }
    ]
  ]
});

foam.LIB({
  name: 'foam',

  methods: [
    function ENUM(m) {
      m.class = m.class || 'foam.core.EnumModel';
      return foam.CLASS(m);
    }
  ]
});
<commit_msg>Add a factory on label returning name as label is 'required' for Java Enum generation.<commit_after>/**
 * @license
 * Copyright 2017 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * For those familiar with Java, FOAM Enums are very similar to Java enums in
 * design.
 *
 * An Enum is essentially a class with a fixed number of named instances.
 * The instances are frequently referred to as Enum Values, or the 'values'
 * of an Enum.
 *
 * Enums have most of the features available to FOAM classes, including
 * properties, methods, constants, templates, and listeners.
 *
 * Enums extend from FObject, so they inherit FObject features such as
 * pub/sub events, diffing, hashCode, etc.
 *
 * Enums also have a few built-in properties by default. Every Enum has an
 * 'ordinal' property, which is a integer unique to all the Enum Values of a
 * particular Enum. Each enum also has a 'name' property, which is the name
 * given to each Enum Value.
 *
 * Example usage:
 *

 * // To define an enum we use the foam.ENUM() function.
 * foam.ENUM({
 *   name: 'IssueStatus',
 *
 *   // Enums share many features with regular classes, the properties
 *   // and methods we want our enums to have are defined as follows.
 *   properties: [
 *     {
 *       class: 'Boolean',
 *       name: 'consideredOpen',
 *       value: true
 *     }
 *   ],
 *
 *   methods: [
 *     function foo() {
 *       return this.label + ( this.consideredOpen ? ' is' : ' is not' ) +
 *           ' considered open.';
 *     }
 *   ],
 *
 *   // Use the values: key to define the actual Enum Values that we
 *   // want to exist.
 *   values: [
 *     {
 *       name: 'OPEN'
 *     },
 *     {
 *       // The ordinal can be specified explicitly.
 *       name: 'CLOSED',
 *       ordinal: 100
 *     },
 *     {
 *       // If the ordinal isn't given explicitly it is auto assigned as
 *       // the previous ordinal + 1
 *       name: 'ASSIGNED'
 *     },
 *     {
 *       // You can specify the label, which will be used when rendering in a
 *       // combo box or similar
 *       name: 'UNVERIFIED',
 *       label: 'Unverified'
 *     },
 *     {
 *       // Values for additional properties to your enum are also defined
 *       // inline.
 *       name: 'FIXED',
 *       label: 'Fixed',
 *       consideredOpen: false
 *     }
 *   ]
 * });
 *
 * console.log(IssueStatus.OPEN.name); // outputs "OPEN"
 * console.log(IssueStatus.ASSIGNED.consideredOpen); // outputs "true"
 *
 * // Enum value ordinals can be specified.
 * console.log(IssueStatus.CLOSED.ordinal); // outputs 100
 * // values without specified ordinals get auto assigned.
 * console.log(IssueStatus.ASSIGNED.ordinal); // outputs 101
 *
 * // Methods can be called on the enum values.
 * // outputs "Fixed is not considered open."
 * console.log(IssueStatus.FIXED.foo());
 *
 * // To store enums on a class, it is recommended to use the Enum property
 * // type.
 * foam.CLASS({
 *   name: 'Issue',
 *   properties: [
 *     {
 *       class: 'Enum',
 *       of: 'IssueStatus',
 *       name: 'status'
 *     }
 *   ]
 * });
 *
 * var issue = Issue.create({ status: IssueStatus.UNVERIFIED });
 * console.log(issue.status.label); // outputs "Unverified"
 *
 * // Enum properties give you some convenient adapting.
 * // You can set the property to the ordinal or the
 * // name of an enum, and it will set the property
 * // to the correct Enum value.
 *
 * issue.status = 100;
 *
 * issue.status === IssueStatus.CLOSED; // is true
 *
 * // Enum properties also allow you to assign them via the name
 * // of the enum.
 *
 * issue.status = "ASSIGNED"
 *
 * issue.status === IssueStatus.ASSIGNED; // is true
 *
 * The extent of all Enum values can be accessed from either the collection or from any
 * individual Enum value:
 * console.log(IssueStatus.VALUES, IssueStatus.CLOSED.VALUES);
 *
 * Values can be specified as just Strings if you don't want to explicitly set the label
 * or ordinal. Ex.:
 *
 * foam.ENUM({
 *  name: 'DaysOfWeek',
 *  values: [
 *    'SUNDAY',
 *    'MONDAY',
 *    'TUESDAY',
 *    'WEDNESDAY',
 *    'THURSDAY',
 *    'FRIDAY',
 *    'SATURDAY'
 *  ]
 * });
 *
 *

 */
// TODO: Make extend Model so can override methods (or do some other way).
foam.CLASS({
  package: 'foam.core.internal',
  name: 'EnumValueAxiom',

  documentation: 'The definition of a single Enum value.',

  properties: [
    {
      name: 'ordinal',
      getter: function() { return this.definition.ordinal; },
      setter: function(o) { this.definition.ordinal = o; }
    },
    {
      name: 'name',
      getter: function() { return this.definition.name; }
    },
    'definition'
  ],

  methods: [
    function installInClass(cls) {
      var e = cls.create(this.definition);
      cls.installConstant(this.name, e);
      cls.VALUES.push(e);
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'EnumModel',
  extends: 'Model',

  documentation: 'Model for defining Enum(erations).',

  properties: [
    [ 'extends', 'foam.core.AbstractEnum' ],
    {
      class: 'AxiomArray',
      of: 'foam.core.internal.EnumValueAxiom',
      name: 'values',
      adapt: function(_, v) {
        var used = {}; // map of ordinals used to check for duplicates

        var next = 0;
        for ( var i = 0 ; i < v.length ; i++ ) {
          var def = v[i];

          if ( foam.String.isInstance(def) ) {
            def = { label: def, name: foam.String.constantize(def) };
          }

          if ( def.ordinal || def.ordinal === 0 ) {
            next = def.ordinal + 1;
          } else {
            def.ordinal = next++;
          }

          if ( ! foam.core.internal.EnumValueAxiom.isInstance(def) ) {
            v[i] = def = foam.core.internal.EnumValueAxiom.create({definition: def});
          }

          if ( used[def.ordinal] ) {
            throw this.id +
                ' Enum error: duplicate ordinal found ' + def.name + ' ' +
                used[def.ordinal] + ' both have an ordinal of ' + def.ordinal;
          }

          used[def.ordinal] = def.name;
        }

        return v;
      }
    }
  ]
});

foam.CLASS({
  package: 'foam.core',
  name: 'AbstractEnum',

  documentation: 'Abstract base class for all Enum classes.',

  axioms: [
    foam.pattern.Multiton.create({property: 'ordinal'}),
    {
      installInClass: function(cls) {
        // Each sub-class of AbstractEnum gets it's own VALUES array.
        Object.defineProperty(cls, 'VALUES', {
          get: function() {
            return this.private_.VALUES || ( this.private_.VALUES = [] );
          },
          configurable: true,
          enumerable: false
        });
      },
      installInProto: function(p) {
        Object.defineProperty(p, 'VALUES', {
          get: function() { return this.cls_.VALUES; },
          configurable: true,
          enumerable: false
        });
      }
    }
  ],

  properties: [
    {
      class: 'Int',
      name: 'ordinal',
      final: true
    },
    {
      class: 'String',
      name: 'name',
      final: true
    },
    {
      class: 'String',
      name: 'label',
      final: true,
      factory: function() {
        return this.name;
      }
    }
  ],

  methods: [
    function toString() { return this.name; }
  ]
});

// TODO(adamvy): Support default values.
foam.CLASS({
  package: 'foam.core',
  name: 'Enum',
  extends: 'Property',

  documentation: 'A Property type for storing enum values.',

  properties: [
    {
      class: 'Class',
      name: 'of',
      required: true
    },
    [
      'adapt',
      function(o, n, prop) {
        var of = prop.of;

        if ( n && n.cls_ === of ) return n;

        var type = foam.typeOf(n), ret;

        if ( type === foam.String ) {
          ret = of[foam.String.constantize(n)];
        } else if ( type === foam.Number ) {
          ret = of.create({ordinal: n}, foam.__context__);
        }

        if ( ret ) return ret;

        throw 'Attempt to set invalid Enum value. Enum: ' + of.id + ', value: ' + n;
      }
    ]
  ]
});

foam.LIB({
  name: 'foam',

  methods: [
    function ENUM(m) {
      m.class = m.class || 'foam.core.EnumModel';
      return foam.CLASS(m);
    }
  ]
});
<|endoftext|>


<commit_before>var assert = require('assert')
var opcodes = require('./opcodes')

// FIXME: use ECPubKey, currently the circular dependency breaks everything.
//
// Solutions:
//  * Remove ECPubKey.getAddress
//    - Minimal change, but likely unpopular
//  * Move all script related functionality out of Address
//    - Means a lot of changes to Transaction/Wallet
//  * Ignore it (existing solution)
//  * Some form of hackery with commonjs
//
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')

var ECSignature = require('./ecsignature')
var Script = require('./script')

function classifyOutput(script) {
  assert(script instanceof Script, 'Expected Script, got ', script)

  if (isPubKeyHashOutput.call(script)) {
    return 'pubkeyhash'
  } else if (isScriptHashOutput.call(script)) {
    return 'scripthash'
  } else if (isMultisigOutput.call(script)) {
    return 'multisig'
  } else if (isPubKeyOutput.call(script)) {
    return 'pubkey'
  } else if (isNulldataOutput.call(script)) {
    return 'nulldata'
  } else {
    return 'nonstandard'
  }
}

function classifyInput(script) {
  assert(script instanceof Script, 'Expected Script, got ', script)

  if (isPubKeyHashInput.call(script)) {
    return 'pubkeyhash'
  } else if (isScriptHashInput.call(script)) {
    return 'scripthash'
  } else if (isMultisigInput.call(script)) {
    return 'multisig'
  } else if (isPubKeyInput.call(script)) {
    return 'pubkey'
  } else {
    return 'nonstandard'
  }
}

function isCanonicalPubKey(buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    // FIXME: boo
    ecurve.Point.decodeFrom(curve, buffer)
  } catch (e) {
    if (!(e.message.match(/Invalid sequence (length|tag)/))) throw e

    return false
  }

  return true
}

function isCanonicalSignature(buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    ECSignature.parseScriptSignature(buffer)
  } catch(e) {
    if (!(e.message.match(/Not a DER sequence|Invalid sequence length|Expected a DER integer|R length is zero|S length is zero|R value excessively padded|S value excessively padded|R value is negative|S value is negative|Invalid hashType/))) throw e

    return false
  }

  return true
}

function isPubKeyHashInput() {
  return this.chunks.length === 2 &&
    isCanonicalSignature(this.chunks[0]) &&
    isCanonicalPubKey(this.chunks[1])
}

function isPubKeyHashOutput() {
  return this.chunks.length === 5 &&
    this.chunks[0] === opcodes.OP_DUP &&
    this.chunks[1] === opcodes.OP_HASH160 &&
    Buffer.isBuffer(this.chunks[2]) &&
    this.chunks[2].length === 20 &&
    this.chunks[3] === opcodes.OP_EQUALVERIFY &&
    this.chunks[4] === opcodes.OP_CHECKSIG
}

function isPubKeyInput() {
  return this.chunks.length === 1 &&
    isCanonicalSignature(this.chunks[0])
}

function isPubKeyOutput() {
  return this.chunks.length === 2 &&
    isCanonicalPubKey(this.chunks[0]) &&
    this.chunks[1] === opcodes.OP_CHECKSIG
}

function isScriptHashInput() {
  if (this.chunks.length < 2) return false
  var lastChunk = this.chunks[this.chunks.length - 1]

  if (!Buffer.isBuffer(lastChunk)) return false

  var scriptSig = Script.fromChunks(this.chunks.slice(0, -1))
  var scriptPubKey = Script.fromBuffer(lastChunk)

  return classifyInput(scriptSig, false) === classifyOutput(scriptPubKey)
}

function isScriptHashOutput() {
  return this.chunks.length === 3 &&
    this.chunks[0] === opcodes.OP_HASH160 &&
    Buffer.isBuffer(this.chunks[1]) &&
    this.chunks[1].length === 20 &&
    this.chunks[2] === opcodes.OP_EQUAL
}

function isMultisigInput() {
  return this.chunks[0] === opcodes.OP_0 &&
    this.chunks.slice(1).every(isCanonicalSignature)
}

function isMultisigOutput() {
  if (this.chunks < 4) return false
  if (this.chunks[this.chunks.length - 1] !== opcodes.OP_CHECKMULTISIG) return false

  var mOp = this.chunks[0]
  if (mOp === opcodes.OP_0) return false
  if (mOp < opcodes.OP_1) return false
  if (mOp > opcodes.OP_16) return false

  var nOp = this.chunks[this.chunks.length - 2]
  if (nOp === opcodes.OP_0) return false
  if (nOp < opcodes.OP_1) return false
  if (nOp > opcodes.OP_16) return false

  var m = mOp - (opcodes.OP_1 - 1)
  var n = nOp - (opcodes.OP_1 - 1)
  if (n < m) return false

  var pubKeys = this.chunks.slice(1, -2)
  if (n < pubKeys.length) return false

  return pubKeys.every(isCanonicalPubKey)
}

function isNulldataOutput() {
  return this.chunks[0] === opcodes.OP_RETURN
}

// Standard Script Templates
// {pubKey} OP_CHECKSIG
function pubKeyOutput(pubKey) {
  return Script.fromChunks([
    pubKey.toBuffer(),
    opcodes.OP_CHECKSIG
  ])
}

// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput(hash) {
  assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)

  return Script.fromChunks([
    opcodes.OP_DUP,
    opcodes.OP_HASH160,
    hash,
    opcodes.OP_EQUALVERIFY,
    opcodes.OP_CHECKSIG
  ])
}

// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput(hash) {
  assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)

  return Script.fromChunks([
    opcodes.OP_HASH160,
    hash,
    opcodes.OP_EQUAL
  ])
}

// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput(m, pubKeys) {
  assert(Array.isArray(pubKeys), 'Expected Array, got ' + pubKeys)
  assert(pubKeys.length >= m, 'Not enough pubKeys provided')

  var pubKeyBuffers = pubKeys.map(function(pubKey) {
    return pubKey.toBuffer()
  })
  var n = pubKeys.length

  return Script.fromChunks([].concat(
    (opcodes.OP_1 - 1) + m,
    pubKeyBuffers,
    (opcodes.OP_1 - 1) + n,
    opcodes.OP_CHECKMULTISIG
  ))
}

// {signature}
function pubKeyInput(signature) {
  assert(Buffer.isBuffer(signature), 'Expected Buffer, got ' + signature)

  return Script.fromChunks([signature])
}

// {signature} {pubKey}
function pubKeyHashInput(signature, pubKey) {
  assert(Buffer.isBuffer(signature), 'Expected Buffer, got ' + signature)

  return Script.fromChunks([signature, pubKey.toBuffer()])
}

// <scriptSig> {serialized scriptPubKey script}
function scriptHashInput(scriptSig, scriptPubKey) {
  return Script.fromChunks([].concat(
    scriptSig.chunks,
    scriptPubKey.toBuffer()
  ))
}

// OP_0 [signatures ...]
function multisigInput(signatures, scriptPubKey) {
  if (scriptPubKey) {
    assert(isMultisigOutput.call(scriptPubKey))

    var m = scriptPubKey.chunks[0]
    var k = m - (opcodes.OP_1 - 1)
    assert(k <= signatures.length, 'Not enough signatures provided')
  }

  return Script.fromChunks([].concat(opcodes.OP_0, signatures))
}

module.exports = {
  classifyInput: classifyInput,
  classifyOutput: classifyOutput,
  multisigInput: multisigInput,
  multisigOutput: multisigOutput,
  pubKeyHashInput: pubKeyHashInput,
  pubKeyHashOutput: pubKeyHashOutput,
  pubKeyInput: pubKeyInput,
  pubKeyOutput: pubKeyOutput,
  scriptHashInput: scriptHashInput,
  scriptHashOutput: scriptHashOutput
}
<commit_msg>scripts: remove unused 2nd argument in function call<commit_after>var assert = require('assert')
var opcodes = require('./opcodes')

// FIXME: use ECPubKey, currently the circular dependency breaks everything.
//
// Solutions:
//  * Remove ECPubKey.getAddress
//    - Minimal change, but likely unpopular
//  * Move all script related functionality out of Address
//    - Means a lot of changes to Transaction/Wallet
//  * Ignore it (existing solution)
//  * Some form of hackery with commonjs
//
var ecurve = require('ecurve')
var curve = ecurve.getCurveByName('secp256k1')

var ECSignature = require('./ecsignature')
var Script = require('./script')

function classifyOutput(script) {
  assert(script instanceof Script, 'Expected Script, got ', script)

  if (isPubKeyHashOutput.call(script)) {
    return 'pubkeyhash'
  } else if (isScriptHashOutput.call(script)) {
    return 'scripthash'
  } else if (isMultisigOutput.call(script)) {
    return 'multisig'
  } else if (isPubKeyOutput.call(script)) {
    return 'pubkey'
  } else if (isNulldataOutput.call(script)) {
    return 'nulldata'
  } else {
    return 'nonstandard'
  }
}

function classifyInput(script) {
  assert(script instanceof Script, 'Expected Script, got ', script)

  if (isPubKeyHashInput.call(script)) {
    return 'pubkeyhash'
  } else if (isScriptHashInput.call(script)) {
    return 'scripthash'
  } else if (isMultisigInput.call(script)) {
    return 'multisig'
  } else if (isPubKeyInput.call(script)) {
    return 'pubkey'
  } else {
    return 'nonstandard'
  }
}

function isCanonicalPubKey(buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    // FIXME: boo
    ecurve.Point.decodeFrom(curve, buffer)
  } catch (e) {
    if (!(e.message.match(/Invalid sequence (length|tag)/))) throw e

    return false
  }

  return true
}

function isCanonicalSignature(buffer) {
  if (!Buffer.isBuffer(buffer)) return false

  try {
    ECSignature.parseScriptSignature(buffer)
  } catch(e) {
    if (!(e.message.match(/Not a DER sequence|Invalid sequence length|Expected a DER integer|R length is zero|S length is zero|R value excessively padded|S value excessively padded|R value is negative|S value is negative|Invalid hashType/))) throw e

    return false
  }

  return true
}

function isPubKeyHashInput() {
  return this.chunks.length === 2 &&
    isCanonicalSignature(this.chunks[0]) &&
    isCanonicalPubKey(this.chunks[1])
}

function isPubKeyHashOutput() {
  return this.chunks.length === 5 &&
    this.chunks[0] === opcodes.OP_DUP &&
    this.chunks[1] === opcodes.OP_HASH160 &&
    Buffer.isBuffer(this.chunks[2]) &&
    this.chunks[2].length === 20 &&
    this.chunks[3] === opcodes.OP_EQUALVERIFY &&
    this.chunks[4] === opcodes.OP_CHECKSIG
}

function isPubKeyInput() {
  return this.chunks.length === 1 &&
    isCanonicalSignature(this.chunks[0])
}

function isPubKeyOutput() {
  return this.chunks.length === 2 &&
    isCanonicalPubKey(this.chunks[0]) &&
    this.chunks[1] === opcodes.OP_CHECKSIG
}

function isScriptHashInput() {
  if (this.chunks.length < 2) return false
  var lastChunk = this.chunks[this.chunks.length - 1]

  if (!Buffer.isBuffer(lastChunk)) return false

  var scriptSig = Script.fromChunks(this.chunks.slice(0, -1))
  var scriptPubKey = Script.fromBuffer(lastChunk)

  return classifyInput(scriptSig) === classifyOutput(scriptPubKey)
}

function isScriptHashOutput() {
  return this.chunks.length === 3 &&
    this.chunks[0] === opcodes.OP_HASH160 &&
    Buffer.isBuffer(this.chunks[1]) &&
    this.chunks[1].length === 20 &&
    this.chunks[2] === opcodes.OP_EQUAL
}

function isMultisigInput() {
  return this.chunks[0] === opcodes.OP_0 &&
    this.chunks.slice(1).every(isCanonicalSignature)
}

function isMultisigOutput() {
  if (this.chunks < 4) return false
  if (this.chunks[this.chunks.length - 1] !== opcodes.OP_CHECKMULTISIG) return false

  var mOp = this.chunks[0]
  if (mOp === opcodes.OP_0) return false
  if (mOp < opcodes.OP_1) return false
  if (mOp > opcodes.OP_16) return false

  var nOp = this.chunks[this.chunks.length - 2]
  if (nOp === opcodes.OP_0) return false
  if (nOp < opcodes.OP_1) return false
  if (nOp > opcodes.OP_16) return false

  var m = mOp - (opcodes.OP_1 - 1)
  var n = nOp - (opcodes.OP_1 - 1)
  if (n < m) return false

  var pubKeys = this.chunks.slice(1, -2)
  if (n < pubKeys.length) return false

  return pubKeys.every(isCanonicalPubKey)
}

function isNulldataOutput() {
  return this.chunks[0] === opcodes.OP_RETURN
}

// Standard Script Templates
// {pubKey} OP_CHECKSIG
function pubKeyOutput(pubKey) {
  return Script.fromChunks([
    pubKey.toBuffer(),
    opcodes.OP_CHECKSIG
  ])
}

// OP_DUP OP_HASH160 {pubKeyHash} OP_EQUALVERIFY OP_CHECKSIG
function pubKeyHashOutput(hash) {
  assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)

  return Script.fromChunks([
    opcodes.OP_DUP,
    opcodes.OP_HASH160,
    hash,
    opcodes.OP_EQUALVERIFY,
    opcodes.OP_CHECKSIG
  ])
}

// OP_HASH160 {scriptHash} OP_EQUAL
function scriptHashOutput(hash) {
  assert(Buffer.isBuffer(hash), 'Expected Buffer, got ' + hash)

  return Script.fromChunks([
    opcodes.OP_HASH160,
    hash,
    opcodes.OP_EQUAL
  ])
}

// m [pubKeys ...] n OP_CHECKMULTISIG
function multisigOutput(m, pubKeys) {
  assert(Array.isArray(pubKeys), 'Expected Array, got ' + pubKeys)
  assert(pubKeys.length >= m, 'Not enough pubKeys provided')

  var pubKeyBuffers = pubKeys.map(function(pubKey) {
    return pubKey.toBuffer()
  })
  var n = pubKeys.length

  return Script.fromChunks([].concat(
    (opcodes.OP_1 - 1) + m,
    pubKeyBuffers,
    (opcodes.OP_1 - 1) + n,
    opcodes.OP_CHECKMULTISIG
  ))
}

// {signature}
function pubKeyInput(signature) {
  assert(Buffer.isBuffer(signature), 'Expected Buffer, got ' + signature)

  return Script.fromChunks([signature])
}

// {signature} {pubKey}
function pubKeyHashInput(signature, pubKey) {
  assert(Buffer.isBuffer(signature), 'Expected Buffer, got ' + signature)

  return Script.fromChunks([signature, pubKey.toBuffer()])
}

// <scriptSig> {serialized scriptPubKey script}
function scriptHashInput(scriptSig, scriptPubKey) {
  return Script.fromChunks([].concat(
    scriptSig.chunks,
    scriptPubKey.toBuffer()
  ))
}

// OP_0 [signatures ...]
function multisigInput(signatures, scriptPubKey) {
  if (scriptPubKey) {
    assert(isMultisigOutput.call(scriptPubKey))

    var m = scriptPubKey.chunks[0]
    var k = m - (opcodes.OP_1 - 1)
    assert(k <= signatures.length, 'Not enough signatures provided')
  }

  return Script.fromChunks([].concat(opcodes.OP_0, signatures))
}

module.exports = {
  classifyInput: classifyInput,
  classifyOutput: classifyOutput,
  multisigInput: multisigInput,
  multisigOutput: multisigOutput,
  pubKeyHashInput: pubKeyHashInput,
  pubKeyHashOutput: pubKeyHashOutput,
  pubKeyInput: pubKeyInput,
  pubKeyOutput: pubKeyOutput,
  scriptHashInput: scriptHashInput,
  scriptHashOutput: scriptHashOutput
}
<|endoftext|>


<commit_before>var debug = require('debug')('cm:server');
var NewsfeedAgg = require('./models/newsfeed.model.js');
var Votes = require('../../votes/models/votes.js');
var SubTopics = require('../../trees/treeNodes.js');
var Post = require('../../discussion/models/posts.js');

var NewsfeedListener = {

    onAfterVoted: function (newVote) {
        Votes.findOne({_id: newVote._id})
            .exec(function (err, doc) {
                if (doc) {
                    var postId = doc.voteTypeId;
                    var voteType = doc.voteType;
                    if (voteType == "discussion"|| "discussionReply") {

                        Post.findOne({_id: postId})
                            .exec(function (err, result) {
                                if (result) {
                                    var courseId = result.course;
                                    var postName = result.title;
                                    if (courseId) {
                                        var nf = new NewsfeedAgg(
                                            {
                                                userId: newVote.createdBy,
                                                actionSubjectIds: postId,
                                                actionSubject: "vote",
                                                actionName: postName,
                                                courseId: courseId,
                                                actionType: "added",
                                                dateAdded: newVote.dateUpdated
                                            }
                                        );
                                        nf.save(
                                            function (err, doc) {
                                                if (!err) debug('');
                                                else
                                                    debug(err);
                                            }
                                        );
                                    } else {
                                        if (result.parentPost) {
                                            Post.findOne({_id: result.parentPost})
                                                .exec(function (err, parentResult) {
                                                    if (parentResult) {
                                                        var nf = new NewsfeedAgg(
                                                            {
                                                                userId: newVote.createdBy,
                                                                actionSubjectIds: postId,
                                                                actionSubject: "vote",
                                                                actionName: parentResult.title,
                                                                courseId: parentResult.course,
                                                                actionType: "added",
                                                                dateAdded: newVote.dateUpdated
                                                            }
                                                        );
                                                        nf.save(
                                                            function (err, doc) {
                                                                if (!err) debug('');
                                                                else
                                                                    debug(err);
                                                            }
                                                        );
                                                    }
                                                })
                                        }
                                    }

                                }
                            })
                    }

                }
            });

    },

    onAfterSubTopicCreated: function (newSubTopic) {
        SubTopics.findOne({_id: newSubTopic._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "sub topic",
                                actionName : doc.name,
                                courseId: courseId,
                                actionType: "created",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    onAfterSubTopicEdited: function (editSubTopic) {
        SubTopics.findOne({_id: editSubTopic._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "sub topic",
                                actionName : doc.name,
                                courseId: courseId,
                                actionType: "edited",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    onAfterContentNodeCreated: function (newContentNode) {
        SubTopics.findOne({_id: newContentNode._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "content node",
                                actionName: doc.name,
                                courseId: courseId,
                                actionType: "created",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    onAfterContentNodeEdited: function (editContentNode) {
        SubTopics.findOne({_id: editContentNode._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "content node",
                                actionName: doc.name,
                                courseId: courseId,
                                actionType: "edited",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    }

};

module.exports = NewsfeedListener;
<commit_msg>Newsfeed - Add listener for Treenodes and Courses<commit_after>var debug = require('debug')('cm:server');
var NewsfeedAgg = require('./models/newsfeed.model.js');
var Votes = require('../../votes/models/votes.js');
var SubTopics = require('../../trees/treeNodes.js');
var Post = require('../../discussion/models/posts.js');
var Courses = require('../../catalogs/courses.js');

var NewsfeedListener = {

    //Listener for Courses
    onAfterCourseCreated: function (newCourse) {
        Courses.findOne({_id: newCourse._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc._id;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "course",
                                actionName : doc.name,
                                courseId: courseId,
                                actionType: "created",
                                dateAdded: doc.dateAdded
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    onAfterCourseEdited: function (editCourse) {
        Courses.findOne({_id: editCourse._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc._id;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "course",
                                actionName : doc.name,
                                courseId: courseId,
                                actionType: "edited",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    //Listener for Votes
    onAfterVoted: function (newVote) {
        Votes.findOne({_id: newVote._id})
            .exec(function (err, doc) {
                if (doc) {
                    var postId = doc.voteTypeId;
                    var voteType = doc.voteType;
                    if (voteType == "discussion"|| "discussionReply") {

                        Post.findOne({_id: postId})
                            .exec(function (err, result) {
                                if (result) {
                                    var courseId = result.course;
                                    var postName = result.title;
                                    if (courseId) {
                                        var nf = new NewsfeedAgg(
                                            {
                                                userId: newVote.createdBy,
                                                actionSubjectIds: postId,
                                                actionSubject: "vote",
                                                actionName: postName,
                                                courseId: courseId,
                                                actionType: "added",
                                                dateAdded: newVote.dateUpdated
                                            }
                                        );
                                        nf.save(
                                            function (err, doc) {
                                                if (!err) debug('');
                                                else
                                                    debug(err);
                                            }
                                        );
                                    } else {
                                        if (result.parentPost) {
                                            Post.findOne({_id: result.parentPost})
                                                .exec(function (err, parentResult) {
                                                    if (parentResult) {
                                                        var nf = new NewsfeedAgg(
                                                            {
                                                                userId: newVote.createdBy,
                                                                actionSubjectIds: postId,
                                                                actionSubject: "vote",
                                                                actionName: parentResult.title,
                                                                courseId: parentResult.course,
                                                                actionType: "added",
                                                                dateAdded: newVote.dateUpdated
                                                            }
                                                        );
                                                        nf.save(
                                                            function (err, doc) {
                                                                if (!err) debug('');
                                                                else
                                                                    debug(err);
                                                            }
                                                        );
                                                    }
                                                })
                                        }
                                    }

                                }
                            })
                    }

                }
            });

    },

    //Listener for Treenodes - Subtopics
    onAfterSubTopicCreated: function (newSubTopic) {
        SubTopics.findOne({_id: newSubTopic._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "sub topic",
                                actionName : doc.name,
                                courseId: courseId,
                                actionType: "created",
                                dateAdded: doc.dateAdded
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    onAfterSubTopicEdited: function (editSubTopic) {
        SubTopics.findOne({_id: editSubTopic._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "sub topic",
                                actionName : doc.name,
                                courseId: courseId,
                                actionType: "edited",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    //Listener for Treenodes - Content Node
    onAfterContentNodeCreated: function (newContentNode) {
        SubTopics.findOne({_id: newContentNode._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "content node",
                                actionName: doc.name,
                                courseId: courseId,
                                actionType: "created",
                                dateAdded: doc.dateAdded
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    onAfterContentNodeEdited: function (editContentNode) {
        SubTopics.findOne({_id: editContentNode._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "content node",
                                actionName: doc.name,
                                courseId: courseId,
                                actionType: "edited",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    //Listener for Treenodes - Node (whats different with subtopics?)
    onAfterNodeEdited: function (editNode) {
        SubTopics.findOne({_id: editNode._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "node",
                                actionName: doc.name,
                                courseId: courseId,
                                actionType: "edited",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    },

    onAfterNodeDeleted: function (deleteNode) {
        SubTopics.findOne({_id: deleteNode._id})
            .exec(function (err, doc) {
                if (doc) {
                    var courseId = doc.courseId;
                    if (courseId) {
                        var nf = new NewsfeedAgg(
                            {
                                userId: doc.createdBy,
                                actionSubjectIds: doc.id,
                                actionSubject: "node",
                                actionName: doc.name,
                                courseId: courseId,
                                actionType: "deleted",
                                dateAdded: doc.dateUpdated
                            }
                        );
                        nf.save(
                            function (err, doc) {
                                if (!err) debug('');
                                else
                                    debug(err);
                            }
                        );
                    }

                }
            });

    }

};

module.exports = NewsfeedListener;
<|endoftext|>