<commit_before>Meteor.methods({

  inviteUser: function(invitation){

    check(invitation, Match.Any);

    // invite user returns the following hash
    // { newUser : true|false }
    // newUser is true if the person being invited is not on the site yet

    // invitation can either contain userId or an email address :
    // { invitedUserEmail : 'bob@gmail.com' } or { userId : 'user-id' }

    check(invitation, Match.OneOf(
      { invitedUserEmail : String },
      { userId : String }
    ));

    var user = invitation.invitedUserEmail ?
          Meteor.users.findOne({ emails : { $elemMatch: { address: invitation.invitedUserEmail } } }) :
          Meteor.users.findOne({ _id : invitation.userId });

    var userEmail = invitation.invitedUserEmail ? invitation.invitedUserEmail :Users.getEmail(user);
    var currentUser = Meteor.user();
    var currentUserIsAdmin = Users.is.admin(currentUser);
    var currentUserCanInvite = currentUserIsAdmin || (currentUser.telescope.inviteCount > 0 && Users.can.invite(currentUser));

    // check if the person is already invited
    if(user && Users.is.invited(user)){
      throw new Meteor.Error(403, "This person is already invited.");
    } else {
      if (!currentUserCanInvite){
        throw new Meteor.Error(701, "You can't invite this user, sorry.");
      }

      // don't allow duplicate multiple invite for the same person
      var existingInvite = Invites.findOne({ invitedUserEmail : userEmail });

      if (existingInvite) {
        throw new Meteor.Error(403, "Somebody has already invited this person.");
      }

      // create an invite
      // consider invite accepted if the invited person has an account already
      Invites.insert({
        invitingUserId: Meteor.userId(),
        invitedUserEmail: userEmail,
        accepted: typeof user !== "undefined"
      });

      // update invinting user
      Meteor.users.update(Meteor.userId(), {$inc:{"telescope.inviteCount": -1, "telescope.invitedCount": 1}});

      if(user){
        // update invited user
        Meteor.users.update(user._id, {
          $set: {
            "telescope.isInvited": true,
            "telescope.invitedBy": Meteor.userId(),
            "telescope.invitedByName": Users.getDisplayName(currentUser)
          }
        });
      }

      var communityName = Settings.get('title','Telescope'),
          emailSubject = 'You are invited to try '+communityName,
          emailProperties = {
            newUser : typeof user === 'undefined',
            communityName : communityName,
            actionLink : user ? Telescope.utils.getSigninUrl() : Telescope.utils.getSignupUrl(),
            invitedBy : Users.getDisplayName(currentUser),
            profileUrl : Users.getProfileUrl(currentUser),
            siteUrl: Settings.get("siteUrl")
          };

      Meteor.setTimeout(function () {
        Telescope.email.buildAndSend(userEmail, emailSubject, 'emailInvite', emailProperties);
      }, 1);

    }

    return {
      newUser : typeof user === 'undefined'
    };
  },
  unInviteUser: function (userId) {
    Meteor.users.update(userId, {$set: {"telescope.isInvited": false}});
  }
});
<commit_msg>Edit email trailing slash<commit_after>Meteor.methods({

  inviteUser: function(invitation){

    check(invitation, Match.Any);

    // invite user returns the following hash
    // { newUser : true|false }
    // newUser is true if the person being invited is not on the site yet

    // invitation can either contain userId or an email address :
    // { invitedUserEmail : 'bob@gmail.com' } or { userId : 'user-id' }

    check(invitation, Match.OneOf(
      { invitedUserEmail : String },
      { userId : String }
    ));

    var user = invitation.invitedUserEmail ?
          Meteor.users.findOne({ emails : { $elemMatch: { address: invitation.invitedUserEmail } } }) :
          Meteor.users.findOne({ _id : invitation.userId });

    var userEmail = invitation.invitedUserEmail ? invitation.invitedUserEmail :Users.getEmail(user);
    var currentUser = Meteor.user();
    var currentUserIsAdmin = Users.is.admin(currentUser);
    var currentUserCanInvite = currentUserIsAdmin || (currentUser.telescope.inviteCount > 0 && Users.can.invite(currentUser));

    // check if the person is already invited
    if(user && Users.is.invited(user)){
      throw new Meteor.Error(403, "This person is already invited.");
    } else {
      if (!currentUserCanInvite){
        throw new Meteor.Error(701, "You can't invite this user, sorry.");
      }

      // don't allow duplicate multiple invite for the same person
      var existingInvite = Invites.findOne({ invitedUserEmail : userEmail });

      if (existingInvite) {
        throw new Meteor.Error(403, "Somebody has already invited this person.");
      }

      // create an invite
      // consider invite accepted if the invited person has an account already
      Invites.insert({
        invitingUserId: Meteor.userId(),
        invitedUserEmail: userEmail,
        accepted: typeof user !== "undefined"
      });

      // update invinting user
      Meteor.users.update(Meteor.userId(), {$inc:{"telescope.inviteCount": -1, "telescope.invitedCount": 1}});

      if(user){
        // update invited user
        Meteor.users.update(user._id, {
          $set: {
            "telescope.isInvited": true,
            "telescope.invitedBy": Meteor.userId(),
            "telescope.invitedByName": Users.getDisplayName(currentUser)
          }
        });
      }

      var communityName = Settings.get('title','Telescope'),
          emailSubject = 'You are invited to try '+communityName,
          emailProperties = {
            newUser : typeof user === 'undefined',
            communityName : communityName,
            actionLink : user ? Telescope.utils.getSigninUrl() : Telescope.utils.getSignupUrl(),
            invitedBy : Users.getDisplayName(currentUser),
            profileUrl : Users.getProfileUrl(currentUser),
            siteUrl: Settings.get("siteUrl").replace(/\/$/, '')
          };

      Meteor.setTimeout(function () {
        Telescope.email.buildAndSend(userEmail, emailSubject, 'emailInvite', emailProperties);
      }, 1);

    }

    return {
      newUser : typeof user === 'undefined'
    };
  },
  unInviteUser: function (userId) {
    Meteor.users.update(userId, {$set: {"telescope.isInvited": false}});
  }
});
<|endoftext|>


<commit_before>if(typeof require === 'function') {
  const buster    = require("buster")
      , Sequelize = require("../index")
      , Helpers   = require('./buster-helpers')
      , dialects  = Helpers.getSupportedDialects()
}

buster.spec.expose()

dialects.forEach(function(dialect) {
  describe('DAOFactory@' + dialect, function() {
    before(function(done) {
      var self = this

      Helpers.initTests({
        dialect: dialect,
        beforeComplete: function(sequelize, DataTypes) {
          self.sequelize = sequelize
          self.User      = sequelize.define('User', {
            username:     DataTypes.STRING,
            secretValue:  DataTypes.STRING,
            data:         DataTypes.STRING
          })
        },
        onComplete: function(sequelize) {
          self.User.sync({ force: true }).success(done)
        }
      })
    })

    describe('create', function() {
      it('should only store the values passed in the witelist', function(done) {
        var self = this
          , data = { username: 'Peter', secretValue: '42' }

        this.User.create(data, ['username']).success(function(user) {
          self.User.find(user.id).success(function(_user) {
            expect(_user.username).toEqual(data.username)
            expect(_user.secretValue).not.toEqual(data.secretValue)
            expect(_user.secretValue).toEqual(null)
            done()
          })
        })
      })

      it('should store all values if no whitelist is specified', function(done) {
        var self = this
          , data = { username: 'Peter', secretValue: '42' }

        this.User.create(data).success(function(user) {
          self.User.find(user.id).success(function(_user) {
            expect(_user.username).toEqual(data.username)
            expect(_user.secretValue).toEqual(data.secretValue)
            done()
          })
        })
      })

      it('saves data with single quote', function(done) {
        var quote = "single'quote"
          , self  = this

        this.User.create({ data: quote }).success(function(user) {
          expect(user.data).toEqual(quote, 'memory single quote')

          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(quote, 'SQL single quote')
            done()
          })
        })
      })

      it('saves data with double quote', function(done) {
        var quote = 'double"quote'
          , self  = this

        this.User.create({ data: quote }).success(function(user) {
          expect(user.data).toEqual(quote, 'memory double quote')

          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(quote, 'SQL double quote')
            done()
          })
        })
      })

      it('saves stringified JSON data', function(done) {
        var json = JSON.stringify({ key: 'value' })
          , self = this

        this.User.create({ data: json }).success(function(user) {
          expect(user.data).toEqual(json, 'memory data')
          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(json, 'SQL data')
            done()
          })
        })
      })

      it('stores the current date in createdAt', function(done) {
        this.User.create({ username: 'foo' }).success(function(user) {
          expect(parseInt(+user.createdAt/1000)).toEqual(parseInt(+new Date()/1000))
          done()
        })
      })
    })
  })
})
<commit_msg>let's see if this fixes the specs on travis<commit_after>if(typeof require === 'function') {
  const buster    = require("buster")
      , Sequelize = require("../index")
      , Helpers   = require('./buster-helpers')
      , dialects  = Helpers.getSupportedDialects()
}

buster.spec.expose()

dialects.forEach(function(dialect) {
  describe('DAOFactory@' + dialect, function() {
    before(function(done) {
      var self = this

      Helpers.initTests({
        dialect: dialect,
        beforeComplete: function(sequelize, DataTypes) {
          self.sequelize = sequelize
          self.User      = sequelize.define('User', {
            username:     DataTypes.STRING,
            secretValue:  DataTypes.STRING,
            data:         DataTypes.STRING
          })
        },
        onComplete: function(sequelize) {
          self.User.sync({ force: true }).success(done)
        }
      })
    })

    describe('create', function() {
      it('should only store the values passed in the witelist', function(done) {
        var self = this
          , data = { username: 'Peter', secretValue: '42' }

        this.User.create(data, ['username']).success(function(user) {
          self.User.find(user.id).success(function(_user) {
            expect(_user.username).toEqual(data.username)
            expect(_user.secretValue).not.toEqual(data.secretValue)
            expect(_user.secretValue).toEqual(null)
            done()
          })
        })
      })

      it('should store all values if no whitelist is specified', function(done) {
        var self = this
          , data = { username: 'Peter', secretValue: '42' }

        this.User.create(data).success(function(user) {
          self.User.find(user.id).success(function(_user) {
            expect(_user.username).toEqual(data.username)
            expect(_user.secretValue).toEqual(data.secretValue)
            done()
          })
        })
      })

      it('saves data with single quote', function(done) {
        var quote = "single'quote"
          , self  = this

        this.User.create({ data: quote }).success(function(user) {
          expect(user.data).toEqual(quote, 'memory single quote')

          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(quote, 'SQL single quote')
            done()
          })
        })
      })

      it('saves data with double quote', function(done) {
        var quote = 'double"quote'
          , self  = this

        this.User.create({ data: quote }).success(function(user) {
          expect(user.data).toEqual(quote, 'memory double quote')

          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(quote, 'SQL double quote')
            done()
          })
        })
      })

      it('saves stringified JSON data', function(done) {
        var json = JSON.stringify({ key: 'value' })
          , self = this

        this.User.create({ data: json }).success(function(user) {
          expect(user.data).toEqual(json, 'memory data')
          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(json, 'SQL data')
            done()
          })
        })
      })

      it('stores the current date in createdAt', function(done) {
        this.User.create({ username: 'foo' }).success(function(user) {
          expect(parseInt(+user.createdAt/5000)).toEqual(parseInt(+new Date()/5000))
          done()
        })
      })
    })
  })
})
<|endoftext|>


<commit_before>module.exports = function (grunt) {
  grunt.loadNpmTasks('grunt-typescript');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['typescript', 'cssmin']);

  grunt.initConfig({
    typescript: {
      base: {
        src: ['lib/ICloneable.ts',
              'lib/GameManager.ts',
              'lib/GameScreen.ts',
              'lib/GameObject.ts',
              'lib/FPSDisplay.ts',
              'lib/Line.ts',
              'lib/Vector3.ts',
              'lib/Plane.ts',
              'lib/Matrix4.ts',
              'lib/Camera.ts',
              'lib/Mesh.ts',
              'lib/Object3D.ts',
              'lib/Mesh/Cube.ts',
              'lib/Mesh/Pyramid.ts',
              'lib/Mesh/Circle.ts',
              'lib/Mesh/Crater.ts',
              'lib/LineClipping.ts',
              'game/Mesh/Crater.ts',
              'game/Mesh/Terrain.ts',
              'game/Mesh/Tank.ts',
              'game/Player.ts',
              'game/Game.ts',
              'game/CollisionTester.ts',
              'lib/Keyboard.ts',
              'lib/Renderer.ts'

        ],
        dest: 'js/compiled.js',
        target: 'ES5',
        options: {
            'module': 'commonjs',
            'sourceMap': true
        }
      }
    },
    watch: {
      scripts: {
        files: ['lib/*.ts', 'style/*.css'],
        tasks: ['default']
      }
    },
    cssmin: {
      minify: {
        expand: true,
        cwd: '',
        src: ['css/*.css', 'css/!*.min.css'],
        dest: '',
        ext: '.min.css'
      }
    }
  });
};

/*grunt init
npm install grunt-typescript --save-dev
npm install grunt-rename --save-dev
npm install grunt-contrib-cssmin --save-dev
npm install grunt-contrib-watch --save-dev*/<commit_msg>Removed unused processing steps.<commit_after>module.exports = function (grunt) {
  grunt.loadNpmTasks('grunt-typescript');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-contrib-watch');

  grunt.registerTask('default', ['typescript', 'cssmin']);

  grunt.initConfig({
    typescript: {
      base: {
        src: ['lib/ICloneable.ts',
              'lib/GameManager.ts',
              'lib/GameScreen.ts',
              'lib/GameObject.ts',
              'lib/FPSDisplay.ts',
              'lib/Line.ts',
              'lib/Vector3.ts',
              'lib/Plane.ts',
              'lib/Matrix4.ts',
              'lib/Camera.ts',
              'lib/Mesh.ts',
              'lib/Object3D.ts',
              'lib/Mesh/Cube.ts',
              'lib/Mesh/Pyramid.ts',
              'lib/Mesh/Circle.ts',
              'lib/Mesh/Crater.ts',
              'lib/LineClipping.ts',
              'game/Mesh/Crater.ts',
              'game/Mesh/Terrain.ts',
              'game/Mesh/Tank.ts',
              'game/Player.ts',
              'game/Game.ts',
              'game/CollisionTester.ts',
              'lib/Keyboard.ts',
              'lib/Renderer.ts'

        ],
        dest: 'js/compiled.js',
        target: 'ES5',
        options: {
            'module': 'commonjs',
            'sourceMap': true
        }
      }
    },
    watch: {
      scripts: {
        files: ['lib/*.ts', 'style/*.css'],
        tasks: ['default']
      }
    },
    cssmin: {
      minify: {
        expand: true,
        cwd: '',
        src: ['css/*.css', 'css/!*.min.css'],
        dest: '',
        ext: '.min.css'
      }
    }
  });
};

/*grunt init
npm install grunt-typescript --save-dev
npm install grunt-rename --save-dev
npm install grunt-contrib-cssmin --save-dev
npm install grunt-contrib-watch --save-dev*/<|endoftext|>


<commit_before>
const RG = require('./rg');

RG.Factory = require('./factory');
RG.Factory.Battle = require('./factory.battle');

/* GameMaster objects reacts to various events caused by player and other
 * actors, and shapes the game world based on them. For example,
 * GameMaster can:
 *   - start battles on the area player entered
 *   - spawn special events and actors
 *   - spawn special items etc.
 */
const GameMaster = function(pool, game) {
    this.eventPool = pool;
    this.player = null;
    this.game = game;
    this.fact = new RG.Factory.Battle(game);

    // Lookup table for battles by level ID
    this.battles = {};

    this.setPlayer = player => {
        this.player = player;
    };
    this.setWorld = world => {this.world = world;};

    this.hasNotify = true;
    this.notify = (evtName, args) => {
        if (evtName === RG.EVT_LEVEL_CHANGED) {
            console.log('GameMaster EVT_LEVEL_CHANGED triggered');
            const {actor, target, src} = args;
            if (actor.isPlayer()) {
                const srcID = src.getID();
                if (this.battles.hasOwnProperty(srcID)) {
                    const battleLevel = this.battles[srcID].getLevel();

                    if (battleLevel.getID() === target.getID()) {
                        // Entered a battle
                        console.log('Player entered battle. Getting sel obj');
                        actor.add(new RG.Component.InBattle());
                        // Get army selection object
                        const obj = this.getSelArmyObject(actor, this.battles[srcID]);
                        actor.getBrain().setSelectionObject(obj);
                    }
                }
            }
        }
        else if (evtName === RG.EVT_TILE_CHANGED) {
            console.log('EVT_TILE_CHANGED triggered');
            // Should spawn battle etc event
            if (!this.player) {
                console.log('\tBut player is NULL for the moment');
                return;
            }
            console.log('\tPlayer not null. Creating battle');
            const level = this.player.getLevel();
            const id = level.getID();
            if (!this.battles.hasOwnProperty(id)) {
                this.battles[id] = this.fact.createBattle(level);
                this.game.addBattle(this.battles[id]);
            }
        }
        else if (evtName === RG.EVT_BATTLE_OVER) {
            const {battle} = args;
            if (battle) {
                this.addBadgesForActors(battle);
                this.moveActorsOutOfBattle(battle);
            }
            else {
                const json = JSON.stringify(args);
                RG.err('Game.Master', 'notify',
                    `Args ${json} does not contain "battle"`);
            }
            console.log('GameMaster registered battle over');
            RG.gameMsg('Battle is over!');
            // TODO delete the battle (but keep the level)
        }
    };
    RG.POOL.listenEvent(RG.EVT_LEVEL_CHANGED, this);
    RG.POOL.listenEvent(RG.EVT_TILE_CHANGED, this);
    RG.POOL.listenEvent(RG.EVT_BATTLE_OVER, this);

    /* Adds BattleBadges after a battle is over. */
    this.addBadgesForActors = battle => {
        const armies = battle.getArmies();
        armies.forEach(army => {
            const actors = army.getActors();
            const ids = actors.map(actor => actor.getID());

            actors.forEach(actor => {
                const badge = new RG.Component.BattleBadge();
                if (army.isDefeated()) {
                    badge.setStatus('Defeated');
                }
                else {
                    badge.setStatus('Won');
                }
                const battleData = {
                    name: battle.getName(),
                    allies: ids
                };
                badge.setData(battleData);
                actor.add(badge);

                let name = actor.getName();
                name = `Battle-tested ${name}`;
                actor.setName(name);
            });
        });
    };

    /* Moves actors out of the battle level into the parent level of the battle
     * (at the moment this is always Area.Tile level. */
    this.moveActorsOutOfBattle = battle => {
        const level = battle.getLevel();
        const conns = level.getConnections();

        if (!conns || conns.length === 0) {
            RG.err('Game.Master', 'moveActorsOutOfBattle',
                'No exit connnection in level');
        }

        const exit = conns[0];
        const targetLevel = exit.getTargetLevel();

        const armies = battle.getArmies();
        armies.forEach(army => {
            const actors = army.getActors();
            actors.forEach(actor => {
                if (!actor.isPlayer()) {
                    if (level.removeActor(actor)) {
                        targetLevel.addActorToFreeCell(actor);
                    }
                    else {
                        const json = JSON.stringify(actor.toJSON());
                        RG.err('Game.Master', 'moveActorsOutOfBattle',
                            `removeActor failed for actor ${json}`);
                    }
                }
                else {
                    const selObj = this.getSelLeaveBattle(actor, level);
                    actor.getBrain().setSelectionObject(selObj);
                }
            });
        });

    };

    /* Returns the selection object for player to select an army. */
    this.getSelArmyObject = function(player, battle) {
        return {
            showMenu: () => true,
            getMenu: () => {
                RG.gameMsg('Please select an army to join:');
                const armies = battle.getArmies();
                const menuObj = {};
                armies.forEach((army, i) => {
                    menuObj[i] = ' Army ' + army.getName();
                });
                menuObj['Any other key'] = 'Take no side';
                return menuObj;
            },
            select: code => {
                const selection = RG.codeToIndex(code);
                const armies = battle.getArmies();
                if (selection < armies.length) {
                    const army = armies[selection];
                    return () => {
                        army.addActor(player);
                        const actors = army.getActors();
                        actors.forEach(actor => {
                            actor.addFriend(player);
                        });
                    };
                }
                return null;
            }
        };
    };

    this.getSelLeaveBattle = function(player, level) {
        return {
            showMenu: () => true,
            getMenu: () => {
                RG.gameMsg('Battle is over! Do you want to leave battle?');
                return {
                    0: 'Leave immediately',
                    1: 'Stay behind to scavenge the bodies of the dead.'
                };
            },
            select: code => {
                if (parseInt(code, 10) === 0) {
                    const stairs = level.getStairs()[0];
                    if (!stairs.useStairs(player)) {
                        RG.err('GameMaster', 'moveActorsOutOfBattle',
                            'Cannot move player out of battle via useStairs');
                    }
                    else {
                        const name = player.getName();
                        RG.gameMsg(`${name} leaves the battlefield`);
                    }
                }
                return null;
            }
        };
    };

    /* Serializes the object into JSON. */
    this.toJSON = function() {
        const keys = Object.keys(this.battles);
        const battles = {};
        keys.forEach(id => {
            battles[id] = this.battles[id].toJSON();
        });
        return {
            battles
        };
    };
};

module.exports = GameMaster;
<commit_msg>Added a constructor function to getSelBattle() to return this, when invalid key is pressed.<commit_after>
const RG = require('./rg');

RG.Factory = require('./factory');
RG.Factory.Battle = require('./factory.battle');

/* GameMaster objects reacts to various events caused by player and other
 * actors, and shapes the game world based on them. For example,
 * GameMaster can:
 *   - start battles on the area player entered
 *   - spawn special events and actors
 *   - spawn special items etc.
 */
const GameMaster = function(pool, game) {
    this.eventPool = pool;
    this.player = null;
    this.game = game;
    this.fact = new RG.Factory.Battle(game);

    // Lookup table for battles by level ID
    this.battles = {};

    this.setPlayer = player => {
        this.player = player;
    };
    this.setWorld = world => {this.world = world;};

    this.hasNotify = true;
    this.notify = (evtName, args) => {
        if (evtName === RG.EVT_LEVEL_CHANGED) {
            console.log('GameMaster EVT_LEVEL_CHANGED triggered');
            const {actor, target, src} = args;
            if (actor.isPlayer()) {
                const srcID = src.getID();
                if (this.battles.hasOwnProperty(srcID)) {
                    const battleLevel = this.battles[srcID].getLevel();

                    if (battleLevel.getID() === target.getID()) {
                        // Entered a battle
                        console.log('Player entered battle. Getting sel obj');
                        actor.add(new RG.Component.InBattle());
                        // Get army selection object
                        const obj = this.getSelArmyObject(actor, this.battles[srcID]);
                        actor.getBrain().setSelectionObject(obj);
                    }
                }
            }
        }
        else if (evtName === RG.EVT_TILE_CHANGED) {
            console.log('EVT_TILE_CHANGED triggered');
            // Should spawn battle etc event
            if (!this.player) {
                console.log('\tBut player is NULL for the moment');
                return;
            }
            console.log('\tPlayer not null. Creating battle');
            const level = this.player.getLevel();
            const id = level.getID();
            if (!this.battles.hasOwnProperty(id)) {
                this.battles[id] = this.fact.createBattle(level);
                this.game.addBattle(this.battles[id]);
            }
        }
        else if (evtName === RG.EVT_BATTLE_OVER) {
            const {battle} = args;
            if (battle) {
                this.addBadgesForActors(battle);
                this.moveActorsOutOfBattle(battle);
            }
            else {
                const json = JSON.stringify(args);
                RG.err('Game.Master', 'notify',
                    `Args ${json} does not contain "battle"`);
            }
            console.log('GameMaster registered battle over');
            RG.gameMsg('Battle is over!');
            // TODO delete the battle (but keep the level)
        }
    };
    RG.POOL.listenEvent(RG.EVT_LEVEL_CHANGED, this);
    RG.POOL.listenEvent(RG.EVT_TILE_CHANGED, this);
    RG.POOL.listenEvent(RG.EVT_BATTLE_OVER, this);

    /* Adds BattleBadges after a battle is over. */
    this.addBadgesForActors = battle => {
        const armies = battle.getArmies();
        armies.forEach(army => {
            const actors = army.getActors();
            const ids = actors.map(actor => actor.getID());

            actors.forEach(actor => {
                const badge = new RG.Component.BattleBadge();
                if (army.isDefeated()) {
                    badge.setStatus('Defeated');
                }
                else {
                    badge.setStatus('Won');
                }
                const battleData = {
                    name: battle.getName(),
                    allies: ids
                };
                badge.setData(battleData);
                actor.add(badge);

                let name = actor.getName();
                name = `Battle-tested ${name}`;
                actor.setName(name);
            });
        });
    };

    /* Moves actors out of the battle level into the parent level of the battle
     * (at the moment this is always Area.Tile level. */
    this.moveActorsOutOfBattle = battle => {
        const level = battle.getLevel();
        const conns = level.getConnections();

        if (!conns || conns.length === 0) {
            RG.err('Game.Master', 'moveActorsOutOfBattle',
                'No exit connnection in level');
        }

        const exit = conns[0];
        const targetLevel = exit.getTargetLevel();

        const armies = battle.getArmies();
        armies.forEach(army => {
            const actors = army.getActors();
            actors.forEach(actor => {
                if (!actor.isPlayer()) {
                    if (level.removeActor(actor)) {
                        targetLevel.addActorToFreeCell(actor);
                    }
                    else {
                        const json = JSON.stringify(actor.toJSON());
                        RG.err('Game.Master', 'moveActorsOutOfBattle',
                            `removeActor failed for actor ${json}`);
                    }
                }
                else {
                    const selObj = this.getSelLeaveBattle(actor, level);
                    actor.getBrain().setSelectionObject(selObj);
                }
            });
        });

    };

    /* Returns the selection object for player to select an army. */
    this.getSelArmyObject = function(player, battle) {
        return {
            showMenu: () => true,
            getMenu: () => {
                RG.gameMsg('Please select an army to join:');
                const armies = battle.getArmies();
                const menuObj = {};
                armies.forEach((army, i) => {
                    menuObj[i] = ' Army ' + army.getName();
                });
                menuObj['Any other key'] = 'Take no side';
                return menuObj;
            },
            select: code => {
                const selection = RG.codeToIndex(code);
                const armies = battle.getArmies();
                if (selection < armies.length) {
                    const army = armies[selection];
                    return () => {
                        army.addActor(player);
                        const actors = army.getActors();
                        actors.forEach(actor => {
                            actor.addFriend(player);
                        });
                    };
                }
                return null;
            }
        };
    };

    this.getSelLeaveBattle = function(player, level) {
        const selObj = function() {
            this.showMenu = () => true;
            this.getMenu = () => {
                RG.gameMsg('Battle is over! Do you want to leave battle?');
                return {
                    0: 'Leave immediately',
                    1: 'Stay behind to scavenge the bodies of the dead.'
                };
            };
            this.select = code => {
                const selection = RG.codeToIndex(code);
                if (selection === 0) {
                    const stairs = level.getStairs()[0];
                    if (!stairs.useStairs(player)) {
                        RG.err('GameMaster', 'moveActorsOutOfBattle',
                            'Cannot move player out of battle via useStairs');
                    }
                    else {
                        const name = player.getName();
                        RG.gameMsg(`${name} leaves the battlefield`);
                    }
                }
                if (selection === 1) {
                    // TODO add some dishonor for the player or some necromancy
                    // effect etc
                    return null;
                }
                return this;
            };
        };
        return new selObj();
    };

    /* Serializes the object into JSON. */
    this.toJSON = function() {
        const keys = Object.keys(this.battles);
        const battles = {};
        keys.forEach(id => {
            battles[id] = this.battles[id].toJSON();
        });
        return {
            battles
        };
    };
};

module.exports = GameMaster;
<|endoftext|>


<commit_before>import { getOwner } from '@ember/application';
import { get } from '@ember/object';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import Service, { inject as service } from '@ember/service';
import { transitionTo } from '../private-api';
import { modelType } from '@cardstack/rendering/helpers/cs-model-type';
import injectOptional from 'ember-inject-optional';
import { defaultBranch } from '@cardstack/plugin-utils/environment';

export default Service.extend({
  overlays: service('ember-overlays'),
  resourceMetadata: service(),
  marks: alias('overlays.marks'),
  cardstackEdges: service(),

  fields: computed('marks', function() {
    return this.get('marks').filter(m => m.group === 'cardstack-fields');
  }),

  contentPages: computed('marks', function() {
    return this.get('marks').filter(m => m.group === 'cardstack-pages');
  }),

  activeContentItem: computed('contentPages', function() {
    return this.get('contentPages')[0];
  }),

  _activeItemMeta: computed('activeContentItem', function() {
    let model = this.get('activeContentItem.model')
    if (model) {
      return this.get('resourceMetadata').read(model);
    }
  }),

  branch: alias('_activeItemMeta.branch'),

  activeFields: computed('activeContentItem', 'fields', function() {
    let item = this.get('activeContentItem');
    let activeItemModel = item.model;
    let owned = ownedRelatedRecords([item.model]);
    if (item) {
      return this.get('fields').filter(f => {
        let fieldModel = f.model.content;
        if (fieldModel === activeItemModel) {
          return true;
        }
        if (owned.includes(fieldModel)) {
          return true;
        }
        return false;
      });
    } else {
      return [];
    }
  }),

  // Can tools be enabled at all? This affects whether we will offer a
  // launcher button
  available: computed('sessionService.session.isAuthenticated', function() {
    // If cardstack-session service is available, tools are only
    // available when the session is authenticated. Otherwise we
    // default to always available.
    return !this.get('sessionService') || this.get('sessionService.session.isAuthenticated');
  }),

  creatableTypes: alias('sessionService.creatableTypes'),

  sessionService: injectOptional.service('cardstack-session'),

  // Tools are active when the user has hit the launcher button and
  // revealed the toolbars.
  active: false,

  // Which tab are we showing in the toolbox?
  activePanel: 'cs-composition-panel',
  activePanelChoices: computed(function() {
    return [
      {
        id: 'cs-composition-panel',
        icon: {
          name: 'write',
          width: 13,
          height: 18
        },
      }
    ];
  }),

  // Are we viewing the current URL as a normal page in its own right,
  // or in one of its other forms (like a preview card)?
  previewFormat: 'page',
  previewFormatChoices: computed(function() {
    return [
      {
        id: 'page',
        description: 'Page',
        icon: {
          name: 'page',
          width: 18,
          height: 24
        }
      },
      {
        id: 'cards',
        description: 'Card',
        icon: {
          name: 'tiles',
          width: 20,
          height: 24
        }
      }
    ];
  }),

  requestedEditing: false,

  // This is a placeholder until I integrate the auth system here.
  mayEditLive: computed(function() {
    let { cardstack } = getOwner(this).resolveRegistration('config:environment');
    if (cardstack && typeof cardstack.mayEditLive === 'boolean') {
      return cardstack.mayEditLive;
    } else {
      return true;
    }
  }),

  editing: computed('requestedEditing', 'branch', function() {
    return this.get('requestedEditing') &&
      (this.get('mayEditLive') ||
       this.get('branch') !== defaultBranch);
  }),

  init() {
    this._super();
    let priorState;
    try {
      let item = localStorage.getItem('cardstack-tools');
      if (item) {
        priorState = JSON.parse(item);
        for (let key in priorState) {
          this.set(key, priorState[key]);
        }
      }
    } catch (err) {
      // Ignored
    }
    this.persistentState = priorState || {};

    /* --  Ephemermal state -- */

    // a field is highlighted when we're drawing a blue border around it
    this.highlightedFieldId = null;

    // a field is opened when the user is actively editing it
    this.openedFieldId = null;

    // Register items for edges

    this.get('cardstackEdges').registerTopLevelComponent('cardstack-tools-edges');
  },

  _updatePersistent(key, value) {
    this.persistentState[key] = value;
    localStorage.setItem('cardstack-tools', JSON.stringify(this.persistentState));
    this.set(key, value);
  },

  setPreviewFormat(mode) {
    this._updatePersistent('previewFormat', mode);
  },

  setActive(isActive) {
    this._updatePersistent('active', isActive);
  },

  setActivePanel(which) {
    this._updatePersistent('activePanel', which);
    if (which === 'cs-create-menu') {
      if (!this.get('mayEditLive') && this.get('branch') === defaultBranch) {
        this.setBranch('draft');
      }
    }
  },

  setEditing(which) {
    this._updatePersistent('requestedEditing', which);
    if (!this.get('mayEditLive') && this.get('branch') === defaultBranch) {
      this.setBranch('draft');
    }
  },

  setBranch(which) {
    let model = this.get('activeContentItem.model')
    if (model && model.get('slug')) {
      let {
        name,
        args,
        queryParams
      } = this.get('cardstackRouting').routeFor(modelType(model), model.get('slug'), which);
      transitionTo(getOwner(this), name, args, queryParams);
    }
  },

  openField(which) {
    this.set('openedFieldId', which ? which.id : null);
  },

  highlightField(which) {
    this.set('highlightedFieldId', which ? which.id : null);
  }

});

function ownedRelatedRecords(records, out = []) {
  let [record, ...rest] = records;
  if (!record) {
    return out;
  }

  let recordClass = record.constructor;
  get(recordClass, 'relationships').forEach(([ relationshipDefinition ]) => {
    let { meta } = relationshipDefinition;
    let { owned } = meta.options;
    if (owned) {
      let relatedRecords = record.get(meta.name);
      if (meta.kind === 'hasMany') {
        relatedRecords = relatedRecords.toArray();
      }
      rest = rest.concat(relatedRecords);
      out = out.concat(relatedRecords);
    }
  });
  return ownedRelatedRecords(rest, out);
}

<commit_msg>DS.Model.relationships does not return a property with meta on. Use the metaForProperty method instead<commit_after>import { getOwner } from '@ember/application';
import { get } from '@ember/object';
import { computed } from '@ember/object';
import { alias } from '@ember/object/computed';
import Service, { inject as service } from '@ember/service';
import { transitionTo } from '../private-api';
import { modelType } from '@cardstack/rendering/helpers/cs-model-type';
import injectOptional from 'ember-inject-optional';
import { defaultBranch } from '@cardstack/plugin-utils/environment';

export default Service.extend({
  overlays: service('ember-overlays'),
  resourceMetadata: service(),
  marks: alias('overlays.marks'),
  cardstackEdges: service(),

  fields: computed('marks', function() {
    return this.get('marks').filter(m => m.group === 'cardstack-fields');
  }),

  contentPages: computed('marks', function() {
    return this.get('marks').filter(m => m.group === 'cardstack-pages');
  }),

  activeContentItem: computed('contentPages', function() {
    return this.get('contentPages')[0];
  }),

  _activeItemMeta: computed('activeContentItem', function() {
    let model = this.get('activeContentItem.model')
    if (model) {
      return this.get('resourceMetadata').read(model);
    }
  }),

  branch: alias('_activeItemMeta.branch'),

  activeFields: computed('activeContentItem', 'fields', function() {
    let item = this.get('activeContentItem');
    let activeItemModel = item.model;
    let owned = ownedRelatedRecords([item.model]);
    if (item) {
      return this.get('fields').filter(f => {
        let fieldModel = f.model.content;
        if (fieldModel === activeItemModel) {
          return true;
        }
        if (owned.includes(fieldModel)) {
          return true;
        }
        return false;
      });
    } else {
      return [];
    }
  }),

  // Can tools be enabled at all? This affects whether we will offer a
  // launcher button
  available: computed('sessionService.session.isAuthenticated', function() {
    // If cardstack-session service is available, tools are only
    // available when the session is authenticated. Otherwise we
    // default to always available.
    return !this.get('sessionService') || this.get('sessionService.session.isAuthenticated');
  }),

  creatableTypes: alias('sessionService.creatableTypes'),

  sessionService: injectOptional.service('cardstack-session'),

  // Tools are active when the user has hit the launcher button and
  // revealed the toolbars.
  active: false,

  // Which tab are we showing in the toolbox?
  activePanel: 'cs-composition-panel',
  activePanelChoices: computed(function() {
    return [
      {
        id: 'cs-composition-panel',
        icon: {
          name: 'write',
          width: 13,
          height: 18
        },
      }
    ];
  }),

  // Are we viewing the current URL as a normal page in its own right,
  // or in one of its other forms (like a preview card)?
  previewFormat: 'page',
  previewFormatChoices: computed(function() {
    return [
      {
        id: 'page',
        description: 'Page',
        icon: {
          name: 'page',
          width: 18,
          height: 24
        }
      },
      {
        id: 'cards',
        description: 'Card',
        icon: {
          name: 'tiles',
          width: 20,
          height: 24
        }
      }
    ];
  }),

  requestedEditing: false,

  // This is a placeholder until I integrate the auth system here.
  mayEditLive: computed(function() {
    let { cardstack } = getOwner(this).resolveRegistration('config:environment');
    if (cardstack && typeof cardstack.mayEditLive === 'boolean') {
      return cardstack.mayEditLive;
    } else {
      return true;
    }
  }),

  editing: computed('requestedEditing', 'branch', function() {
    return this.get('requestedEditing') &&
      (this.get('mayEditLive') ||
       this.get('branch') !== defaultBranch);
  }),

  init() {
    this._super();
    let priorState;
    try {
      let item = localStorage.getItem('cardstack-tools');
      if (item) {
        priorState = JSON.parse(item);
        for (let key in priorState) {
          this.set(key, priorState[key]);
        }
      }
    } catch (err) {
      // Ignored
    }
    this.persistentState = priorState || {};

    /* --  Ephemermal state -- */

    // a field is highlighted when we're drawing a blue border around it
    this.highlightedFieldId = null;

    // a field is opened when the user is actively editing it
    this.openedFieldId = null;

    // Register items for edges

    this.get('cardstackEdges').registerTopLevelComponent('cardstack-tools-edges');
  },

  _updatePersistent(key, value) {
    this.persistentState[key] = value;
    localStorage.setItem('cardstack-tools', JSON.stringify(this.persistentState));
    this.set(key, value);
  },

  setPreviewFormat(mode) {
    this._updatePersistent('previewFormat', mode);
  },

  setActive(isActive) {
    this._updatePersistent('active', isActive);
  },

  setActivePanel(which) {
    this._updatePersistent('activePanel', which);
    if (which === 'cs-create-menu') {
      if (!this.get('mayEditLive') && this.get('branch') === defaultBranch) {
        this.setBranch('draft');
      }
    }
  },

  setEditing(which) {
    this._updatePersistent('requestedEditing', which);
    if (!this.get('mayEditLive') && this.get('branch') === defaultBranch) {
      this.setBranch('draft');
    }
  },

  setBranch(which) {
    let model = this.get('activeContentItem.model')
    if (model && model.get('slug')) {
      let {
        name,
        args,
        queryParams
      } = this.get('cardstackRouting').routeFor(modelType(model), model.get('slug'), which);
      transitionTo(getOwner(this), name, args, queryParams);
    }
  },

  openField(which) {
    this.set('openedFieldId', which ? which.id : null);
  },

  highlightField(which) {
    this.set('highlightedFieldId', which ? which.id : null);
  }

});

function ownedRelatedRecords(records, out = []) {
  let [record, ...rest] = records;
  if (!record) {
    return out;
  }

  let recordClass = record.constructor;
  get(recordClass, 'relationships').forEach(([ relationshipDefinition ]) => {
    let meta = recordClass.metaForProperty(relationshipDefinition.name);
    let { owned } = meta.options;
    if (owned) {
      let relatedRecords = record.get(meta.name);
      if (meta.kind === 'hasMany') {
        relatedRecords = relatedRecords.toArray();
      }
      rest = rest.concat(relatedRecords);
      out = out.concat(relatedRecords);
    }
  });
  return ownedRelatedRecords(rest, out);
}

<|endoftext|>


<commit_before>function clone(obj) {
	if (typeof obj == 'object') {
		return $.extend(true, {}, obj);
	} else {
		return obj;
	}
};

function getKeys(obj) {
    var keys = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
                    keys.push(key);
        }
    }
    return keys;
}

var app = angular.module('opalApp', ['$strap.directives']);

app.controller('TableCtrl', function($scope, $http) {
	var editing = false;
	var deleting = false;

	$scope.rows = [];

	$scope.rix = 0; // row index
	$scope.cix = 0; // column index
	$scope.iix = 0; // item index

	$scope.mouseRix = -1; // index of row mouse is currently over
	$scope.mouseCix = -1; // index of column mouse is currently over

	$http.get('assets/records.json').success(function(rows) {
		for (var rix = 0; rix < rows.length; rix++) {
			for (var cix = 0; cix < $scope.columns.length; cix++) {
				if ($scope.columns[cix].multi) {
					rows[rix][$scope.columns[cix].name].push({});
				}
			}
		}
		$scope.rows = rows;
	});

	$scope.columns = [
		{name: 'location', title: 'Location', multi: false},
		{name: 'demographics', title: 'Demographics', multi: false},
		{name: 'diagnosis', title: 'Diagnosis', multi: true},
		{name: 'pastMedicalHistory', title: 'Past Medical History', multi: true},
		{name: 'generalNotes', title: 'Notes', multi: true},
		{name: 'travel', title: 'Travel', multi: true},
		{name: 'antimicrobials', title: 'Antimicrobials', multi: true},
		{name: 'microbiology', title: 'Microbiology', multi: true},
		{name: 'microbiologyComments', title: 'Microbiology Input', multi: true},
		{name: 'plan', title: 'Plan', multi: false},
		{name: 'discharge', title: 'Discharge', multi: false},
	];

	$scope.getCix = function(name) {
		for (var cix = 0; cix < $scope.columns.length; cix++) {
			if ($scope.columns[cix].name == name) {
				return cix;
			}
		}
		throw 'Unexpected column name: ' + name
	};

	var option_lists = [
		'antimicrobial',
		'antimicrobial_route',
		'condition',
		'destination',
		'patient_category',
		'travel_reason',
	];

	for (var i = 0; i < option_lists.length; i++) {
		(function(option) {
			$http.get('options/' + option + '_list/').success(function(data) {
				$scope[option + '_list'] = data;
			});
		})(option_lists[i]);
	}

	$scope.microbiology_test_list = [
		'Broncheoalveolar lavage MC&S',
		'Blood Culture',
		'CSF AFB microscopy & TB culture',
		'CSF MC&S',
		'Fluid MC&S',
		'Lymph Node MC&S',
		'Pleural MC&S',
		'Sputum AFB microscopy & TB culture',
		'Sputum MC&S',
		'Stool MC&S',
		'Stool OCP',
		'Throat Swab MC&S',
		'Tissue AFB microscopy & TB culture',
		'Tissue MC&S',
		'Urine AFB microscopy & TB culture',
		'Urine MC&S',
		'Wound swab MC&S',
		'CMV Serology',
		'Dengue Serology',
		'Hepatitis A Serology',
		'Hepatitis E Serology',
		'Measles Serology',
		'Rubella Serology',
		'Toxoplasmosis Serology',
		'VZV Serology',
		'Brucella Serology',
		'EBV Serology',
		'HIV',
		'Hepatitis B Serology',
		'Syphilis Serology',
		'Cryptococcal antigen',
		'Dengue PCR',
		'JC Virus PCR',
		'MRSA PCR',
		'Rickettsia PCR',
		'Scrub Typhus PCR',
		'Borrleia Screening Serology',
		'Brorleia Reference Serology',
		'Viral Haemorrhagic Fever PCR',
		'Amoebic Serology',
		'Cystercicosis Serology',
		'Fasciola Serology',
		'Filaria Serology',
		'Hydatid Serology',
		'Strongyloides Serology',
		'Toxcocara Serology',
		'Trypanosomiasis brucei Serology',
		'Trypanosomiasis cruzi serology',
		'Hepatitis C Serology',
		'Hepatitis D Serology',
		'HHV-6 Serology',
		'HHV-7 Serology',
		'HTLV Serology',
		'CMV Viral Load',
		'EBV Viral Load ',
		'HBV Viral Load',
		'HCV Viral Load',
		'HHV-6 Viral Load',
		'HHV-7 Viral Load',
		'HHV-8 Viral Load',
		'HIV Viral Load',
		'Measles PCR',
		'VZV Viral Load',
		'Babesia Film',
		'Malaria Film',
		'Microfilarial Film',
		'Swab PCR',
		'C. difficile',
		'Leishmaniasis PCR',
		'CSF PCR',
		'Respiratory Virus PCR',
		'Stool PCR',
		'Stool Parasitology PCR',
		'Other',
	];

	function startEdit() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var columnName = $scope.columns[cix].name;

		editing = true;
		if ($scope.columns[cix]['multi']) {
			$scope.editing = clone($scope.rows[rix][columnName][iix]);
		} else {
			$scope.editing = clone($scope.rows[rix][columnName]);
		}
		$('#' + columnName + '-modal').modal();
		$('#' + columnName + '-modal').find('input,textarea').first().focus();
	};

	function startDelete() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var column = $scope.columns[cix];

		if (!column.multi) {
			return;
		}

		if ($scope.rows[rix][column.name].length == 1) {
			return;
		}

		deleting = true;
		$('#delete-confirmation').modal();
		$('#delete-confirmation').find('.btn-primary').focus();
	};

	function clearModal(columnName) {
		$('#' + columnName + '-modal').modal('hide')

		// See https://github.com/openhealthcare/opal/issues/28
		document.activeElement.blur();
	};

	$scope.addRecord = function() {
		var newRecord = {};
		var column;

		for (var cix = 0; cix < $scope.columns.length; cix++) {
			column = $scope.columns[cix];
			if (column.multi) {
				newRecord[column.name] = [{}];
			}
		}

		$scope.rows.push(newRecord);
		$scope.selectItem($scope.rows.length - 1, 0, 0);
		startEdit();
	};

	$scope.saveEdit = function() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var columnName = $scope.columns[cix].name;

		clearModal(columnName);
		editing = false;

		if ($scope.columns[cix]['multi']) {
			$scope.rows[rix][columnName][iix] = clone($scope.editing);
			if (iix + 1 == getNumItems(rix, cix)) {
				$scope.rows[rix][columnName].push({});
			}
		} else {
			$scope.rows[rix][columnName] = clone($scope.editing);
		}
	};

	$scope.cancelEdit = function() {
		var cix = $scope.cix;
		var columnName = $scope.columns[cix].name;

		clearModal(columnName);
		editing = false;
	};

	$scope.doDelete = function() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var column = $scope.columns[cix];

		$scope.rows[rix][column.name].splice(iix, 1);
		deleting = false;
	};

	$scope.cancelDelete = function() {
		deleting = false;
	};

	$scope.selectItem = function(rix, cix, iix) {
		$scope.rix = rix;
		$scope.cix = cix;
		$scope.iix = iix;
	}

	$scope.editItem = function(rix, cix, iix) {
		$scope.selectItem(rix, cix, iix);
		startEdit();
	}

	$scope.mouseEnter = function(rix, columnName) {
		$scope.mouseRix = rix;
		$scope.mouseCix = $scope.getCix(columnName);
	}

	$scope.mouseLeave = function() {
		$scope.mouseRix = -1;
		$scope.mouseCix = -1;
	}

	function getNumItems(rix, cix) {
		var column = $scope.columns[cix];
		if (column.multi) {
			return $scope.rows[rix][column.name].length;
		} else {
			return 1;
		}
	};

	$scope.keypress = function(e) {
		if (editing) {
			switch (e.keyCode) {
				case 27: // escape
					$scope.cancelEdit();
					break;
			}
		} else if (deleting) {
			// ignore all keystrokes here
		} else {
			switch (e.keyCode) {
				case 37: // left
				case 72: // h
					goLeft();
					break;
				case 39: // right
				case 76: // l
					goRight();
					break;
				case 38: // up
				case 75: // k
					goUp();
					break;
				case 40: // down
				case 74: // j
					goDown();
					break;
				case 13: // enter
					startEdit();
					break;
				case 46: // delete
					startDelete();
					break;
			}
		}
	}

	function goLeft() {
		if ($scope.cix > 0) {
			$scope.cix--;
			$scope.iix = 0;
		}
	}

	function goRight() {
		if ($scope.cix < $scope.columns.length - 1) {
			$scope.cix++;
			$scope.iix = 0;
		}
	}

	function goUp() {
		if ($scope.iix > 0) {
			$scope.iix--;
		} else {
			if ($scope.rix > 0) {
				$scope.rix--;
				$scope.iix = getNumItems($scope.rix, $scope.cix) - 1;
			}
		}
	}

	function goDown() {
		if ($scope.iix < getNumItems($scope.rix, $scope.cix) - 1) {
			$scope.iix++;
		} else {
			if ($scope.rix < $scope.rows.length - 1) {
				$scope.rix++;
				$scope.iix = 0;
			}
		}
	}
});

app.directive('field', function() {
	return {
		restrict: 'E',
		template: function(tElement, tAttrs) {
			var column = tAttrs.column;
			var iterable = 'row.' + column;
			var contents;

			if (tAttrs.single == 'yes') {
				iterable = '[' + iterable + ']';
				contents = '<fielditem column="' + column + '"/>';
			} else {
				contents = '' +
				     '' +
				       '<fielditem column="' + column + '"/>' +
				     '' +
				     '' +
				       '' +
					 'Add' +
				       ' ' + // the nbsp is so that row heights don't change when Add is visible
				     ''
			}

			return '' +
			  '
' +
			    '<li ng-repeat="item in ' + iterable + '"' +
			        'ng-click="selectItem($parent.$index,' + // $parent.$index is the row index
				                     'getCix(\'' + column + '\'),' +
						     '$index)"' + // $index is the item index
			        'ng-dblclick="editItem($parent.$index,' +
				                      'getCix(\'' + column + '\'),' +
						      '$index)"' +
			        'ng-class="{selected: $parent.$index == rix && ' +
				                     'getCix(\'' + column + '\') == cix && ' +
						     '$index == iix}">' +
			       contents +
			   '
' +
			 '
';
		},
	}
});

app.directive('fielditem', function() {
	return {
		restrict: 'E',
		templateUrl: function(tElement, tAttrs) {
			return 'assets/templates/' + tAttrs.column + '.html'
		},
	}
});

app.directive('modal', function() {
	return {
		restrict: 'E',
		template: function(tElement, tAttrs) {
			var column = tAttrs.column;
			return '' +
			  '
' +
			    '
' +
			      '<button type="button" class="close" data-dismiss="modal" ng-click="cancelEdit()">×</button>' +
			      '
{{columns[getCix("' + column + '")].title}}
' +
			    '
' +
			    '
<modalform column="' + column + '" />
' +
			    '
' +
			      '<button class="btn" data-dismiss="modal" ng-click="cancelEdit()">Cancel</button>' +
			      '<button class="btn btn-primary" data-dismiss="modal" ng-click="saveEdit()">Save changes</button>' +
			    '
' +
			  '
'

		},
	}
});

app.directive('modalform', function() {
	return {
		restrict: 'E',
		templateUrl: function(tElement, tAttrs) {
			return 'assets/templates/' + tAttrs.column + '-modal.html'
		},
	}
});
<commit_msg>Change heading to Microbiology Results<commit_after>function clone(obj) {
	if (typeof obj == 'object') {
		return $.extend(true, {}, obj);
	} else {
		return obj;
	}
};

function getKeys(obj) {
    var keys = [];
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
                    keys.push(key);
        }
    }
    return keys;
}

var app = angular.module('opalApp', ['$strap.directives']);

app.controller('TableCtrl', function($scope, $http) {
	var editing = false;
	var deleting = false;

	$scope.rows = [];

	$scope.rix = 0; // row index
	$scope.cix = 0; // column index
	$scope.iix = 0; // item index

	$scope.mouseRix = -1; // index of row mouse is currently over
	$scope.mouseCix = -1; // index of column mouse is currently over

	$http.get('assets/records.json').success(function(rows) {
		for (var rix = 0; rix < rows.length; rix++) {
			for (var cix = 0; cix < $scope.columns.length; cix++) {
				if ($scope.columns[cix].multi) {
					rows[rix][$scope.columns[cix].name].push({});
				}
			}
		}
		$scope.rows = rows;
	});

	$scope.columns = [
		{name: 'location', title: 'Location', multi: false},
		{name: 'demographics', title: 'Demographics', multi: false},
		{name: 'diagnosis', title: 'Diagnosis', multi: true},
		{name: 'pastMedicalHistory', title: 'Past Medical History', multi: true},
		{name: 'generalNotes', title: 'Notes', multi: true},
		{name: 'travel', title: 'Travel', multi: true},
		{name: 'antimicrobials', title: 'Antimicrobials', multi: true},
		{name: 'microbiology', title: 'Microbiology Results', multi: true},
		{name: 'microbiologyComments', title: 'Microbiology Input', multi: true},
		{name: 'plan', title: 'Plan', multi: false},
		{name: 'discharge', title: 'Discharge', multi: false},
	];

	$scope.getCix = function(name) {
		for (var cix = 0; cix < $scope.columns.length; cix++) {
			if ($scope.columns[cix].name == name) {
				return cix;
			}
		}
		throw 'Unexpected column name: ' + name
	};

	var option_lists = [
		'antimicrobial',
		'antimicrobial_route',
		'condition',
		'destination',
		'patient_category',
		'travel_reason',
	];

	for (var i = 0; i < option_lists.length; i++) {
		(function(option) {
			$http.get('options/' + option + '_list/').success(function(data) {
				$scope[option + '_list'] = data;
			});
		})(option_lists[i]);
	}

	$scope.microbiology_test_list = [
		'Broncheoalveolar lavage MC&S',
		'Blood Culture',
		'CSF AFB microscopy & TB culture',
		'CSF MC&S',
		'Fluid MC&S',
		'Lymph Node MC&S',
		'Pleural MC&S',
		'Sputum AFB microscopy & TB culture',
		'Sputum MC&S',
		'Stool MC&S',
		'Stool OCP',
		'Throat Swab MC&S',
		'Tissue AFB microscopy & TB culture',
		'Tissue MC&S',
		'Urine AFB microscopy & TB culture',
		'Urine MC&S',
		'Wound swab MC&S',
		'CMV Serology',
		'Dengue Serology',
		'Hepatitis A Serology',
		'Hepatitis E Serology',
		'Measles Serology',
		'Rubella Serology',
		'Toxoplasmosis Serology',
		'VZV Serology',
		'Brucella Serology',
		'EBV Serology',
		'HIV',
		'Hepatitis B Serology',
		'Syphilis Serology',
		'Cryptococcal antigen',
		'Dengue PCR',
		'JC Virus PCR',
		'MRSA PCR',
		'Rickettsia PCR',
		'Scrub Typhus PCR',
		'Borrleia Screening Serology',
		'Brorleia Reference Serology',
		'Viral Haemorrhagic Fever PCR',
		'Amoebic Serology',
		'Cystercicosis Serology',
		'Fasciola Serology',
		'Filaria Serology',
		'Hydatid Serology',
		'Strongyloides Serology',
		'Toxcocara Serology',
		'Trypanosomiasis brucei Serology',
		'Trypanosomiasis cruzi serology',
		'Hepatitis C Serology',
		'Hepatitis D Serology',
		'HHV-6 Serology',
		'HHV-7 Serology',
		'HTLV Serology',
		'CMV Viral Load',
		'EBV Viral Load ',
		'HBV Viral Load',
		'HCV Viral Load',
		'HHV-6 Viral Load',
		'HHV-7 Viral Load',
		'HHV-8 Viral Load',
		'HIV Viral Load',
		'Measles PCR',
		'VZV Viral Load',
		'Babesia Film',
		'Malaria Film',
		'Microfilarial Film',
		'Swab PCR',
		'C. difficile',
		'Leishmaniasis PCR',
		'CSF PCR',
		'Respiratory Virus PCR',
		'Stool PCR',
		'Stool Parasitology PCR',
		'Other',
	];

	function startEdit() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var columnName = $scope.columns[cix].name;

		editing = true;
		if ($scope.columns[cix]['multi']) {
			$scope.editing = clone($scope.rows[rix][columnName][iix]);
		} else {
			$scope.editing = clone($scope.rows[rix][columnName]);
		}
		$('#' + columnName + '-modal').modal();
		$('#' + columnName + '-modal').find('input,textarea').first().focus();
	};

	function startDelete() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var column = $scope.columns[cix];

		if (!column.multi) {
			return;
		}

		if ($scope.rows[rix][column.name].length == 1) {
			return;
		}

		deleting = true;
		$('#delete-confirmation').modal();
		$('#delete-confirmation').find('.btn-primary').focus();
	};

	function clearModal(columnName) {
		$('#' + columnName + '-modal').modal('hide')

		// See https://github.com/openhealthcare/opal/issues/28
		document.activeElement.blur();
	};

	$scope.addRecord = function() {
		var newRecord = {};
		var column;

		for (var cix = 0; cix < $scope.columns.length; cix++) {
			column = $scope.columns[cix];
			if (column.multi) {
				newRecord[column.name] = [{}];
			}
		}

		$scope.rows.push(newRecord);
		$scope.selectItem($scope.rows.length - 1, 0, 0);
		startEdit();
	};

	$scope.saveEdit = function() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var columnName = $scope.columns[cix].name;

		clearModal(columnName);
		editing = false;

		if ($scope.columns[cix]['multi']) {
			$scope.rows[rix][columnName][iix] = clone($scope.editing);
			if (iix + 1 == getNumItems(rix, cix)) {
				$scope.rows[rix][columnName].push({});
			}
		} else {
			$scope.rows[rix][columnName] = clone($scope.editing);
		}
	};

	$scope.cancelEdit = function() {
		var cix = $scope.cix;
		var columnName = $scope.columns[cix].name;

		clearModal(columnName);
		editing = false;
	};

	$scope.doDelete = function() {
		var rix = $scope.rix;
		var cix = $scope.cix;
		var iix = $scope.iix;
		var column = $scope.columns[cix];

		$scope.rows[rix][column.name].splice(iix, 1);
		deleting = false;
	};

	$scope.cancelDelete = function() {
		deleting = false;
	};

	$scope.selectItem = function(rix, cix, iix) {
		$scope.rix = rix;
		$scope.cix = cix;
		$scope.iix = iix;
	}

	$scope.editItem = function(rix, cix, iix) {
		$scope.selectItem(rix, cix, iix);
		startEdit();
	}

	$scope.mouseEnter = function(rix, columnName) {
		$scope.mouseRix = rix;
		$scope.mouseCix = $scope.getCix(columnName);
	}

	$scope.mouseLeave = function() {
		$scope.mouseRix = -1;
		$scope.mouseCix = -1;
	}

	function getNumItems(rix, cix) {
		var column = $scope.columns[cix];
		if (column.multi) {
			return $scope.rows[rix][column.name].length;
		} else {
			return 1;
		}
	};

	$scope.keypress = function(e) {
		if (editing) {
			switch (e.keyCode) {
				case 27: // escape
					$scope.cancelEdit();
					break;
			}
		} else if (deleting) {
			// ignore all keystrokes here
		} else {
			switch (e.keyCode) {
				case 37: // left
				case 72: // h
					goLeft();
					break;
				case 39: // right
				case 76: // l
					goRight();
					break;
				case 38: // up
				case 75: // k
					goUp();
					break;
				case 40: // down
				case 74: // j
					goDown();
					break;
				case 13: // enter
					startEdit();
					break;
				case 46: // delete
					startDelete();
					break;
			}
		}
	}

	function goLeft() {
		if ($scope.cix > 0) {
			$scope.cix--;
			$scope.iix = 0;
		}
	}

	function goRight() {
		if ($scope.cix < $scope.columns.length - 1) {
			$scope.cix++;
			$scope.iix = 0;
		}
	}

	function goUp() {
		if ($scope.iix > 0) {
			$scope.iix--;
		} else {
			if ($scope.rix > 0) {
				$scope.rix--;
				$scope.iix = getNumItems($scope.rix, $scope.cix) - 1;
			}
		}
	}

	function goDown() {
		if ($scope.iix < getNumItems($scope.rix, $scope.cix) - 1) {
			$scope.iix++;
		} else {
			if ($scope.rix < $scope.rows.length - 1) {
				$scope.rix++;
				$scope.iix = 0;
			}
		}
	}
});

app.directive('field', function() {
	return {
		restrict: 'E',
		template: function(tElement, tAttrs) {
			var column = tAttrs.column;
			var iterable = 'row.' + column;
			var contents;

			if (tAttrs.single == 'yes') {
				iterable = '[' + iterable + ']';
				contents = '<fielditem column="' + column + '"/>';
			} else {
				contents = '' +
				     '' +
				       '<fielditem column="' + column + '"/>' +
				     '' +
				     '' +
				       '' +
					 'Add' +
				       ' ' + // the nbsp is so that row heights don't change when Add is visible
				     ''
			}

			return '' +
			  '
' +
			    '<li ng-repeat="item in ' + iterable + '"' +
			        'ng-click="selectItem($parent.$index,' + // $parent.$index is the row index
				                     'getCix(\'' + column + '\'),' +
						     '$index)"' + // $index is the item index
			        'ng-dblclick="editItem($parent.$index,' +
				                      'getCix(\'' + column + '\'),' +
						      '$index)"' +
			        'ng-class="{selected: $parent.$index == rix && ' +
				                     'getCix(\'' + column + '\') == cix && ' +
						     '$index == iix}">' +
			       contents +
			   '
' +
			 '
';
		},
	}
});

app.directive('fielditem', function() {
	return {
		restrict: 'E',
		templateUrl: function(tElement, tAttrs) {
			return 'assets/templates/' + tAttrs.column + '.html'
		},
	}
});

app.directive('modal', function() {
	return {
		restrict: 'E',
		template: function(tElement, tAttrs) {
			var column = tAttrs.column;
			return '' +
			  '
' +
			    '
' +
			      '<button type="button" class="close" data-dismiss="modal" ng-click="cancelEdit()">×</button>' +
			      '
{{columns[getCix("' + column + '")].title}}
' +
			    '
' +
			    '
<modalform column="' + column + '" />
' +
			    '
' +
			      '<button class="btn" data-dismiss="modal" ng-click="cancelEdit()">Cancel</button>' +
			      '<button class="btn btn-primary" data-dismiss="modal" ng-click="saveEdit()">Save changes</button>' +
			    '
' +
			  '
'

		},
	}
});

app.directive('modalform', function() {
	return {
		restrict: 'E',
		templateUrl: function(tElement, tAttrs) {
			return 'assets/templates/' + tAttrs.column + '-modal.html'
		},
	}
});
<|endoftext|>


<commit_before>if(typeof require === 'function') {
  const buster    = require("buster")
      , Sequelize = require("../index")
      , Helpers   = require('./buster-helpers')
      , dialects  = ['sqlite', 'mysql', 'postgres']
}

buster.spec.expose()

dialects.forEach(function(dialect) {
  describe('DAOFactory@' + dialect, function() {
    before(function(done) {
      var self = this

      Helpers.initTests({
        dialect: dialect,
        beforeComplete: function(sequelize, DataTypes) {
          self.sequelize = sequelize
          self.User      = sequelize.define('User', {
            username:  { type: DataTypes.STRING },
            touchedAt: { type: DataTypes.DATE, defaultValue: DataTypes.NOW }
          })
        },
        onComplete: function(sequelize) {
          self.User.sync({ force: true }).success(done)
        }
      })
    })

    describe('create', function() {
      before(function(done) {
        this.User = this.sequelize.define('User', {
          username: Sequelize.STRING,
          secretValue: Sequelize.STRING,
          data: Sequelize.STRING
        })

        this.User
          .sync({ force: true })
          .success(done)
          .error(function(err) { console.log(err) })
      })

      it('should only store the values passed in the witelist', function(done) {
        var self = this
          , data = { username: 'Peter', secretValue: '42' }

        this.User.create(data, ['username']).success(function(user) {
          self.User.find(user.id).success(function(_user) {
            expect(_user.username).toEqual(data.username)
            expect(_user.secretValue).not.toEqual(data.secretValue)
            expect(_user.secretValue).toEqual(null)
            done()
          })
        })
      })

      it('should store all values if no whitelist is specified', function(done) {
        var self = this
          , data = { username: 'Peter', secretValue: '42' }

        this.User.create(data).success(function(user) {
          self.User.find(user.id).success(function(_user) {
            expect(_user.username).toEqual(data.username)
            expect(_user.secretValue).toEqual(data.secretValue)
            done()
          })
        })
      })

      it('saves data with single quote', function(done) {
        var quote = "single'quote"
          , self  = this

        this.User.create({ data: quote }).success(function(user) {
          expect(user.data).toEqual(quote, 'memory single quote')

          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(quote, 'SQL single quote')
            done()
          })
        })
      })

      it('saves data with double quote', function(done) {
        var quote = 'double"quote'
          , self  = this

        this.User.create({ data: quote }).success(function(user) {
          expect(user.data).toEqual(quote, 'memory double quote')

          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(quote, 'SQL double quote')
            done()
          })
        })
      })

      it('saves stringified JSON data', function(done) {
        var json = JSON.stringify({ key: 'value' })
          , self = this

        this.User.create({ data: json }).success(function(user) {
          expect(user.data).toEqual(json, 'memory data')
          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(json, 'SQL data')
            done()
          })
        })
      })
    })
  })
})
<commit_msg>fixed user model<commit_after>if(typeof require === 'function') {
  const buster    = require("buster")
      , Sequelize = require("../index")
      , Helpers   = require('./buster-helpers')
      , dialects  = ['sqlite', 'mysql', 'postgres']
}

buster.spec.expose()

dialects.forEach(function(dialect) {
  describe('DAOFactory@' + dialect, function() {
    before(function(done) {
      var self = this

      Helpers.initTests({
        dialect: dialect,
        beforeComplete: function(sequelize, DataTypes) {
          self.sequelize = sequelize
          self.User      = sequelize.define('User', {
            username: DataTypes.STRING,
            secretValue: DataTypes.STRING,
            data: DataTypes.STRING
          })
        },
        onComplete: function(sequelize) {
          self.User.sync({ force: true }).success(done)
        }
      })
    })

    describe('create', function() {
      it('=>should only store the values passed in the witelist', function(done) {
        var self = this
          , data = { username: 'Peter', secretValue: '42' }

        this.User.create(data, ['username']).success(function(user) {
          self.User.find(user.id).success(function(_user) {
            expect(_user.username).toEqual(data.username)
            expect(_user.secretValue).not.toEqual(data.secretValue)
            expect(_user.secretValue).toEqual(null)
            done()
          })
        })
      })

      it('should store all values if no whitelist is specified', function(done) {
        var self = this
          , data = { username: 'Peter', secretValue: '42' }

        this.User.create(data).success(function(user) {
          self.User.find(user.id).success(function(_user) {
            expect(_user.username).toEqual(data.username)
            expect(_user.secretValue).toEqual(data.secretValue)
            done()
          })
        })
      })

      it('saves data with single quote', function(done) {
        var quote = "single'quote"
          , self  = this

        this.User.create({ data: quote }).success(function(user) {
          expect(user.data).toEqual(quote, 'memory single quote')

          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(quote, 'SQL single quote')
            done()
          })
        })
      })

      it('saves data with double quote', function(done) {
        var quote = 'double"quote'
          , self  = this

        this.User.create({ data: quote }).success(function(user) {
          expect(user.data).toEqual(quote, 'memory double quote')

          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(quote, 'SQL double quote')
            done()
          })
        })
      })

      it('saves stringified JSON data', function(done) {
        var json = JSON.stringify({ key: 'value' })
          , self = this

        this.User.create({ data: json }).success(function(user) {
          expect(user.data).toEqual(json, 'memory data')
          self.User.find({where: { id: user.id }}).success(function(user) {
            expect(user.data).toEqual(json, 'SQL data')
            done()
          })
        })
      })
    })
  })
})
<|endoftext|>


<commit_before>// Generated on 2014-06-03 using generator-jekyllrb 1.2.1
'use strict';

// Directory reference:
//   css: css
//   compass: _scss
//   javascript: js
//   images: img
//   fonts: fonts

module.exports = function (grunt) {
  // Show elapsed time after tasks run
  require('time-grunt')(grunt);
  // Load all Grunt tasks
  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    // Configurable paths
    yeoman: {
      app: 'app',
      dist: 'dist'
    },
    watch: {
      compass: {
        files: ['<%= yeoman.app %>/_scss/**/*.{scss,sass}'],
        tasks: ['compass:server', 'autoprefixer:server']
      },
      autoprefixer: {
        files: ['<%= yeoman.app %>/css/**/*.css'],
        tasks: ['copy:stageCss', 'autoprefixer:server']
      },
      jekyll: {
        files: [
          '<%= yeoman.app %>/**/*.{html,yml,md,mkd,markdown}',
          '!<%= yeoman.app %>/_bower_components/**/*'
        ],
        tasks: ['jekyll:server']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '.jekyll/**/*.html',
          '.tmp/css/**/*.css',
          '{.tmp,<%= yeoman.app %>}/<%= js %>/**/*.js',
          '<%= yeoman.app %>/img/**/*.{gif,jpg,jpeg,png,svg,webp}'
        ]
      }
    },
    connect: {
      options: {
        port: 9000,
        livereload: 35729,
        // change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          open: true,
          base: [
            '.tmp',
            '.jekyll',
            '<%= yeoman.app %>'
          ]
        }
      },
      dist: {
        options: {
          open: true,
          base: [
            '<%= yeoman.dist %>'
          ]
        }
      },
      test: {
        options: {
          base: [
            '.tmp',
            '.jekyll',
            'test',
            '<%= yeoman.app %>'
          ]
        }
      }
    },
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '<%= yeoman.dist %>/*',
            // Running Jekyll also cleans the target directory.  Exclude any
            // non-standard `keep_files` here (e.g., the generated files
            // directory from Jekyll Picture Tag).
            '!<%= yeoman.dist %>/.git*'
          ]
        }]
      },
      server: [
        '.tmp',
        '.jekyll'
      ]
    },
    compass: {
      options: {
        // If you're using global Sass gems, require them here.
        // require: ['singularity', 'jacket'],
        bundleExec: true,
        sassDir: '<%= yeoman.app %>/_scss',
        cssDir: '.tmp/css',
        imagesDir: '<%= yeoman.app %>/img',
        javascriptsDir: '<%= yeoman.app %>/js',
        relativeAssets: false,
        httpImagesPath: '/img',
        httpGeneratedImagesPath: '/img/generated',
        outputStyle: 'expanded',
        raw: 'extensions_dir = "<%= yeoman.app %>/_bower_components"\n'
      },
      dist: {
        options: {
          generatedImagesDir: '<%= yeoman.dist %>/img/generated'
        }
      },
      server: {
        options: {
          debugInfo: true,
          generatedImagesDir: '.tmp/img/generated'
        }
      }
    },
    autoprefixer: {
      options: {
        browsers: ['last 2 versions']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>/css',
          src: '**/*.css',
          dest: '<%= yeoman.dist %>/css'
        }]
      },
      server: {
        files: [{
          expand: true,
          cwd: '.tmp/css',
          src: '**/*.css',
          dest: '.tmp/css'
        }]
      }
    },
    jekyll: {
      options: {
        bundleExec: true,
        config: '_config.yml,_config.build.yml',
        src: '<%= yeoman.app %>'
      },
      dist: {
        options: {
          dest: '<%= yeoman.dist %>',
        }
      },
      server: {
        options: {
          config: '_config.yml',
          dest: '.jekyll'
        }
      },
      check: {
        options: {
          doctor: true
        }
      }
    },
    useminPrepare: {
      options: {
        dest: '<%= yeoman.dist %>'
      },
      html: '<%= yeoman.dist %>/index.html'
    },
    usemin: {
      options: {
        assetsDirs: '<%= yeoman.dist %>',
      },
      html: ['<%= yeoman.dist %>/**/*.html'],
      css: ['<%= yeoman.dist %>/css/**/*.css']
    },
    htmlmin: {
      dist: {
        options: {
          collapseWhitespace: true,
          collapseBooleanAttributes: true,
          removeAttributeQuotes: true,
          removeRedundantAttributes: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.html',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    // Usemin adds files to concat
    concat: {},
    // Usemin adds files to uglify
    uglify: {},
    // Usemin adds files to cssmin
    cssmin: {
      dist: {
        options: {
          check: 'gzip'
        }
      }
    },
    imagemin: {
      dist: {
        options: {
          progressive: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.{jpg,jpeg,png}',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.svg',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          src: [
            // Jekyll processes and moves HTML and text files.
            // Usemin moves CSS and javascript inside of Usemin blocks.
            // Copy moves asset files and directories.
            'img/**/*',
            'fonts/**/*',
            // Like Jekyll, exclude files & folders prefixed with an underscore.
            '!**/_*{,/**}'
            // Explicitly add any files your site needs for distribution here.
            //'_bower_components/jquery/jquery.js',
            //'favicon.ico',
            //'apple-touch*.png'
          ],
          dest: '<%= yeoman.dist %>'
        }]
      },
      // Copy CSS into .tmp directory for Autoprefixer processing
      stageCss: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>/css',
          src: '**/*.css',
          dest: '.tmp/css'
        }]
      }
    },
    filerev: {
      options: {
        length: 4
      },
      dist: {
        files: [{
          src: [
            '<%= yeoman.dist %>/js/**/*.js',
            '<%= yeoman.dist %>/css/**/*.css',
            '<%= yeoman.dist %>/img/**/*.{gif,jpg,jpeg,png,svg,webp}',
            '<%= yeoman.dist %>/fonts/**/*.{eot*,otf,svg,ttf,woff}'
          ]
        }]
      }
    },
    buildcontrol: {
      dist: {
        options: {
          remote: '../',
          branch: 'gh-pages',
          commit: true,
          push: true
        }
      }
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= yeoman.app %>/js/**/*.js',
        'test/spec/**/*.js'
      ]
    },
    csslint: {
      options: {
        csslintrc: '.csslintrc'
      },
      check: {
        src: [
          '<%= yeoman.app %>/css/**/*.css',
          '<%= yeoman.app %>/_scss/**/*.scss'
        ]
      }
    },
    concurrent: {
      server: [
        'compass:server',
        'copy:stageCss',
        'jekyll:server'
      ],
      dist: [
        'compass:dist',
        'copy:dist'
      ]
    }
  });

  // Define Tasks
  grunt.registerTask('serve', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'concurrent:server',
      'autoprefixer:server',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', function () {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve']);
  });

  // No real tests yet. Add your own.
  grunt.registerTask('test', [
  //   'clean:server',
  //   'concurrent:test',
  //   'connect:test'
  ]);

  grunt.registerTask('check', [
    'clean:server',
    'jekyll:check',
    'compass:server',
    'jshint:all',
    'csslint:check'
  ]);

  grunt.registerTask('build', [
    'clean',
    // Jekyll cleans files from the target directory, so must run first
    'jekyll:dist',
    'concurrent:dist',
    'useminPrepare',
    'concat',
    'autoprefixer:dist',
    'cssmin',
    'uglify',
    'imagemin',
    'svgmin',
    'filerev',
    'usemin',
    'htmlmin'
    ]);

  grunt.registerTask('deploy', [
    'check',
    'test',
    'build',
    'buildcontrol'
    ]);

  grunt.registerTask('default', [
    'check',
    'test',
    'build'
  ]);
};
<commit_msg>adding CNAME and everything<commit_after>// Generated on 2014-05-13 using generator-jekyllrb 1.2.1
'use strict';

// Directory reference:
//   css: css
//   compass: _scss
//   javascript: js
//   images: img
//   fonts: fonts

module.exports = function (grunt) {
  // Show elapsed time after tasks run
  require('time-grunt')(grunt);
  // Load all Grunt tasks
  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    // Configurable paths
    yeoman: {
      app: 'app',
      dist: 'dist'
    },
    watch: {
      compass: {
        files: ['<%= yeoman.app %>/_scss/**/*.{scss,sass}'],
        tasks: ['compass:server', 'autoprefixer:server']
      },
      autoprefixer: {
        files: ['<%= yeoman.app %>/css/**/*.css'],
        tasks: ['copy:stageCss', 'autoprefixer:server']
      },
      jekyll: {
        files: [
          '<%= yeoman.app %>/**/*.{html,yml,md,mkd,markdown}',
          '!<%= yeoman.app %>/_bower_components/**/*'
        ],
        tasks: ['jekyll:server']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '.jekyll/**/*.html',
          '.tmp/css/**/*.css',
          '{.tmp,<%= yeoman.app %>}/<%= js %>/**/*.js',
          '<%= yeoman.app %>/img/**/*.{gif,jpg,jpeg,png,svg,webp}'
        ]
      }
    },
    connect: {
      options: {
        port: 9000,
        livereload: 35729,
        // change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          open: true,
          base: [
            '.tmp',
            '.jekyll',
            '<%= yeoman.app %>'
          ]
        }
      },
      dist: {
        options: {
          open: true,
          base: [
            '<%= yeoman.dist %>'
          ]
        }
      },
      test: {
        options: {
          base: [
            '.tmp',
            '.jekyll',
            'test',
            '<%= yeoman.app %>'
          ]
        }
      }
    },
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '<%= yeoman.dist %>/*',
            // Running Jekyll also cleans the target directory.  Exclude any
            // non-standard `keep_files` here (e.g., the generated files
            // directory from Jekyll Picture Tag).
            '!<%= yeoman.dist %>/.git*'
          ]
        }]
      },
      server: [
        '.tmp',
        '.jekyll'
      ]
    },
    compass: {
      options: {
        // If you're using global Sass gems, require them here.
        // require: ['singularity', 'jacket'],
        bundleExec: true,
        sassDir: '<%= yeoman.app %>/_scss',
        cssDir: '.tmp/css',
        imagesDir: '<%= yeoman.app %>/img',
        javascriptsDir: '<%= yeoman.app %>/js',
        relativeAssets: false,
        httpImagesPath: '/img',
        httpGeneratedImagesPath: '/img/generated',
        outputStyle: 'expanded',
        raw: 'extensions_dir = "<%= yeoman.app %>/_bower_components"\n'
      },
      dist: {
        options: {
          generatedImagesDir: '<%= yeoman.dist %>/img/generated'
        }
      },
      server: {
        options: {
          debugInfo: true,
          generatedImagesDir: '.tmp/img/generated'
        }
      }
    },
    autoprefixer: {
      options: {
        browsers: ['last 2 versions']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>/css',
          src: '**/*.css',
          dest: '<%= yeoman.dist %>/css'
        }]
      },
      server: {
        files: [{
          expand: true,
          cwd: '.tmp/css',
          src: '**/*.css',
          dest: '.tmp/css'
        }]
      }
    },
    jekyll: {
      options: {
        bundleExec: true,
        config: '_config.yml,_config.build.yml',
        src: '<%= yeoman.app %>'
      },
      dist: {
        options: {
          dest: '<%= yeoman.dist %>',
        }
      },
      server: {
        options: {
          config: '_config.yml',
          dest: '.jekyll'
        }
      },
      check: {
        options: {
          doctor: true
        }
      }
    },
    useminPrepare: {
      options: {
        dest: '<%= yeoman.dist %>'
      },
      html: '<%= yeoman.dist %>/index.html'
    },
    usemin: {
      options: {
        assetsDirs: '<%= yeoman.dist %>',
      },
      html: ['<%= yeoman.dist %>/**/*.html'],
      css: ['<%= yeoman.dist %>/css/**/*.css']
    },
    htmlmin: {
      dist: {
        options: {
          collapseWhitespace: true,
          collapseBooleanAttributes: true,
          removeAttributeQuotes: true,
          removeRedundantAttributes: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.html',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    // Usemin adds files to concat
    concat: {},
    // Usemin adds files to uglify
    uglify: {},
    // Usemin adds files to cssmin
    cssmin: {
      dist: {
        options: {
          check: 'gzip'
        }
      }
    },
    imagemin: {
      dist: {
        options: {
          progressive: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.{jpg,jpeg,png}',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.svg',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          src: [
            // Jekyll processes and moves HTML and text files.
            // Usemin moves CSS and javascript inside of Usemin blocks.
            // Copy moves asset files and directories.
            'img/**/*',
            'fonts/**/*',
            // Like Jekyll, exclude files & folders prefixed with an underscore.
            '!**/_*{,/**}',
            // Explicitly add any files your site needs for distribution here.
            'favicon.ico',
            'apple-touch*.png',
            'CNAME'
          ],
          dest: '<%= yeoman.dist %>'
        }]
      },
      // Copy CSS into .tmp directory for Autoprefixer processing
      stageCss: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>/css',
          src: '**/*.css',
          dest: '.tmp/css'
        }]
      }
    },
    filerev: {
      options: {
        length: 4
      },
      dist: {
        files: [{
          src: [
            '<%= yeoman.dist %>/js/**/*.js',
            '<%= yeoman.dist %>/css/**/*.css',
            '<%= yeoman.dist %>/img/**/*.{gif,jpg,jpeg,png,svg,webp}',
            '<%= yeoman.dist %>/fonts/**/*.{eot*,otf,svg,ttf,woff}'
          ]
        }]
      }
    },
    buildcontrol: {
      dist: {
        options: {
          remote: '../',
          branch: 'gh-pages',
          commit: true,
          push: true
        }
      }
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= yeoman.app %>/js/**/*.js',
        'test/spec/**/*.js'
      ]
    },
    csslint: {
      options: {
        csslintrc: '.csslintrc'
      },
      check: {
        src: [
          '<%= yeoman.app %>/css/**/*.css',
          '<%= yeoman.app %>/_scss/**/*.scss'
        ]
      }
    },
    concurrent: {
      server: [
        'compass:server',
        'copy:stageCss',
        'jekyll:server'
      ],
      dist: [
        'compass:dist',
        'copy:dist'
      ]
    }
  });

  // Define Tasks
  grunt.registerTask('serve', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'concurrent:server',
      'autoprefixer:server',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', function () {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve']);
  });

  // No real tests yet. Add your own.
  grunt.registerTask('test', [
  //   'clean:server',
  //   'concurrent:test',
  //   'connect:test'
  ]);

  grunt.registerTask('check', [
    'clean:server',
    'jekyll:check',
    'compass:server',
    'jshint:all'
    //'csslint:check'
  ]);

  grunt.registerTask('build', [
    'clean',
    // Jekyll cleans files from the target directory, so must run first
    'jekyll:dist',
    'concurrent:dist',
    'useminPrepare',
    'concat',
    'autoprefixer:dist',
    'cssmin',
    'uglify',
    'imagemin',
    'svgmin',
    'filerev',
    'usemin',
    'htmlmin'
    ]);

  grunt.registerTask('deploy', [
    'check',
    'test',
    'build',
    'buildcontrol'
    ]);

  grunt.registerTask('default', [
    'check',
    'test',
    'build'
  ]);
};
<|endoftext|>