<commit_before>/**
 * Builds the query that retrieve the list of all classifications.
 */
const classifications = () => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT ?classification ?code ?label WHERE {
    ?classification rdf:type skos:ConceptScheme ; skos:notation ?code ; skos:prefLabel ?label .
  } ORDER BY ?code
 `

/**
 * Builds the query that gets the details about a classification.
 */
 //TODO @Franck workaround the fact the DB is not returning any line otherwise
const classificationDetails = uri => `
  PREFIX dcterms: <http://purl.org/dc/terms/>
  PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
  SELECT ?code ?label ?issued WHERE {
    <${uri}> skos:notation ?code ; skos:prefLabel ?label ; dcterms:issued ?issued .
  }
`

/**
 * Builds the query that gets the levels of a classification.
 * Using SPARQL 1.1 property paths, see https://www.w3.org/TR/sparql11-query/#propertypaths
 */
const classificationLevels = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT DISTINCT ?level ?depth ?label
  WHERE {
    <${uri}> xkos:levels/rdf:rest*/rdf:first ?level .
    ?level xkos:depth ?depth ; skos:prefLabel ?label .
  } ORDER BY ?depth
`
/**
 * Builds the query that gets the correspondence tables for a given classification.
 * TODO Improve the database, all tables don't have a label.
 */
const classificationCorrespondences = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT ?table ?definition ?code WHERE {
    ?table xkos:compares <${uri}> ;
           skos:definition ?definition
    OPTIONAL {
      ?table skos:notation ?code
    }
    # We miss somme correspondences where there is no definition in english
    FILTER ( langMatches(lang(?definition), "EN"))
  }
`

/**
 * Builds the query that gets all the correspondence tables.
 * TODO Improve the database, all tables don't have a label.
 */
const correspondences = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT ?table ?label WHERE {
    ?table rdf:type xkos:Corresponce .
    OPTIONAL { ?table skos:prefLabel ?label }
  }
`

/**
 * Builds the query that gets the list of items of a given level.
 */
const levelItems = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT ?item ?code ?label WHERE {
    <${uri}> skos:member ?item .
    ?item skos:notation ?code ; skos:prefLabel ?label .
  } ORDER BY ?code
`

/**
 * Builds the query that gets the list of items of a given level.
 */
const classificationItems = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT DISTINCT ?item ?code ?label WHERE {
    <${uri}> xkos:levels/rdf:rest*/rdf:first ?level .
    ?level skos:member ?item .
    ?item skos:notation ?code ; skos:prefLabel ?label .
  } ORDER BY ?code LIMIT 25
`

const itemDetails = item => `
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT ?label ?code ?label ?text ?cl ?clCode ?clLabel ?parent ?parentCode
      ?parentLabel {
    <${item}> skos:prefLabel ?label ;
              skos:notation ?code ;
              skos:inScheme ?cl .
    ?cl skos:prefLabel ?clLabel

    OPTIONAL {
      ?cl skos:notation ?clCode .
    }

    OPTIONAL {
      <${item}> skos:broader ?parent .
        ?parent skos:prefLabel ?parentLabel .
      OPTIONAL { ?parent skos:notation ?parentCode . }
      FILTER ( langMatches(lang(?parentLabel), "EN"))
    }

    # if we use only one OPTIONAL keyword, we will not receive the note
    # if there is no parent
    OPTIONAL {
     <${item}> xkos:coreContentNote ?content .
     ?content xkos:plainText ?text .
    }
    FILTER (
      langMatches(lang(?label), "EN") &&
      langMatches(lang(?clLabel), "EN"))
  }
`

const itemChildren = item => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT ?item ?code ?label {
    <${item}> skos:narrower ?item .
    ?item skos:notation ?code .
    ?item skos:prefLabel ?label
    FILTER (langMatches(lang(?label), "EN"))
  } ORDER BY ?code
`

const itemCorrespondences = hash => {
  const  [item, correspondenceTable] = hash.split('||');
  return `
    PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
    PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
    SELECT ?association ?item ?code ?label {
    {
    <${correspondenceTable}> xkos:madeOf ?association .
  ?association xkos:sourceConcept <${item}> ;
               xkos:targetConcept ?item .
               ?item skos:notation ?code .
               ?item skos:prefLabel ?label
               FILTER (langMatches(lang(?label), "EN"))
    }
    UNION {

  <${correspondenceTable}> xkos:madeOf ?association .
  ?association xkos:targetConcept <${item}> ;
               xkos:sourceConcept ?item .
               ?item skos:notation ?code .
               ?item skos:prefLabel ?label
               FILTER (langMatches(lang(?label), "EN"))

  }
  }
  `
}

const correspondenceDetails = correspondence => `
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT ?classification ?code ?label {
    <${correspondence}> xkos:compares ?classification .
    ?classification skos:prefLabel ?label ;
                    skos:notation ?code
  }
`
const searchEverything = keyword => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT DISTINCT ?subject ?predicate ?match ?score WHERE {
    ?subject ?predicate ?match .
    (?match ?score) <tag:stardog:api:property:textMatch> '${keyword}*'.
  }
`

const searchItems = hash => {
  const  [keyword, searchForCode] = hash.split('||');
  if(searchForCode){
    return  `
    PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
    PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
    SELECT DISTINCT
      ?item ?code ?itemLabel
      ?classification ?classificationLabel ?coreContentNoteText ?additionalContentNoteText
    WHERE {
      ?item skos:inScheme ?classification ;
            skos:notation ?code ;
            skos:prefLabel ?itemLabel .

      ?classification skos:prefLabel ?classificationLabel .
      FILTER regex(?code, "${keyword}", "i")
    } order by ?code
    `
  }else{
    console.log('on cherche pas des codes')
  return  `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT DISTINCT
    ?item ?code ?itemLabel
    ?classification ?classificationLabel ?coreContentNoteText ?additionalContentNoteText
  WHERE {
    ?item skos:inScheme ?classification ;
          skos:notation ?code ;
          skos:prefLabel ?itemLabel ;
          xkos:coreContentNote ?coreContentNote ;
          xkos:additionalContentNote ?additionalContentNote .
    ?coreContentNote xkos:plainText ?coreContentNoteText .
    ?additionalContentNote   xkos:plainText ?additionalContentNoteText .
    ?classification skos:prefLabel ?classificationLabel .
    (?match ?score) <tag:stardog:api:property:textMatch> '${keyword}*'.
    FILTER ( langMatches(lang(?itemLabel), "EN"))
  } order by ?code
`}
}

export default {
  classifications,
  classificationDetails,
  classificationItems,
  classificationLevels,
  classificationCorrespondences,
  correspondences,
  levelItems,
  itemCorrespondences,
  itemDetails,
  itemChildren,
  correspondenceDetails,
  searchEverything,
  searchItems
}
<commit_msg>Improved search for non indexede properties<commit_after>/**
 * Builds the query that retrieve the list of all classifications.
 */
const classifications = () => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT ?classification ?code ?label WHERE {
    ?classification rdf:type skos:ConceptScheme ; skos:notation ?code ; skos:prefLabel ?label .
  } ORDER BY ?code
 `

/**
 * Builds the query that gets the details about a classification.
 */
 //TODO @Franck workaround the fact the DB is not returning any line otherwise
const classificationDetails = uri => `
  PREFIX dcterms: <http://purl.org/dc/terms/>
  PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
  SELECT ?code ?label ?issued WHERE {
    <${uri}> skos:notation ?code ; skos:prefLabel ?label ; dcterms:issued ?issued .
  }
`

/**
 * Builds the query that gets the levels of a classification.
 * Using SPARQL 1.1 property paths, see https://www.w3.org/TR/sparql11-query/#propertypaths
 */
const classificationLevels = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT DISTINCT ?level ?depth ?label
  WHERE {
    <${uri}> xkos:levels/rdf:rest*/rdf:first ?level .
    ?level xkos:depth ?depth ; skos:prefLabel ?label .
  } ORDER BY ?depth
`
/**
 * Builds the query that gets the correspondence tables for a given classification.
 * TODO Improve the database, all tables don't have a label.
 */
const classificationCorrespondences = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT ?table ?definition ?code WHERE {
    ?table xkos:compares <${uri}> ;
           skos:definition ?definition
    OPTIONAL {
      ?table skos:notation ?code
    }
    # We miss somme correspondences where there is no definition in english
    FILTER ( langMatches(lang(?definition), "EN"))
  }
`

/**
 * Builds the query that gets all the correspondence tables.
 * TODO Improve the database, all tables don't have a label.
 */
const correspondences = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT ?table ?label WHERE {
    ?table rdf:type xkos:Corresponce .
    OPTIONAL { ?table skos:prefLabel ?label }
  }
`

/**
 * Builds the query that gets the list of items of a given level.
 */
const levelItems = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT ?item ?code ?label WHERE {
    <${uri}> skos:member ?item .
    ?item skos:notation ?code ; skos:prefLabel ?label .
  } ORDER BY ?code
`

/**
 * Builds the query that gets the list of items of a given level.
 */
const classificationItems = uri => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT DISTINCT ?item ?code ?label WHERE {
    <${uri}> xkos:levels/rdf:rest*/rdf:first ?level .
    ?level skos:member ?item .
    ?item skos:notation ?code ; skos:prefLabel ?label .
  } ORDER BY ?code LIMIT 25
`

const itemDetails = item => `
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT ?label ?code ?label ?text ?cl ?clCode ?clLabel ?parent ?parentCode
      ?parentLabel {
    <${item}> skos:prefLabel ?label ;
              skos:notation ?code ;
              skos:inScheme ?cl .
    ?cl skos:prefLabel ?clLabel

    OPTIONAL {
      ?cl skos:notation ?clCode .
    }

    OPTIONAL {
      <${item}> skos:broader ?parent .
        ?parent skos:prefLabel ?parentLabel .
      OPTIONAL { ?parent skos:notation ?parentCode . }
      FILTER ( langMatches(lang(?parentLabel), "EN"))
    }

    # if we use only one OPTIONAL keyword, we will not receive the note
    # if there is no parent
    OPTIONAL {
     <${item}> xkos:coreContentNote ?content .
     ?content xkos:plainText ?text .
    }
    FILTER (
      langMatches(lang(?label), "EN") &&
      langMatches(lang(?clLabel), "EN"))
  }
`

const itemChildren = item => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT ?item ?code ?label {
    <${item}> skos:narrower ?item .
    ?item skos:notation ?code .
    ?item skos:prefLabel ?label
    FILTER (langMatches(lang(?label), "EN"))
  } ORDER BY ?code
`

const itemCorrespondences = hash => {
  const  [item, correspondenceTable] = hash.split('||');
  return `
    PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
    PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
    SELECT ?association ?item ?code ?label {
    {
    <${correspondenceTable}> xkos:madeOf ?association .
  ?association xkos:sourceConcept <${item}> ;
               xkos:targetConcept ?item .
               ?item skos:notation ?code .
               ?item skos:prefLabel ?label
               FILTER (langMatches(lang(?label), "EN"))
    }
    UNION {

  <${correspondenceTable}> xkos:madeOf ?association .
  ?association xkos:targetConcept <${item}> ;
               xkos:sourceConcept ?item .
               ?item skos:notation ?code .
               ?item skos:prefLabel ?label
               FILTER (langMatches(lang(?label), "EN"))

  }
  }
  `
}

const correspondenceDetails = correspondence => `
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  PREFIX xkos:<http://rdf-vocabulary.ddialliance.org/xkos#>
  SELECT ?classification ?code ?label {
    <${correspondence}> xkos:compares ?classification .
    ?classification skos:prefLabel ?label ;
                    skos:notation ?code
  }
`
const searchEverything = keyword => `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT DISTINCT ?subject ?predicate ?match ?score WHERE {
    ?subject ?predicate ?match .
    (?match ?score) <tag:stardog:api:property:textMatch> '${keyword}*'.
  }
`

const searchItems = hash => {
  const  [keyword, searchForCode] = hash.split('||');
  if(searchForCode==='true'){
    return  `
    PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
    PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
    SELECT DISTINCT
      ?item ?code ?itemLabel
      ?classification ?classificationLabel ?coreContentNoteText ?additionalContentNoteText
    WHERE {
      ?item skos:inScheme ?classification ;
            skos:notation ?code ;
            skos:prefLabel ?itemLabel .
      ?classification skos:prefLabel ?classificationLabel .
      FILTER regex(?code, "${keyword}", "i")
    } order by ?code
    `
  }else{

  return  `
  PREFIX rdf:<http://www.w3.org/1999/02/22-rdf-syntax-ns#>
  PREFIX skos:<http://www.w3.org/2004/02/skos/core#>
  SELECT DISTINCT
    ?item ?code ?itemLabel
    ?classification ?classificationLabel ?coreContentNoteText ?additionalContentNoteText
  WHERE {
    ?item skos:inScheme ?classification ;
          skos:notation ?code ;
          skos:prefLabel ?itemLabel ;
          xkos:coreContentNote ?coreContentNote ;
          xkos:additionalContentNote ?additionalContentNote .
    ?coreContentNote xkos:plainText ?coreContentNoteText .
    ?additionalContentNote   xkos:plainText ?additionalContentNoteText .
    ?classification skos:prefLabel ?classificationLabel .

    FILTER ( langMatches(lang(?itemLabel), "EN") &&
    (
      regex(?code, "${keyword}", "i") ||
      regex(?itemLabel, "${keyword}", "i") ||
      regex(?coreContentNoteText, "${keyword}", "i") ||
      regex(?additionalContentNoteText, "${keyword}", "i") ||
      regex(?classificationLabel, "${keyword}", "i")
    ))
  } order by ?code
`}
}

export default {
  classifications,
  classificationDetails,
  classificationItems,
  classificationLevels,
  classificationCorrespondences,
  correspondences,
  levelItems,
  itemCorrespondences,
  itemDetails,
  itemChildren,
  correspondenceDetails,
  searchEverything,
  searchItems
}
<|endoftext|>


<commit_before>const PLAYER_MAX_HEALTH = 3;
const PLAYER_FALL_SPEED_LIMIT = 1000;
const PLAYER_VELOCITY = 300;
const PLAYER_JUMP_VELOCITY = 300;
const PLAYER_JUMP_SWIPE_THRESHOLD = 50;
export const PLAYER_SPIKE_VELOCITY = 50;

export class Player extends Phaser.Sprite {

    constructor(game, state, x, y) {
        super(game, x, y, 'player');
        this.state = state;
        this.anchor.setTo(0.5);
        this.game.add.existing(this);
        this.game.physics.arcade.enable(this);
        this.game.camera.follow(this);
        this.maxHealth = PLAYER_MAX_HEALTH;
        this.health = 1; // TODO: start with less health for testing
        this.tooFast = false;
        //Adding gamepad controller
        if(this.game.input.gamepad.supported && this.game.input.gamepad.active && this.game.input.gamepad.pad1.connected) {
            this.pad = this.game.input.gamepad.pad1;
        }
        this.allowJump = true;
        this.immune = false;
    }

    update() {
        //Checking Input
        this.body.velocity.x = 0;

        if(this.isMovingLeft()) {
            this.body.velocity.x -= PLAYER_VELOCITY;
            this.scale.setTo(-1, 1);
        }
        if(this.isMovingRight()) {
            this.body.velocity.x += PLAYER_VELOCITY;
            this.scale.setTo(1, 1);
        }

        if(this.body.velocity.y > PLAYER_FALL_SPEED_LIMIT) {
            this.tooFast = true;
        }

        if (this.canJump() && this.isJumping()) {
            this.body.velocity.y = -PLAYER_JUMP_VELOCITY;
        }

        this.body.allowGravity = true;
        // player.body.velocity.y = 0;
        this.state.physics.arcade.overlap(this, this.state.rope, function(player) {
            if (player.isGrabbingTheRope()) {
                player.disableGravity();
            }
        });

        this.state.physics.arcade.overlap(this, this.state.chests, function(player, chest) {
            if(!chest.open) {
                //Opening the chest and cancel player jump
                player.allowJump = false;
                if(player.isGrabbingTheRope()) {
                    chest.open = true;
                    //Spawning coins
                    let n = this.game.rnd.integerInRange(1, 5);
                    for(let i = 0; i < n; i++) {
                        let coin = this.state.coins.getFirstExists(false);
                        if(coin) {
                            coin.reset(chest.x, chest.y);
                        } else {
                            coin = this.state.coins.create(chest.x, chest.y, 'coin');
                            coin.anchor.setTo(0.5);
                        }
                        coin.allowedPickup = false;
                        let coinTimer = this.game.time.create(this.game, true);
                        coinTimer.add(1*Phaser.Timer.SECOND, function() {
                            coin.allowedPickup = true;
                        }, this);
                        coinTimer.start();
                        coin.body.bounce.set(0.9);
                        coin.body.velocity.x = this.game.rnd.between(-100, 100);
                        coin.body.velocity.y = this.game.rnd.between(-200, -50);
                    }
                    let timer = this.game.time.create(this.game, true);
                    timer.add(0.5*Phaser.Timer.SECOND, function() {
                        player.allowJump = true;
                    }, this);
                    timer.start();
                }
            }
        }, null, this);
    }

    isMovingLeft() {
        return this.game.input.keyboard.isDown(Phaser.Keyboard.A) || this.pad && (this.pad.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || this.pad.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1) ||
        this.game.input.activePointer.isDown && this.game.input.activePointer.position.x < this.position.x;
    }

    isMovingRight() {
        return this.game.input.keyboard.isDown(Phaser.Keyboard.D) || this.pad && (this.pad.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || this.pad.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1) ||
        this.game.input.activePointer.isDown && this.game.input.activePointer.position.x > this.position.x;
    }

    canJump() {
        return this.body.blocked.down && this.allowJump;
    }

    isJumping() {
        return this.game.input.keyboard.isDown(Phaser.Keyboard.W) || this.pad &&
        (this.pad.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || this.pad.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1) ||
        this.game.input.activePointer.isDown && this.game.input.activePointer.position.y - this.game.input.activePointer.positionDown.y < -PLAYER_JUMP_SWIPE_THRESHOLD;
    }

    isGrabbingTheRope() {
        return this.game.input.keyboard.isDown(Phaser.Keyboard.W) || this.pad &&
        (this.pad.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || this.pad.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1) ||
        this.game.input.activePointer.isDown;
    }

    loseHealth(health) {
        console.log(this.immune);
        if(!this.immune) {
            this.health -= health;
            this.immune = true;
            let timer = this.game.time.create(this.game, true);
            timer.add(2*Phaser.Timer.SECOND, function() {
                console.log("immune");
                this.immune = false;
            }, this);
            timer.start();
        }
    }

    loseAllHealth() {
        this.health = 0;
    }

    isDead() {
        return this.health <= 0;
    }

    disableGravity () {
        this.body.allowGravity = false;
        this.body.velocity.y = 0;
    }
}
<commit_msg>Player immunity<commit_after>const PLAYER_MAX_HEALTH = 3;
const PLAYER_FALL_SPEED_LIMIT = 1000;
const PLAYER_VELOCITY = 300;
const PLAYER_JUMP_VELOCITY = 300;
const PLAYER_JUMP_SWIPE_THRESHOLD = 50;
export const PLAYER_SPIKE_VELOCITY = 50;

export class Player extends Phaser.Sprite {

    constructor(game, state, x, y) {
        super(game, x, y, 'player');
        this.state = state;
        this.anchor.setTo(0.5);
        this.game.add.existing(this);
        this.game.physics.arcade.enable(this);
        this.game.camera.follow(this);
        this.maxHealth = PLAYER_MAX_HEALTH;
        this.health = 1; // TODO: start with less health for testing
        this.tooFast = false;
        //Adding gamepad controller
        if(this.game.input.gamepad.supported && this.game.input.gamepad.active && this.game.input.gamepad.pad1.connected) {
            this.pad = this.game.input.gamepad.pad1;
        }
        this.allowJump = true;
        this.immune = false;
    }

    update() {
        //Checking Input
        this.body.velocity.x = 0;

        if(this.isMovingLeft()) {
            this.body.velocity.x -= PLAYER_VELOCITY;
            this.scale.setTo(-1, 1);
        }
        if(this.isMovingRight()) {
            this.body.velocity.x += PLAYER_VELOCITY;
            this.scale.setTo(1, 1);
        }

        if(this.body.velocity.y > PLAYER_FALL_SPEED_LIMIT) {
            this.tooFast = true;
        }

        if (this.canJump() && this.isJumping()) {
            this.body.velocity.y = -PLAYER_JUMP_VELOCITY;
        }

        this.body.allowGravity = true;
        // player.body.velocity.y = 0;
        this.state.physics.arcade.overlap(this, this.state.rope, function(player) {
            if (player.isGrabbingTheRope()) {
                player.disableGravity();
            }
        });

        this.state.physics.arcade.overlap(this, this.state.chests, function(player, chest) {
            if(!chest.open) {
                //Opening the chest and cancel player jump
                player.allowJump = false;
                if(player.isGrabbingTheRope()) {
                    chest.open = true;
                    //Spawning coins
                    let n = this.game.rnd.integerInRange(1, 5);
                    for(let i = 0; i < n; i++) {
                        let coin = this.state.coins.getFirstExists(false);
                        if(coin) {
                            coin.reset(chest.x, chest.y);
                        } else {
                            coin = this.state.coins.create(chest.x, chest.y, 'coin');
                            coin.anchor.setTo(0.5);
                        }
                        coin.allowedPickup = false;
                        let coinTimer = this.game.time.create(this.game, true);
                        coinTimer.add(1*Phaser.Timer.SECOND, function() {
                            coin.allowedPickup = true;
                        }, this);
                        coinTimer.start();
                        coin.body.bounce.set(0.9);
                        coin.body.velocity.x = this.game.rnd.between(-100, 100);
                        coin.body.velocity.y = this.game.rnd.between(-200, -50);
                    }
                    let timer = this.game.time.create(this.game, true);
                    timer.add(0.5*Phaser.Timer.SECOND, function() {
                        player.allowJump = true;
                    }, this);
                    timer.start();
                }
            }
        }, null, this);
    }

    isMovingLeft() {
        return this.game.input.keyboard.isDown(Phaser.Keyboard.A) || this.pad && (this.pad.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || this.pad.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1) ||
        this.game.input.activePointer.isDown && this.game.input.activePointer.position.x < this.position.x;
    }

    isMovingRight() {
        return this.game.input.keyboard.isDown(Phaser.Keyboard.D) || this.pad && (this.pad.isDown(Phaser.Gamepad.XBOX360_DPAD_LEFT) || this.pad.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_X) < -0.1) ||
        this.game.input.activePointer.isDown && this.game.input.activePointer.position.x > this.position.x;
    }

    canJump() {
        return this.body.blocked.down && this.allowJump;
    }

    isJumping() {
        return this.game.input.keyboard.isDown(Phaser.Keyboard.W) || this.pad &&
        (this.pad.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || this.pad.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1) ||
        this.game.input.activePointer.isDown && this.game.input.activePointer.position.y - this.game.input.activePointer.positionDown.y < -PLAYER_JUMP_SWIPE_THRESHOLD;
    }

    isGrabbingTheRope() {
        return this.game.input.keyboard.isDown(Phaser.Keyboard.W) || this.pad &&
        (this.pad.isDown(Phaser.Gamepad.XBOX360_DPAD_UP) || this.pad.axis(Phaser.Gamepad.XBOX360_STICK_LEFT_Y) > 0.1) ||
        this.game.input.activePointer.isDown;
    }

    loseHealth(health) {
        console.log(this.immune);
        if(!this.immune) {
            this.health -= health;
            this.immune = true;
            let timer = this.game.time.create(this.game, true);
            timer.add(2*Phaser.Timer.SECOND, function() {
                this.immune = false;
            }, this);
            timer.start();
        }
    }

    loseAllHealth() {
        this.health = 0;
    }

    isDead() {
        return this.health <= 0;
    }

    disableGravity () {
        this.body.allowGravity = false;
        this.body.velocity.y = 0;
    }
}
<|endoftext|>


<commit_before>'use strict';

const contextMenuStyle = `

`;

/**
 * 컨텍스트 메뉴
 * 서브 메뉴 지원
 *
 * @class ContextMenu
 */
export default class ContextMenu {

	/**
	 * Creates an instance of ContextMenu.
	 *
	 * @param {Array} items 컨텍스트 메뉴 아이템 배열
	 * @param {Player} Player Player Object
	 */
	constructor(items, Player) {

		/**
		 * 메뉴아이템 배열
		 * @type {Array}
		 */
		this.items = items;

		/**
		 * Player Object
		 * @type {Player}
		 */
		this.player = Player;

		/**
		 * 컨텍스트 메뉴 엘리먼트
		 * @type {Element}
		 */
		this.el = null;

		/**
		 * 메뉴이벤트 배열
		 * @type {Array}
		 */
		this.events = [];

		// 초기화
		this.init(items);

		return this;
	}

	/**
	 * 초기화. items 교체해서 재설정 가능
	 * @param {Array} items 컨텍스트 메뉴 아이템 배열
	 */
	init(items) {
		this.items = items;
		this.events = [];
		this.el = document.createElement('div');
		this.el.setAttribute('class', 'mplayer-context-menu');
		this.el.setAttribute('tabindex', '0');
		this.el.innerHTML = `
			${contextMenuStyle}

${this.createTree(this.items)}

		`;
		this.applyEvent();
	}

	/**
	 * 트리메뉴 HTML 스트링 생성
	 * @param {Array} items
	 */
	createTree(items) {
		let str = '';
		for(let i=0, len=items.length; i<len; ++i) {
			this.events.push(items[i].action);
			str += `

					${items[i].title}
					${items[i].group ? `<ul class="mplayer-context-sub">${this.createTree(items[i].group)}</ul>` : ``}

			`;
		}

		return str;
	}

	/**
	 * 이벤트 적용
	 */
	applyEvent() {
		this.el.querySelectorAll('.mplayer-context-link').forEach((el, i) => {
			el.addEventListener('click', this.events[i].bind(this.player), false);
		});
	}

	/**
	 * 메뉴 보이기
	 * @param {MouseEvent} e
	 */
	show(e) {
		this.hide();
		window.addEventListener('click', this.hide, false);
		window.addEventListener('resize', this.hide, false);
		document.body.appendChild(this.el);
		this.position(e);
		this.el.focus();
	}

	/**
	 * 메뉴 숨기기
	 */
	hide() {
		let tg = document.querySelectorAll('.mplayer-context-menu');
		for(let i=0, len=tg.length; i<len; ++i) {
			document.body.removeChild(tg[i]);
		}
		window.removeEventListener('click', this.hide, false);
		window.removeEventListener('resize', this.hide, false);
	}

	/**
	 * 위치 계산하여 설정
	 * @param {MouseEvent} e
	 */
	position(e) {
		var el = this.el,
			winWidth = document.documentElement.clientWidth || document.body.clientWidth,
			winHeight = document.documentElement.clientHeight || document.body.clientHeight,
			scrollTop = window.scrollY,
			scrollLeft = window.scrollX,
			bottomLimit = winHeight - el.offsetHeight + scrollTop,
			rightLimit = winWidth - el.offsetWidth + scrollLeft,
			top = e.clientY + scrollTop,
			left = e.clientX + scrollLeft;

		if(left >= rightLimit) {
			this.el.classList.add('mplayer-context-dir-left')
			left = rightLimit;
		}

		if(top >= bottomLimit) {
			this.el.classList.add('mplayer-context-dir-top')
			top = bottomLimit;
		}

		el.setAttribute('style', `top:${top}px; left:${left}px`);
	}
}<commit_msg>윈도우 contextmenu에서도 닫기<commit_after>'use strict';

const contextMenuStyle = `

`;
// 상위 엘리먼트 탐색
	var closest = function(el, selector) {
		var matches = el.webkitMatchesSelector ? 'webkitMatchesSelector' : (el.msMatchesSelector ? 'msMatchesSelector' : 'matches');
		while (el.parentElement) {
			if (el[matches](selector)) return el;
			el = el.parentElement;
		}
		return null;
	};
/**
 * 컨텍스트 메뉴
 * 서브 메뉴 지원
 *
 * @class ContextMenu
 */
export default class ContextMenu {

	/**
	 * Creates an instance of ContextMenu.
	 *
	 * @param {Array} items 컨텍스트 메뉴 아이템 배열
	 * @param {Player} Player Player Object
	 */
	constructor(items, Player) {

		/**
		 * 메뉴아이템 배열
		 * @type {Array}
		 */
		this.items = items;

		/**
		 * Player Object
		 * @type {Player}
		 */
		this.player = Player;

		/**
		 * 컨텍스트 메뉴 엘리먼트
		 * @type {Element}
		 */
		this.el = null;

		/**
		 * 메뉴이벤트 배열
		 * @type {Array}
		 */
		this.events = [];

		// 초기화
		this.init(items);

		return this;
	}

	/**
	 * 초기화. items 교체해서 재설정 가능
	 * @param {Array} items 컨텍스트 메뉴 아이템 배열
	 */
	init(items) {
		this.items = items;
		this.events = [];
		this.el = document.createElement('div');
		this.el.setAttribute('class', 'mplayer-context-menu');
		this.el.setAttribute('tabindex', '0');
		this.el.innerHTML = `
			${contextMenuStyle}

${this.createTree(this.items)}

		`;
		this.applyEvent();
	}

	/**
	 * 트리메뉴 HTML 스트링 생성
	 * @param {Array} items
	 */
	createTree(items) {
		let str = '';
		for(let i=0, len=items.length; i<len; ++i) {
			this.events.push(items[i].action);
			str += `

					${items[i].title}
					${items[i].group ? `<ul class="mplayer-context-sub">${this.createTree(items[i].group)}</ul>` : ``}

			`;
		}

		return str;
	}

	/**
	 * 이벤트 적용
	 */
	applyEvent() {
		this.el.querySelectorAll('.mplayer-context-link').forEach((el, i) => {
			el.addEventListener('click', this.events[i].bind(this.player), false);
		});
	}

	/**
	 * 메뉴 보이기
	 * @param {MouseEvent} e
	 */
	show(e) {
		this.hide();
		window.addEventListener('click', this.hide, false);
		window.addEventListener('contextmenu', this.hide, false);
		window.addEventListener('resize', this.hide, false);
		document.body.appendChild(this.el);
		this.position(e);
		this.el.focus();
	}

	/**
	 * 메뉴 숨기기
	 */
	hide(e) {
		if(e && e.type === 'contextmenu' && closest(e.target, '.mplayer')) {
			return false;
		}

		let tg = document.querySelectorAll('.mplayer-context-menu');
		for(let i=0, len=tg.length; i<len; ++i) {
			document.body.removeChild(tg[i]);
		}

		window.removeEventListener('click', this.hide, false);
		window.removeEventListener('contextmenu', this.hide, false);
		window.removeEventListener('resize', this.hide, false);
	}

	/**
	 * 위치 계산하여 설정
	 * @param {MouseEvent} e
	 */
	position(e) {
		var el = this.el,
			winWidth = document.documentElement.clientWidth || document.body.clientWidth,
			winHeight = document.documentElement.clientHeight || document.body.clientHeight,
			scrollTop = window.scrollY,
			scrollLeft = window.scrollX,
			bottomLimit = winHeight - el.offsetHeight + scrollTop,
			rightLimit = winWidth - el.offsetWidth + scrollLeft,
			top = e.clientY + scrollTop,
			left = e.clientX + scrollLeft;

		if(left >= rightLimit) {
			this.el.classList.add('mplayer-context-dir-left')
			left = rightLimit;
		}

		if(top >= bottomLimit) {
			this.el.classList.add('mplayer-context-dir-top')
			top = bottomLimit;
		}

		el.setAttribute('style', `top:${top}px; left:${left}px`);
	}
}<|endoftext|>


<commit_before>var uuid = require('node-uuid');
var shell = require('shelljs');
var AWS = require('aws-sdk');

var cloudformation = new AWS.CloudFormation({
  "region": "ap-southeast-2"
});

var stack = require('./cf-stack.json');

var userdata = shell.exec("python create_mime.py cloud-config.yaml:cloud-config userdata-script.sh:x-shellscript", {silent: true}).output;
stack.Resources.Ec2Instance.Properties.UserData["Fn::Base64"] = userdata;

cloudformation.createStack({
  "StackName": "nodeapp-" + uuid.v4(),
  "TemplateBody": JSON.stringify(stack)
}, function(err, data) {
  if (err) console.log(err, err.stack); // an error occurred
  else     console.log(data);           // successful response
});
<commit_msg>Show status of CF stack creation<commit_after>var uuid = require('node-uuid');
var shell = require('shelljs');
var AWS = require('aws-sdk');

var cloudformation = new AWS.CloudFormation({
  "region": "ap-southeast-2"
});

var stack = require('./cf-stack.json');

var userdata = shell.exec("python create_mime.py cloud-config.yaml:cloud-config userdata-script.sh:x-shellscript", {silent: true}).output;
stack.Resources.Ec2Instance.Properties.UserData["Fn::Base64"] = userdata;

var stackName = "nodeapp-" + uuid.v4();

cloudformation.createStack({
  "StackName": stackName,
  "TemplateBody": JSON.stringify(stack)
}, function(err, data) {
  if (err) {
    console.log(err, err.stack);
  } else {
    console.log(data);
    setTimeout(function() {
      cloudformation.describeStackEvents({"StackName": stackName}, function(err, data) {
        if (err) {
          console.log(err, err.stack);
        } else {
          console.log(data.StackEvents[0].ResourceStatus);
        }
      });
    }, 30 * 1000);
  }
});
<|endoftext|>


<commit_before>/* eslint consistent-return: 1 */
import uuid from 'uuid';
import sjcl from 'sjcl';
import request from 'superagent';
import Document from './Document';
import { Config } from './Config';
import Immutable from 'immutable';

const { Promise } = global;

export const Events = {
  NO_DOCUMENT_ID: 'store:no-document-id',
  DOCUMENT_NOT_FOUND: 'store:document-not-found',
  APP_IS_OFFLINE: 'store:app-is-offline',
  APP_IS_ONLINE: 'store:app-is-online',
  CHANGE: 'store:change',
  SYNCHRONIZE: 'store:synchronize',
  DECRYPTION_FAILED: 'store:decryption_failed',
  CONFLICT: 'store:conflict',
  UPDATE_WITHOUT_CONFLICT: 'store:update-without-conflict',
};

export default class Store {

  constructor(name, events, endpoint, localforage) {
    this.state = {
      // we automatically create a default document, but it might not be used
      document: new Document(),
      // we automatically generate a secret, but it might not be used
      secret: sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 10), 0),
    };

    this.events = events;
    this.endpoint = endpoint;
    this.localforage = localforage;

    this.localforage.config({
      name: Config.APP_NAME,
      storeName: name,
    });
  }

  /**
   * The aim of this method is to load a document by:
   *
   *   0. No ID => Events.NO_DOCUMENT_ID
   *   1. Looking into the local database first
   *     1.1. If it is not found => go to 2.
   *     1.2. If found, we attempt to decrypt it
   *       1.2.1 Decryption OK => document loaded + Events.CHANGE
   *       1.2.2 Decryption KO => Events.DECRYPTION_FAILED
   *   2. Fetch the document on the server
   *     2.1 Found => We attempt to decrypt it
   *       2.1.1 Decryption OK => document loaded + Events.CHANGE
   *       2.1.2 Decryption KO => Events.DECRYPTION_FAILED
   *     2.2 Not found => Events.DOCUMENT_NOT_FOUND
   *
   */
  load(id, secret) {
    if (!id) {
      this.events.emit(Events.NO_DOCUMENT_ID, this.state);

      return Promise.reject('No document id');
    }

    return this
      .localforage
      .getItem(id)
      .then((document) => {
        if (null === document) {
          return Promise.reject('document not found');
        }

        return Promise.resolve(Immutable.fromJS(document));
      })
      .catch(() => {
        return request
          .get(`${this.endpoint}/documents/${id}`)
          .set('Accept', 'application/json')
          .set('Content-Type', 'application/json')
          .then(this._handleRequestSuccess.bind(this))
          .catch(this._handleRequestError.bind(this))
          .then((res) => {
            return Promise.resolve(new Document({
              uuid: res.body.uuid,
              content: res.body.content,
              last_modified: res.body.last_modified
            }));
          });
      })
      .then((document) => {
        return this
          .decrypt(document.get('content'), secret)
          .then((decryptedContent) => {
            this._setState({
              document: new Document({
                uuid: document.get('uuid'),
                content: decryptedContent,
                last_modified: document.get('last_modified'),
                last_modified_locally: document.get('last_modified_locally')
              }),
              secret: secret
            });
          });
      })
      .then(() => {
        return this._localPersist();
      });
  }

  /**
   * This method is called when the document has been updated by the user
   */
  update(document) {
    // we don't want to store default content
    if (document.hasDefaultContent()) {
      return;
    }

    this._setState({
      document: new Document({
        uuid: document.get('uuid'),
        content: document.get('content'),
        last_modified: document.get('last_modified'),
        last_modified_locally: Date.now()
      }),
      secret: this.state.secret
    });

    return this._localPersist();
  }

  /**
   * Synchronize current document between local and server databases
   */
  sync() {
    if (this.state.document.hasDefaultContent()) {
      return Promise.resolve('No need to sync');
    }

    // document is new
    if (this.state.document.isNew()) {
      return this._serverPersist();
    }

    return request
      .get(`${this.endpoint}/documents/${this.state.document.get('uuid')}`)
      .set('Accept', 'application/json')
      .set('Content-Type', 'application/json')
      .then(this._handleRequestSuccess.bind(this))
      .catch(this._handleRequestError.bind(this))
      .then((res) => {
        const localDoc = this.state.document;
        const serverDoc = new Document({
          uuid: res.body.uuid,
          content: res.body.content,
          last_modified: res.body.last_modified
        });

        if (serverDoc.get('last_modified') === localDoc.get('last_modified')) {
          // here, document on the server has not been updated, so we can
          // probably push safely
          if (serverDoc.get('last_modified') < localDoc.get('last_modified_locally')) {
            return this._serverPersist();
          }

          return Promise.resolve('nothing to do');
        }

        // In theory, it should never happened, but... what happens if:
        // localDoc.get('last_modified') > serverDoc.get('last_modified') ?
        if (serverDoc.get('last_modified') > localDoc.get('last_modified')) {
          if (localDoc.hasNoLocalChanges()) {
            const secret = this.state.secret;

            return this
              .decrypt(serverDoc.content, secret)
              .then((decryptedContent) => {
                const updatedDocument = new Document({
                  uuid: serverDoc.get('uuid'),
                  content: decryptedContent,
                  last_modified: serverDoc.get('last_modified')
                });

                this._setState(
                  {
                    document: updatedDocument,
                    secret: secret
                  },
                  Events.UPDATE_WITHOUT_CONFLICT,
                  {
                    document: updatedDocument
                  }
                );
              })
              .then(() => {
                return this._localPersist();
              });
          }

          // someone fucking modified my document!
          // but I also modified it so... let's fork \o/

          // generate a new secret for fork'ed document
          const forkSecret = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 10), 0);

          // what we want is to create a fork
          return this
            .encrypt(localDoc.content, forkSecret)
            .then((encryptedContent) => {
              const fork = new Document({
                uuid: uuid.v4(),
                content: localDoc.content
              });

              // persist fork'ed document
              return this.localforage.setItem(
                fork.get('uuid'),
                new Document({
                  uuid: fork.get('uuid'),
                  content: encryptedContent
                }).toJS()
              )
              .then(() => {
                return Promise.resolve(fork);
              });
            })
            .then((fork) => {
              // now, we can update the former doc with server content
              const former = new Document({
                uuid: serverDoc.get('uuid'),
                content: serverDoc.get('content'),
                last_modified: serverDoc.get('last_modified')
              });

              return this
                .localforage
                .setItem(
                  former.get('uuid'),
                  former.toJS()
                )
                .then(() => {
                  const conflictState = {
                    fork: {
                      document: fork,
                      secret: forkSecret
                    },
                    document: former,
                    secret: this.state.secret
                  };

                  // state is now sync'ed with fork
                  this._setState(
                    conflictState.fork,
                    Events.CONFLICT,
                    conflictState
                  );

                  return Promise.resolve(conflictState);
                });
            });
        }
      });
  }

  // Pure / side-effect free method
  decrypt(content, secret) {
    try {
      return Promise.resolve(sjcl.decrypt(secret, content));
    } catch (e) {
      this.events.emit(Events.DECRYPTION_FAILED, this.state);

      return Promise.reject('decryption failed');
    }
  }

  // Pure / side-effect free method
  encrypt(content, secret) {
    return Promise.resolve(sjcl.encrypt(secret, content, { ks: 256 }));
  }

  // Impure / side-effect free method
  _localPersist() {
    const doc = this.state.document;
    const secret = this.state.secret;

    return this
      .encrypt(doc.get('content'), secret)
      .then((encryptedContent) => {
        return this.localforage.setItem(
          doc.get('uuid'),
          new Document({
            uuid: doc.get('uuid'),
            content: encryptedContent,
            last_modified: doc.get('last_modified'),
            last_modified_locally: doc.get('last_modified_locally')
          }).toJS()
        );
      })
      .then(() => {
        return Promise.resolve(this.state);
      });
  }

  // Impure / side-effect free method
  _serverPersist() {
    const doc = this.state.document;
    const secret = this.state.secret;

    return this
      .encrypt(doc.get('content'), secret)
      .then((encryptedContent) => {
        return request
          .put(`${this.endpoint}/documents/${doc.get('uuid')}`)
          .set('Accept', 'application/json')
          .set('Content-Type', 'application/json')
          .send({
            content: encryptedContent
          })
          .then(this._handleRequestSuccess.bind(this))
          .catch(this._handleRequestError.bind(this))
          .then((res) => {
            this._setState(
              {
                document: new Document({
                  uuid: doc.get('uuid'),
                  content: doc.get('content'),
                  last_modified: res.body.last_modified,
                  last_modified_locally: null
                }),
                secret: secret
              },
              Events.SYNCHRONIZE
            );

            return this._localPersist();
          });
      }
    );
  }

  _handleRequestSuccess(res) {
    this.events.emit(Events.APP_IS_ONLINE);

    return Promise.resolve(res);
  }

  _handleRequestError(err) {
    if (err.response && 404 === err.response.statusCode) {
      this.events.emit(Events.DOCUMENT_NOT_FOUND, this.state);

      return Promise.reject('document not found');
    }

    this.events.emit(Events.APP_IS_OFFLINE);

    return Promise.reject('request failed (network)');
  }

  _setState(newState, eventName, eventState) {
    this.state = newState;

    this.events.emit(eventName || Events.CHANGE, eventState || this.state);
  }
}
<commit_msg>Bad comment<commit_after>/* eslint consistent-return: 1 */
import uuid from 'uuid';
import sjcl from 'sjcl';
import request from 'superagent';
import Document from './Document';
import { Config } from './Config';
import Immutable from 'immutable';

const { Promise } = global;

export const Events = {
  NO_DOCUMENT_ID: 'store:no-document-id',
  DOCUMENT_NOT_FOUND: 'store:document-not-found',
  APP_IS_OFFLINE: 'store:app-is-offline',
  APP_IS_ONLINE: 'store:app-is-online',
  CHANGE: 'store:change',
  SYNCHRONIZE: 'store:synchronize',
  DECRYPTION_FAILED: 'store:decryption_failed',
  CONFLICT: 'store:conflict',
  UPDATE_WITHOUT_CONFLICT: 'store:update-without-conflict',
};

export default class Store {

  constructor(name, events, endpoint, localforage) {
    this.state = {
      // we automatically create a default document, but it might not be used
      document: new Document(),
      // we automatically generate a secret, but it might not be used
      secret: sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 10), 0),
    };

    this.events = events;
    this.endpoint = endpoint;
    this.localforage = localforage;

    this.localforage.config({
      name: Config.APP_NAME,
      storeName: name,
    });
  }

  /**
   * The aim of this method is to load a document by:
   *
   *   0. No ID => Events.NO_DOCUMENT_ID
   *   1. Looking into the local database first
   *     1.1. If it is not found => go to 2.
   *     1.2. If found, we attempt to decrypt it
   *       1.2.1 Decryption OK => document loaded + Events.CHANGE
   *       1.2.2 Decryption KO => Events.DECRYPTION_FAILED
   *   2. Fetch the document on the server
   *     2.1 Found => We attempt to decrypt it
   *       2.1.1 Decryption OK => document loaded + Events.CHANGE
   *       2.1.2 Decryption KO => Events.DECRYPTION_FAILED
   *     2.2 Not found => Events.DOCUMENT_NOT_FOUND
   *
   */
  load(id, secret) {
    if (!id) {
      this.events.emit(Events.NO_DOCUMENT_ID, this.state);

      return Promise.reject('No document id');
    }

    return this
      .localforage
      .getItem(id)
      .then((document) => {
        if (null === document) {
          return Promise.reject('document not found');
        }

        return Promise.resolve(Immutable.fromJS(document));
      })
      .catch(() => {
        return request
          .get(`${this.endpoint}/documents/${id}`)
          .set('Accept', 'application/json')
          .set('Content-Type', 'application/json')
          .then(this._handleRequestSuccess.bind(this))
          .catch(this._handleRequestError.bind(this))
          .then((res) => {
            return Promise.resolve(new Document({
              uuid: res.body.uuid,
              content: res.body.content,
              last_modified: res.body.last_modified
            }));
          });
      })
      .then((document) => {
        return this
          .decrypt(document.get('content'), secret)
          .then((decryptedContent) => {
            this._setState({
              document: new Document({
                uuid: document.get('uuid'),
                content: decryptedContent,
                last_modified: document.get('last_modified'),
                last_modified_locally: document.get('last_modified_locally')
              }),
              secret: secret
            });
          });
      })
      .then(() => {
        return this._localPersist();
      });
  }

  /**
   * This method is called when the document has been updated by the user
   */
  update(document) {
    // we don't want to store default content
    if (document.hasDefaultContent()) {
      return;
    }

    this._setState({
      document: new Document({
        uuid: document.get('uuid'),
        content: document.get('content'),
        last_modified: document.get('last_modified'),
        last_modified_locally: Date.now()
      }),
      secret: this.state.secret
    });

    return this._localPersist();
  }

  /**
   * Synchronize current document between local and server databases
   */
  sync() {
    if (this.state.document.hasDefaultContent()) {
      return Promise.resolve('No need to sync');
    }

    // document is new
    if (this.state.document.isNew()) {
      return this._serverPersist();
    }

    return request
      .get(`${this.endpoint}/documents/${this.state.document.get('uuid')}`)
      .set('Accept', 'application/json')
      .set('Content-Type', 'application/json')
      .then(this._handleRequestSuccess.bind(this))
      .catch(this._handleRequestError.bind(this))
      .then((res) => {
        const localDoc = this.state.document;
        const serverDoc = new Document({
          uuid: res.body.uuid,
          content: res.body.content,
          last_modified: res.body.last_modified
        });

        if (serverDoc.get('last_modified') === localDoc.get('last_modified')) {
          // here, document on the server has not been updated, so we can
          // probably push safely
          if (serverDoc.get('last_modified') < localDoc.get('last_modified_locally')) {
            return this._serverPersist();
          }

          return Promise.resolve('nothing to do');
        }

        // In theory, it should never happened, but... what happens if:
        // localDoc.get('last_modified') > serverDoc.get('last_modified') ?
        if (serverDoc.get('last_modified') > localDoc.get('last_modified')) {
          if (localDoc.hasNoLocalChanges()) {
            const secret = this.state.secret;

            return this
              .decrypt(serverDoc.content, secret)
              .then((decryptedContent) => {
                const updatedDocument = new Document({
                  uuid: serverDoc.get('uuid'),
                  content: decryptedContent,
                  last_modified: serverDoc.get('last_modified')
                });

                this._setState(
                  {
                    document: updatedDocument,
                    secret: secret
                  },
                  Events.UPDATE_WITHOUT_CONFLICT,
                  {
                    document: updatedDocument
                  }
                );
              })
              .then(() => {
                return this._localPersist();
              });
          }

          // someone modified my document!
          // ... but I also modified it so... let's fork \o/

          // generate a new secret for fork'ed document
          const forkSecret = sjcl.codec.base64.fromBits(sjcl.random.randomWords(8, 10), 0);

          // what we want is to create a fork
          return this
            .encrypt(localDoc.content, forkSecret)
            .then((encryptedContent) => {
              const fork = new Document({
                uuid: uuid.v4(),
                content: localDoc.content
              });

              // persist fork'ed document
              return this.localforage.setItem(
                fork.get('uuid'),
                new Document({
                  uuid: fork.get('uuid'),
                  content: encryptedContent
                }).toJS()
              )
              .then(() => {
                return Promise.resolve(fork);
              });
            })
            .then((fork) => {
              // now, we can update the former doc with server content
              const former = new Document({
                uuid: serverDoc.get('uuid'),
                content: serverDoc.get('content'),
                last_modified: serverDoc.get('last_modified')
              });

              return this
                .localforage
                .setItem(
                  former.get('uuid'),
                  former.toJS()
                )
                .then(() => {
                  const conflictState = {
                    fork: {
                      document: fork,
                      secret: forkSecret
                    },
                    document: former,
                    secret: this.state.secret
                  };

                  // state is now sync'ed with fork
                  this._setState(
                    conflictState.fork,
                    Events.CONFLICT,
                    conflictState
                  );

                  return Promise.resolve(conflictState);
                });
            });
        }
      });
  }

  // Pure / side-effect free method
  decrypt(content, secret) {
    try {
      return Promise.resolve(sjcl.decrypt(secret, content));
    } catch (e) {
      this.events.emit(Events.DECRYPTION_FAILED, this.state);

      return Promise.reject('decryption failed');
    }
  }

  // Pure / side-effect free method
  encrypt(content, secret) {
    return Promise.resolve(sjcl.encrypt(secret, content, { ks: 256 }));
  }

  // Impure / side-effect free method
  _localPersist() {
    const doc = this.state.document;
    const secret = this.state.secret;

    return this
      .encrypt(doc.get('content'), secret)
      .then((encryptedContent) => {
        return this.localforage.setItem(
          doc.get('uuid'),
          new Document({
            uuid: doc.get('uuid'),
            content: encryptedContent,
            last_modified: doc.get('last_modified'),
            last_modified_locally: doc.get('last_modified_locally')
          }).toJS()
        );
      })
      .then(() => {
        return Promise.resolve(this.state);
      });
  }

  // Impure / side-effect free method
  _serverPersist() {
    const doc = this.state.document;
    const secret = this.state.secret;

    return this
      .encrypt(doc.get('content'), secret)
      .then((encryptedContent) => {
        return request
          .put(`${this.endpoint}/documents/${doc.get('uuid')}`)
          .set('Accept', 'application/json')
          .set('Content-Type', 'application/json')
          .send({
            content: encryptedContent
          })
          .then(this._handleRequestSuccess.bind(this))
          .catch(this._handleRequestError.bind(this))
          .then((res) => {
            this._setState(
              {
                document: new Document({
                  uuid: doc.get('uuid'),
                  content: doc.get('content'),
                  last_modified: res.body.last_modified,
                  last_modified_locally: null
                }),
                secret: secret
              },
              Events.SYNCHRONIZE
            );

            return this._localPersist();
          });
      }
    );
  }

  _handleRequestSuccess(res) {
    this.events.emit(Events.APP_IS_ONLINE);

    return Promise.resolve(res);
  }

  _handleRequestError(err) {
    if (err.response && 404 === err.response.statusCode) {
      this.events.emit(Events.DOCUMENT_NOT_FOUND, this.state);

      return Promise.reject('document not found');
    }

    this.events.emit(Events.APP_IS_OFFLINE);

    return Promise.reject('request failed (network)');
  }

  _setState(newState, eventName, eventState) {
    this.state = newState;

    this.events.emit(eventName || Events.CHANGE, eventState || this.state);
  }
}
<|endoftext|>


<commit_before>// External Deps
import React from 'react';
import Radium from 'radium';
import { GatewayProvider, GatewayDest } from 'react-gateway';

// Theme
import { grey, slightlyDarkerBlack } from 'theme/variables';
import { labelGreyLarge } from 'theme/mixins';

// Sub-layouts
import TopLeftSection from 'layouts/topLeftSection';
import TopRightSection from 'layouts/topRightSection';
import BottomSection from 'layouts/bottomSection';

// Components
import Octicon from 'react-octicon';
import { ConnectedSaveButton, ConnectedLoadButton } from './connectedComponents';

const GithubLink = Radium(() => (

    <Octicon name="mark-github" mega/>

));

// layout constants
const APP_WIDTH = 1400;
const APP_HEIGHT = 800;
const APP_PADDING = 40;

const HEADER_HEIGHT = 50;
const FOOTER_HEIGHT = 30;

const TOP_BOTTOM_DIVIDER_HEIGHT = 3;
const TOP_HEIGHT = Math.ceil(APP_HEIGHT * 0.64) - (TOP_BOTTOM_DIVIDER_HEIGHT * 2);
const BOTTOM_HEIGHT = APP_HEIGHT - TOP_HEIGHT - (TOP_BOTTOM_DIVIDER_HEIGHT * 2);

const INSTRUMENT_SEPERATOR_WIDTH = 1;

const TOP_LEFT_WIDTH = Math.ceil(APP_WIDTH * 0.23) - INSTRUMENT_SEPERATOR_WIDTH;
const TOP_RIGHT_WIDTH = APP_WIDTH - TOP_LEFT_WIDTH ;

const TOP_HORIZONTAL_SEPERATOR_HEIGHT = TOP_HEIGHT - 10;

@Radium
class AppLayout extends React.Component {
  shouldComponentUpdate() {
    return false;
  }

  render() {
    const styles = {
      pageWrapper: {
        position: 'relative',
        width: '100%', height: '100%',
        minWidth: APP_WIDTH + APP_PADDING, minHeight: APP_HEIGHT + HEADER_HEIGHT + FOOTER_HEIGHT + APP_PADDING
      },

      wrapper: {
        position: 'absolute',
        width: APP_WIDTH, height: APP_HEIGHT + HEADER_HEIGHT + FOOTER_HEIGHT,
        top: 0, left: 0, right: 0, bottom: 0,
        margin: 'auto',
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center'
      },

      headerWrapper: {
        width: APP_WIDTH, height: HEADER_HEIGHT,
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between'
      },

      saveLoadClearWrapper: {
        display: 'flex',
        flexDirection: 'row'
      },

      footerWrapper: {
        width: APP_WIDTH, height: FOOTER_HEIGHT,
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between'
      },

      appWrapper: {
        width: APP_WIDTH, height: APP_HEIGHT,
        display: 'flex',
        flexDirection: 'column'
      },

      topBottomDivider: {
        width: APP_WIDTH, height: TOP_BOTTOM_DIVIDER_HEIGHT,
        backgroundColor: grey
      },

      topHorizontalDivider: {
        width: INSTRUMENT_SEPERATOR_WIDTH, height: TOP_HORIZONTAL_SEPERATOR_HEIGHT,
        backgroundColor: grey
      },

      topWrapper: {
        width: APP_WIDTH, height: TOP_HEIGHT,
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center'
      },

      bottomWrapper: {
        width: APP_WIDTH, height: BOTTOM_HEIGHT
      }
    };

    return (
      <GatewayProvider>

          <GatewayDest name="knobOverlay" />

                <ConnectedLoadButton size={35} />
                <ConnectedSaveButton size={35} />

              <GithubLink />

                <TopLeftSection width={TOP_LEFT_WIDTH} height={TOP_HEIGHT} />

                <TopRightSection width={TOP_RIGHT_WIDTH} height={TOP_HEIGHT}
                                 seperatorWidth={INSTRUMENT_SEPERATOR_WIDTH} />

                <BottomSection width={APP_WIDTH} height={BOTTOM_HEIGHT} topLeftWidth={TOP_LEFT_WIDTH} />

                Tutorial

                Made with <Octicon name="heart" /> by
                  Vincent Riemer

                Report an Issue

      </GatewayProvider>
    );
  }
}

export default AppLayout;<commit_msg>add padding to footer<commit_after>// External Deps
import React from 'react';
import Radium from 'radium';
import { GatewayProvider, GatewayDest } from 'react-gateway';

// Theme
import { grey, slightlyDarkerBlack } from 'theme/variables';
import { labelGreyLarge } from 'theme/mixins';

// Sub-layouts
import TopLeftSection from 'layouts/topLeftSection';
import TopRightSection from 'layouts/topRightSection';
import BottomSection from 'layouts/bottomSection';

// Components
import Octicon from 'react-octicon';
import { ConnectedSaveButton, ConnectedLoadButton } from './connectedComponents';

const GithubLink = Radium(() => (

    <Octicon name="mark-github" mega/>

));

// layout constants
const APP_WIDTH = 1400;
const APP_HEIGHT = 800;
const APP_PADDING = 40;

const HEADER_HEIGHT = 50;
const FOOTER_HEIGHT = 30;

const TOP_BOTTOM_DIVIDER_HEIGHT = 3;
const TOP_HEIGHT = Math.ceil(APP_HEIGHT * 0.64) - (TOP_BOTTOM_DIVIDER_HEIGHT * 2);
const BOTTOM_HEIGHT = APP_HEIGHT - TOP_HEIGHT - (TOP_BOTTOM_DIVIDER_HEIGHT * 2);

const INSTRUMENT_SEPERATOR_WIDTH = 1;

const TOP_LEFT_WIDTH = Math.ceil(APP_WIDTH * 0.23) - INSTRUMENT_SEPERATOR_WIDTH;
const TOP_RIGHT_WIDTH = APP_WIDTH - TOP_LEFT_WIDTH ;

const TOP_HORIZONTAL_SEPERATOR_HEIGHT = TOP_HEIGHT - 10;

@Radium
class AppLayout extends React.Component {
  shouldComponentUpdate() {
    return false;
  }

  render() {
    const styles = {
      pageWrapper: {
        position: 'relative',
        width: '100%', height: '100%',
        minWidth: APP_WIDTH + APP_PADDING, minHeight: APP_HEIGHT + HEADER_HEIGHT + FOOTER_HEIGHT + APP_PADDING
      },

      wrapper: {
        position: 'absolute',
        width: APP_WIDTH, height: APP_HEIGHT + HEADER_HEIGHT + FOOTER_HEIGHT,
        top: 0, left: 0, right: 0, bottom: 0,
        margin: 'auto',
        display: 'flex',
        flexDirection: 'column',
        alignItems: 'center'
      },

      headerWrapper: {
        width: APP_WIDTH, height: HEADER_HEIGHT,
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between'
      },

      saveLoadClearWrapper: {
        display: 'flex',
        flexDirection: 'row'
      },

      footerWrapper: {
        width: APP_WIDTH, height: FOOTER_HEIGHT,
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center',
        justifyContent: 'space-between',
        paddingLeft: 10, paddingRight: 10
      },

      appWrapper: {
        width: APP_WIDTH, height: APP_HEIGHT,
        display: 'flex',
        flexDirection: 'column'
      },

      topBottomDivider: {
        width: APP_WIDTH, height: TOP_BOTTOM_DIVIDER_HEIGHT,
        backgroundColor: grey
      },

      topHorizontalDivider: {
        width: INSTRUMENT_SEPERATOR_WIDTH, height: TOP_HORIZONTAL_SEPERATOR_HEIGHT,
        backgroundColor: grey
      },

      topWrapper: {
        width: APP_WIDTH, height: TOP_HEIGHT,
        display: 'flex',
        flexDirection: 'row',
        alignItems: 'center'
      },

      bottomWrapper: {
        width: APP_WIDTH, height: BOTTOM_HEIGHT
      }
    };

    return (
      <GatewayProvider>

          <GatewayDest name="knobOverlay" />

                <ConnectedLoadButton size={35} />
                <ConnectedSaveButton size={35} />

              <GithubLink />

                <TopLeftSection width={TOP_LEFT_WIDTH} height={TOP_HEIGHT} />

                <TopRightSection width={TOP_RIGHT_WIDTH} height={TOP_HEIGHT}
                                 seperatorWidth={INSTRUMENT_SEPERATOR_WIDTH} />

                <BottomSection width={APP_WIDTH} height={BOTTOM_HEIGHT} topLeftWidth={TOP_LEFT_WIDTH} />

                Tutorial

                Made with <Octicon name="heart" /> by
                  Vincent Riemer

                Report an Issue

      </GatewayProvider>
    );
  }
}

export default AppLayout;<|endoftext|>


<commit_before>// The contents of this file will be executed before any of
// your view controllers are ever executed, including the index.
// You have access to all functionality on the `Alloy` namespace.
//
// This is a great place to do any initialization for your app
// or create any global variables/functions that you'd like to
// make available throughout your app. You can easily make things
// accessible globally by attaching them to the `Alloy.Globals`
// object. For example:
//
// Alloy.Globals.someGlobalFunction = function(){};

/*
 * App Singleton
 * @type {Object}
 */
Alloy.Globals.App = {

	/**
	 * Applications Settings
	 */
	Settings: {
		menuWidth: "265dp"
	},

	/**
	 * Navigation Widget using for routing controllers
	 * @type {Object}
	 */
	Navigator: {
		menuView: null,		// The underlying view that encompasses the menu
		mainView: null,		// The top most view that represents the main UI
		contentView: null,	// The content area of the mainView - this is linked to the Navigator.open() method
		currentController: null,	// A reference to the currentController being viewed within the contentView
		menuVisible: false,			// Flag to denote if the menu view is being show or not

		/**
		 * init - initializes the Navigator obejct, by setting the necessary views to the corresponding
		 * views declared within the XML
		 * @type {Object} _params : {menuView, mainView, contentView} references to Ti.UI.View Objects
		 */
		init: function(_params){
			this.menuView =_params.menuView;
			this.mainView = _params.mainView;
			this.contentView = _params.contentView;
			Ti.API.debug("Navigator.init - complete");

			_params.startPage && this.open(_params.startPage);
		},

		/**
		 * open - responsible for opening new views into the contentView. Additionally handles the removal of pre-existing views
		 * @type {String} _controller : the name of the view/controller you want to open
		 * @type {Object} _options : additional properties you want to pass into the new view/controller
		 */
		open: function(_controller, _options){

			if( _controller && this.contentView) {

				if( (this.currentController && (_controller !== this.currentController.getView().id)) // If the user is clicking on a different menu item
					||  !this.currentController ) { // OR there is no defined current controller

					/**
					 * Record the navigation event in Analytics if a currentController exists otherwise create a feature event for the new session
					 */
					this.currentController && Ti.Analytics.navEvent( this.currentController.getView().id, _controller)
										   || Ti.Analytics.featureEvent("new_session", null);

					/**
					 * If we have a reference to an existing view/controller, lets make sure to remove it
					 * from the contentView and set it to null (otherwise you get a memory leak)
					 */
					if(this.currentController){
						this.contentView.remove(this.currentController.getView()); // <- You MUST remove the view before setting the controller to null!
						this.currentController = null; // releases the memory
						Ti.API.info('Old View Collected!');
					}
					/**
					 * If the menu is visible, lets close the primary view
					 */
					this.menuVisible && this.showhidemenu();

					/**
					 * Create a your new controller and add its view to the contentView
					 */
					this.currentController = Alloy.createController(_controller, _options);
					this.contentView.add(this.currentController.getView());
				}
			}
			else {
				Ti.API.error("Either a controller was not specified or the Navigator object has not been properly initiallized.");
			}

			Ti.API.debug("Navigator.open - complete");
		},

		modal: function(_controller, _options) {

			if(_controller){
				/**
				 * Create a new window to handle the modal dialog
				 */
				var modalWin = Ti.UI.createWindow();

				/**
				 * Create the view controller, and add the primary view to the modal window
				 */
				var modalController = Alloy.createController(_controller, _options);
				modalWin.add(modalWin.getView());

				/**
				 * Open the window as modal
				 */
				modalWin.open({modal: true});

			}
			else {
				Ti.API.error("Mandatory parameter '_controller' not specified");
			}
		},

		/**
		 * showhidemenu  - Manages the function to hide or display the unerlying menu
		 * @type {String} direction - optional. If you want to trigger the menu based on a swipe, pass in the
		 * 							 string from the swipe gesture that represents direction and the function
		 *  							 will determine if the menu should open based on state
		 */
		showhidemenu: function(direction) {
			Ti.API.info('showhidemenu');
			/**
			 * Use the actual screen dimensions for the calculations
			 */
			this.mainView.width=Ti.Platform.displayCaps.platformWidth;

			/**
			 * Animate the mainView x pixels based on the App Settings (see above) if it currently isn't open, if its open move it back to the left
			 */
			var l =  !this.menuVisible ? Alloy.Globals.App.Settings.menuWidth : 0;

			if( !direction || 								 // <- No swipe input - just open the menu
				(direction === 'left' && this.menuVisible) ||  // <- If swiping left and the menu is open close it
				(direction ==='right' && !this.menuVisible)) {  // <- If swiping right and the menu is closed, open it

				this.mainView.animate({
					left: l,
					duration:100
				});

				this.menuVisible = !this.menuVisible
			}
		}
	},

	/**
	 * Initialize the application
	 * NOTE: This should only be fired in index controller file and only once.
	 * @type {Function}
	 */
	init: function() {
		// TODO: Sanity Check to make sure globals are set properly

		// Global system Events -- see below for more information
		Ti.Network.addEventListener('change', _.bind(this.networkObserverUpdate, this));
		Ti.App.addEventListener('pause', _.bind(this.exit, this));
		Ti.App.addEventListener('close', _.bind(this.exit, this));
		Ti.App.addEventListener('resume', _.bind(this.resume, this));
		Ti.Gesture.addEventListener('orientationchange', _.bind(this.orientationObserverUpdate, this));

		// Register push-notifications
		this.registerPush();
	},

	/**
	 * Registers the app for push notifications
	 */
	registerPush: function() {
		this.log('debug', 'APP.registerPush');
	},
	/**
	 * Global network event handler
	 * @param {Object} _event Standard Ti callback
	 */
	networkObserverUpdate: function(_event) {
		this.log('debug', 'APP.networkObserverUpdate');
	},
	/**
     * Sets the current orientation of the device constant
     * @type {String}
     */
    currentOrientation: (Ti.Gesture.orientation == Ti.UI.LANDSCAPE_LEFT || Ti.Gesture.orientation == Ti.UI.LANDSCAPE_RIGHT) ? 'landscape' : 'portrait',
	/**
	 * Global orientation change event handler
	 * @param {Object} e Standard Ti callback
	 */
	orientationObserverUpdate: function(e) {
		this.log('debug', 'APP.orientationObserverUpdate');

		// Shortcut for current orientation
		var type = (e.orientation == Ti.UI.LANDSCAPE_LEFT || e.orientation == Ti.UI.LANDSCAPE_RIGHT) ? 'landscape' : 'portrait';

		// Make sure it's a different orientation before proceeding
		if (this.currentOrientation != type) {
			// If it's an undesired orientation, just ignore
			if (e.orientation == Ti.UI.FACE_UP || e.orientation == Ti.UI.FACE_DOWN || e.orientation == Ti.UI.UNKNOWN ) return;

			//Saves the current orientation
			this.currentOrientation = type;

			if (this.Navigator.currentController && this.Navigation.currentController.orientationUpdate) {
            	this.Navigation.currentController.orientationUpdate(type);
            }

			Ti.App.fireEvent('updateOrientation', {
				orientation: type
			});
        }
	},
	/**
	 * Exit event observer
	 */
	exit: function() {
		this.log('debug', 'APP.exit');
	},
	/**
	 * Resume event observer
	 */
	resume: function() {
		this.log('debug', 'APP.resume');
	},
	/**
	 * Pause event observer
	 */
	pause: function() {
		this.log('debug', 'APP.pause');
	},
	/**
	 * Logger utility for console data
	 */
	log: function(_serverity, _msg) {
		switch(_serverity.toLowerCase()) {
			case 'debug':
				Ti.API.info(_msg);
				break;
			case 'error':
				Ti.API.error(_msg);
				break;
			case 'info':
				Ti.API.info(_msg);
				break;
			case 'log':
				Ti.API.log(_msg);
				break;
			case 'trace':
				Ti.API.trace(_msg);
				break;
			case 'warn':
				Ti.API.warn(_msg);
				break;
		}
	}
};
<commit_msg>+ FIX - sliding out the menu made the mainWIndow twice as large as it should be, this was because of the switch to DP as the default unit. Fix is to divide the platform width by 2 on Android<commit_after>// The contents of this file will be executed before any of
// your view controllers are ever executed, including the index.
// You have access to all functionality on the `Alloy` namespace.
//
// This is a great place to do any initialization for your app
// or create any global variables/functions that you'd like to
// make available throughout your app. You can easily make things
// accessible globally by attaching them to the `Alloy.Globals`
// object. For example:
//
// Alloy.Globals.someGlobalFunction = function(){};

/*
 * App Singleton
 * @type {Object}
 */
Alloy.Globals.App = {

	/**
	 * Applications Settings
	 */
	Settings: {
		menuWidth: "265dp"
	},

	/**
	 * Navigation Widget using for routing controllers
	 * @type {Object}
	 */
	Navigator: {
		menuView: null,		// The underlying view that encompasses the menu
		mainView: null,		// The top most view that represents the main UI
		contentView: null,	// The content area of the mainView - this is linked to the Navigator.open() method
		currentController: null,	// A reference to the currentController being viewed within the contentView
		menuVisible: false,			// Flag to denote if the menu view is being show or not

		/**
		 * init - initializes the Navigator obejct, by setting the necessary views to the corresponding
		 * views declared within the XML
		 * @type {Object} _params : {menuView, mainView, contentView} references to Ti.UI.View Objects
		 */
		init: function(_params){
			this.menuView =_params.menuView;
			this.mainView = _params.mainView;
			this.contentView = _params.contentView;
			Ti.API.debug("Navigator.init - complete");

			_params.startPage && this.open(_params.startPage);
		},

		/**
		 * open - responsible for opening new views into the contentView. Additionally handles the removal of pre-existing views
		 * @type {String} _controller : the name of the view/controller you want to open
		 * @type {Object} _options : additional properties you want to pass into the new view/controller
		 */
		open: function(_controller, _options){

			if( _controller && this.contentView) {

				if( (this.currentController && (_controller !== this.currentController.getView().id)) // If the user is clicking on a different menu item
					||  !this.currentController ) { // OR there is no defined current controller

					/**
					 * Record the navigation event in Analytics if a currentController exists otherwise create a feature event for the new session
					 */
					this.currentController && Ti.Analytics.navEvent( this.currentController.getView().id, _controller)
										   || Ti.Analytics.featureEvent("new_session", null);

					/**
					 * If we have a reference to an existing view/controller, lets make sure to remove it
					 * from the contentView and set it to null (otherwise you get a memory leak)
					 */
					if(this.currentController){
						this.contentView.remove(this.currentController.getView()); // <- You MUST remove the view before setting the controller to null!
						this.currentController = null; // releases the memory
						Ti.API.info('Old View Collected!');
					}
					/**
					 * If the menu is visible, lets close the primary view
					 */
					this.menuVisible && this.showhidemenu();

					/**
					 * Create a your new controller and add its view to the contentView
					 */
					this.currentController = Alloy.createController(_controller, _options);
					this.contentView.add(this.currentController.getView());
				}
			}
			else {
				Ti.API.error("Either a controller was not specified or the Navigator object has not been properly initiallized.");
			}

			Ti.API.debug("Navigator.open - complete");
		},

		modal: function(_controller, _options) {

			if(_controller){
				/**
				 * Create a new window to handle the modal dialog
				 */
				var modalWin = Ti.UI.createWindow();

				/**
				 * Create the view controller, and add the primary view to the modal window
				 */
				var modalController = Alloy.createController(_controller, _options);
				modalWin.add(modalWin.getView());

				/**
				 * Open the window as modal
				 */
				modalWin.open({modal: true});

			}
			else {
				Ti.API.error("Mandatory parameter '_controller' not specified");
			}
		},

		/**
		 * showhidemenu  - Manages the function to hide or display the unerlying menu
		 * @type {String} direction - optional. If you want to trigger the menu based on a swipe, pass in the
		 * 							 string from the swipe gesture that represents direction and the function
		 *  							 will determine if the menu should open based on state
		 */
		showhidemenu: function(direction) {

			Ti.API.info('showhidemenu');
			/**
			 * Use the actual screen dimensions for the calculations
			 */
			if(OS_ANDROID) // ANDROID HACK - Because we are setting the system units to DP we need to divide by 2 on Android
				this.mainView.width=Ti.Platform.displayCaps.platformWidth/2;
			else
				this.mainView.width = Ti.Platform.displayCaps.platformWidth

			/**
			 * Animate the mainView x pixels based on the App Settings (see above) if it currently isn't open, if its open move it back to the left
			 */
			var l =  !this.menuVisible ? Alloy.Globals.App.Settings.menuWidth : 0;

			if( !direction || 								 // <- No swipe input - just open the menu
				(direction === 'left' && this.menuVisible) ||  // <- If swiping left and the menu is open close it
				(direction ==='right' && !this.menuVisible)) {  // <- If swiping right and the menu is closed, open it

				this.mainView.animate({
					left: l,
					duration:100
				});

				this.menuVisible = !this.menuVisible
			}
		}
	},

	/**
	 * Initialize the application
	 * NOTE: This should only be fired in index controller file and only once.
	 * @type {Function}
	 */
	init: function() {
		// TODO: Sanity Check to make sure globals are set properly

		// Global system Events -- see below for more information
		Ti.Network.addEventListener('change', _.bind(this.networkObserverUpdate, this));
		Ti.App.addEventListener('pause', _.bind(this.exit, this));
		Ti.App.addEventListener('close', _.bind(this.exit, this));
		Ti.App.addEventListener('resume', _.bind(this.resume, this));
		Ti.Gesture.addEventListener('orientationchange', _.bind(this.orientationObserverUpdate, this));

		// Register push-notifications
		this.registerPush();
	},

	/**
	 * Registers the app for push notifications
	 */
	registerPush: function() {
		this.log('debug', 'APP.registerPush');
	},
	/**
	 * Global network event handler
	 * @param {Object} _event Standard Ti callback
	 */
	networkObserverUpdate: function(_event) {
		this.log('debug', 'APP.networkObserverUpdate');
	},
	/**
     * Sets the current orientation of the device constant
     * @type {String}
     */
    currentOrientation: (Ti.Gesture.orientation == Ti.UI.LANDSCAPE_LEFT || Ti.Gesture.orientation == Ti.UI.LANDSCAPE_RIGHT) ? 'landscape' : 'portrait',
	/**
	 * Global orientation change event handler
	 * @param {Object} e Standard Ti callback
	 */
	orientationObserverUpdate: function(e) {
		this.log('debug', 'APP.orientationObserverUpdate');

		// Shortcut for current orientation
		var type = (e.orientation == Ti.UI.LANDSCAPE_LEFT || e.orientation == Ti.UI.LANDSCAPE_RIGHT) ? 'landscape' : 'portrait';

		// Make sure it's a different orientation before proceeding
		if (this.currentOrientation != type) {
			// If it's an undesired orientation, just ignore
			if (e.orientation == Ti.UI.FACE_UP || e.orientation == Ti.UI.FACE_DOWN || e.orientation == Ti.UI.UNKNOWN ) return;

			//Saves the current orientation
			this.currentOrientation = type;

			if (this.Navigator.currentController && this.Navigation.currentController.orientationUpdate) {
            	this.Navigation.currentController.orientationUpdate(type);
            }

			Ti.App.fireEvent('updateOrientation', {
				orientation: type
			});
        }
	},
	/**
	 * Exit event observer
	 */
	exit: function() {
		this.log('debug', 'APP.exit');
	},
	/**
	 * Resume event observer
	 */
	resume: function() {
		this.log('debug', 'APP.resume');
	},
	/**
	 * Pause event observer
	 */
	pause: function() {
		this.log('debug', 'APP.pause');
	},
	/**
	 * Logger utility for console data
	 */
	log: function(_serverity, _msg) {
		switch(_serverity.toLowerCase()) {
			case 'debug':
				Ti.API.info(_msg);
				break;
			case 'error':
				Ti.API.error(_msg);
				break;
			case 'info':
				Ti.API.info(_msg);
				break;
			case 'log':
				Ti.API.log(_msg);
				break;
			case 'trace':
				Ti.API.trace(_msg);
				break;
			case 'warn':
				Ti.API.warn(_msg);
				break;
		}
	}
};
<|endoftext|>


<commit_before>export default bmpImage => new Promise(resolve => {
    // If the input is an ArrayBuffer, we need to convert it to a `Blob` and give it a URL so we can use it as an
    // `src`. If it's a data URI, we can use it as-is.
    const imageUrl = bmpImage instanceof String ?
        bmpImage :
        window.URL.createObjectURL(new Blob([bmpImage], {type: 'image/bmp'}));

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const image = document.createElement('img');

    image.addEventListener('load', () => {
        ctx.drawImage(image, 0, 0);

        const dataUrl = canvas.toDataURL('image/png');

        // Revoke URL. If a blob URL was generated earlier, this allows the blob to be GC'd and prevents a memory leak.
        window.URL.revokeObjectURL(imageUrl);

        resolve(dataUrl);
    });

    image.setAttribute('src', imageUrl);
});
<commit_msg>set bmp canvas dimensions properly<commit_after>export default bmpImage => new Promise(resolve => {
    // If the input is an ArrayBuffer, we need to convert it to a `Blob` and give it a URL so we can use it as an
    // `src`. If it's a data URI, we can use it as-is.
    const imageUrl = bmpImage instanceof String ?
        bmpImage :
        window.URL.createObjectURL(new Blob([bmpImage], {type: 'image/bmp'}));

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    const image = document.createElement('img');

    image.addEventListener('load', () => {
        canvas.width = image.naturalWidth;
        canvas.height = image.naturalHeight;
        ctx.drawImage(image, 0, 0);

        const dataUrl = canvas.toDataURL('image/png');

        // Revoke URL. If a blob URL was generated earlier, this allows the blob to be GC'd and prevents a memory leak.
        window.URL.revokeObjectURL(imageUrl);

        resolve(dataUrl);
    });

    image.setAttribute('src', imageUrl);
});
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');

var GitHubApi = require('github');
var github = new GitHubApi({
  version: '3.0.0'
});

var githubUserInfo = function (name, cb) {
  github.user.getFrom({
    user: name
  }, function (err, res) {
    if (err) {
      throw err;
    }
    cb(JSON.parse(JSON.stringify(res)));
  });
};

var GruntStaticSiteGenerator = module.exports = function GruntStaticSiteGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);

  this.on('end', function () {
    this.installDependencies({ skipInstall: options['skip-install'] });
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(GruntStaticSiteGenerator, yeoman.generators.Base);

GruntStaticSiteGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(this.yeoman);

  var prompts = [{
    name: 'projectName',
    message: 'What is the name of your project?'
  },

  {
    name: 'projectDescription',
    message: 'Describe your project:',
    default: 'A generator for Yeoman'
  },

  {
    name: 'githubUser',
    message: 'Would you mind telling me your username on Github?',
    default: 'someuser'
  },

  {
    type: 'confirm',
    name: 'ghpages',
    message: 'Use grunt-gh-pages to automate pushing your site to GitHub Pages?'
  }
  ];

  this.prompt(prompts, function (props) {
    this.projectName = props.projectName;
    this.projectDescription = props.projectDescription;
    this.githubUser = props.githubUser;
    this.ghpages = props.ghpages;

    cb();
  }.bind(this));
};

GruntStaticSiteGenerator.prototype.userInfo = function userInfo() {
  var done = this.async();

  githubUserInfo(this.githubUser, function (res) {
    /*jshint camelcase:false */
    this.realname = res.name;
    this.email = res.email;
    this.githubUrl = res.html_url;
    done();
  }.bind(this));
};

GruntStaticSiteGenerator.prototype.app = function app() {
  this.mkdir('templates');

  this.copy('_bower.json', 'bower.json');

  this.copy('_app.js', 'app.js');
  this.copy('_style.css', 'style.css');
  this.copy('_index.ejs', 'index.ejs');
  this.copy('_readme.md', 'readme.md');

  if (this.ghpages === true){
    this.copy('_packageGH.json', 'package.json');
    this.copy('_GruntfileGH.js', 'Gruntfile.js');
  } else {
    this.copy('_package.json', 'package.json');
    this.copy('_Gruntfile.js', 'Gruntfile.js');
  }
};

GruntStaticSiteGenerator.prototype.projectfiles = function projectfiles() {
  //this.copy('jshintrc', '.jshintrc');
};
<commit_msg>fix prompt default<commit_after>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');

var GitHubApi = require('github');
var github = new GitHubApi({
  version: '3.0.0'
});

var githubUserInfo = function (name, cb) {
  github.user.getFrom({
    user: name
  }, function (err, res) {
    if (err) {
      throw err;
    }
    cb(JSON.parse(JSON.stringify(res)));
  });
};

var GruntStaticSiteGenerator = module.exports = function GruntStaticSiteGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);

  this.on('end', function () {
    this.installDependencies({ skipInstall: options['skip-install'] });
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(GruntStaticSiteGenerator, yeoman.generators.Base);

GruntStaticSiteGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(this.yeoman);

  var prompts = [{
    name: 'projectName',
    message: 'What is the name of your project?'
  },

  {
    name: 'projectDescription',
    message: 'Describe your project:',
    default: 'My awesome site.'
  },

  {
    name: 'githubUser',
    message: 'Would you mind telling me your username on Github?',
    default: 'someuser'
  },

  {
    type: 'confirm',
    name: 'ghpages',
    message: 'Use grunt-gh-pages to automate pushing your site to GitHub Pages?'
  }
  ];

  this.prompt(prompts, function (props) {
    this.projectName = props.projectName;
    this.projectDescription = props.projectDescription;
    this.githubUser = props.githubUser;
    this.ghpages = props.ghpages;

    cb();
  }.bind(this));
};

GruntStaticSiteGenerator.prototype.userInfo = function userInfo() {
  var done = this.async();

  githubUserInfo(this.githubUser, function (res) {
    /*jshint camelcase:false */
    this.realname = res.name;
    this.email = res.email;
    this.githubUrl = res.html_url;
    done();
  }.bind(this));
};

GruntStaticSiteGenerator.prototype.app = function app() {
  this.mkdir('templates');

  this.copy('_bower.json', 'bower.json');

  this.copy('_app.js', 'app.js');
  this.copy('_style.css', 'style.css');
  this.copy('_index.ejs', 'index.ejs');
  this.copy('_readme.md', 'readme.md');

  if (this.ghpages === true){
    this.copy('_packageGH.json', 'package.json');
    this.copy('_GruntfileGH.js', 'Gruntfile.js');
  } else {
    this.copy('_package.json', 'package.json');
    this.copy('_Gruntfile.js', 'Gruntfile.js');
  }
};

GruntStaticSiteGenerator.prototype.projectfiles = function projectfiles() {
  //this.copy('jshintrc', '.jshintrc');
};
<|endoftext|>


<commit_before>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var fs = require('fs');

var TestGenerator = module.exports = function TestGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);

  this.argument('appname', { type: String, required: false });
  this.appname = this.appname || path.basename(process.cwd());
  this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));

  this.on('end', function () {
    // this.installDependencies({ skipInstall: options['skip-install'] });
    this.installDependencies({
      bower: this.environment === 'browser' ? true : false,
      npm: true,
      skipInstall: options['skip-install'],
      callback: function() {
        console.log('Everything is ready!');
      }
    });
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(TestGenerator, yeoman.generators.Base);

TestGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(this.yeoman);

  var allFiles = fs.readdirSync(process.cwd());
  var prompts = [];

  var jsFiles = allFiles.filter( function( file ) {
    return file.substr(file.length - 3) === '.js';
  });

  prompts.push({
    type: 'list',
    name: 'environment',
    message: 'Do you want to test your algorithm in the browser or with Node?',
    choices: ['Node', 'browser'],
    default: 'browser'
  });

  if (jsFiles.length === 0) {
    prompts.push({
      name: 'algorithm',
      message: 'Please enter a name for the algorithm you\'d like to test',
      default: this.appname
    });
  } else {
    prompts.push({
      type: 'list',
      name: 'file',
      message: 'Hey, I found js files in this directory. Which one contains the algorithm you\'d like to test?',
      choices: jsFiles
    });
  }

  this.prompt(prompts, function (response) {
    this.file = response.file || response.algorithm + '.js';
    this.algorithm = response.algorithm || response.file.split('.')[0];
    this.environment = response.environment || 'browser';
    cb();
  }.bind(this));
};

TestGenerator.prototype.app = function projectFiles() {
  var fileExists = fs.existsSync(path.resolve(process.cwd(), this.file));

  // scaffold out the tests based on env
  if (this.environment === 'Node') {
    this.template('_spec-node.js', 'spec/' + this.file);
    this.template('_package.json', 'package.json');
  } else if (this.environment === 'browser') {
    this.template('_index.html', 'index.html');
    this.template('_spec-browser.js', 'spec/' + this.file);
    this.template('_bower.json', 'bower.json');
    this.copy('bowerrc', '.bowerrc');
  }

  // Create the src file if one doesn't already exist
  if (!fileExists) {
    this.template((this.environment === 'Node' ? '_src-node.js' : '_src-browser.js'), this.file);
  }

  // this.copy('editorconfig', '.editorconfig');
  // this.copy('jshintrc', '.jshintrc');
};
<commit_msg>(fix) Issue with defaults<commit_after>'use strict';
var util = require('util');
var path = require('path');
var yeoman = require('yeoman-generator');
var fs = require('fs');

var TestGenerator = module.exports = function TestGenerator(args, options, config) {
  yeoman.generators.Base.apply(this, arguments);

  this.argument('appname', { type: String, required: false });
  this.appname = this.appname || path.basename(process.cwd());
  this.appname = this._.camelize(this._.slugify(this._.humanize(this.appname)));

  this.on('end', function () {
    // this.installDependencies({ skipInstall: options['skip-install'] });
    this.installDependencies({
      npm: this.environment === 'Node' ? true : false,
      bower: this.environment === 'browser' ? true : false,
      skipInstall: options['skip-install'],
      callback: function() {
        console.log('Everything is ready!');
      }
    });
  });

  this.pkg = JSON.parse(this.readFileAsString(path.join(__dirname, '../package.json')));
};

util.inherits(TestGenerator, yeoman.generators.Base);

TestGenerator.prototype.askFor = function askFor() {
  var cb = this.async();

  // have Yeoman greet the user.
  console.log(this.yeoman);

  var allFiles = fs.readdirSync(process.cwd());
  var prompts = [];

  var jsFiles = allFiles.filter( function( file ) {
    return file.substr(file.length - 3) === '.js';
  });

  prompts.push({
    type: 'list',
    name: 'environment',
    message: 'Do you want to test your algorithm in the browser or with Node?',
    choices: ['Node', 'browser'],
    default: 'browser'
  });

  if (jsFiles.length === 0) {
    prompts.push({
      name: 'algorithm',
      message: 'Please enter a name for the algorithm you\'d like to test',
      default: this.appname
    });
  } else {
    prompts.push({
      type: 'list',
      name: 'file',
      message: 'Hey, I found js files in this directory. Which one contains the algorithm you\'d like to test?',
      choices: jsFiles
    });
  }

  this.prompt(prompts, function (response) {
    this.file = response.file || response.algorithm + '.js';
    this.algorithm = response.algorithm || response.file.split('.')[0];
    this.environment = response.environment || 'browser';
    cb();
  }.bind(this));
};

TestGenerator.prototype.app = function projectFiles() {
  var fileExists = fs.existsSync(path.resolve(process.cwd(), this.file));

  // scaffold out the tests based on env
  if (this.environment === 'Node') {
    this.template('_spec-node.js', 'spec/' + this.file);
    this.template('_package.json', 'package.json');
  } else if (this.environment === 'browser') {
    this.template('_index.html', 'index.html');
    this.template('_spec-browser.js', 'spec/' + this.file);
    this.template('_bower.json', 'bower.json');
    this.copy('bowerrc', '.bowerrc');
  }

  // Create the src file if one doesn't already exist
  if (!fileExists) {
    this.template((this.environment === 'Node' ? '_src-node.js' : '_src-browser.js'), this.file);
  }

  // this.copy('editorconfig', '.editorconfig');
  // this.copy('jshintrc', '.jshintrc');
};
<|endoftext|>


<commit_before>'use strict';
var path = require('path');
var fs = require('fs');
var superb = require('superb');
var yeoman = require('yeoman-generator');
var _s = require('underscore.string');

module.exports = yeoman.generators.Base.extend({
	init: function () {
		var cb = this.async();

		this.prompt([{
			name: 'pluginName',
			message: 'What do you want to name your gulp plugin?',
			default: this.appname.replace(/\s/g, '-'),
			filter: function (val) {
				return _s.slugify(val.replace(/^gulp-/, ''));
			}.bind(this)
		}, {
			name: 'githubUsername',
			message: 'What is your GitHub username?',
			store: true,
			validate: function (val) {
				return val.length > 0 ? true : 'You have to provide a username';
			}
		}], function (props) {
			this.pluginName = props.pluginName;
			this.camelPluginName = _s.camelize(props.pluginName);
			this.githubUsername = props.githubUsername;
			this.name = this.user.git.name();
			this.email = this.user.git.email();
			this.superb = superb();

			// workaround npm issue
			fs.writeFileSync(path.join(this.sourceRoot(), '.gitignore'), 'node_modules\n');

			this.template('.editorconfig');
			this.template('.gitattributes');
			this.template('.gitignore');
			this.template('.jshintrc');
			this.template('.travis.yml');
			this.template('index.js');
			this.template('license');
			// needed so npm doesn't try to use it and fail
			this.template('_package.json', 'package.json');
			this.template('_readme.md', 'readme.md');
			this.template('test.js');

			cb();
		}.bind(this));
	}
});
<commit_msg>run `npm install` after scaffolding - fixes #6<commit_after>'use strict';
var path = require('path');
var fs = require('fs');
var superb = require('superb');
var yeoman = require('yeoman-generator');
var _s = require('underscore.string');

module.exports = yeoman.generators.Base.extend({
	init: function () {
		var cb = this.async();

		this.prompt([{
			name: 'pluginName',
			message: 'What do you want to name your gulp plugin?',
			default: this.appname.replace(/\s/g, '-'),
			filter: function (val) {
				return _s.slugify(val.replace(/^gulp-/, ''));
			}.bind(this)
		}, {
			name: 'githubUsername',
			message: 'What is your GitHub username?',
			store: true,
			validate: function (val) {
				return val.length > 0 ? true : 'You have to provide a username';
			}
		}], function (props) {
			this.pluginName = props.pluginName;
			this.camelPluginName = _s.camelize(props.pluginName);
			this.githubUsername = props.githubUsername;
			this.name = this.user.git.name();
			this.email = this.user.git.email();
			this.superb = superb();

			// workaround npm issue
			fs.writeFileSync(path.join(this.sourceRoot(), '.gitignore'), 'node_modules\n');

			this.template('.editorconfig');
			this.template('.gitattributes');
			this.template('.gitignore');
			this.template('.jshintrc');
			this.template('.travis.yml');
			this.template('index.js');
			this.template('license');
			// needed so npm doesn't try to use it and fail
			this.template('_package.json', 'package.json');
			this.template('_readme.md', 'readme.md');
			this.template('test.js');

			cb();
		}.bind(this));
	},
	install: function () {
		this.installDependencies({bower: false});
	}
});
<|endoftext|>


<commit_before>import $ from 'jquery';
import client from './lib/sprintly-client';
import router from './router'

// Enable React dev tools
var React = require('react');
window.React = React;
window.$ = $;

$(function() {
  window.manifold = router(client);
});
<commit_msg>removing jquery dep<commit_after>import client from './lib/sprintly-client';
import router from './router'

// Enable React dev tools
var React = require('react');
window.React = React;
window.manifold = router(client);
<|endoftext|>