<commit_before>define([
  './core',
  './method',
  './regex/unicode',
  './regex/typeset',
  './fibre'
], function( Han, $, UNICODE, TYPESET, Fibre ) {

function createBdGroup( portion, match ) {
  var clazz = portion.index === 0 && portion.isEnd
    ? 'biaodian cjk'
    : 'biaodian cjk portion ' + (
      portion.index === 0
      ? 'isFirst is-first'
      : portion.isEnd
      ? 'isEnd is-end'
      : 'isInner is-inner'
    )
  var elem = $.create( 'h-char-group', clazz )
  elem.innerHTML = portion.text
  return elem
}

function createBdChar( char ) {
  var div     = $.create( 'div' )
  var unicode = char.charCodeAt( 0 ).toString( 16 )
  var clazz   = 'biaodian cjk ' + (
    char.match( TYPESET.char.biaodian.open )
      ? 'bd-open'
      : char.match( TYPESET.char.biaodian.close )
      ? 'bd-close bd-end'
      : char.match( TYPESET.char.biaodian.end )
      ? 'bd-end'
      : char.match(new RegExp( UNICODE.biaodian.liga ))
      ? 'bd-liga'
      : ''
  )
  div.innerHTML = (
    '<h-char unicode="' + unicode +
    '" class="' + clazz +
    '">' + char + '</h-char>'
  )
  return div.firstChild
}

$.extend( Fibre.fn, {
  // Force punctuation & biaodian typesetting rules to be applied.
  jinzify: function( selector ) {
    return (
    this
    .filter( selector || null )
    .avoid( 'h-jinze' )
    .replace(
      TYPESET.jinze.touwei,
      function( portion, match ) {
        var elem = $.create( 'h-jinze', 'touwei' )
        elem.innerHTML = match[0]
        return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 ) ? elem : ''
      }
    )
    .replace(
      TYPESET.jinze.wei,
      function( portion, match ) {
        var elem = $.create( 'h-jinze', 'wei' )
        elem.innerHTML = match[0]
        return portion.index === 0 ? elem : ''
      }
    )
    .replace(
      TYPESET.jinze.tou,
      function( portion, match ) {
        var elem = $.create( 'h-jinze', 'tou' )
        elem.innerHTML = match[0]
        return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 )
          ? elem : ''
      }
    )
    .replace(
      TYPESET.jinze.middle,
      function( portion, match ) {
        var elem = $.create( 'h-jinze', 'middle' )
        elem.innerHTML = match[0]
        return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 )
          ? elem : ''
      }
    )
    .endAvoid()
    .endFilter()
    )
  },

  groupify: function( option ) {
    var option = $.extend({
      biaodian: false,
    //punct: false,
      hanzi: false,   // Includes Kana
      kana: false,
      eonmun: false,
      western: false  // Includes Latin, Greek and Cyrillic
    }, option || {})

    this.avoid( 'h-hangable, h-char-group, h-word' )

    if ( option.biaodian ) {
      this.replace(
        TYPESET.group.biaodian[ 0 ], createBdGroup
      ).replace(
        TYPESET.group.biaodian[ 1 ], createBdGroup
      )
    }
    if ( option.hanzi || option.cjk ) {
      this.wrap(
        TYPESET.group.hanzi, $.clone( $.create( 'h-char-group', 'hanzi cjk' ))
      )
    }
    if ( option.western ) {
      this.wrap(
        TYPESET.group.western, $.clone( $.create( 'h-word', 'western' ))
      )
    }
    if ( option.kana ) {
      this.wrap(
        TYPESET.group.kana, $.clone( $.create( 'h-char-group', 'kana' ))
      )
    }
    if ( option.eonmun || option.hangul ) {
      this.wrap(
        TYPESET.group.eonmun, $.clone( $.create( 'h-word', 'eonmun hangul' ))
      )
    }

    this.endAvoid()
    return this
  },

  charify: function( option ) {
    var option = $.extend({
      biaodian: false,
      punct: false,
      hanzi: false,     // Includes Kana
      latin: false,
      ellinika: false,
      kirillica: false,
      kana: false,
      eonmun: false
    }, option || {})

    this.avoid( 'h-char' )

    if ( option.biaodian ) {
      this.replace(
        TYPESET.char.biaodian.all,
        function( portion, match ) {  return createBdChar( match[0] )  }
      ).replace(
        TYPESET.char.biaodian.liga,
        function( portion, match ) {  return createBdChar( match[0] )  }
      )
    }
    if ( option.hanzi || option.cjk ) {
      this.wrap(
        TYPESET.char.hanzi, $.clone( $.create( 'h-char', 'hanzi cjk' ))
      )
    }
    if ( option.punct ) {
      this.wrap(
        TYPESET.char.punct.all, $.clone( $.create( 'h-char', 'punct' ))
      )
    }
    if ( option.latin ) {
      this.wrap(
        TYPESET.char.latin, $.clone( $.create( 'h-char', 'alphabet latin' ))
      )
    }
    if ( option.ellinika || option.greek ) {
      this.wrap(
        TYPESET.char.ellinika, $.clone( $.create( 'h-char', 'alphabet ellinika greek' ))
      )
    }
    if ( option.kirillica || option.cyrillic ) {
      this.wrap(
        TYPESET.char.kirillica, $.clone( $.create( 'h-char', 'alphabet kirillica cyrillic' ))
      )
    }
    if ( option.kana ) {
      this.wrap(
        TYPESET.char.kana, $.clone( $.create( 'h-char', 'kana' ))
      )
    }
    if ( option.eonmun || option.hangul ) {
      this.wrap(
        TYPESET.char.eonmun, $.clone( $.create( 'h-char', 'eonmun hangul' ))
      )
    }

    this.endAvoid()
    return this
  }
})

Han.find = Fibre

void [
  'setMode',
  'wrap', 'replace', 'revert',
  'addBoundary', 'removeBoundary',
  'avoid', 'endAvoid',
  'filter', 'endFilter',
  'jinzify', 'groupify', 'charify'
].forEach(function( method ) {
  Han.fn[ method ] = function() {
    if ( !this.finder ) {
      // Share the same selector
      this.finder = Han.find( this.context )
    }

    this.finder[ method ]( arguments[ 0 ], arguments[ 1 ] )
    return this
  }
})

return Han
})
<commit_msg>Add `Han.find.fn.normalize()`<commit_after>define([
  './core',
  './method',
  './regex/unicode',
  './regex/typeset',
  './fibre'
], function( Han, $, UNICODE, TYPESET, Fibre ) {

var isNodeNormalizeNormal = (function() {
    //// Disabled `Node.normalize()` for temp due to
    //// issue below in IE11.
    //// See: http://stackoverflow.com/questions/22337498/why-does-ie11-handle-node-normalize-incorrectly-for-the-minus-symbol
    var div = $.create( 'div' )

    div.appendChild( $.create( '', '0-' ))
    div.appendChild( $.create( '', '2' ))
    div.normalize()

    return div.firstChild.length !== 2
})()

function createBdGroup( portion, match ) {
  var clazz = portion.index === 0 && portion.isEnd
    ? 'biaodian cjk'
    : 'biaodian cjk portion ' + (
      portion.index === 0
      ? 'isFirst is-first'
      : portion.isEnd
      ? 'isEnd is-end'
      : 'isInner is-inner'
    )
  var elem = $.create( 'h-char-group', clazz )
  elem.innerHTML = portion.text
  return elem
}

function createBdChar( char ) {
  var div     = $.create( 'div' )
  var unicode = char.charCodeAt( 0 ).toString( 16 )
  var clazz   = 'biaodian cjk ' + (
    char.match( TYPESET.char.biaodian.open )
      ? 'bd-open'
      : char.match( TYPESET.char.biaodian.close )
      ? 'bd-close bd-end'
      : char.match( TYPESET.char.biaodian.end )
      ? 'bd-end'
      : char.match(new RegExp( UNICODE.biaodian.liga ))
      ? 'bd-liga'
      : ''
  )
  div.innerHTML = (
    '<h-char unicode="' + unicode +
    '" class="' + clazz +
    '">' + char + '</h-char>'
  )
  return div.firstChild
}

$.extend( Fibre.fn, {
  normalize: function() {
    if ( isNodeNormalizeNormal ) {
      this.context.normalize()
    }
    return this
  },

  // Force punctuation & biaodian typesetting rules to be applied.
  jinzify: function( selector ) {
    return (
    this
    .filter( selector || null )
    .avoid( 'h-jinze' )
    .replace(
      TYPESET.jinze.touwei,
      function( portion, match ) {
        var elem = $.create( 'h-jinze', 'touwei' )
        elem.innerHTML = match[0]
        return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 ) ? elem : ''
      }
    )
    .replace(
      TYPESET.jinze.wei,
      function( portion, match ) {
        var elem = $.create( 'h-jinze', 'wei' )
        elem.innerHTML = match[0]
        return portion.index === 0 ? elem : ''
      }
    )
    .replace(
      TYPESET.jinze.tou,
      function( portion, match ) {
        var elem = $.create( 'h-jinze', 'tou' )
        elem.innerHTML = match[0]
        return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 )
          ? elem : ''
      }
    )
    .replace(
      TYPESET.jinze.middle,
      function( portion, match ) {
        var elem = $.create( 'h-jinze', 'middle' )
        elem.innerHTML = match[0]
        return (( portion.index === 0 && portion.isEnd ) || portion.index === 1 )
          ? elem : ''
      }
    )
    .endAvoid()
    .endFilter()
    )
  },

  groupify: function( option ) {
    var option = $.extend({
      biaodian: false,
    //punct: false,
      hanzi: false,   // Includes Kana
      kana: false,
      eonmun: false,
      western: false  // Includes Latin, Greek and Cyrillic
    }, option || {})

    this.avoid( 'h-hangable, h-char-group, h-word' )

    if ( option.biaodian ) {
      this.replace(
        TYPESET.group.biaodian[ 0 ], createBdGroup
      ).replace(
        TYPESET.group.biaodian[ 1 ], createBdGroup
      )
    }
    if ( option.hanzi || option.cjk ) {
      this.wrap(
        TYPESET.group.hanzi, $.clone( $.create( 'h-char-group', 'hanzi cjk' ))
      )
    }
    if ( option.western ) {
      this.wrap(
        TYPESET.group.western, $.clone( $.create( 'h-word', 'western' ))
      )
    }
    if ( option.kana ) {
      this.wrap(
        TYPESET.group.kana, $.clone( $.create( 'h-char-group', 'kana' ))
      )
    }
    if ( option.eonmun || option.hangul ) {
      this.wrap(
        TYPESET.group.eonmun, $.clone( $.create( 'h-word', 'eonmun hangul' ))
      )
    }

    this.endAvoid()
    return this
  },

  charify: function( option ) {
    var option = $.extend({
      biaodian: false,
      punct: false,
      hanzi: false,     // Includes Kana
      latin: false,
      ellinika: false,
      kirillica: false,
      kana: false,
      eonmun: false
    }, option || {})

    this.avoid( 'h-char' )

    if ( option.biaodian ) {
      this.replace(
        TYPESET.char.biaodian.all,
        function( portion, match ) {  return createBdChar( match[0] )  }
      ).replace(
        TYPESET.char.biaodian.liga,
        function( portion, match ) {  return createBdChar( match[0] )  }
      )
    }
    if ( option.hanzi || option.cjk ) {
      this.wrap(
        TYPESET.char.hanzi, $.clone( $.create( 'h-char', 'hanzi cjk' ))
      )
    }
    if ( option.punct ) {
      this.wrap(
        TYPESET.char.punct.all, $.clone( $.create( 'h-char', 'punct' ))
      )
    }
    if ( option.latin ) {
      this.wrap(
        TYPESET.char.latin, $.clone( $.create( 'h-char', 'alphabet latin' ))
      )
    }
    if ( option.ellinika || option.greek ) {
      this.wrap(
        TYPESET.char.ellinika, $.clone( $.create( 'h-char', 'alphabet ellinika greek' ))
      )
    }
    if ( option.kirillica || option.cyrillic ) {
      this.wrap(
        TYPESET.char.kirillica, $.clone( $.create( 'h-char', 'alphabet kirillica cyrillic' ))
      )
    }
    if ( option.kana ) {
      this.wrap(
        TYPESET.char.kana, $.clone( $.create( 'h-char', 'kana' ))
      )
    }
    if ( option.eonmun || option.hangul ) {
      this.wrap(
        TYPESET.char.eonmun, $.clone( $.create( 'h-char', 'eonmun hangul' ))
      )
    }

    this.endAvoid()
    return this
  }
})

$.extend( Han, {
  isNodeNormalizeNormal: isNodeNormalizeNormal,
  find: Fibre
})

void [
  'setMode',
  'wrap', 'replace', 'revert',
  'addBoundary', 'removeBoundary',
  'avoid', 'endAvoid',
  'filter', 'endFilter',
  'jinzify', 'groupify', 'charify'
].forEach(function( method ) {
  Han.fn[ method ] = function() {
    if ( !this.finder ) {
      // Share the same selector
      this.finder = Han.find( this.context )
    }

    this.finder[ method ]( arguments[ 0 ], arguments[ 1 ] )
    return this
  }
})

return Han
})
<|endoftext|>


<commit_before>'use strict';

Darwinator.GameState = function() {
  this.player   = null;
  this.enemies  = null;
  this.cursors  = null;
  this.map      = null;
  this.tileset  = null;
  this.layer    = null;
  this.fps      = null;
  this.stats    = null;
  this.health   = null;
  this.pauseText = null;
  this.spawnPositions = [];
  this.numberOfEnemies = 10;
}

Darwinator.GameState.prototype = {

  create: function () {
    this.loadLevel();
    this.game.world.setBounds(0,0, this.map.widthInPixels, this.map.heightInPixels);

    this.cursors = this.game.input.keyboard.createCursorKeys();

    this.player = new Darwinator.Player(this.game, 160, 620, this.cursors, 100, 5, 5);
    this.player.scale.setTo(2,2);
    this.game.add.existing(this.player);
    this.game.camera.follow(this.player);

    this.initSpawnPosition();
    this.spawnEnemies();

    // For development only
    this.fps = this.game.add.text(16, 16, 'FPS: 0', { fontSize: '16px', fill: '#F08' });
    this.fps.fixedToCamera = true;

    this.stats = this.game.add.text(16, 40, '', { fontSize: '16px', fill: '#F08' });
    this.stats.fixedToCamera = true;

    this.health = this.game.add.text(16, 64, '', {fontSize: '16px', fill: '#F08' });
    this.health.fixedToCamera = true;

    this.gameOver = this.game.add.text(this.game.width / 2, this.game.height / 2, '', {fontSize: '48px', fill:'#F08'});
    this.gameOver.fixedToCamera = true;

    Darwinator.Pathfinder = new EasyStar.js();
    //Darwinator.Pathfinder.enableDiagonals();
    var indexes = Darwinator.Helpers.convertTileMap(this.map.layers[0].data);
    Darwinator.Pathfinder.setGrid(indexes);
    Darwinator.Pathfinder.setAcceptableTiles([1337, 168, 156, 157, 158, 172, 173, 174, 188, 189, 190, 205]);

    var x = this.game.width / 2
    , y = this.game.height / 2;
    this.pauseText = this.game.add.text(x, y, 'Game paused', { fontSize: '16px', fill: '#fff', align: 'center' });
    this.pauseText.anchor.setTo(0.5, 0.5);
    this.pauseText.fixedToCamera = true;
    this.pauseText.renderable = false;
    this.pauseText.visible = false;
  },

  loadLevel: function() {
    this.map = this.game.add.tilemap('level1');
    this.map.addTilesetImage('tiles', 'tiles');

    Darwinator.setTileSize(this.map.tileWidth, this.map.tileHeight);

    this.map.setCollisionByExclusion([1337, 168, 156, 157, 158, 172, 173, 174, 188, 189, 190, 205]);
    this.map.createLayer('Tile Layer 2');
    this.layer = this.map.createLayer('Tile Layer 1');
    this.layer.debug = true;

    this.map.collisionLayer = this.layer;
    this.layer.resizeWorld();
  },

  spawnEnemies: function () {
    var spawnIndexes = new Array(this.spawnPositions.length);

    for (var i = 0; i < spawnIndexes.length; i++) {
      spawnIndexes[i] = i;
    }

    var rInd;
    var pos;
    while (this.numberOfEnemies && spawnIndexes.length) {
      rInd = Math.round(Math.random() * spawnIndexes.length -1);
      pos = spawnIndexes.splice(rInd,1);
      this.enemies.add(new Darwinator.Enemy(this.game, this.player,
        this.spawnPositions[pos][0],
        this.spawnPositions[pos][1], 100));
      this.numberOfEnemies--;
    }
  },

  initSpawnPosition: function () {
    var matrix = Darwinator.Helpers.convertTileMap(this.map.layers[0].data);

    this.enemies = this.game.add.group();

    for (var i = 0; i < matrix.length; i++) {
      for(var j = 0; j < matrix[i].length; j++) {
        if (matrix[i][j] === 168){
          this.spawnPositions.push(Darwinator.Helpers.tileToPixels(j,i));
        }
      }
    }
  },

  update: function () {
    // TODO: Move this to the nonexistent resume callback
    if (this.pauseText.visible) this.pauseText.visible = false;

    this.game.physics.collide(this.player, this.layer);
    this.game.physics.collide(this.enemies, this.layer);
    this.game.physics.collide(this.enemies, this.enemies);

    // For development only
    this.fps.content = 'FPS: ' + this.game.time.fps;
    this.stats.content = 'Player stamina: ' + Math.round(this.player.currBreath) + '/' + this.player.stamina;
    this.health.content = 'Health: ' + this.player.health;
  },

  paused: function () {
    this.pauseText.visible = true;
  }

};
<commit_msg>Correctly matched the parameters passed to enemy<commit_after>'use strict';

Darwinator.GameState = function() {
  this.player   = null;
  this.enemies  = null;
  this.cursors  = null;
  this.map      = null;
  this.tileset  = null;
  this.layer    = null;
  this.fps      = null;
  this.stats    = null;
  this.health   = null;
  this.pauseText = null;
  this.spawnPositions = [];
  this.numberOfEnemies = 10;
}

Darwinator.GameState.prototype = {

  create: function () {
    this.loadLevel();
    this.game.world.setBounds(0,0, this.map.widthInPixels, this.map.heightInPixels);

    this.cursors = this.game.input.keyboard.createCursorKeys();

    this.player = new Darwinator.Player(this.game, 160, 620, this.cursors, 100, 5, 5);
    this.player.scale.setTo(2,2);
    this.game.add.existing(this.player);
    this.game.camera.follow(this.player);

    this.initSpawnPosition();
    this.spawnEnemies();

    // For development only
    this.fps = this.game.add.text(16, 16, 'FPS: 0', { fontSize: '16px', fill: '#F08' });
    this.fps.fixedToCamera = true;

    this.stats = this.game.add.text(16, 40, '', { fontSize: '16px', fill: '#F08' });
    this.stats.fixedToCamera = true;

    this.health = this.game.add.text(16, 64, '', {fontSize: '16px', fill: '#F08' });
    this.health.fixedToCamera = true;

    this.gameOver = this.game.add.text(this.game.width / 2, this.game.height / 2, '', {fontSize: '48px', fill:'#F08'});
    this.gameOver.fixedToCamera = true;

    Darwinator.Pathfinder = new EasyStar.js();
    //Darwinator.Pathfinder.enableDiagonals();
    var indexes = Darwinator.Helpers.convertTileMap(this.map.layers[0].data);
    Darwinator.Pathfinder.setGrid(indexes);
    Darwinator.Pathfinder.setAcceptableTiles([1337, 168, 156, 157, 158, 172, 173, 174, 188, 189, 190, 205]);

    var x = this.game.width / 2
    , y = this.game.height / 2;
    this.pauseText = this.game.add.text(x, y, 'Game paused', { fontSize: '16px', fill: '#fff', align: 'center' });
    this.pauseText.anchor.setTo(0.5, 0.5);
    this.pauseText.fixedToCamera = true;
    this.pauseText.renderable = false;
    this.pauseText.visible = false;
  },

  loadLevel: function() {
    this.map = this.game.add.tilemap('level1');
    this.map.addTilesetImage('tiles', 'tiles');

    Darwinator.setTileSize(this.map.tileWidth, this.map.tileHeight);

    this.map.setCollisionByExclusion([1337, 168, 156, 157, 158, 172, 173, 174, 188, 189, 190, 205]);
    this.map.createLayer('Tile Layer 2');
    this.layer = this.map.createLayer('Tile Layer 1');
    this.layer.debug = true;

    this.map.collisionLayer = this.layer;
    this.layer.resizeWorld();
  },

  spawnEnemies: function () {
    var spawnIndexes = new Array(this.spawnPositions.length);

    for (var i = 0; i < spawnIndexes.length; i++) {
      spawnIndexes[i] = i;
    }

    var rInd;
    var pos;
    while (this.numberOfEnemies && spawnIndexes.length) {
      rInd = Math.round(Math.random() * spawnIndexes.length -1);
      pos = spawnIndexes.splice(rInd,1);
      this.enemies.add(new Darwinator.Enemy(this.game, this.player,
        this.spawnPositions[pos][0],
        this.spawnPositions[pos][1], 100, 0, 0));
      this.numberOfEnemies--;
    }
  },

  initSpawnPosition: function () {
    var matrix = Darwinator.Helpers.convertTileMap(this.map.layers[0].data);

    this.enemies = this.game.add.group();

    for (var i = 0; i < matrix.length; i++) {
      for(var j = 0; j < matrix[i].length; j++) {
        if (matrix[i][j] === 168){
          this.spawnPositions.push(Darwinator.Helpers.tileToPixels(j,i));
        }
      }
    }
  },

  update: function () {
    // TODO: Move this to the nonexistent resume callback
    if (this.pauseText.visible) this.pauseText.visible = false;

    this.game.physics.collide(this.player, this.layer);
    this.game.physics.collide(this.enemies, this.layer);
    this.game.physics.collide(this.enemies, this.enemies);

    // For development only
    this.fps.content = 'FPS: ' + this.game.time.fps;
    this.stats.content = 'Player stamina: ' + Math.round(this.player.currBreath) + '/' + this.player.stamina;
    this.health.content = 'Health: ' + this.player.health;
  },

  paused: function () {
    this.pauseText.visible = true;
  }

};
<|endoftext|>


<commit_before>// Author: XrXr
// https://github.com/XrXr/WhenIsKateLive
// License: MIT
(function(){
    "use strict";
    var entry_date = new Date();

    var to_local = (function(){
        var target_offset = entry_date.getTimezoneOffset();
        return function(moment_instance){
            moment_instance.zone(target_offset);
            return moment_instance;
        };
    })();

    var streams = (function(){
        var PST_OFFSET = 480; // PST = GMT-8, 8 * 60 = 480. PST's offset from gmt is 480 minutes
        var PDT_OFFSET = 420;
        var weekday_names = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
        function iso_to_eng (num) {
            if (num < 1 || num > 7 || !Number.isInteger(num)){
                throw new Error("Invalid iso day of week");
            }
            return weekday_names[num - 1];
        }

        function eng_to_iso (name) {
            var lowered = name.toLowerCase();
            var index = weekday_names.indexOf(lowered);
            if (index === -1){
                throw new Error("Invalid weekday name");
            }
            return index + 1;
        }

        function Schedule(weekday_name, start, duration) {
            // This object makes schedule entries readable
            if (!(this instanceof Schedule)){
                return new Schedule(weekday_name, start, duration);
            }
            this.key = weekday_name.toLowerCase();
            this.start = start;
            this.isoWeekday = eng_to_iso(weekday_name);
            this.duration = duration;
        }
        // its probably better to construct these in less steps
        // however this is much more readable;
        var SCHEDULE = [Schedule("Monday", 20, 3),
                        Schedule("Tuesday", 13, 2),
                        Schedule("Thursday", 22, 2),
                        Schedule("Saturday", 20, 3)];

        function Stream(start_time, duration) {
            // new Stream() and Stream() both work
            if (!(this instanceof Stream)){
                return new Stream(start_time, duration);
            }
            this.start = start_time.clone();
            this.end = start_time.clone();
            this.end.add('hours', duration);
            this.duration = duration;
        }

        Stream.prototype.convert_time = function(){
            to_local(this.start);
            to_local(this.end);
        };

        Stream.prototype.normalize = function(){
            // move start and end to the first week of 1970
            this.start.year(1970);
            this.start.isoWeek(1);

            this.end.year(1970);
            this.end.isoWeek(1);
        };

        Stream.prototype.toString = function(){
            var start_signature = this.start.format("a");
            if (start_signature === this.end.format("a")){
                return this.start.format("h") + " to " +
                       this.end.format("h") + " " + start_signature;
            }
            return this.start.format("h a") + " to " + this.end.format("h a");
        };

        Stream.prototype.is_live = function(timestamp){
            // timestamp needs to be normalized first
            return timestamp >= this.start.unix() && timestamp <= this.end.unix();
        };

        var streams = {};
        var base = moment(0);
        base.zone(PST_OFFSET);
        // very glad ther is only one defination of DST
        if (moment(entry_date).isDST()){
            base.zone(PDT_OFFSET);
        }
        var temp = null;
        Object.defineProperty(streams, "length", {value: SCHEDULE.length});
        SCHEDULE.forEach(function(e, index){
            temp = base.clone();
            temp.isoWeekday(e.isoWeekday);
            temp.hours(e.start);
            streams[index] = new Stream(temp, e.duration);
            streams[index].convert_time();
        });

        function compare_moment_instance (a, b) {
            return a.start.unix() - b.start.unix();
        }

        Object.defineProperty(streams, "get_sorted_array", {
            // return an array with all the Stream sorted in
            // chronological order
            value: (function(){
                // sort once
                var sorted = null;
                return function (){
                    if (sorted !== null){
                        return sorted;
                    }
                    var result = [];
                    for (var key in this) {
                        if (this.hasOwnProperty(key)) {
                            result.push(this[key]);
                        }
                    }
                    sorted = result.sort(compare_moment_instance);
                    return result;
                };
            })()
        });
        return streams;
    })();

    function normalize (moment_instance) {
        // return a Moment instance that has the same day of week and hour info
        // with the begining of the week at the Unix Epoch.
        // does not mutate the original
        var normalized = moment(0);
        // This should do nothing in a normal use case. However, if the system timezone is changed
        // during the execution of this script, this will make sure all the output is self consistent
        // (all times are converted to the first observed timezone)
        to_local(normalized);
        normalized.year(1970);
        normalized.isoWeek(1);
        normalized.isoWeekday(moment_instance.isoWeekday());
        normalized.hours(moment_instance.hours());
        normalized.minutes(moment_instance.minutes());
        normalized.seconds(moment_instance.seconds());
        return normalized;
    }

    function find_next_stream (streams, now) {
        // return a Stream that is currently live
        // if no such Stream exist, return the Stream with the closest start time
        var sorted = streams.get_sorted_array();
        var found;
        sorted.some(function(stream, index){
            if (now.isAfter(stream.end)){
                return false;  // continue
            }
            found = stream;
            return true; // break
        });
        if (!found){
            return sorted[0];
        }
        return found;
    }

    var get_countdown = (function(){
        function pluralize (integer, string) {
            var base = integer + " " + string;
            if (integer > 1){
                return base + 's';
            }
            return base;
        }

        function format_countdown (in_seconds) {
            var duration = moment.duration(in_seconds * 1000);
            var days = duration.days();
            var hours = duration.hours();
            var minutes = duration.minutes();
            var seconds = duration.seconds();
            var result = [];
            if (days){
                result.push(pluralize(days, 'day'));
            }
            if (hours){
                result.push(pluralize(hours, 'hour'));
            }
            if (minutes){
                result.push(pluralize(minutes, 'minute'));
            }
            if (seconds){
                result.push(pluralize(seconds, 'second'));
            }
            return result.join(", ");
        }

        function get_countdown (now_unix, stream) {
            var delta = stream.start.unix() - now_unix;
            if (delta > 0){
                return format_countdown(delta);
            }
            if (delta < 0){
                return format_countdown(stream.start.clone().add('weeks', 1).unix() - now_unix);
            }
            // this should never happen. See tick()
            throw new Error("get_countdown() called with Invalid arguments");
        }
        return get_countdown;
    })();

    var update_dom = (function(){
        function find (selector) {
            return document.querySelector(selector);
        }

        function get_regex (name) {
            return new RegExp("(?:^|\\s)" +
                name + "(?!\\S)", 'g');
        }

        function add_class (node, name) {
            if (node.className === ""){
                node.className += " " + name;
            }
        }

        function remove_class (node, name) {
            if (!node.className){
                return;
            }
            if (node.className.match(get_regex(name)).length > 0){
                node.className = node.className.replace(get_regex(name), '');
            }
        }

        var trs = document.querySelectorAll('tr');
        var head_tr = trs[0];
        while (head_tr.children.length < streams.length){
            head_tr.appendChild(document.createElement("th"));
        }
        for (var i = 0; i < streams.length; i++) {
            head_tr.children[i].textContent = streams[i].start.format("dddd");
        }

        var body_tr = trs[1];
        while (body_tr.children.length < streams.length){
            body_tr.appendChild(document.createElement("td"));
        }
        for (var i = 0; i < streams.length; i++) {
            body_tr.children[i].textContent = streams[i].toString();
        }

        find("small").textContent = "All times are converted to your local time";

        var prefix = find("h3");
        var countdown = find("h1").children[0];
        var hide_class = "soft-hide";
        var clock = "disguise prefix";

        function update_dom (live, countdown_string) {
            // second argument is ignored if live is true
            if (live){
                add_class(prefix, hide_class);
                remove_class(countdown, clock);
                countdown.textContent = "Kate is live right now! Click to watch";
                countdown.href = "http://www.twitch.tv/lovelymomo";
                return;
            }
            remove_class(prefix, hide_class);
            add_class(countdown, clock);
            countdown.textContent = countdown_string;
            countdown.href = "#";
        }
        return update_dom;
    })();

    var stream = streams[0];
    var last_check = true;
    // TODO: this needs better implementation
    // countdown dom update should be in the fastest lane
    function tick() {
        // check if the stream currently holding is live
        // yes -> show dom
        // no  -> was the last live check yes?
        //        yes -> change holding stream to the next stream, recursion
        //         no -> calculate time until start, show dom
        var now = normalize(moment());
        var now_unix = now.unix();
        var is_live = stream.is_live(now_unix);
        if (is_live){
            last_check = true;
            return update_dom(true);
        }
        // TODO: this could be: check if now is after stream.end
        if (last_check){
            last_check = false;
            stream = find_next_stream(streams, now);
            return tick();
        }
        last_check = false;
        return update_dom(false, get_countdown(now_unix, stream));
    }
    /********Entry point*********/
    tick();
    setInterval(tick, 1000);
})();<commit_msg>Fix typo in comment<commit_after>// Author: XrXr
// https://github.com/XrXr/WhenIsKateLive
// License: MIT
(function(){
    "use strict";
    var entry_date = new Date();

    var to_local = (function(){
        var target_offset = entry_date.getTimezoneOffset();
        return function(moment_instance){
            moment_instance.zone(target_offset);
            return moment_instance;
        };
    })();

    var streams = (function(){
        var PST_OFFSET = 480; // PST = GMT-8, 8 * 60 = 480. PST's offset from gmt is 480 minutes
        var PDT_OFFSET = 420;
        var weekday_names = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"];
        function iso_to_eng (num) {
            if (num < 1 || num > 7 || !Number.isInteger(num)){
                throw new Error("Invalid iso day of week");
            }
            return weekday_names[num - 1];
        }

        function eng_to_iso (name) {
            var lowered = name.toLowerCase();
            var index = weekday_names.indexOf(lowered);
            if (index === -1){
                throw new Error("Invalid weekday name");
            }
            return index + 1;
        }

        function Schedule(weekday_name, start, duration) {
            // This object makes schedule entries readable
            if (!(this instanceof Schedule)){
                return new Schedule(weekday_name, start, duration);
            }
            this.key = weekday_name.toLowerCase();
            this.start = start;
            this.isoWeekday = eng_to_iso(weekday_name);
            this.duration = duration;
        }
        // its probably better to construct these in less steps
        // however this is much more readable;
        var SCHEDULE = [Schedule("Monday", 20, 3),
                        Schedule("Tuesday", 13, 2),
                        Schedule("Thursday", 22, 2),
                        Schedule("Saturday", 20, 3)];

        function Stream(start_time, duration) {
            // new Stream() and Stream() both work
            if (!(this instanceof Stream)){
                return new Stream(start_time, duration);
            }
            this.start = start_time.clone();
            this.end = start_time.clone();
            this.end.add('hours', duration);
            this.duration = duration;
        }

        Stream.prototype.convert_time = function(){
            to_local(this.start);
            to_local(this.end);
        };

        Stream.prototype.normalize = function(){
            // move start and end to the first week of 1970
            this.start.year(1970);
            this.start.isoWeek(1);

            this.end.year(1970);
            this.end.isoWeek(1);
        };

        Stream.prototype.toString = function(){
            var start_signature = this.start.format("a");
            if (start_signature === this.end.format("a")){
                return this.start.format("h") + " to " +
                       this.end.format("h") + " " + start_signature;
            }
            return this.start.format("h a") + " to " + this.end.format("h a");
        };

        Stream.prototype.is_live = function(timestamp){
            // timestamp needs to be normalized first
            return timestamp >= this.start.unix() && timestamp <= this.end.unix();
        };

        var streams = {};
        var base = moment(0);
        base.zone(PST_OFFSET);
        // very glad there is only one defination of DST
        if (moment(entry_date).isDST()){
            base.zone(PDT_OFFSET);
        }
        var temp = null;
        Object.defineProperty(streams, "length", {value: SCHEDULE.length});
        SCHEDULE.forEach(function(e, index){
            temp = base.clone();
            temp.isoWeekday(e.isoWeekday);
            temp.hours(e.start);
            streams[index] = new Stream(temp, e.duration);
            streams[index].convert_time();
        });

        function compare_moment_instance (a, b) {
            return a.start.unix() - b.start.unix();
        }

        Object.defineProperty(streams, "get_sorted_array", {
            // return an array with all the Stream sorted in
            // chronological order
            value: (function(){
                // sort once
                var sorted = null;
                return function (){
                    if (sorted !== null){
                        return sorted;
                    }
                    var result = [];
                    for (var key in this) {
                        if (this.hasOwnProperty(key)) {
                            result.push(this[key]);
                        }
                    }
                    sorted = result.sort(compare_moment_instance);
                    return result;
                };
            })()
        });
        return streams;
    })();

    function normalize (moment_instance) {
        // return a Moment instance that has the same day of week and hour info
        // with the begining of the week at the Unix Epoch.
        // does not mutate the original
        var normalized = moment(0);
        // This should do nothing in a normal use case. However, if the system timezone is changed
        // during the execution of this script, this will make sure all the output is self consistent
        // (all times are converted to the first observed timezone)
        to_local(normalized);
        normalized.year(1970);
        normalized.isoWeek(1);
        normalized.isoWeekday(moment_instance.isoWeekday());
        normalized.hours(moment_instance.hours());
        normalized.minutes(moment_instance.minutes());
        normalized.seconds(moment_instance.seconds());
        return normalized;
    }

    function find_next_stream (streams, now) {
        // return a Stream that is currently live
        // if no such Stream exist, return the Stream with the closest start time
        var sorted = streams.get_sorted_array();
        var found;
        sorted.some(function(stream, index){
            if (now.isAfter(stream.end)){
                return false;  // continue
            }
            found = stream;
            return true; // break
        });
        if (!found){
            return sorted[0];
        }
        return found;
    }

    var get_countdown = (function(){
        function pluralize (integer, string) {
            var base = integer + " " + string;
            if (integer > 1){
                return base + 's';
            }
            return base;
        }

        function format_countdown (in_seconds) {
            var duration = moment.duration(in_seconds * 1000);
            var days = duration.days();
            var hours = duration.hours();
            var minutes = duration.minutes();
            var seconds = duration.seconds();
            var result = [];
            if (days){
                result.push(pluralize(days, 'day'));
            }
            if (hours){
                result.push(pluralize(hours, 'hour'));
            }
            if (minutes){
                result.push(pluralize(minutes, 'minute'));
            }
            if (seconds){
                result.push(pluralize(seconds, 'second'));
            }
            return result.join(", ");
        }

        function get_countdown (now_unix, stream) {
            var delta = stream.start.unix() - now_unix;
            if (delta > 0){
                return format_countdown(delta);
            }
            if (delta < 0){
                return format_countdown(stream.start.clone().add('weeks', 1).unix() - now_unix);
            }
            // this should never happen. See tick()
            throw new Error("get_countdown() called with Invalid arguments");
        }
        return get_countdown;
    })();

    var update_dom = (function(){
        function find (selector) {
            return document.querySelector(selector);
        }

        function get_regex (name) {
            return new RegExp("(?:^|\\s)" +
                name + "(?!\\S)", 'g');
        }

        function add_class (node, name) {
            if (node.className === ""){
                node.className += " " + name;
            }
        }

        function remove_class (node, name) {
            if (!node.className){
                return;
            }
            if (node.className.match(get_regex(name)).length > 0){
                node.className = node.className.replace(get_regex(name), '');
            }
        }

        var trs = document.querySelectorAll('tr');
        var head_tr = trs[0];
        while (head_tr.children.length < streams.length){
            head_tr.appendChild(document.createElement("th"));
        }
        for (var i = 0; i < streams.length; i++) {
            head_tr.children[i].textContent = streams[i].start.format("dddd");
        }

        var body_tr = trs[1];
        while (body_tr.children.length < streams.length){
            body_tr.appendChild(document.createElement("td"));
        }
        for (var i = 0; i < streams.length; i++) {
            body_tr.children[i].textContent = streams[i].toString();
        }

        find("small").textContent = "All times are converted to your local time";

        var prefix = find("h3");
        var countdown = find("h1").children[0];
        var hide_class = "soft-hide";
        var clock = "disguise prefix";

        function update_dom (live, countdown_string) {
            // second argument is ignored if live is true
            if (live){
                add_class(prefix, hide_class);
                remove_class(countdown, clock);
                countdown.textContent = "Kate is live right now! Click to watch";
                countdown.href = "http://www.twitch.tv/lovelymomo";
                return;
            }
            remove_class(prefix, hide_class);
            add_class(countdown, clock);
            countdown.textContent = countdown_string;
            countdown.href = "#";
        }
        return update_dom;
    })();

    var stream = streams[0];
    var last_check = true;
    // TODO: this needs better implementation
    // countdown dom update should be in the fastest lane
    function tick() {
        // check if the stream currently holding is live
        // yes -> show dom
        // no  -> was the last live check yes?
        //        yes -> change holding stream to the next stream, recursion
        //         no -> calculate time until start, show dom
        var now = normalize(moment());
        var now_unix = now.unix();
        var is_live = stream.is_live(now_unix);
        if (is_live){
            last_check = true;
            return update_dom(true);
        }
        // TODO: this could be: check if now is after stream.end
        if (last_check){
            last_check = false;
            stream = find_next_stream(streams, now);
            return tick();
        }
        last_check = false;
        return update_dom(false, get_countdown(now_unix, stream));
    }
    /********Entry point*********/
    tick();
    setInterval(tick, 1000);
})();<|endoftext|>


<commit_before>var React = require('react');
var intl = require('./translate.js')
var {FormControl, InputGroup, FormGroup, Col, Row, Grid, Button, ButtonGroup} = require('react-bootstrap');
var {ColP} = require('./gridp.js')
var GlobalConst = require('./global_const.js')

// inject GlobalConst...
var elementRelation = GlobalConst.elementRelation
var bahamutRelation = GlobalConst.bahamutRelation
var bahamutFURelation = GlobalConst.bahamutFURelation
var supportAbilities = GlobalConst.supportAbilities
var selector = GlobalConst.selector
var zenith = GlobalConst.zenith
var Jobs = GlobalConst.Jobs
var armTypes = GlobalConst.armTypes
var jobTypes = GlobalConst.jobTypes
var keyTypes = GlobalConst.keyTypes
var skilltypes = GlobalConst.skilltypes
var skillAmounts = GlobalConst.skillAmounts
var elementTypes = GlobalConst.elementTypes
var summonTypes = GlobalConst.summonTypes
var summonElementTypes = GlobalConst.summonElementTypes
var raceTypes = GlobalConst.raceTypes
var filterElementTypes = GlobalConst.filterElementTypes
var enemyDefenseType = GlobalConst.enemyDefenseType

var SummonList = React.createClass({
    getInitialState: function() {
        var sm = []
        for(var i=0; i < this.props.summonNum; i++) { sm.push(i); }

        return {
            smlist: [],
            defaultElement: "fire",
            summons: sm,
            arrayForCopy: {},
        };
    },
    updateSummonNum: function(num) {
        var summons = this.state.summons

        if(summons.length < num) {
            var maxvalue = Math.max.apply(null, summons)
            for(var i = 0; i < (num - summons.length); i++){
                summons.push(i + maxvalue + 1)
            }
        } else {
            // ==の場合は考えなくてよい (問題がないので)
            while(summons.length > num){
                summons.pop();
            }
        }
        this.setState({summons: summons})
    },
    componentWillReceiveProps: function(nextProps) {
        if(nextProps.dataName != this.props.dataName) {
            this.setState({smlist: nextProps.dataForLoad});
            return 0;
        }

        if (parseInt(nextProps.summonNum) < parseInt(this.props.summonNum)) {
            var newsmlist = this.state.smlist;
            while(newsmlist.length > nextProps.summonNum) {
                newsmlist.pop();
            }
            this.setState({smlist: newsmlist})
        }
        this.updateSummonNum(nextProps.summonNum)
    },
    handleOnCopy: function(id, keyid, state) {
        var newsummons = this.state.summons
        var maxvalue = Math.max.apply(null, newsummons)

        newsummons.splice(id + 1, 0, maxvalue + 1)
        newsummons.pop();
        this.setState({summons: newsummons})

        // arrayForCopyにコピー対象のstateを入れておいて、
        // componentDidMountで読み出されるようにする
        var newArrayForCopy = this.state.arrayForCopy;
        newArrayForCopy[id + 1] = state;
        this.setState(newArrayForCopy);

        // smlist側の更新
        var newsmlist = this.state.smlist;
        newsmlist.splice(id + 1, 0, state)
        newsmlist.pop();
        this.setState({smlist: newsmlist})

        // Root へ変化を伝搬
        this.props.onChange(newsmlist);
    },
    handleOnRemove: function(id, keyid, state) {
        // 第3引数の state は初期stateが入っている
        var newsummons = this.state.summons
        var maxvalue = Math.max.apply(null, newsummons)

        // 該当の "key" を持つものを削除する
        newsummons.splice(this.state.summons.indexOf(keyid), 1)
        // 1個補充
        newsummons.push(maxvalue + 1)
        this.setState({summons: newsummons})

        // arrayForCopyに初期stateを入れておいて、
        // componentDidMountで読み出されるようにする
        // (二重にonChangeが呼び出されることを防ぐ)
        var newArrayForCopy = this.state.arrayForCopy;
        newArrayForCopy[newsummons.length - 1] = state;
        this.setState(newArrayForCopy);

        var newsmlist = this.state.smlist;
        // 削除した分をalistからも削除
        newsmlist.splice(id, 1)
        // 1個補充
        newsmlist.push(state)
        this.setState({smlist: newsmlist})

        // Root へ変化を伝搬
        this.props.onChange(newsmlist);
    },
    handleOnChange: function(key, state){
        var newsmlist = this.state.smlist;
        newsmlist[key] = state;
        this.setState({smlist: newsmlist})
        this.props.onChange(newsmlist);
    },
    handleEvent: function(key, e) {
        var newState = this.state
        newState[key] = e.target.value
        this.setState(newState)
    },
    render: function() {
        var locale = this.props.locale;
        var summons = this.state.summons;
        var hChange = this.handleOnChange;
        var hRemove = this.handleOnRemove;
        var hCopy = this.handleOnCopy;
        var dataName = this.props.dataName;
        var defaultElement = this.state.defaultElement;
        var dataForLoad = this.props.dataForLoad;
        var arrayForCopy = this.state.arrayForCopy;

        return (

                {intl.translate("属性一括変更", locale)}
                <FormControl componentClass="select" value={this.state.defaultElement} onChange={this.handleEvent.bind(this, "defaultElement")}> {selector[locale].summonElements} </FormControl>

 {intl.translate("召喚石", locale)}

                <Grid fluid>
                    <Row>
                    {summons.map(function(sm, ind) {
                        return <Summon key={sm} keyid={sm} onRemove={hRemove} onCopy={hCopy} onChange={hChange} id={ind} dataName={dataName} defaultElement={defaultElement} locale={locale} dataForLoad={dataForLoad} arrayForCopy={arrayForCopy[ind]}/>;
                    })}
                    </Row>
                </Grid>

        );
    }
});

var Summon = React.createClass({
    getInitialState: function() {
        return {
            selfSummonType: "magna",
            selfSummonAmount: 100,
            selfSummonAmount2: 0,
            selfElement: "fire",
            friendSummonType: "element",
            friendSummonAmount: 80,
            friendSummonAmount2: 0,
            friendElement: "fire",
            attack: 0,
            hp: 0,
            hpBonus: 0,
            DA: 0,
            TA: 0,
            criticalRatio: 0.0,
        };
    },
    componentDidMount: function(){
       var state = this.state;

       // もし dataForLoad に自分に該当するキーがあるなら読み込む
       // (データロード時に新しく増えた場合)
       if(this.props.dataForLoad != undefined) {
           var summon = this.props.dataForLoad;

           if(this.props.id in summon) {
               state = summon[this.props.id]
               this.setState(state)
               return 0;
           }
       }

       // もし arrayForCopy に自分に該当するキーがあるなら読み込む
       // (コピーの場合)
       if(this.props.arrayForCopy != undefined) {
           var state = this.props.arrayForCopy;
           this.setState(state)
           return 0;
       }

       // 初期化後 state を 上の階層に渡しておく
       // summonList では onChange が勝手に上に渡してくれるので必要なし
       this.props.onChange(this.props.id, state);
    },
    componentWillReceiveProps: function(nextProps){
        // データロード時のみ読み込み
        if(nextProps.dataName != this.props.dataName) {
            // 対応するIDが無い場合は undefined が飛んでくる
            if(nextProps.dataForLoad != undefined) {
               var summon = nextProps.dataForLoad;

               if(this.props.id in summon) {
                   this.setState(summon[this.props.id])
               }
            }
            return 0;
        }

        if(nextProps.defaultElement != this.props.defaultElement) {
            var newState = this.state
            newState["selfElement"] = nextProps.defaultElement
            newState["friendElement"] = nextProps.defaultElement
            this.setState(newState);
            this.props.onChange(this.props.id, newState);
        }
    },
    handleEvent: function(key, e) {
        var newState = this.state
        newState[key] = e.target.value
        this.setState(newState)
    },
    handleSelectEvent: function(key, e) {
        var newState = this.state
        newState[key] = e.target.value
        this.setState(newState)
        this.props.onChange(this.props.id, newState)
    },
    handleOnBlur: function(e) {
        this.props.onChange(this.props.id, this.state)
    },
    clickRemoveButton: function(e) {
        this.props.onRemove(this.props.id, this.props.keyid, this.getInitialState())
    },
    clickCopyButton: function(e, state) {
        this.props.onCopy(this.props.id, this.props.keyid, this.state)
    },
    handleSummonAmountChange(type, ind, e){
        var newState = this.state
        if(type == "self") {
            if(ind == 0){
                newState["selfSummonAmount"] = e.target.value
            } else {
                newState["selfSummonAmount2"] = e.target.value
            }
        } else {
            if(ind == 0){
                newState["friendSummonAmount"] = e.target.value
            } else {
                newState["friendSummonAmount2"] = e.target.value
            }
        }
        this.setState(newState)
        this.props.onChange(this.props.id, newState)
    },
    render: function() {
        var locale = this.props.locale

        var selfSummon = [{"label": "", "input": "select"}, {"input": "hidden"}]
        if(this.state.selfSummonType == "odin"){
            selfSummon[1] = {"label": intl.translate("キャラ", locale)+ " ", "input": "select"}
            selfSummon[0].label = intl.translate("属性", locale) + " "
        }
        var friendSummon = [{"label": "", "input": "select"}, {"input": "hidden"}]
        if(this.state.friendSummonType == "odin"){
            friendSummon[1] = {"label": intl.translate("キャラ", locale) + " ", "input": "select"}
            friendSummon[0].label = intl.translate("属性", locale) + " "
        }
        return (
            <ColP sxs={12} ssm={6} smd={4} className="col-no-bordered">

                            {intl.translate("自分の石", locale)}

                                <FormControl componentClass="select" value={this.state.selfElement} onChange={this.handleSelectEvent.bind(this, "selfElement")} >{selector[locale].summonElements}</FormControl>

                                <FormControl componentClass="select" value={this.state.selfSummonType} onChange={this.handleSelectEvent.bind(this, "selfSummonType")} >{selector[locale].summons}</FormControl>

                                {selfSummon[0].label}<FormControl componentClass="select" value={this.state.selfSummonAmount} onChange={this.handleSummonAmountChange.bind(this, "self", 0)}>{selector.summonAmounts}</FormControl>
                                {selfSummon[1].label}<FormControl componentClass="select" className={selfSummon[1].input} value={this.state.selfSummonAmount2} onChange={this.handleSummonAmountChange.bind(this, "self", 1)}>{selector.summonAmounts}</FormControl>

                            {intl.translate("フレの石", locale)}

                                <FormControl componentClass="select" value={this.state.friendElement} onChange={this.handleSelectEvent.bind(this, "friendElement")} >{selector[locale].summonElements}</FormControl>

                                <FormControl componentClass="select" value={this.state.friendSummonType} onChange={this.handleSelectEvent.bind(this, "friendSummonType")} >{selector[locale].summons}</FormControl>

                                {friendSummon[0].label}<FormControl componentClass="select" value={this.state.friendSummonAmount} onChange={this.handleSummonAmountChange.bind(this, "friend", 0)}>{selector.summonAmounts}</FormControl>
                                {friendSummon[1].label}<FormControl componentClass="select" className={friendSummon[1].input} value={this.state.friendSummonAmount2} onChange={this.handleSummonAmountChange.bind(this, "friend", 1)}>{selector.summonAmounts}</FormControl>

                            {intl.translate("合計攻撃力", locale)}

                                <FormControl type="number" min="0" value={this.state.attack} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "attack")}/>

                            {intl.translate("合計HP", locale)}

                                <FormControl type="number" min="0" value={this.state.hp} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "hp")}/>

                            {intl.translate("HP加護", locale)}

                    <FormControl type="number" min="0" value={this.state.hpBonus} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "hpBonus")}/>

                            {intl.translate("DA加護", locale)}

                    <FormControl type="number" min="0" value={this.state.DA} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "DA")}/>

                            {intl.translate("TA加護", locale)}

                                <FormControl type="number" min="0" value={this.state.TA} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "TA")}/>

                <ButtonGroup style={{"width": "100%"}}>
                    <Button bsStyle="primary" style={{"width": "50%", "margin": "2px 0px 2px 0px"}} onClick={this.clickRemoveButton}>{intl.translate("内容を消去", locale)}</Button>
                    <Button bsStyle="primary" style={{"width": "50%", "margin": "2px 0px 2px 0px"}} onClick={this.clickCopyButton}>{intl.translate("コピー", locale)}</Button>
                </ButtonGroup>
            </ColP>
        );
    }
});

module.exports.SummonList = SummonList;
module.exports.Summon = Summon;
<commit_msg>召喚石のコピーと削除の挙動を修正. #38<commit_after>var React = require('react');
var intl = require('./translate.js')
var {FormControl, InputGroup, FormGroup, Col, Row, Grid, Button, ButtonGroup} = require('react-bootstrap');
var {ColP} = require('./gridp.js')
var GlobalConst = require('./global_const.js')

// inject GlobalConst...
var elementRelation = GlobalConst.elementRelation
var bahamutRelation = GlobalConst.bahamutRelation
var bahamutFURelation = GlobalConst.bahamutFURelation
var supportAbilities = GlobalConst.supportAbilities
var selector = GlobalConst.selector
var zenith = GlobalConst.zenith
var Jobs = GlobalConst.Jobs
var armTypes = GlobalConst.armTypes
var jobTypes = GlobalConst.jobTypes
var keyTypes = GlobalConst.keyTypes
var skilltypes = GlobalConst.skilltypes
var skillAmounts = GlobalConst.skillAmounts
var elementTypes = GlobalConst.elementTypes
var summonTypes = GlobalConst.summonTypes
var summonElementTypes = GlobalConst.summonElementTypes
var raceTypes = GlobalConst.raceTypes
var filterElementTypes = GlobalConst.filterElementTypes
var enemyDefenseType = GlobalConst.enemyDefenseType

var SummonList = React.createClass({
    getInitialState: function() {
        // summonsはkey管理のためだけの配列
        // summonsのindexが表示順 = Summonのprops.idになる
        var sm = []
        for(var i=0; i < this.props.summonNum; i++) { sm.push(i); }

        return {
            smlist: [],
            defaultElement: "fire",
            summons: sm,
            arrayForCopy: {},
        };
    },
    updateSummonNum: function(num) {
        var summons = this.state.summons

        if(summons.length < num) {
            var maxvalue = Math.max.apply(null, summons)
            for(var i = 0; i < (num - summons.length); i++){
                summons.push(i + maxvalue + 1)
            }
        } else {
            // ==の場合は考えなくてよい (問題がないので)
            while(summons.length > num){
                summons.pop();
            }
        }
        this.setState({summons: summons})
    },
    componentWillReceiveProps: function(nextProps) {
        if(nextProps.dataName != this.props.dataName) {
            this.setState({smlist: nextProps.dataForLoad});
            return 0;
        }

        if (parseInt(nextProps.summonNum) < parseInt(this.props.summonNum)) {
            var newsmlist = this.state.smlist;
            while(newsmlist.length > nextProps.summonNum) {
                newsmlist.pop();
            }
            this.setState({smlist: newsmlist})
        }
        this.updateSummonNum(nextProps.summonNum)
    },
    handleOnCopy: function(id, state) {
        // arrayForCopyにコピー対象のstateを入れておいて、
        // componentWillReceivePropsで読み出されるようにする
        var newArrayForCopy = this.state.arrayForCopy;
        newArrayForCopy[id + 1] = JSON.parse(JSON.stringify(state));
        this.setState(newArrayForCopy);

        // smlist側の更新
        var newsmlist = this.state.smlist;
        newsmlist[id + 1] = JSON.parse(JSON.stringify(state))
        this.setState({smlist: newsmlist})

        // Root へ変化を伝搬
        this.props.onChange(newsmlist);
    },
    handleOnRemove: function(id, initialState) {
        // arrayForCopyに初期stateを入れておいて、
        // componentWillReceivePropsで読み出されるようにする
        var newArrayForCopy = this.state.arrayForCopy;
        newArrayForCopy[id] = initialState;
        this.setState(newArrayForCopy);

        // smlist側の更新
        var newsmlist = this.state.smlist;
        newsmlist[id] = initialState;
        this.setState({smlist: newsmlist})

        // Root へ変化を伝搬
        this.props.onChange(newsmlist);
    },
    copyCompleted: function(id) {
        var state = this.state;
        delete state["arrayForCopy"][id];
        this.setState(state);
    },
    handleOnChange: function(key, state){
        var newsmlist = this.state.smlist;
        newsmlist[key] = state;
        this.setState({smlist: newsmlist})
        this.props.onChange(newsmlist);
    },
    handleEvent: function(key, e) {
        var newState = this.state
        newState[key] = e.target.value
        this.setState(newState)
    },
    render: function() {
        var locale = this.props.locale;
        var summons = this.state.summons;
        var hChange = this.handleOnChange;
        var hRemove = this.handleOnRemove;
        var hCopy = this.handleOnCopy;
        var dataName = this.props.dataName;
        var defaultElement = this.state.defaultElement;
        var dataForLoad = this.props.dataForLoad;
        var arrayForCopy = this.state.arrayForCopy;
        var copyCompleted = this.copyCompleted;

        return (

                {intl.translate("属性一括変更", locale)}
                <FormControl componentClass="select" value={this.state.defaultElement} onChange={this.handleEvent.bind(this, "defaultElement")}> {selector[locale].summonElements} </FormControl>

 {intl.translate("召喚石", locale)}

                <Grid fluid>
                    <Row>
                    {summons.map(function(sm, ind) {
                        return <Summon key={sm} onRemove={hRemove} onCopy={hCopy} onChange={hChange} id={ind} dataName={dataName} defaultElement={defaultElement} copyCompleted={copyCompleted} locale={locale} dataForLoad={dataForLoad} arrayForCopy={arrayForCopy[ind]}/>;
                    })}
                    </Row>
                </Grid>

        );
    }
});

var Summon = React.createClass({
    getInitialState: function() {
        return {
            selfSummonType: "magna",
            selfSummonAmount: 100,
            selfSummonAmount2: 0,
            selfElement: "fire",
            friendSummonType: "element",
            friendSummonAmount: 80,
            friendSummonAmount2: 0,
            friendElement: "fire",
            attack: 0,
            hp: 0,
            hpBonus: 0,
            DA: 0,
            TA: 0,
            criticalRatio: 0.0,
        };
    },
    componentDidMount: function(){
       var state = this.state;

       // もし dataForLoad に自分に該当するキーがあるなら読み込む
       // (データロード時に新しく増えた場合)
       if(this.props.dataForLoad != undefined) {
           var summon = this.props.dataForLoad;

           if(this.props.id in summon) {
               state = summon[this.props.id]
               this.setState(state)
               return 0;
           }
       }

       // 初期化後 state を 上の階層に渡しておく
       // summonList では onChange が勝手に上に渡してくれるので必要なし
       this.props.onChange(this.props.id, state);
    },
    componentWillReceiveProps: function(nextProps){
        // データロード時のみ読み込み
        if(nextProps.dataName != this.props.dataName) {
            // 対応するIDが無い場合は undefined が飛んでくる
            if(nextProps.dataForLoad != undefined) {
               var summon = nextProps.dataForLoad;

               if(this.props.id in summon) {
                   this.setState(summon[this.props.id])
               }
            }
            return 0;
        }

        // もし arrayForCopy に自分に該当するキーがあるなら読み込む
        // コピー(またはリセット)後はSummonListに伝えて該当データを消す
        if(nextProps.arrayForCopy != undefined) {
            var state = nextProps.arrayForCopy;
            this.setState(state)
            this.props.copyCompleted(this.props.id);
            return 0;
        }

        if(nextProps.defaultElement != this.props.defaultElement) {
            var newState = this.state
            newState["selfElement"] = nextProps.defaultElement
            newState["friendElement"] = nextProps.defaultElement
            this.setState(newState);
            this.props.onChange(this.props.id, newState);
        }
    },
    handleEvent: function(key, e) {
        var newState = this.state
        newState[key] = e.target.value
        this.setState(newState)
    },
    handleSelectEvent: function(key, e) {
        var newState = this.state
        newState[key] = e.target.value
        this.setState(newState)
        this.props.onChange(this.props.id, newState)
    },
    handleOnBlur: function(e) {
        this.props.onChange(this.props.id, this.state)
    },
    clickRemoveButton: function(e) {
        this.props.onRemove(this.props.id, this.getInitialState())
    },
    clickCopyButton: function(e, state) {
        this.props.onCopy(this.props.id, this.state)
    },
    handleSummonAmountChange(type, ind, e){
        var newState = this.state
        if(type == "self") {
            if(ind == 0){
                newState["selfSummonAmount"] = e.target.value
            } else {
                newState["selfSummonAmount2"] = e.target.value
            }
        } else {
            if(ind == 0){
                newState["friendSummonAmount"] = e.target.value
            } else {
                newState["friendSummonAmount2"] = e.target.value
            }
        }
        this.setState(newState)
        this.props.onChange(this.props.id, newState)
    },
    render: function() {
        var locale = this.props.locale

        var selfSummon = [{"label": "", "input": "select"}, {"input": "hidden"}]
        if(this.state.selfSummonType == "odin"){
            selfSummon[1] = {"label": intl.translate("キャラ", locale)+ " ", "input": "select"}
            selfSummon[0].label = intl.translate("属性", locale) + " "
        }
        var friendSummon = [{"label": "", "input": "select"}, {"input": "hidden"}]
        if(this.state.friendSummonType == "odin"){
            friendSummon[1] = {"label": intl.translate("キャラ", locale) + " ", "input": "select"}
            friendSummon[0].label = intl.translate("属性", locale) + " "
        }
        return (
            <ColP sxs={12} ssm={6} smd={4} className="col-no-bordered">

                            {intl.translate("自分の石", locale)}

                                <FormControl componentClass="select" value={this.state.selfElement} onChange={this.handleSelectEvent.bind(this, "selfElement")} >{selector[locale].summonElements}</FormControl>

                                <FormControl componentClass="select" value={this.state.selfSummonType} onChange={this.handleSelectEvent.bind(this, "selfSummonType")} >{selector[locale].summons}</FormControl>

                                {selfSummon[0].label}<FormControl componentClass="select" value={this.state.selfSummonAmount} onChange={this.handleSummonAmountChange.bind(this, "self", 0)}>{selector.summonAmounts}</FormControl>
                                {selfSummon[1].label}<FormControl componentClass="select" className={selfSummon[1].input} value={this.state.selfSummonAmount2} onChange={this.handleSummonAmountChange.bind(this, "self", 1)}>{selector.summonAmounts}</FormControl>

                            {intl.translate("フレの石", locale)}

                                <FormControl componentClass="select" value={this.state.friendElement} onChange={this.handleSelectEvent.bind(this, "friendElement")} >{selector[locale].summonElements}</FormControl>

                                <FormControl componentClass="select" value={this.state.friendSummonType} onChange={this.handleSelectEvent.bind(this, "friendSummonType")} >{selector[locale].summons}</FormControl>

                                {friendSummon[0].label}<FormControl componentClass="select" value={this.state.friendSummonAmount} onChange={this.handleSummonAmountChange.bind(this, "friend", 0)}>{selector.summonAmounts}</FormControl>
                                {friendSummon[1].label}<FormControl componentClass="select" className={friendSummon[1].input} value={this.state.friendSummonAmount2} onChange={this.handleSummonAmountChange.bind(this, "friend", 1)}>{selector.summonAmounts}</FormControl>

                            {intl.translate("合計攻撃力", locale)}

                                <FormControl type="number" min="0" value={this.state.attack} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "attack")}/>

                            {intl.translate("合計HP", locale)}

                                <FormControl type="number" min="0" value={this.state.hp} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "hp")}/>

                            {intl.translate("HP加護", locale)}

                    <FormControl type="number" min="0" value={this.state.hpBonus} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "hpBonus")}/>

                            {intl.translate("DA加護", locale)}

                    <FormControl type="number" min="0" value={this.state.DA} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "DA")}/>

                            {intl.translate("TA加護", locale)}

                                <FormControl type="number" min="0" value={this.state.TA} onBlur={this.handleOnBlur} onChange={this.handleEvent.bind(this, "TA")}/>

                <ButtonGroup style={{"width": "100%"}}>
                    <Button bsStyle="primary" style={{"width": "50%", "margin": "2px 0px 2px 0px"}} onClick={this.clickRemoveButton}>{intl.translate("内容を消去", locale)}</Button>
                    <Button bsStyle="primary" style={{"width": "50%", "margin": "2px 0px 2px 0px"}} onClick={this.clickCopyButton}>{intl.translate("コピー", locale)}</Button>
                </ButtonGroup>
            </ColP>
        );
    }
});

module.exports.SummonList = SummonList;
module.exports.Summon = Summon;
<|endoftext|>


<commit_before>/* PSEUDO CODE FOR LOGIN MENU

1. COLLECT DATA ENTERED INTO THE <INPUT>
2. WHEN .LOGIN-SUBMIT IS 'CLICKED'  `GET/users/id` TO DATABASE TO BE VERIFIED?
*/

;(function(){
  angular.module('Front-Rails', [ ])

// .run(function($http, $rootScope) {
//   $http.get('https://stackundertow.herokuapp.com/questions')
//     .then(function(response){
//       // $rootScope.query = "hello";
//
//        $rootScope.query = response.data[0].query;
//
//       // $rootScope.questions = response.data;
//     })
//
// })

  .controller('questionList', function ($scope) {
    $scope.questions = [
  {
    "id": 23,
    "user_id": 3,
    "query": "What is Fully-configurable 4th generation algorithm?",
    "description": "No really, what is it?",
    "upvotes": 83,
    "downvotes": 5,
    "votes_quality": 78,
    "votes_count": 88,
    "answers": [
      {
        "id": 12,
        "user_id": 3,
        "question_id": 23,
        "description": "If we synthesize the system, we can get to the SMS protocol through the cross-platform SSL application!",
        "upvotes": 94,
        "downvotes": 39,
        "accepted": false,
        "votes_quality": 55,
        "votes_count": 133
      },
      {
        "id": 16,
        "user_id": 4,
        "question_id": 23,
        "description": "We need to index the solid state HDD transmitter!",
        "upvotes": 40,
        "downvotes": 3,
        "accepted": false,
        "votes_quality": 37,
        "votes_count": 43
      }
    ]
  },{
    "id": 7,
    "user_id": 3,
    "query": "What is Robust incremental challenge?",
    "description": "No really, what is it?",
    "upvotes": 81,
    "downvotes": 43,
    "votes_quality": 38,
    "votes_count": 124,
    "answers": [
      {
        "id": 41,
        "user_id": 4,
        "question_id": 7,
        "description": "Use the cross-platform JBOD protocol, then you can hack the auxiliary application!",
        "upvotes": 62,
        "downvotes": 38,
        "accepted": false,
        "votes_quality": 24,
        "votes_count": 100
      },
      {
        "id": 7,
        "user_id": 3,
        "question_id": 7,
        "description": "Use the online JSON circuit, then you can program the wireless card!",
        "upvotes": 66,
        "downvotes": 88,
        "accepted": false,
        "votes_quality": -22,
        "votes_count": 154
      },
      {
        "id": 46,
        "user_id": 3,
        "question_id": 7,
        "description": "You can't transmit the hard drive without copying the solid state AGP alarm!",
        "upvotes": 25,
        "downvotes": 55,
        "accepted": false,
        "votes_quality": -30,
        "votes_count": 80
      },
      {
        "id": 59,
        "user_id": 4,
        "question_id": 7,
        "description": "Use the multi-byte HDD capacitor, then you can reboot the redundant capacitor!",
        "upvotes": 29,
        "downvotes": 80,
        "accepted": false,
        "votes_quality": -51,
        "votes_count": 109
      }
    ]
  }
  ];
})
.controller('answersToAQuestion', function ($scope) {
   $scope.answers = [
     {
  "id": 1,
  "user_id": 2,
  "question_id": 1,
  "description": "Imagination Land",
  "upvotes": 30,
  "downvotes": 6,
  "accepted": true,
  "votes_quality": 24,
  "votes_count": 36
},
     {
  "id": 2,
  "user_id": 2,
  "question_id": 1,
  "description": "Canada",
  "upvotes": 50,
  "downvotes": 6,
  "accepted": true,
  "votes_quality": 44,
  "votes_count": 56
}
  ];
});

})();

/* Signup and Login menu drop down*/
$('.search a[href]').on('click', function(event){
  event.preventDefault();
    $(this).add(this.hash)
    .toggleClass('active')
    .siblings().removeClass('active');
});

$('.redirect a[href]').on('click', function(event){
  event.preventDefault();
    $(this).add(this.hash)
    .toggleClass('active')
    .siblings().removeClass('active');
});

$('.list').on('click', function(event){
  event.preventDefault();
  console.log("HEY");
    $('.active').removeClass('active');
});

$('aside').on('click', function(event){
  event.preventDefault();
  console.log("HEY");
    $('.active').removeClass('active');
});
/* Signup and Login menu drop down*/
<commit_msg>added routeProvider<commit_after>/* PSEUDO CODE FOR LOGIN MENU

1. COLLECT DATA ENTERED INTO THE <INPUT>
2. WHEN .LOGIN-SUBMIT IS 'CLICKED'  `GET/users/id` TO DATABASE TO BE VERIFIED?
*/

;(function(){
  angular.module('Front-Rails', ['ngRoute'], function($routeProvider){
  $routeProvider
    .when('/', {
      redirectTo: "top-questions"
    })
    .when('/top-questions', {
      templateUrl: 'top-questions.html'
    })

    .when('/question', {
      templateUrl: 'question.html'
    })
})
.run(function($http, $rootScope) {
  $http.get('https://stackundertow.herokuapp.com/questions')
    .then(function(response){
      // $rootScope.query = response.data.query;

      //  $rootScope.questions = response.data;

      $rootScope.questions = response.data;
    })
});

// angular.module('Front-Rails')
//   .config(function($routeProvider){
//     $routeProvider
//   });

})(); //END OF IFFE

//   .controller('questionList', function ($scope) {
//     $scope.questions = [
//   {
//     "id": 23,
//     "user_id": 3,
//     "query": "What is Fully-configurable 4th generation algorithm?",
//     "description": "No really, what is it?",
//     "upvotes": 83,
//     "downvotes": 5,
//     "votes_quality": 78,
//     "votes_count": 88,
//     "answers": [
//       {
//         "id": 12,
//         "user_id": 3,
//         "question_id": 23,
//         "description": "If we synthesize the system, we can get to the SMS protocol through the cross-platform SSL application!",
//         "upvotes": 94,
//         "downvotes": 39,
//         "accepted": false,
//         "votes_quality": 55,
//         "votes_count": 133
//       },
//       {
//         "id": 16,
//         "user_id": 4,
//         "question_id": 23,
//         "description": "We need to index the solid state HDD transmitter!",
//         "upvotes": 40,
//         "downvotes": 3,
//         "accepted": false,
//         "votes_quality": 37,
//         "votes_count": 43
//       }
//     ]
//   },{
//     "id": 7,
//     "user_id": 3,
//     "query": "What is Robust incremental challenge?",
//     "description": "No really, what is it?",
//     "upvotes": 81,
//     "downvotes": 43,
//     "votes_quality": 38,
//     "votes_count": 124,
//     "answers": [
//       {
//         "id": 41,
//         "user_id": 4,
//         "question_id": 7,
//         "description": "Use the cross-platform JBOD protocol, then you can hack the auxiliary application!",
//         "upvotes": 62,
//         "downvotes": 38,
//         "accepted": false,
//         "votes_quality": 24,
//         "votes_count": 100
//       },
//       {
//         "id": 7,
//         "user_id": 3,
//         "question_id": 7,
//         "description": "Use the online JSON circuit, then you can program the wireless card!",
//         "upvotes": 66,
//         "downvotes": 88,
//         "accepted": false,
//         "votes_quality": -22,
//         "votes_count": 154
//       },
//       {
//         "id": 46,
//         "user_id": 3,
//         "question_id": 7,
//         "description": "You can't transmit the hard drive without copying the solid state AGP alarm!",
//         "upvotes": 25,
//         "downvotes": 55,
//         "accepted": false,
//         "votes_quality": -30,
//         "votes_count": 80
//       },
//       {
//         "id": 59,
//         "user_id": 4,
//         "question_id": 7,
//         "description": "Use the multi-byte HDD capacitor, then you can reboot the redundant capacitor!",
//         "upvotes": 29,
//         "downvotes": 80,
//         "accepted": false,
//         "votes_quality": -51,
//         "votes_count": 109
//       }
//     ]
//   }
//   ];
// })
// .controller('answersToAQuestion', function ($scope) {
//    $scope.answers = [
//      {
//   "id": 1,
//   "user_id": 2,
//   "question_id": 1,
//   "description": "Imagination Land",
//   "upvotes": 30,
//   "downvotes": 6,
//   "accepted": true,
//   "votes_quality": 24,
//   "votes_count": 36
// },
//      {
//   "id": 2,
//   "user_id": 2,
//   "question_id": 1,
//   "description": "Canada",
//   "upvotes": 50,
//   "downvotes": 6,
//   "accepted": true,
//   "votes_quality": 44,
//   "votes_count": 56
// }
//   ];
// });

/* Signup and Login menu drop down*/
$('.search a[href]').on('click', function(event){
  event.preventDefault();
    $(this).add(this.hash)
    .toggleClass('active')
    .siblings().removeClass('active');
});

$('.redirect a[href]').on('click', function(event){
  event.preventDefault();
    $(this).add(this.hash)
    .toggleClass('active')
    .siblings().removeClass('active');
});

$('.list').on('click', function(event){
  event.preventDefault();
  console.log("HEY");
    $('.active').removeClass('active');
});

$('aside').on('click', function(event){
  event.preventDefault();
  console.log("HEY");
    $('.active').removeClass('active');
});
/* Signup and Login menu drop down*/
<|endoftext|>


<commit_before>/* global ga:false */

(function (window, undefined) {

    'use strict';

    var document = window.document;

    // -----------------------------------------------------------------
    // | Google Universal Analytics                                    |
    // -----------------------------------------------------------------

    function handleClickEvent(e) {

        var action;
        var category;
        var label;
        var target = hasAttr(e.target, 'data-ga-action');
        var url;
        var value;

        var openInNewTab = false;

        if ( target !== undefined ) {

            action = target.getAttribute('data-ga-action') || undefined;     // required
            category = target.getAttribute('data-ga-category') || undefined; // required
            label = target.getAttribute('data-ga-label') || undefined;
            url = target.getAttribute('href');
            value = parseInt(target.getAttribute('data-ga-value'), 10) || undefined;

            if ( ga !== undefined &&
                 category !== undefined &&
                 action !== undefined ) {

                // Handle outbound links manually to ensure that
                // they are registered with Google Analytics
                e.preventDefault();

                // 1. Ensure that links which need to be open in a new
                //    tab, are so.
                //
                //  These include:
                //
                //  * `Download` links
                //
                //     The `Download` links aren't directing the user
                //     away from the page, so using `window.location.href`
                //     in this case may cause unwanted problems.
                //
                //     E.g: If the user clicks on a `Download` link
                //     before all the page's content is downloaded, the
                //     browser will abort any remaining downloads. This
                //     happens because the browser considers that it no
                //     longer needs to download anything from current
                //     page and should start downloading the next page
                //     and its content.
                //
                //  * Outbound links that are opened by the user using
                //    ctrl+click (or cmd+click on Macintosh)

                if ( category === 'Download' ||
                     e.ctrlKey === true ||
                     e.metaKey === true ) {

                    openInNewTab = true;
                    window.open(url);  // This is done here, and not
                                       // in `hitCallback` so that it
                                       // prevents the browser popup
                                       // blocking behavior
                }

                (function (url) {

                    var timeout;

                    // Register the event
                    ga('send', 'event', category, action, label, value, {

                        // 2. Ensure that outbound links are registered
                        //    before navigating away from the current page
                        //    https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced#hitCallback

                        'hitCallback': function () {
                            if ( openInNewTab === false ) {
                                if ( timeout !== undefined ) {
                                    clearTimeout(timeout);
                                }
                                window.location = url;
                            }
                        }

                    });

                    // In case `hitCallback` takes too long
                    timeout = setTimeout(function () {
                        if ( openInNewTab === false ) {
                            window.location.href = url;
                        }
                    }, 1000);

                }(url));

            }
        }
    }

    // Check if an element or any of its parents has the specified attribute
    function hasAttr(element, attribute) {

        if ( element.hasAttribute(attribute) === true ) {
            return element;
        } else if ( element.parentNode !== document.body ) {
            return hasAttr(element.parentNode, attribute);
        }

        return undefined;
    }

    // More information about the Google Universal Analytics:
    // https://developers.google.com/analytics/devguides/collection/analyticsjs/
    // https://mathiasbynens.be/notes/async-analytics-snippet#universal-analytics

    function loadGoogleAnalytics() {

        /* jshint ignore:start */
        (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;e=o.createElement(i);r=o.getElementsByTagName(i)[0];e.src='//www.google-analytics.com/analytics.js';r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
        /* jshint ignore:end */

        // Create tracker object
        ga('create', 'UA-17904194-1', 'auto');

        // Send a page view
        // https://developers.google.com/analytics/devguides/collection/analyticsjs/pages
        ga('send', 'pageview');

        // Track events
        // https://developers.google.com/analytics/devguides/collection/analyticsjs/events
        window.document.addEventListener('click', handleClickEvent);

    }

    // -----------------------------------------------------------------
    // | Twitter                                                       |
    // -----------------------------------------------------------------

    // Tweet Buttons
    // https://dev.twitter.com/docs/tweet-button

    function loadTweetButtons() {
        /* jshint ignore:start */
        !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src='http://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document,'script','twitter-wjs');
        /* jshint ignore:end */
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    loadGoogleAnalytics();
    window.onload = loadTweetButtons;

}(window));
<commit_msg>Use a protocol relative `src` for tweet buttons<commit_after>/* global ga:false */

(function (window, undefined) {

    'use strict';

    var document = window.document;

    // -----------------------------------------------------------------
    // | Google Universal Analytics                                    |
    // -----------------------------------------------------------------

    function handleClickEvent(e) {

        var action;
        var category;
        var label;
        var target = hasAttr(e.target, 'data-ga-action');
        var url;
        var value;

        var openInNewTab = false;

        if ( target !== undefined ) {

            action = target.getAttribute('data-ga-action') || undefined;     // required
            category = target.getAttribute('data-ga-category') || undefined; // required
            label = target.getAttribute('data-ga-label') || undefined;
            url = target.getAttribute('href');
            value = parseInt(target.getAttribute('data-ga-value'), 10) || undefined;

            if ( ga !== undefined &&
                 category !== undefined &&
                 action !== undefined ) {

                // Handle outbound links manually to ensure that
                // they are registered with Google Analytics
                e.preventDefault();

                // 1. Ensure that links which need to be open in a new
                //    tab, are so.
                //
                //  These include:
                //
                //  * `Download` links
                //
                //     The `Download` links aren't directing the user
                //     away from the page, so using `window.location.href`
                //     in this case may cause unwanted problems.
                //
                //     E.g: If the user clicks on a `Download` link
                //     before all the page's content is downloaded, the
                //     browser will abort any remaining downloads. This
                //     happens because the browser considers that it no
                //     longer needs to download anything from current
                //     page and should start downloading the next page
                //     and its content.
                //
                //  * Outbound links that are opened by the user using
                //    ctrl+click (or cmd+click on Macintosh)

                if ( category === 'Download' ||
                     e.ctrlKey === true ||
                     e.metaKey === true ) {

                    openInNewTab = true;
                    window.open(url);  // This is done here, and not
                                       // in `hitCallback` so that it
                                       // prevents the browser popup
                                       // blocking behavior
                }

                (function (url) {

                    var timeout;

                    // Register the event
                    ga('send', 'event', category, action, label, value, {

                        // 2. Ensure that outbound links are registered
                        //    before navigating away from the current page
                        //    https://developers.google.com/analytics/devguides/collection/analyticsjs/advanced#hitCallback

                        'hitCallback': function () {
                            if ( openInNewTab === false ) {
                                if ( timeout !== undefined ) {
                                    clearTimeout(timeout);
                                }
                                window.location = url;
                            }
                        }

                    });

                    // In case `hitCallback` takes too long
                    timeout = setTimeout(function () {
                        if ( openInNewTab === false ) {
                            window.location.href = url;
                        }
                    }, 1000);

                }(url));

            }
        }
    }

    // Check if an element or any of its parents has the specified attribute
    function hasAttr(element, attribute) {

        if ( element.hasAttribute(attribute) === true ) {
            return element;
        } else if ( element.parentNode !== document.body ) {
            return hasAttr(element.parentNode, attribute);
        }

        return undefined;
    }

    // More information about the Google Universal Analytics:
    // https://developers.google.com/analytics/devguides/collection/analyticsjs/
    // https://mathiasbynens.be/notes/async-analytics-snippet#universal-analytics

    function loadGoogleAnalytics() {

        /* jshint ignore:start */
        (function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+new Date;e=o.createElement(i);r=o.getElementsByTagName(i)[0];e.src='//www.google-analytics.com/analytics.js';r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));
        /* jshint ignore:end */

        // Create tracker object
        ga('create', 'UA-17904194-1', 'auto');

        // Send a page view
        // https://developers.google.com/analytics/devguides/collection/analyticsjs/pages
        ga('send', 'pageview');

        // Track events
        // https://developers.google.com/analytics/devguides/collection/analyticsjs/events
        window.document.addEventListener('click', handleClickEvent);

    }

    // -----------------------------------------------------------------
    // | Twitter                                                       |
    // -----------------------------------------------------------------

    // Tweet Buttons
    // https://dev.twitter.com/docs/tweet-button

    function loadTweetButtons() {
        /* jshint ignore:start */
        !function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src='//platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document,'script','twitter-wjs');
        /* jshint ignore:end */
    }

    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    loadGoogleAnalytics();
    window.onload = loadTweetButtons;

}(window));
<|endoftext|>


<commit_before>
import { config } from './config';
import { request } from './lib';

export function createAccessToken(clientID) {

    let basicAuth = window.btoa(`${clientID}:`);

    return request({

        method: 'post',
        url: config.authApiUrl,
        headers: {
            'Authorization': `Basic ${basicAuth}`,
            'Content-Type':  `application/x-www-form-urlencoded; charset=utf-8`
        },
        body: `grant_type=client_credentials`

    }).then(res => {

        if (!res || !res.access_token) {
            throw new Error(`Auth Api response error:\n\n${JSON.stringify(res, 0, 4)}`);
        }

        return res.access_token;
    });
}

export function createCheckoutToken(clientID, paymentDetails) {

    paymentDetails = { ...paymentDetails };
    paymentDetails.intent = paymentDetails.intent || 'sale';
    paymentDetails.redirect_urls = paymentDetails.redirect_urls || {};
    paymentDetails.redirect_urls.return_url = paymentDetails.redirect_urls.return_url || `${window.location.protocol}://${window.location.host}`;
    paymentDetails.redirect_urls.cancel_url = paymentDetails.redirect_urls.cancel_url || `${window.location.protocol}://${window.location.host}`;
    paymentDetails.payer = paymentDetails.payer || {};
    paymentDetails.payer.payment_method = paymentDetails.payer.payment_method || 'paypal';

    return createAccessToken(clientID).then(accessToken => {

        return request({
            method: 'post',
            url: config.paymentApiUrl,
            headers: {
                'Authorization': `Bearer ${accessToken}`
            },
            body: JSON.stringify(paymentDetails)
        });

    }).then(res => {

        if (res && res.links && res.links.length) {
            let links = res.links;

            for (let i = 0, len = links.length; i < len; i++) {
                if (links[i].method === 'REDIRECT') {
                    let match = links[i].href.match(/token=((EC-)?[A-Z0-9]{17})/);
                    if (match) {
                        return match[1];
                    }
                    break;
                }
            }
        }

        throw new Error(`Payment Api response error:\n\n${JSON.stringify(res, 0, 4)}`);
    });
}

export function createBillingToken(clientID, paymentDetails) {

    paymentDetails = { ...paymentDetails };
    paymentDetails.plan = paymentDetails.plan || {};
    paymentDetails.plan.merchant_preferences = paymentDetails.plan.merchant_preferences || {};
    paymentDetails.plan.merchant_preferences.return_url = paymentDetails.plan.merchant_preferences.return_url || `${window.location.protocol}://${window.location.host}`;
    paymentDetails.plan.merchant_preferences.cancel_url = paymentDetails.plan.merchant_preferences.cancel_url || `${window.location.protocol}://${window.location.host}`;
    paymentDetails.payer = paymentDetails.payer || {};
    paymentDetails.payer.payment_method = paymentDetails.payer.payment_method || 'paypal';

    return createAccessToken(clientID).then(accessToken => {

        return request({
            method: 'post',
            url: config.billingApiUrl,
            headers: {
                'Authorization': `Bearer ${accessToken}`
            },
            body: JSON.stringify(paymentDetails)
        });

    }).then(res => {

        if (res && res.token_id) {
            return res.token_id;
        }

        throw new Error(`Billing Api response error:\n\n${JSON.stringify(res, 0, 4)}`);
    });
}
<commit_msg>Fix default cancel and return urls<commit_after>
import { config } from './config';
import { request } from './lib';

export function createAccessToken(clientID) {

    let basicAuth = window.btoa(`${clientID}:`);

    return request({

        method: 'post',
        url: config.authApiUrl,
        headers: {
            'Authorization': `Basic ${basicAuth}`,
            'Content-Type':  `application/x-www-form-urlencoded; charset=utf-8`
        },
        body: `grant_type=client_credentials`

    }).then(res => {

        if (!res || !res.access_token) {
            throw new Error(`Auth Api response error:\n\n${JSON.stringify(res, 0, 4)}`);
        }

        return res.access_token;
    });
}

export function createCheckoutToken(clientID, paymentDetails) {

    paymentDetails = { ...paymentDetails };
    paymentDetails.intent = paymentDetails.intent || 'sale';
    paymentDetails.redirect_urls = paymentDetails.redirect_urls || {};
    paymentDetails.redirect_urls.return_url = paymentDetails.redirect_urls.return_url || `${window.location.protocol}//${window.location.host}`;
    paymentDetails.redirect_urls.cancel_url = paymentDetails.redirect_urls.cancel_url || `${window.location.protocol}//${window.location.host}`;
    paymentDetails.payer = paymentDetails.payer || {};
    paymentDetails.payer.payment_method = paymentDetails.payer.payment_method || 'paypal';

    return createAccessToken(clientID).then(accessToken => {

        return request({
            method: 'post',
            url: config.paymentApiUrl,
            headers: {
                'Authorization': `Bearer ${accessToken}`
            },
            body: JSON.stringify(paymentDetails)
        });

    }).then(res => {

        if (res && res.links && res.links.length) {
            let links = res.links;

            for (let i = 0, len = links.length; i < len; i++) {
                if (links[i].method === 'REDIRECT') {
                    let match = links[i].href.match(/token=((EC-)?[A-Z0-9]{17})/);
                    if (match) {
                        return match[1];
                    }
                    break;
                }
            }
        }

        throw new Error(`Payment Api response error:\n\n${JSON.stringify(res, 0, 4)}`);
    });
}

export function createBillingToken(clientID, paymentDetails) {

    paymentDetails = { ...paymentDetails };
    paymentDetails.plan = paymentDetails.plan || {};
    paymentDetails.plan.merchant_preferences = paymentDetails.plan.merchant_preferences || {};
    paymentDetails.plan.merchant_preferences.return_url = paymentDetails.plan.merchant_preferences.return_url || `${window.location.protocol}//${window.location.host}`;
    paymentDetails.plan.merchant_preferences.cancel_url = paymentDetails.plan.merchant_preferences.cancel_url || `${window.location.protocol}//${window.location.host}`;
    paymentDetails.payer = paymentDetails.payer || {};
    paymentDetails.payer.payment_method = paymentDetails.payer.payment_method || 'paypal';

    return createAccessToken(clientID).then(accessToken => {

        return request({
            method: 'post',
            url: config.billingApiUrl,
            headers: {
                'Authorization': `Bearer ${accessToken}`
            },
            body: JSON.stringify(paymentDetails)
        });

    }).then(res => {

        if (res && res.token_id) {
            return res.token_id;
        }

        throw new Error(`Billing Api response error:\n\n${JSON.stringify(res, 0, 4)}`);
    });
}
<|endoftext|>