<commit_before>var Vec2d = require('../util/Vector2d'),
    GameConsts = require('../GameConsts');

function Growl(x, y, target, lifetime, relativeLifetime) {
    this.id = 'growl';

    this.element = new createjs.Container();

	var fireball = new createjs.Bitmap("./img/fireball.png");
	this.element.scaleX = this.element.scaleY = 0.3;

    fireball.image.onload = function() {
		this.element.regX = this.element.getBounds().width / 2;
		this.element.regY = this.element.getBounds().height / 2;
	}.bind(this);

	this.element.addChild(fireball);

	this.target = target;
    this.element.x = x;
    this.element.y = y;
    this.lifetime = lifetime;
    this.velocity = new Vec2d(0, 0);

	createjs.Tween.get(this.element)
		.to({rotation: relativeLifetime}, relativeLifetime - 1000)
		.to({alpha: 0, rotation: relativeLifetime + 1000}, 1000)
		.call(function() {
			this.element.removeChild(fireball);
		}.bind(this));
}

Growl.prototype.hit = function() {
    this.lifetime = 0;
};

Growl.prototype.isShortAttacking = function() {
    return true;
};

Growl.prototype.getRadius = function() {
    return 20;
};

Growl.prototype.tick = function(event) {
    var current = new Vec2d(this.target.element.x, this.target.element.y);
    var target  = new Vec2d(this.element.x, this.element.y);

    var vector_to_destination = Vec2d.subtract(current, target);
    var distance = vector_to_destination.length();

    // calculate new velocity according to current velocity and position of target
    vector_to_destination.norm().times(0.7);
    this.velocity.norm().times(20);
    this.velocity = this.velocity.plus(vector_to_destination);

    // set speed of monster according to distance to target
    this.velocity.times(100 + distance / 2.5);

    var delta = Vec2d.multiply(this.velocity, event.delta / 8000);

    this.element.x += delta.x;
    this.element.y += delta.y;
};

module.exports = Growl;
<commit_msg>animation<commit_after>var Vec2d = require('../util/Vector2d'),
    GameConsts = require('../GameConsts');

function Growl(x, y, target, lifetime, relativeLifetime) {
    this.id = 'growl';

    this.element = new createjs.Container();

    this.fireball = new createjs.Container();
	var fireball = new createjs.Bitmap("./img/fireball.png");

	this.fireball.scaleX = this.fireball.scaleY = 0.3;

    fireball.image.onload = function() {
		this.fireball.regX = this.fireball.getBounds().width / 2;
		this.fireball.regY = this.fireball.getBounds().height / 2;
	}.bind(this);

	this.fireball.addChild(fireball);
    this.element.addChild(this.fireball);

	this.target = target;
    this.element.x = x;
    this.element.y = y;
    this.lifetime = lifetime;
    this.velocity = new Vec2d(0, 0);

	createjs.Tween.get(this.fireball)
		.to({rotation: relativeLifetime}, relativeLifetime - 500)
		.call(function() {
			this.element.removeChild(this.fireball);
		}.bind(this));

    var data = new createjs.SpriteSheet({
        "images": ['./img/poof.png'],
        "frames": {
            "regX": 0,
            "height": 128,
            "count": 64,
            "regY": 0,
            "width": 128
        },
        "animations": {"empty": [0], "default": [1, 64, "empty"]}
    });

    createjs.Tween.get(this.element)
        .wait(relativeLifetime - 1000)
        .call(function() {
            var animation = new createjs.Sprite(data, "default");
            animation.x = -64;
            animation.y = -64;
            animation.framerate = 60;
            this.element.addChild(animation);
        }.bind(this));
}

Growl.prototype.hit = function() {
    this.lifetime = 0;
};

Growl.prototype.isShortAttacking = function() {
    return true;
};

Growl.prototype.getRadius = function() {
    return 20;
};

Growl.prototype.tick = function(event) {
    var current = new Vec2d(this.target.element.x, this.target.element.y);
    var target  = new Vec2d(this.element.x, this.element.y);

    var vector_to_destination = Vec2d.subtract(current, target);
    var distance = vector_to_destination.length();

    // calculate new velocity according to current velocity and position of target
    vector_to_destination.norm().times(0.7);
    this.velocity.norm().times(20);
    this.velocity = this.velocity.plus(vector_to_destination);

    // set speed of monster according to distance to target
    this.velocity.times(100 + distance / 2.5);

    var delta = Vec2d.multiply(this.velocity, event.delta / 8000);

    this.element.x += delta.x;
    this.element.y += delta.y;
};

module.exports = Growl;
<|endoftext|>


<commit_before>// ==UserScript==
// @name            BeQuiet
// @author          xiaoxiaoflood
// @include         main
// @startup         UC.beQuiet.exec(win);
// @shutdown        UC.beQuiet.destroy();
// @onlyonce
// ==/UserScript==

// inspired by https://addons.mozilla.org/en-US/firefox/addon/be-quiet/

UC.beQuiet = {
  sites: [
    {
      rx: /^https:\/\/www\.deezer\.com\//,
      play: 'li > button.svg-icon-group-btn',
      previous: '.player-controls li button',
      next: '.player-controls li:nth-of-type(5) button'
    },
    {
      rx: /^https:\/\/songa\.nl\//,
      play: '#play_button',
      previous: '#previous_button',
      next: '#next_button'
    },
    {
      rx: /^https:\/\/open\.spotify\.com\//,
      play: '.Root__now-playing-bar .control-button--circled',
      previous: '.Root__now-playing-bar .spoticon-skip-back-16',
      next: '.Root__now-playing-bar .spoticon-skip-forward-16'
    },
    {
      rx: /^https:\/\/www\.twitch\.tv\//,
      play: 'button[data-a-target="player-play-pause-button"]'
    },
    {
      rx: /^https:\/\/vk\.com\//,
      play: '.top_audio_player_play',
      previous: '.top_audio_player_prev',
      next: '.top_audio_player_next'
    },
    {
      rx: /^https:\/\/www\.youtube\.com\//,
      play: '.ytp-play-button'
    }
  ],

  exec: function (win) {
    let document = win.document;
    let gBrowser = win.gBrowser;
    gBrowser.addEventListener('DOMAudioPlaybackStarted', this.audioStarted);
    gBrowser.addEventListener('DOMAudioPlaybackStopped', this.audioStopped);

    let keyset =  _uc.createElement(document, 'keyset', { id: 'beQuiet-keyset' });
    document.getElementById('mainKeyset').insertAdjacentElement('afterend', keyset);

    let playKey = _uc.createElement(document, 'key', {
      id: 'beQuiet-play-key',
      modifiers: 'alt control',
      key: 'S',
      oncommand: 'UC.beQuiet.doAction("play")',
    });
    keyset.appendChild(playKey);

    let previousKey = _uc.createElement(document, 'key', {
      id: 'beQuiet-previous-key',
      modifiers: 'alt control',
      key: 'A',
      oncommand: 'UC.beQuiet.doAction("previous")',
    });
    keyset.appendChild(previousKey);

    let nextKey = _uc.createElement(document, 'key', {
      id: 'beQuiet-next-key',
      modifiers: 'alt control',
      key: 'D',
      oncommand: 'UC.beQuiet.doAction("next")',
    });
    keyset.appendChild(nextKey);

    gBrowser.tabContainer.addEventListener('TabClose', this.onTabClose);
  },

  onTabClose (ev) {
    let closedBrowser = gBrowser.getBrowserForTab(ev.target);
    if (UC.beQuiet.browser == closedBrowser) {
      UC.beQuiet.playing = false;
      return;
    }
    UC.beQuiet.stack.find(browser => {
      if (closedBrowser == browser) {
        let index = UC.beQuiet.stack.indexOf(browser);
        if (index != -1)
          UC.beQuiet.stack.splice(index, 1);
        return true;
      }
    });
  },

  doAction (action) {
    if (!UC.beQuiet.browser)
      return;
    this.sites.find(site => {
      if (site.rx.test(UC.beQuiet.browser.currentURI.spec)) {
        let selector = site[action];
        if (selector)
          UC.beQuiet.browser.messageManager.sendAsyncMessage('bequiet', selector);
        return true;
      }
      return false;
    });
  },

  audioStarted (ev) {
    let browser = ev.target;
    if (UC.beQuiet.sites.find(site => site.rx.test(browser.currentURI.spec))) {
      if (UC.beQuiet.playing && UC.beQuiet.browser != browser) {
        UC.beQuiet.stackingBrowser = UC.beQuiet.browser;
        UC.beQuiet.doAction('play'); // pause
        UC.beQuiet.stack.unshift(UC.beQuiet.browser);
      }
      UC.beQuiet.browser = browser;
    }
    UC.beQuiet.playing = true;
  },

  audioStopped (ev) {
    let browser = ev.target;
    if (UC.beQuiet.stackingBrowser != browser) {
      UC.beQuiet.playing = false;
      if (UC.beQuiet.stack.length) {
        UC.beQuiet.browser = UC.beQuiet.stack.shift();
        UC.beQuiet.doAction('play');
      }
    } else {
      UC.beQuiet.stackingBrowser = null;
    }
  },

  frameScript: 'data:application/javascript;charset=UTF-8,' + encodeURIComponent('(' + (function () {
    let contentListener = (msg) => {
      if (msg.data == 'destroy') {
        removeMessageListener('bequiet', contentListener);
        delete this.contentListener;
      } else {
        content.document.querySelector(msg.data)?.click();
      }
    }
    addMessageListener('bequiet', contentListener);
  }).toString() + ')();'),

  stack: [],

  init: function () {
    Services.mm.loadFrameScript(this.frameScript, true);
  },

  destroy: function () {
    Services.mm.removeDelayedFrameScript(this.frameScript);
    Services.mm.broadcastAsyncMessage('bequiet', 'destroy');
    _uc.windows((doc, win) => {
      let gBrowser = win.gBrowser;
      gBrowser.removeEventListener('DOMAudioPlaybackStarted', this.audioStarted);
      gBrowser.removeEventListener('DOMAudioPlaybackStopped', this.audioStopped);
      doc.getElementById('beQuiet-keyset').remove();
      gBrowser.tabContainer.removeEventListener('TabClose', this.onTabClose);
    });
    delete UC.beQuiet;
  }
}

UC.beQuiet.init();<commit_msg>BeQuiet: updating Spotify selectors and code refactoring with some bugfixes.<commit_after>// ==UserScript==
// @name            BeQuiet
// @author          xiaoxiaoflood
// @include         main
// @startup         UC.beQuiet.exec(win);
// @shutdown        UC.beQuiet.destroy();
// @onlyonce
// ==/UserScript==

// inspired by https://addons.mozilla.org/en-US/firefox/addon/be-quiet/

UC.beQuiet = {
  sites: [
    {
      rx: /^https:\/\/www\.deezer\.com\//,
      play: 'li > button.svg-icon-group-btn',
      previous: '.player-controls li button',
      next: '.player-controls li:nth-of-type(5) button'
    },
    {
      rx: /^https:\/\/songa\.nl\//,
      play: '#play_button',
      previous: '#previous_button',
      next: '#next_button'
    },
    {
      rx: /^https:\/\/open\.spotify\.com\//,
      play: '.Root__now-playing-bar .player-controls__buttons button:nth-child(3)',
      previous: '.Root__now-playing-bar .player-controls__buttons button:nth-child(2)',
      next: '.Root__now-playing-bar .player-controls__buttons button:nth-child(4)'
    },
    {
      rx: /^https:\/\/www\.twitch\.tv\//,
      play: 'button[data-a-target="player-play-pause-button"]'
    },
    {
      rx: /^https:\/\/vk\.com\//,
      play: '.top_audio_player_play',
      previous: '.top_audio_player_prev',
      next: '.top_audio_player_next'
    },
    {
      rx: /^https:\/\/www\.youtube\.com\//,
      play: '.ytp-play-button'
    }
  ],

  exec: function (win) {
    let document = win.document;
    let gBrowser = win.gBrowser;
    gBrowser.addTabsProgressListener(this.progressListener);
    gBrowser.addEventListener('DOMAudioPlaybackStarted', this.audioStarted);
    gBrowser.addEventListener('DOMAudioPlaybackStopped', this.audioStopped);

    let keyset =  _uc.createElement(document, 'keyset', { id: 'beQuiet-keyset' });
    document.getElementById('mainKeyset').insertAdjacentElement('afterend', keyset);

    let playKey = _uc.createElement(document, 'key', {
      id: 'beQuiet-play-key',
      modifiers: 'alt control',
      key: 'S',
      oncommand: 'UC.beQuiet.doAction("play")',
    });
    keyset.appendChild(playKey);

    let previousKey = _uc.createElement(document, 'key', {
      id: 'beQuiet-previous-key',
      modifiers: 'alt control',
      key: 'A',
      oncommand: 'UC.beQuiet.doAction("previous")',
    });
    keyset.appendChild(previousKey);

    let nextKey = _uc.createElement(document, 'key', {
      id: 'beQuiet-next-key',
      modifiers: 'alt control',
      key: 'D',
      oncommand: 'UC.beQuiet.doAction("next")',
    });
    keyset.appendChild(nextKey);

    gBrowser.tabContainer.addEventListener('TabClose', this.onTabClose);
  },

  onTabClose (ev) {
    let closedBrowser = gBrowser.getBrowserForTab(ev.target);
    if (UC.beQuiet.playingStack.includes(closedBrowser)) {
      if (closedBrowser == UC.beQuiet.playingBrowser) {
        UC.beQuiet.doAction('play', UC.beQuiet.prevPlayingBrowser);
      }
      UC.beQuiet.remove(UC.beQuiet.playingStack, closedBrowser);
    }
    UC.beQuiet.remove(UC.beQuiet.stack, closedBrowser);
  },

  progressListener: {
    onLocationChange: function (aBrowser, aWebProgress, aRequest, aLocation, aFlags) {
      if (!aWebProgress.isTopLevel ||
          aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_RELOAD ||
          aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE)
          return;

      if (UC.beQuiet.stack.includes(aBrowser) && !UC.beQuiet.isURLCompatible(aLocation.spec))
        UC.beQuiet.remove(UC.beQuiet.stack, aBrowser);
    }
  },

  doAction (action, browser) {
    if (!browser) {
      if (this.playingBrowser)
        browser = this.playingBrowser;
      else
        browser = this.topStack;
    }

    if (!browser)
      return;

    this.sites.find(site => {
      if (site.rx.test(browser.currentURI.spec)) {
        let selector = site[action];
        if (selector)
          browser.messageManager.sendAsyncMessage('bequiet', selector);
        return true;
      }
      return false;
    });
  },

  audioStarted (ev) {
    let browser = ev.target;
    if (UC.beQuiet.isURLCompatible(browser.currentURI.spec)) {
      UC.beQuiet.addUnique(UC.beQuiet.stack, browser);
      UC.beQuiet.addUnique(UC.beQuiet.playingStack, browser);

      if (UC.beQuiet.prevPlayingBrowser) {
        UC.beQuiet.doAction('play', UC.beQuiet.prevPlayingBrowser);
      }
    }
  },

  isURLCompatible (url) {
    return UC.beQuiet.sites.find(site => site.rx.test(url))
  },

  get playingBrowser () {
    return this.playingStack[this.playingStack.length - 1];
  },

  get prevPlayingBrowser () {
    return this.playingStack[this.playingStack.length - 2];
  },

  get topStack () {
    return this.stack[this.stack.length - 1];
  },

  audioStopped (ev) {
    let browser = ev.target;
    if (browser == UC.beQuiet.playingBrowser) {
      UC.beQuiet.remove(UC.beQuiet.playingStack, UC.beQuiet.playingBrowser);
      if (UC.beQuiet.playingBrowser)
        UC.beQuiet.doAction('play', UC.beQuiet.playingBrowser);
    }
  },

  frameScript: 'data:application/javascript;charset=UTF-8,' + encodeURIComponent('(' + (function () {
    let contentListener = (msg) => {
      if (msg.data == 'destroy') {
        removeMessageListener('bequiet', contentListener);
        delete this.contentListener;
      } else {
        content.document.querySelector(msg.data)?.click();
      }
    }
    addMessageListener('bequiet', contentListener);
  }).toString() + ')();'),

  stack: [],

  playingStack: [],

  addUnique (stack, item) {
    this.remove(stack, item);
    stack.push(item);
  },

  remove (stack, item) {
    let index = stack.indexOf(item);
    if (index != -1) {
      stack.splice(index, 1);
    }
  },

  init: function () {
    Services.mm.loadFrameScript(this.frameScript, true);
  },

  destroy: function () {
    Services.mm.removeDelayedFrameScript(this.frameScript);
    Services.mm.broadcastAsyncMessage('bequiet', 'destroy');
    _uc.windows((doc, win) => {
      let gBrowser = win.gBrowser;
      gBrowser.removeTabsProgressListener(this.progressListener);
      gBrowser.removeEventListener('DOMAudioPlaybackStarted', this.audioStarted);
      gBrowser.removeEventListener('DOMAudioPlaybackStopped', this.audioStopped);
      doc.getElementById('beQuiet-keyset').remove();
      gBrowser.tabContainer.removeEventListener('TabClose', this.onTabClose);
    });
    delete UC.beQuiet;
  }
}

UC.beQuiet.init();<|endoftext|>


<commit_before>var GameView = {
    ARROW_HEIGHT: 14,
    ARROW_WIDTH: 30,
    roundCount: 0,
    maxHp: 0,
    findGameAndRoundId: function( href ) {
        var hrefArray = href.split( "?" )[ 1 ].split( "&" );
        var attribute, gameid, roundid;

        for ( var i = 0; i < hrefArray.length; ++i ) {
            attribute = hrefArray[ i ].split( "=" );
            switch ( attribute[ 0 ] ) {
                case 'roundid':
                    roundid = parseInt( attribute[ 1 ] );
                    break;
                case 'gameid':
                    gameid = parseInt( attribute[ 1 ] );
                    break;
            }
        }
        return {
            gameid: gameid,
            roundid: roundid
        }
    },
    fixUserList: function( creatures ) {
        var hasCreatures = [];
        for ( var i = 0; i < creatures.length; ++i ) {
            creature = creatures[ i ];
            if ( creature.hp > 0 ) {
                hasCreatures[ creature.userid ] = true;
            }
        }

        $( '.playerList li' ).each( function( index, value ) {
            var $node = $( this );
            var userid = $node.attr( 'data-id' );
            var $nameNode = $node.contents()[ 1 ];
            var $newNameNode = $( document.createTextNode( $node.text() ) );

            if ( !hasCreatures[ userid ] ) {
                $newNameNode = $( "" + $newNameNode.text() + "" );
            }
            $nameNode.remove();
            $node.append( $newNameNode );
        } );
    },
    makeUrl: function( gameid, roundid ) {
        return "game/view?gameid=" + gameid + "&roundid=" + roundid;
    },
    fixUrls: function( gameid, roundid ) {
        $( ".next a" ).attr( 'href', this.makeUrl( gameid, roundid + 1 ) );
        $( ".previous a" ).attr( 'href', this.makeUrl( gameid, roundid - 1 ) );
    },
    createCreature: function( creatureInfo, color ) {
        var $creature = $( '

' );
        for ( var attribute in creatureInfo ) {
            var value = creatureInfo[ attribute ];
            $creature.attr( 'data-' + attribute, value );
        }
        $creature.css( {
            left: creatureInfo.x * 20 + 'px',
            top: creatureInfo.y * 20 + 'px'
        } );
        return $creature;
    },
    processCreatures: function( creatures ) {
        $( '.creature' ).remove();
        for ( var i = 0; i < creatures.length; ++i ) {
            var creature = creatures[ i ];
            if ( creature.hp > 0 ) {
                var $user = $( '.playerList li[data-id=' + creature.userid + ']' );
                var username = $user.text();
                var color = $user.find( 'span.bubble' ).attr( 'data-color' );
                creatureInfo = {
                    creatureid: creature.creatureid,
                    username: username,
                    x: creature.x,
                    y: creature.y,
                    hp: creature.hp
                };
                var $creature = GameView.createCreature( creatureInfo, color );
                $( '.gameboard' ).prepend( $creature );
            }
        }
    },
    getMap: function() {
        var href = this.href;
        $.getJSON( href, function( creatures ) {
            var gameInfo = GameView.findGameAndRoundId( href );
            var gameid = gameInfo.gameid;
            var roundid = gameInfo.roundid;

            history.pushState( {}, "", href );

            $( '.round' ).text( 'Round ' + roundid );

            $( '.next' ).toggle( roundid + 1 < GameView.roundCount );
            $( '.previous' ).toggle( roundid - 1 >= 0 );
            GameView.fixUrls( gameid, roundid );

            GameView.processCreatures( creatures );

            GameView.fixUserList( creatures );
        } );
        return false;
    },
    fixWidthAndHeight: function( $element ) {
        if ( $element.attr( 'data-width' ) ) {
            $element.css( 'width', $element.attr( 'data-width' ) );
        }
        if ( $element.attr( 'data-height' ) ) {
            $element.css( 'height', $element.attr( 'data-height' ) );
        }
    },
    ready: function() {
        GameView.fixWidthAndHeight( $( '.game' ) );
        GameView.fixWidthAndHeight( $( '.time' ) );
        GameView.roundCount = $( '.gamemeta h2' ).attr( 'data-rounds' );
        GameView.maxHp = $( '.gamemeta h2' ).attr( 'data-maxHp' );
        $( document ).on( "mouseover", ".creature", function() {
            var id = this.getAttribute( 'data-creatureid' );
            var username = this.getAttribute( 'data-username' );
            var x = this.getAttribute( 'data-x' );
            var y = this.getAttribute( 'data-y' );
            var hp = this.getAttribute( 'data-hp' );
            var $this = $( this );
            var offsetTop = $this.offset().top - $( '.infobubble' ).height() - 14;
            var $infobubble = $( '.infobubble' );
            var positioning;

            $infobubble.show();
            $( '.player' ).text( username );
            $( '.creatureid' ).text( 'Creature ' + id );
            $( '.location' ).text( x + ', ' + y );
            $( '.numeric' ).text( hp + ' / ' + GameView.maxHp );
            $( '.damage' ).css( 'width', Math.floor( 100 * ( GameView.maxHp - hp ) / GameView.maxHp ) + '%' );
            if ( offsetTop < 0 ) {
                positioning = $this.height() + GameView.ARROW_HEIGHT;
                $infobubble.addClass( 'reversed' );
            }
            else { // bubble doesn't fit on the screen
                positioning = -$infobubble.height() - GameView.ARROW_HEIGHT;
            }
            $infobubble.css( 'top', $this.position().top + positioning );
            $infobubble.css( 'left', $this.position().left - $infobubble.width() + GameView.ARROW_WIDTH );
        } );
        $( document ).on( "mouseout", ".creature", function() {
            var $infobubble = $( '.infobubble' );
            $infobubble.removeClass( 'reversed' );
            $infobubble.hide();
        } );
        $( '.next a' ).click( GameView.getMap );
        $( '.previous a' ).click( GameView.getMap );
    }
}
$( document ).ready( GameView.ready );
<commit_msg>Change roundid bug<commit_after>var GameView = {
    ARROW_HEIGHT: 14,
    ARROW_WIDTH: 30,
    roundCount: 0,
    maxHp: 0,
    findGameAndRoundId: function( href ) {
        var hrefArray = href.split( "?" )[ 1 ].split( "&" );
        var attribute, gameid, roundid;

        for ( var i = 0; i < hrefArray.length; ++i ) {
            attribute = hrefArray[ i ].split( "=" );
            switch ( attribute[ 0 ] ) {
                case 'roundid':
                    roundid = parseInt( attribute[ 1 ] );
                    break;
                case 'gameid':
                    gameid = parseInt( attribute[ 1 ] );
                    break;
            }
        }
        return {
            gameid: gameid,
            roundid: roundid
        }
    },
    fixUserList: function( creatures ) {
        var hasCreatures = [];
        for ( var i = 0; i < creatures.length; ++i ) {
            creature = creatures[ i ];
            if ( creature.hp > 0 ) {
                hasCreatures[ creature.userid ] = true;
            }
        }

        $( '.playerList li' ).each( function( index, value ) {
            var $node = $( this );
            var userid = $node.attr( 'data-id' );
            var $nameNode = $node.contents()[ 1 ];
            var $newNameNode = $( document.createTextNode( $node.text() ) );

            if ( !hasCreatures[ userid ] ) {
                $newNameNode = $( "" + $newNameNode.text() + "" );
            }
            $nameNode.remove();
            $node.append( $newNameNode );
        } );
    },
    makeUrl: function( gameid, roundid ) {
        return "game/view?gameid=" + gameid + "&roundid=" + roundid;
    },
    fixUrls: function( gameid, roundid ) {
        $( ".next a" ).attr( 'href', this.makeUrl( gameid, roundid + 1 ) );
        $( ".previous a" ).attr( 'href', this.makeUrl( gameid, roundid - 1 ) );
    },
    createCreature: function( creatureInfo, color ) {
        var $creature = $( '

' );
        for ( var attribute in creatureInfo ) {
            var value = creatureInfo[ attribute ];
            $creature.attr( 'data-' + attribute, value );
        }
        $creature.css( {
            left: creatureInfo.x * 20 + 'px',
            top: creatureInfo.y * 20 + 'px'
        } );
        return $creature;
    },
    processCreatures: function( creatures ) {
        $( '.creature' ).remove();
        for ( var i = 0; i < creatures.length; ++i ) {
            var creature = creatures[ i ];
            if ( creature.hp > 0 ) {
                var $user = $( '.playerList li[data-id=' + creature.userid + ']' );
                var username = $user.text();
                var color = $user.find( 'span.bubble' ).attr( 'data-color' );
                creatureInfo = {
                    creatureid: creature.creatureid,
                    username: username,
                    x: creature.x,
                    y: creature.y,
                    hp: creature.hp
                };
                var $creature = GameView.createCreature( creatureInfo, color );
                $( '.gameboard' ).prepend( $creature );
            }
        }
    },
    getMap: function() {
        var href = this.href;
        $.getJSON( href, function( creatures ) {
            var gameInfo = GameView.findGameAndRoundId( href );
            var gameid = gameInfo.gameid;
            var roundid = gameInfo.roundid;

            history.pushState( {}, "", href );

            $( '.roundid' ).text( 'Round ' + roundid );

            $( '.next' ).toggle( roundid + 1 < GameView.roundCount );
            $( '.previous' ).toggle( roundid - 1 >= 0 );
            GameView.fixUrls( gameid, roundid );

            GameView.processCreatures( creatures );

            GameView.fixUserList( creatures );
        } );
        return false;
    },
    fixWidthAndHeight: function( $element ) {
        if ( $element.attr( 'data-width' ) ) {
            $element.css( 'width', $element.attr( 'data-width' ) );
        }
        if ( $element.attr( 'data-height' ) ) {
            $element.css( 'height', $element.attr( 'data-height' ) );
        }
    },
    ready: function() {
        GameView.fixWidthAndHeight( $( '.game' ) );
        GameView.fixWidthAndHeight( $( '.time' ) );
        GameView.roundCount = $( '.gamemeta h2' ).attr( 'data-rounds' );
        GameView.maxHp = $( '.gamemeta h2' ).attr( 'data-maxHp' );
        $( document ).on( "mouseover", ".creature", function() {
            var id = this.getAttribute( 'data-creatureid' );
            var username = this.getAttribute( 'data-username' );
            var x = this.getAttribute( 'data-x' );
            var y = this.getAttribute( 'data-y' );
            var hp = this.getAttribute( 'data-hp' );
            var $this = $( this );
            var offsetTop = $this.offset().top - $( '.infobubble' ).height() - 14;
            var $infobubble = $( '.infobubble' );
            var positioning;

            $infobubble.show();
            $( '.player' ).text( username );
            $( '.creatureid' ).text( 'Creature ' + id );
            $( '.location' ).text( x + ', ' + y );
            $( '.numeric' ).text( hp + ' / ' + GameView.maxHp );
            $( '.damage' ).css( 'width', Math.floor( 100 * ( GameView.maxHp - hp ) / GameView.maxHp ) + '%' );
            if ( offsetTop < 0 ) {
                positioning = $this.height() + GameView.ARROW_HEIGHT;
                $infobubble.addClass( 'reversed' );
            }
            else { // bubble doesn't fit on the screen
                positioning = -$infobubble.height() - GameView.ARROW_HEIGHT;
            }
            $infobubble.css( 'top', $this.position().top + positioning );
            $infobubble.css( 'left', $this.position().left - $infobubble.width() + GameView.ARROW_WIDTH );
        } );
        $( document ).on( "mouseout", ".creature", function() {
            var $infobubble = $( '.infobubble' );
            $infobubble.removeClass( 'reversed' );
            $infobubble.hide();
        } );
        $( '.next a' ).click( GameView.getMap );
        $( '.previous a' ).click( GameView.getMap );
    }
}
$( document ).ready( GameView.ready );
<|endoftext|>


<commit_before>(function() {
    'use strict';

    angular
        .module('gpApp.layout')
        .controller('View', View);

    View.$inject = ['$mdSidenav', '$mdMedia', 'dataservice', '$log', '$q'];
    function View($mdSidenav, $mdMedia, dataservice, $log, $q) {
        var vm = this;
        vm.title         = '';
        vm.isFullscreen  = false;
        vm.sidenavLock   = sidenavLock;
        vm.fullscreen    = toggleFullscreen;

        vm.toggleSidenav = toggleSidenav;
        vm.closeSidenav  = closeSidenav;
        vm.openSidenav   = openSidenav;

        activate();

        ////////////
        function activate() {
            return dataservice
                .current()
                .then(function(response) {
                    vm.title = response.year + ' ' + response.title;
                    return vm.title;
                });
        }

        function sidenavLock() {
            return $mdMedia('gt-sm') && !vm.isFullscreen ? true : false;
        }
        function toggleFullscreen() {
            var pending = vm.isFullscreen = !vm.isFullscreen || $q.when(true);
            pending.then(function() {
                $mdSidenav('right').close();
            });
            return vm.isfullscreen;
        }

        function toggleSidenav() {
            $mdSidenav('right')
                .toggle()
                .then(function() {
                    $log.debug('Sidenav toggled.');
                });
        }

        function closeSidenav() {
            $mdSidenav('right')
                .close()
                .then(function() {
                    $log.debug('Sidenav closed.');
                });
        }

        function openSidenav() {
            $mdSidenav('right')
                .open()
                .then(function() {
                    $log.debug('Sidenav opened.');
                });
        }
    }
})();<commit_msg>View controller<commit_after>(function() {
    'use strict';

    angular
        .module('gpApp.layout')
        .controller('View', View);

    View.$inject = ['$mdSidenav', '$mdMedia', 'dataservice', '$log', '$q'];
    function View($mdSidenav, $mdMedia, dataservice, $log, $q) {
        var vm = this;
        vm.title         = '';
        vm.toggleSidenav = toggleSidenav;
        vm.closeSidenav  = closeSidenav;
        vm.openSidenav   = openSidenav;

        activate();

        ////////////
        function activate() {
            return dataservice
                .current()
                .then(function(response) {
                    vm.title = response.year + ' ' + response.title;
                    return vm.title;
                });
        }

        function toggleSidenav() {
            $mdSidenav('right')
                .toggle()
                .then(function() {
                    $log.debug('Sidenav toggled.');
                });
        }

        function closeSidenav() {
            $mdSidenav('right')
                .close()
                .then(function() {
                    $log.debug('Sidenav closed.');
                });
        }

        function openSidenav() {
            $mdSidenav('right')
                .open()
                .then(function() {
                    $log.debug('Sidenav opened.');
                });
        }
    }
})();<|endoftext|>


<commit_before>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(proce<commit_msg>Correcting style<commit_after>var child_process = require('child_process')
var fs = require('fs');
var max_sleep = 300
var step = 10
//Added a comment that achieves no real goal.
//Non-blocking loop
//Adjustable step
//Status line
//Add a rough time indicator
//First cut at libfaketime support

var commit_messages = [
  "Fixing an important issue with the universe.",
  "Someone poisoned the waterhole!",
  "You feeling lucky punk?",
  "Five bullets or six?",
  "Fixed memory parsing error #1337",
  "Cleaned out the intertubes",
  "AAAAAAAAAAARGH!",
  "Fixed a typo",
  "Updated the readme",
  "Fixing a typo added in the last readme update",
  "GET A HAIRCUT!",
  "Updated the readme again",
  "Found an issue with the letter 'a', so I fixed it.",
  "Incompatible dimensions found, Cthuhlu Error 666",
  "Who you calling a fool?",
  "How many more of these can I make?",
  "Fixing an error introduced in the last commit",
  "Re-updating the readme.",
  "Work in Progress",
  "WIP",
  "Quick fix",
  "Grammar fix",
  "Fixing punctuation",
  "Correcting style",
  "Logic error",
  "Almost there",
  "Nearly got it",
  "Not quite working",
  "Ooops!",
  "Did I do that?",
  "Commit all the required changes",
  "Really commit all the required changes",
  "Should work now",
  "Back out the last commit",
  "Reverting changes",
  "One more time...",
  "Re-commiting last",
  "One more User Story done",
  "Can work my way through the Kanban",
  "Sprint complete",
  "Well that seemed pretty easy",
  "What do you mean you can't pack up the commit?",
  "Merge in master",
  "Fast-forwarding changes"
]

if ( process.argv[ 2 ] && process.argv[ 3 ] ) {
  var inFile = process.argv[ 2 ]
  var outFile = process.argv[ 3 ]
  if (inFile == outFile) {
    console.error("Aborted: infile and outfile must be different")
    return(-1);
  }
  if (process.argv [ 4 ]) max_sleep = process.argv [ 4 ]
  if (process.argv [ 5 ]) step = parseInt(proces<|endoftext|>


<commit_before>#!/usr/bin/env node

let firebase = require("firebase-admin"),
    glob = require("glob"),
    yamljs = require("yamljs"),
    fs = require("fs-extra"),
    crypto = require('crypto'),
    metaMarked = require("meta-marked"),
    path = require("path"),
    moment = require("moment");

const { getCompilationQuarterValue, getInfoFromPath } = require('./deploy-helper')

let argv = require("optimist").usage("Compile & deploy video - DON'T USE IF YOU DON'T KNOW WHAT IT DOES\n" +
    "Usage: $0 -b [string]")
    .alias({"b": "branch"})
    .describe({
        "b": "branch",
        "l": "language",
        "q": "quarter",
        "m": "mode"
    })
    .demand(["b"])
    .argv;

let branch = argv.b,
    compile_language = argv.l || "*",
    compile_quarter = argv.q || getCompilationQuarterValue(),
    mode = argv.m || "sync";

let API_HOST = "https://sabbath-school.adventech.io/api/",
    MEDIA_HOST = "https://sabbath-school-media.adventech.io/",
    API_VERSION = "v1",
    SOURCE_DIR = "src/",
    SOURCE_VIDEO_FILE = "video.yml",
    SOURCE_COVER_FILE = "cover.png",
    DIST_DIR = "dist/api/" + API_VERSION + "/",
    FIREBASE_DATABASE_VIDEO = "/api/" + API_VERSION + "/video";

let db
if (branch.toLowerCase() === "master") {
    API_HOST = "https://sabbath-school.adventech.io/api/";
    MEDIA_HOST = "https://sabbath-school-media.adventech.io/";
    firebase.initializeApp({
        databaseURL: "https://blistering-inferno-8720.firebaseio.com",
        credential: firebase.credential.cert(require('./deploy-creds.json')),
        databaseAuthVariableOverride: {
            uid: "deploy"
        }
    });
    db = firebase.database();
} else if (branch.toLowerCase() === "stage") {
    API_HOST = "https://sabbath-school-stage.adventech.io/api/";
    MEDIA_HOST = "https://sabbath-school-media-stage.adventech.io/";
    firebase.initializeApp({
        databaseURL: "https://sabbath-school-stage.firebaseio.com",
        credential: firebase.credential.cert(require('./deploy-creds-stage.json')),
        databaseAuthVariableOverride: {
            uid: "deploy"
        }
    });
    db = firebase.database();
} else {
    firebase = {
        app: function () {
            return {
                delete: function () {}
            }
        }
    };
    db = {
        ref: function () {
            return {
                set: function () {},
                child: function () {
                    return {
                        set: function (a) {},
                        once: function () {}
                    }
                }
            }
        },
        goOffline: function () {}
    }
}

let videoAPI = async function (mode) {
    const allowedVideoItemKeys = ['title', 'src', 'thumbnail', 'target', 'duration']
    console.log('Deploying video API');

    let videos = glob.sync(`${SOURCE_DIR}/${compile_language}/${compile_quarter}/${SOURCE_VIDEO_FILE}`);
    let videoAPIJson = []

    let curlConfig = ""

    for (let video of videos) {
        let videoSource = yamljs.load(`${video}`),
            info = getInfoFromPath(video);

        for (let artist of videoSource.video) {
            let videoInfo = {
                artist: artist.artist,
                clips: []
            }

            if (artist.thumbnail) {
                videoInfo.thumbnail = artist.thumbnail
            }

            for (let clip of artist.clips) {
                if (!clip['target'] || !clip['src']) { continue }

                let videoItem = {
                    artist: videoInfo.artist
                }

                videoItem.id = crypto.createHash('sha256').update(artist.artist + clip['target'] + clip['src']).digest('hex');

                for (let k of Object.keys(clip)) {
                    if (allowedVideoItemKeys.indexOf(k) >= 0) {
                        videoItem[k] = clip[k]
                    }
                }

                let extname = path.extname(videoItem.src)

                if (!extname.length || extname.length <= 1 || extname.length > 4 || !/^\./.test(extname)) {
                    extname = ".mp4"
                }

                videoItem.src = `${MEDIA_HOST}video/${info.language}/${info.quarterly}/${videoItem.id}/${videoItem.id}${extname}`

                videoItem.targetIndex = videoItem.target.replace(/\//g, '-')

                if (!videoItem.thumbnail) {
                    if (artist.thumbnail && !/^http/.test(artist.thumbnail.trim())) {
                        artist.thumbnail = `${API_HOST}${API_VERSION}/images/${artist.thumbnail}`
                    }
                    videoItem.thumbnail = artist.thumbnail || `${API_HOST}${API_VERSION}/${info.language}/quarterlies/${info.quarterly}/${SOURCE_COVER_FILE}`
                }

                if (videoItem.duration) {
                    if (typeof videoItem.duration === 'number') {
                        videoItem.duration = moment("2015-01-01").startOf('day').seconds(videoItem.duration).format("H:mm:ss").replace(/^[0:]+(?=\d[\d:]{3})/, '');
                    }
                }

                if (!videoItem.title) {
                    let videoItemInfo = getInfoFromPath(`src/${videoItem.target}`)
                    if (!videoItemInfo.lesson) {
                        continue
                    }

                    if (videoItemInfo.day) {
                        let read = metaMarked(fs.readFileSync(`${SOURCE_DIR}${videoItemInfo.language}/${videoItemInfo.quarterly}/${videoItemInfo.lesson}/${videoItemInfo.day}.md`, "utf-8"))
                        videoItem.title = read.meta.title
                    } else {
                        let lesson = yamljs.load(`${SOURCE_DIR}${videoItemInfo.language}/${videoItemInfo.quarterly}/${videoItemInfo.lesson}/info.yml`)
                        videoItem.title = lesson.title
                    }
                }

                videoInfo.clips.push(videoItem)

                if (mode === "keep" && fs.pathExistsSync(`video/video/${info.language}/${info.quarterly}/${videoItem.id}/${videoItem.id}${extname}`)) {
                    let stats = fs.statSync(`video/video/${info.language}/${info.quarterly}/${videoItem.id}/${videoItem.id}${extname}`);
                    if (stats.size > 0) {
                        fs.outputFileSync(`video/video/${info.language}/${info.quarterly}/${videoItem.id}/.keep`, "");
                    }
                }

                if (mode === "gen" && !fs.pathExistsSync(`video/video/${info.language}/${info.quarterly}/${videoItem.id}/`)) {
                    curlConfig += `
url = "${clip.src}"
output = "video/video/${info.language}/${info.quarterly}/${videoItem.id}/${videoItem.id}${extname}"
-C -
--create-dirs
-L
`
                }
            }

            if (videoInfo.clips.length) {

                videoInfo.clips = videoInfo.clips.sort(function(a, b){
                    if (a.targetIndex < b.targetIndex) {
                        return a.targetIndex.length < b.targetIndex.length ? -1 : 1;
                    }

                    if (a.targetIndex > b.targetIndex) {
                        return a.targetIndex.length > b.targetIndex.length ? 1 : -1;
                    }
                    return 0;
                })

                videoAPIJson.push(videoInfo)
            }
        }

        if (mode === "sync") {
            await db.ref(FIREBASE_DATABASE_VIDEO).child(`${info.language}-${info.quarterly}`).set(videoAPIJson);

            if (videoAPIJson.length) {
                fs.outputFileSync(`${DIST_DIR}${info.language}/quarterlies/${info.quarterly}/video.json`, JSON.stringify(videoAPIJson));
            }
        }
    }

    if (mode === "gen" && curlConfig.trim().length > 1) {
        fs.outputFileSync(`curl-config.txt`, curlConfig);
    }
};

((async function () {
    try {
        await videoAPI(mode);
    } catch (e) {
        console.error(e)
    }
})()).then(() => {
    db.goOffline();
    firebase.app().delete();
});<commit_msg>Fix video deployment bug related to aggregation of all videos<commit_after>#!/usr/bin/env node

let firebase = require("firebase-admin"),
    glob = require("glob"),
    yamljs = require("yamljs"),
    fs = require("fs-extra"),
    crypto = require('crypto'),
    metaMarked = require("meta-marked"),
    path = require("path"),
    moment = require("moment");

const { getCompilationQuarterValue, getInfoFromPath } = require('./deploy-helper')

let argv = require("optimist").usage("Compile & deploy video - DON'T USE IF YOU DON'T KNOW WHAT IT DOES\n" +
    "Usage: $0 -b [string]")
    .alias({"b": "branch"})
    .describe({
        "b": "branch",
        "l": "language",
        "q": "quarter",
        "m": "mode"
    })
    .demand(["b"])
    .argv;

let branch = argv.b,
    compile_language = argv.l || "*",
    compile_quarter = argv.q || getCompilationQuarterValue(),
    mode = argv.m || "sync";

let API_HOST = "https://sabbath-school.adventech.io/api/",
    MEDIA_HOST = "https://sabbath-school-media.adventech.io/",
    API_VERSION = "v1",
    SOURCE_DIR = "src/",
    SOURCE_VIDEO_FILE = "video.yml",
    SOURCE_COVER_FILE = "cover.png",
    DIST_DIR = "dist/api/" + API_VERSION + "/",
    FIREBASE_DATABASE_VIDEO = "/api/" + API_VERSION + "/video";

let db
if (branch.toLowerCase() === "master") {
    API_HOST = "https://sabbath-school.adventech.io/api/";
    MEDIA_HOST = "https://sabbath-school-media.adventech.io/";
    firebase.initializeApp({
        databaseURL: "https://blistering-inferno-8720.firebaseio.com",
        credential: firebase.credential.cert(require('./deploy-creds.json')),
        databaseAuthVariableOverride: {
            uid: "deploy"
        }
    });
    db = firebase.database();
} else if (branch.toLowerCase() === "stage") {
    API_HOST = "https://sabbath-school-stage.adventech.io/api/";
    MEDIA_HOST = "https://sabbath-school-media-stage.adventech.io/";
    firebase.initializeApp({
        databaseURL: "https://sabbath-school-stage.firebaseio.com",
        credential: firebase.credential.cert(require('./deploy-creds-stage.json')),
        databaseAuthVariableOverride: {
            uid: "deploy"
        }
    });
    db = firebase.database();
} else {
    firebase = {
        app: function () {
            return {
                delete: function () {}
            }
        }
    };
    db = {
        ref: function () {
            return {
                set: function () {},
                child: function () {
                    return {
                        set: function (a) {},
                        once: function () {}
                    }
                }
            }
        },
        goOffline: function () {}
    }
}

let videoAPI = async function (mode) {
    const allowedVideoItemKeys = ['title', 'src', 'thumbnail', 'target', 'duration']
    console.log('Deploying video API');

    let videos = glob.sync(`${SOURCE_DIR}/${compile_language}/${compile_quarter}/${SOURCE_VIDEO_FILE}`);
    let curlConfig = ""

    for (let video of videos) {
        let videoAPIJson = []
        let videoSource = yamljs.load(`${video}`),
            info = getInfoFromPath(video);

        for (let artist of videoSource.video) {
            let videoInfo = {
                artist: artist.artist,
                clips: []
            }

            if (artist.thumbnail) {
                videoInfo.thumbnail = artist.thumbnail
            }

            for (let clip of artist.clips) {
                if (!clip['target'] || !clip['src']) { continue }

                let videoItem = {
                    artist: videoInfo.artist
                }

                videoItem.id = crypto.createHash('sha256').update(artist.artist + clip['target'] + clip['src']).digest('hex');

                for (let k of Object.keys(clip)) {
                    if (allowedVideoItemKeys.indexOf(k) >= 0) {
                        videoItem[k] = clip[k]
                    }
                }

                let extname = path.extname(videoItem.src)

                if (!extname.length || extname.length <= 1 || extname.length > 4 || !/^\./.test(extname)) {
                    extname = ".mp4"
                }

                videoItem.src = `${MEDIA_HOST}video/${info.language}/${info.quarterly}/${videoItem.id}/${videoItem.id}${extname}`

                videoItem.targetIndex = videoItem.target.replace(/\//g, '-')

                if (!videoItem.thumbnail) {
                    if (artist.thumbnail && !/^http/.test(artist.thumbnail.trim())) {
                        artist.thumbnail = `${API_HOST}${API_VERSION}/images/${artist.thumbnail}`
                    }
                    videoItem.thumbnail = artist.thumbnail || `${API_HOST}${API_VERSION}/${info.language}/quarterlies/${info.quarterly}/${SOURCE_COVER_FILE}`
                }

                if (videoItem.duration) {
                    if (typeof videoItem.duration === 'number') {
                        videoItem.duration = moment("2015-01-01").startOf('day').seconds(videoItem.duration).format("H:mm:ss").replace(/^[0:]+(?=\d[\d:]{3})/, '');
                    }
                }

                if (!videoItem.title) {
                    let videoItemInfo = getInfoFromPath(`src/${videoItem.target}`)
                    if (!videoItemInfo.lesson) {
                        continue
                    }

                    if (videoItemInfo.day) {
                        let read = metaMarked(fs.readFileSync(`${SOURCE_DIR}${videoItemInfo.language}/${videoItemInfo.quarterly}/${videoItemInfo.lesson}/${videoItemInfo.day}.md`, "utf-8"))
                        videoItem.title = read.meta.title
                    } else {
                        let lesson = yamljs.load(`${SOURCE_DIR}${videoItemInfo.language}/${videoItemInfo.quarterly}/${videoItemInfo.lesson}/info.yml`)
                        videoItem.title = lesson.title
                    }
                }

                videoInfo.clips.push(videoItem)

                if (mode === "keep" && fs.pathExistsSync(`video/video/${info.language}/${info.quarterly}/${videoItem.id}/${videoItem.id}${extname}`)) {
                    let stats = fs.statSync(`video/video/${info.language}/${info.quarterly}/${videoItem.id}/${videoItem.id}${extname}`);
                    if (stats.size > 0) {
                        fs.outputFileSync(`video/video/${info.language}/${info.quarterly}/${videoItem.id}/.keep`, "");
                    }
                }

                if (mode === "gen" && !fs.pathExistsSync(`video/video/${info.language}/${info.quarterly}/${videoItem.id}/`)) {
                    curlConfig += `
url = "${clip.src}"
output = "video/video/${info.language}/${info.quarterly}/${videoItem.id}/${videoItem.id}${extname}"
-C -
--create-dirs
-L
`
                }
            }

            if (videoInfo.clips.length) {

                videoInfo.clips = videoInfo.clips.sort(function(a, b){
                    if (a.targetIndex < b.targetIndex) {
                        return a.targetIndex.length < b.targetIndex.length ? -1 : 1;
                    }

                    if (a.targetIndex > b.targetIndex) {
                        return a.targetIndex.length > b.targetIndex.length ? 1 : -1;
                    }
                    return 0;
                })

                videoAPIJson.push(videoInfo)
            }
        }

        if (mode === "sync") {
            await db.ref(FIREBASE_DATABASE_VIDEO).child(`${info.language}-${info.quarterly}`).set(videoAPIJson);

            if (videoAPIJson.length) {
                fs.outputFileSync(`${DIST_DIR}${info.language}/quarterlies/${info.quarterly}/video.json`, JSON.stringify(videoAPIJson));
            }
        }
    }

    if (mode === "gen" && curlConfig.trim().length > 1) {
        fs.outputFileSync(`curl-config.txt`, curlConfig);
    }
};

((async function () {
    try {
        await videoAPI(mode);
    } catch (e) {
        console.error(e)
    }
})()).then(() => {
    db.goOffline();
    firebase.app().delete();
});<|endoftext|>


<commit_before>/**
 * @fileoverview Runs `prettier` as an ESLint rule.
 * @author Andres Suarez
 */

'use strict';

// ------------------------------------------------------------------------------
//  Requirements
// ------------------------------------------------------------------------------

const diff = require('fast-diff');
const docblock = require('jest-docblock');

// ------------------------------------------------------------------------------
//  Constants
// ------------------------------------------------------------------------------

// Preferred Facebook style.
const FB_PRETTIER_OPTIONS = {
  singleQuote: true,
  trailingComma: 'all',
  bracketSpacing: false,
  jsxBracketSameLine: true,
  parser: 'flow'
};

const LINE_ENDING_RE = /\r\n|[\r\n\u2028\u2029]/;

const OPERATION_INSERT = 'insert';
const OPERATION_DELETE = 'delete';
const OPERATION_REPLACE = 'replace';

// ------------------------------------------------------------------------------
//  Privates
// ------------------------------------------------------------------------------

// Lazily-loaded Prettier.
let prettier;

// ------------------------------------------------------------------------------
//  Helpers
// ------------------------------------------------------------------------------

/**
 * Gets the location of a given index in the source code for a given context.
 * @param {RuleContext} context - The ESLint rule context.
 * @param {number} index - An index in the source code.
 * @returns {Object} An object containing numeric `line` and `column` keys.
 */
function getLocFromIndex(context, index) {
  // If `sourceCode.getLocFromIndex` is available from ESLint, use it - added
  // in ESLint 3.16.0.
  const sourceCode = context.getSourceCode();
  if (typeof sourceCode.getLocFromIndex === 'function') {
    return sourceCode.getLocFromIndex(index);
  }
  const text = sourceCode.getText();
  if (typeof index !== 'number') {
    throw new TypeError('Expected `index` to be a number.');
  }
  if (index < 0 || index > text.length) {
    throw new RangeError('Index out of range.');
  }
  // Loosely based on
  // https://github.com/eslint/eslint/blob/18a519fa/lib/ast-utils.js#L408-L438
  const lineEndingPattern = /\r\n|[\r\n\u2028\u2029]/g;
  let offset = 0;
  let line = 0;
  let match;
  while ((match = lineEndingPattern.exec(text))) {
    const next = match.index + match[0].length;
    if (index < next) {
      break;
    }
    line++;
    offset = next;
  }
  return {
    line: line + 1,
    column: index - offset
  };
}

/**
 * Converts invisible characters to a commonly recognizable visible form.
 * @param {string} str - The string with invisibles to convert.
 * @returns {string} The converted string.
 */
function showInvisibles(str) {
  let ret = '';
  for (let i = 0; i < str.length; i++) {
    switch (str[i]) {
      case ' ':
        ret += '·'; // Middle Dot, \u00B7
        break;
      case '\n':
        ret += '⏎'; // Return Symbol, \u23ce
        break;
      case '\t':
        ret += '↹'; // Left Arrow To Bar Over Right Arrow To Bar, \u21b9
        break;
      default:
        ret += str[i];
        break;
    }
  }
  return ret;
}

/**
 * Generate results for differences between source code and formatted version.
 * @param {string} source - The original source.
 * @param {string} prettierSource - The Prettier formatted source.
 * @returns {Array} - An array contains { operation, offset, insertText, deleteText }
 */
function generateDifferences(source, prettierSource) {
  // fast-diff returns the differences between two texts as a series of
  // INSERT, DELETE or EQUAL operations. The results occur only in these
  // sequences:
  //           /-> INSERT -> EQUAL
  //    EQUAL |           /-> EQUAL
  //           \-> DELETE |
  //                      \-> INSERT -> EQUAL
  // Instead of reporting issues at each INSERT or DELETE, certain sequences
  // are batched together and are reported as a friendlier "replace" operation:
  // - A DELETE immediately followed by an INSERT.
  // - Any number of INSERTs and DELETEs where the joining EQUAL of one's end
  // and another's beginning does not have line endings (i.e. issues that occur
  // on contiguous lines).

  const results = diff(source, prettierSource);
  const differences = [];

  const batch = [];
  let offset = 0; // NOTE: INSERT never advances the offset.
  while (results.length) {
    const result = results.shift();
    const op = result[0];
    const text = result[1];
    switch (op) {
      case diff.INSERT:
      case diff.DELETE:
        batch.push(result);
        break;
      case diff.EQUAL:
        if (results.length) {
          if (batch.length) {
            if (LINE_ENDING_RE.test(text)) {
              flush();
              offset += text.length;
            } else {
              batch.push(result);
            }
          } else {
            offset += text.length;
          }
        }
        break;
      default:
        throw new Error(`Unexpected fast-diff operation "${op}"`);
    }
    if (batch.length && !results.length) {
      flush();
    }
  }

  return differences;

  function flush() {
    let aheadDeleteText = '';
    let aheadInsertText = '';
    while (batch.length) {
      const next = batch.shift();
      const op = next[0];
      const text = next[1];
      switch (op) {
        case diff.INSERT:
          aheadInsertText += text;
          break;
        case diff.DELETE:
          aheadDeleteText += text;
          break;
        case diff.EQUAL:
          aheadDeleteText += text;
          aheadInsertText += text;
          break;
      }
    }
    if (aheadDeleteText && aheadInsertText) {
      differences.push({
        offset,
        operation: OPERATION_REPLACE,
        insertText: aheadInsertText,
        deleteText: aheadDeleteText
      });
    } else if (!aheadDeleteText && aheadInsertText) {
      differences.push({
        offset,
        operation: OPERATION_INSERT,
        insertText: aheadInsertText
      });
    } else if (aheadDeleteText && !aheadInsertText) {
      differences.push({
        offset,
        operation: OPERATION_DELETE,
        deleteText: aheadDeleteText
      });
    }
    offset += aheadDeleteText.length;
  }
}

// ------------------------------------------------------------------------------
//  Rule Definition
// ------------------------------------------------------------------------------

/**
 * Reports an "Insert ..." issue where text must be inserted.
 * @param {RuleContext} context - The ESLint rule context.
 * @param {number} offset - The source offset where to insert text.
 * @param {string} text - The text to be inserted.
 * @returns {void}
 */
function reportInsert(context, offset, text) {
  const pos = getLocFromIndex(context, offset);
  const range = [offset, offset];
  context.report({
    message: 'Insert `{{ code }}`',
    data: { code: showInvisibles(text) },
    loc: { start: pos, end: pos },
    fix(fixer) {
      return fixer.insertTextAfterRange(range, text);
    }
  });
}

/**
 * Reports a "Delete ..." issue where text must be deleted.
 * @param {RuleContext} context - The ESLint rule context.
 * @param {number} offset - The source offset where to delete text.
 * @param {string} text - The text to be deleted.
 * @returns {void}
 */
function reportDelete(context, offset, text) {
  const start = getLocFromIndex(context, offset);
  const end = getLocFromIndex(context, offset + text.length);
  const range = [offset, offset + text.length];
  context.report({
    message: 'Delete `{{ code }}`',
    data: { code: showInvisibles(text) },
    loc: { start, end },
    fix(fixer) {
      return fixer.removeRange(range);
    }
  });
}

/**
 * Reports a "Replace ... with ..." issue where text must be replaced.
 * @param {RuleContext} context - The ESLint rule context.
 * @param {number} offset - The source offset where to replace deleted text
 with inserted text.
 * @param {string} deleteText - The text to be deleted.
 * @param {string} insertText - The text to be inserted.
 * @returns {void}
 */
function reportReplace(context, offset, deleteText, insertText) {
  const start = getLocFromIndex(context, offset);
  const end = getLocFromIndex(context, offset + deleteText.length);
  const range = [offset, offset + deleteText.length];
  context.report({
    message: 'Replace `{{ deleteCode }}` with `{{ insertCode }}`',
    data: {
      deleteCode: showInvisibles(deleteText),
      insertCode: showInvisibles(insertText)
    },
    loc: { start, end },
    fix(fixer) {
      return fixer.replaceTextRange(range, insertText);
    }
  });
}

// ------------------------------------------------------------------------------
//  Module Definition
// ------------------------------------------------------------------------------

module.exports = {
  showInvisibles,
  generateDifferences,
  rules: {
    prettier: {
      meta: {
        fixable: 'code',
        schema: [
          // Prettier options:
          {
            anyOf: [
              { enum: [null, 'fb'] },
              { type: 'object', properties: {}, additionalProperties: true }
            ]
          },
          // Pragma:
          { type: 'string', pattern: '^@\\w+$' }
        ]
      },
      create(context) {
        const pragma = context.options[1]
          ? context.options[1].slice(1) // Remove leading @
          : null;

        const sourceCode = context.getSourceCode();
        const source = sourceCode.text;

        // The pragma is only valid if it is found in a block comment at the very
        // start of the file.
        if (pragma) {
          // ESLint 3.x reports the shebang as a "Line" node, while ESLint 4.x
          // reports it as a "Shebang" node. This works for both versions:
          const hasShebang = source.startsWith('#!');
          const allComments = sourceCode.getAllComments();
          const firstComment = hasShebang ? allComments[1] : allComments[0];
          if (
            !(
              firstComment &&
              firstComment.type === 'Block' &&
              firstComment.loc.start.line === (hasShebang ? 2 : 1) &&
              firstComment.loc.start.column === 0
            )
          ) {
            return {};
          }
          const parsed = docblock.parse(firstComment.value);
          if (parsed[pragma] !== '') {
            return {};
          }
        }

        if (prettier) {
          prettier.clearConfigCache();
        }

        return {
          Program() {
            if (!prettier) {
              // Prettier is expensive to load, so only load it if needed.
              prettier = require('prettier');
            }

            const eslintPrettierOptions =
              context.options[0] === 'fb'
                ? FB_PRETTIER_OPTIONS
                : context.options[0];
            const prettierRcOptions =
              prettier.resolveConfig && prettier.resolveConfig.sync
                ? prettier.resolveConfig.sync(context.getFilename())
                : null;
            const prettierOptions = Object.assign(
              {},
              prettierRcOptions,
              eslintPrettierOptions
            );

            const prettierSource = prettier.format(source, prettierOptions);
            if (source !== prettierSource) {
              const differences = generateDifferences(source, prettierSource);

              differences.forEach(difference => {
                switch (difference.operation) {
                  case OPERATION_INSERT:
                    reportInsert(
                      context,
                      difference.offset,
                      difference.insertText
                    );
                    break;
                  case OPERATION_DELETE:
                    reportDelete(
                      context,
                      difference.offset,
                      difference.deleteText
                    );
                    break;
                  case OPERATION_REPLACE:
                    reportReplace(
                      context,
                      difference.offset,
                      difference.deleteText,
                      difference.insertText
                    );
                    break;
                }
              });
            }
          }
        };
      }
    }
  }
};
<commit_msg>Fix: Guard against older prettier installation (#56)<commit_after>/**
 * @fileoverview Runs `prettier` as an ESLint rule.
 * @author Andres Suarez
 */

'use strict';

// ------------------------------------------------------------------------------
//  Requirements
// ------------------------------------------------------------------------------

const diff = require('fast-diff');
const docblock = require('jest-docblock');

// ------------------------------------------------------------------------------
//  Constants
// ------------------------------------------------------------------------------

// Preferred Facebook style.
const FB_PRETTIER_OPTIONS = {
  singleQuote: true,
  trailingComma: 'all',
  bracketSpacing: false,
  jsxBracketSameLine: true,
  parser: 'flow'
};

const LINE_ENDING_RE = /\r\n|[\r\n\u2028\u2029]/;

const OPERATION_INSERT = 'insert';
const OPERATION_DELETE = 'delete';
const OPERATION_REPLACE = 'replace';

// ------------------------------------------------------------------------------
//  Privates
// ------------------------------------------------------------------------------

// Lazily-loaded Prettier.
let prettier;

// ------------------------------------------------------------------------------
//  Helpers
// ------------------------------------------------------------------------------

/**
 * Gets the location of a given index in the source code for a given context.
 * @param {RuleContext} context - The ESLint rule context.
 * @param {number} index - An index in the source code.
 * @returns {Object} An object containing numeric `line` and `column` keys.
 */
function getLocFromIndex(context, index) {
  // If `sourceCode.getLocFromIndex` is available from ESLint, use it - added
  // in ESLint 3.16.0.
  const sourceCode = context.getSourceCode();
  if (typeof sourceCode.getLocFromIndex === 'function') {
    return sourceCode.getLocFromIndex(index);
  }
  const text = sourceCode.getText();
  if (typeof index !== 'number') {
    throw new TypeError('Expected `index` to be a number.');
  }
  if (index < 0 || index > text.length) {
    throw new RangeError('Index out of range.');
  }
  // Loosely based on
  // https://github.com/eslint/eslint/blob/18a519fa/lib/ast-utils.js#L408-L438
  const lineEndingPattern = /\r\n|[\r\n\u2028\u2029]/g;
  let offset = 0;
  let line = 0;
  let match;
  while ((match = lineEndingPattern.exec(text))) {
    const next = match.index + match[0].length;
    if (index < next) {
      break;
    }
    line++;
    offset = next;
  }
  return {
    line: line + 1,
    column: index - offset
  };
}

/**
 * Converts invisible characters to a commonly recognizable visible form.
 * @param {string} str - The string with invisibles to convert.
 * @returns {string} The converted string.
 */
function showInvisibles(str) {
  let ret = '';
  for (let i = 0; i < str.length; i++) {
    switch (str[i]) {
      case ' ':
        ret += '·'; // Middle Dot, \u00B7
        break;
      case '\n':
        ret += '⏎'; // Return Symbol, \u23ce
        break;
      case '\t':
        ret += '↹'; // Left Arrow To Bar Over Right Arrow To Bar, \u21b9
        break;
      default:
        ret += str[i];
        break;
    }
  }
  return ret;
}

/**
 * Generate results for differences between source code and formatted version.
 * @param {string} source - The original source.
 * @param {string} prettierSource - The Prettier formatted source.
 * @returns {Array} - An array contains { operation, offset, insertText, deleteText }
 */
function generateDifferences(source, prettierSource) {
  // fast-diff returns the differences between two texts as a series of
  // INSERT, DELETE or EQUAL operations. The results occur only in these
  // sequences:
  //           /-> INSERT -> EQUAL
  //    EQUAL |           /-> EQUAL
  //           \-> DELETE |
  //                      \-> INSERT -> EQUAL
  // Instead of reporting issues at each INSERT or DELETE, certain sequences
  // are batched together and are reported as a friendlier "replace" operation:
  // - A DELETE immediately followed by an INSERT.
  // - Any number of INSERTs and DELETEs where the joining EQUAL of one's end
  // and another's beginning does not have line endings (i.e. issues that occur
  // on contiguous lines).

  const results = diff(source, prettierSource);
  const differences = [];

  const batch = [];
  let offset = 0; // NOTE: INSERT never advances the offset.
  while (results.length) {
    const result = results.shift();
    const op = result[0];
    const text = result[1];
    switch (op) {
      case diff.INSERT:
      case diff.DELETE:
        batch.push(result);
        break;
      case diff.EQUAL:
        if (results.length) {
          if (batch.length) {
            if (LINE_ENDING_RE.test(text)) {
              flush();
              offset += text.length;
            } else {
              batch.push(result);
            }
          } else {
            offset += text.length;
          }
        }
        break;
      default:
        throw new Error(`Unexpected fast-diff operation "${op}"`);
    }
    if (batch.length && !results.length) {
      flush();
    }
  }

  return differences;

  function flush() {
    let aheadDeleteText = '';
    let aheadInsertText = '';
    while (batch.length) {
      const next = batch.shift();
      const op = next[0];
      const text = next[1];
      switch (op) {
        case diff.INSERT:
          aheadInsertText += text;
          break;
        case diff.DELETE:
          aheadDeleteText += text;
          break;
        case diff.EQUAL:
          aheadDeleteText += text;
          aheadInsertText += text;
          break;
      }
    }
    if (aheadDeleteText && aheadInsertText) {
      differences.push({
        offset,
        operation: OPERATION_REPLACE,
        insertText: aheadInsertText,
        deleteText: aheadDeleteText
      });
    } else if (!aheadDeleteText && aheadInsertText) {
      differences.push({
        offset,
        operation: OPERATION_INSERT,
        insertText: aheadInsertText
      });
    } else if (aheadDeleteText && !aheadInsertText) {
      differences.push({
        offset,
        operation: OPERATION_DELETE,
        deleteText: aheadDeleteText
      });
    }
    offset += aheadDeleteText.length;
  }
}

// ------------------------------------------------------------------------------
//  Rule Definition
// ------------------------------------------------------------------------------

/**
 * Reports an "Insert ..." issue where text must be inserted.
 * @param {RuleContext} context - The ESLint rule context.
 * @param {number} offset - The source offset where to insert text.
 * @param {string} text - The text to be inserted.
 * @returns {void}
 */
function reportInsert(context, offset, text) {
  const pos = getLocFromIndex(context, offset);
  const range = [offset, offset];
  context.report({
    message: 'Insert `{{ code }}`',
    data: { code: showInvisibles(text) },
    loc: { start: pos, end: pos },
    fix(fixer) {
      return fixer.insertTextAfterRange(range, text);
    }
  });
}

/**
 * Reports a "Delete ..." issue where text must be deleted.
 * @param {RuleContext} context - The ESLint rule context.
 * @param {number} offset - The source offset where to delete text.
 * @param {string} text - The text to be deleted.
 * @returns {void}
 */
function reportDelete(context, offset, text) {
  const start = getLocFromIndex(context, offset);
  const end = getLocFromIndex(context, offset + text.length);
  const range = [offset, offset + text.length];
  context.report({
    message: 'Delete `{{ code }}`',
    data: { code: showInvisibles(text) },
    loc: { start, end },
    fix(fixer) {
      return fixer.removeRange(range);
    }
  });
}

/**
 * Reports a "Replace ... with ..." issue where text must be replaced.
 * @param {RuleContext} context - The ESLint rule context.
 * @param {number} offset - The source offset where to replace deleted text
 with inserted text.
 * @param {string} deleteText - The text to be deleted.
 * @param {string} insertText - The text to be inserted.
 * @returns {void}
 */
function reportReplace(context, offset, deleteText, insertText) {
  const start = getLocFromIndex(context, offset);
  const end = getLocFromIndex(context, offset + deleteText.length);
  const range = [offset, offset + deleteText.length];
  context.report({
    message: 'Replace `{{ deleteCode }}` with `{{ insertCode }}`',
    data: {
      deleteCode: showInvisibles(deleteText),
      insertCode: showInvisibles(insertText)
    },
    loc: { start, end },
    fix(fixer) {
      return fixer.replaceTextRange(range, insertText);
    }
  });
}

// ------------------------------------------------------------------------------
//  Module Definition
// ------------------------------------------------------------------------------

module.exports = {
  showInvisibles,
  generateDifferences,
  rules: {
    prettier: {
      meta: {
        fixable: 'code',
        schema: [
          // Prettier options:
          {
            anyOf: [
              { enum: [null, 'fb'] },
              { type: 'object', properties: {}, additionalProperties: true }
            ]
          },
          // Pragma:
          { type: 'string', pattern: '^@\\w+$' }
        ]
      },
      create(context) {
        const pragma = context.options[1]
          ? context.options[1].slice(1) // Remove leading @
          : null;

        const sourceCode = context.getSourceCode();
        const source = sourceCode.text;

        // The pragma is only valid if it is found in a block comment at the very
        // start of the file.
        if (pragma) {
          // ESLint 3.x reports the shebang as a "Line" node, while ESLint 4.x
          // reports it as a "Shebang" node. This works for both versions:
          const hasShebang = source.startsWith('#!');
          const allComments = sourceCode.getAllComments();
          const firstComment = hasShebang ? allComments[1] : allComments[0];
          if (
            !(
              firstComment &&
              firstComment.type === 'Block' &&
              firstComment.loc.start.line === (hasShebang ? 2 : 1) &&
              firstComment.loc.start.column === 0
            )
          ) {
            return {};
          }
          const parsed = docblock.parse(firstComment.value);
          if (parsed[pragma] !== '') {
            return {};
          }
        }

        if (prettier && prettier.clearConfigCache) {
          prettier.clearConfigCache();
        }

        return {
          Program() {
            if (!prettier) {
              // Prettier is expensive to load, so only load it if needed.
              prettier = require('prettier');
            }

            const eslintPrettierOptions =
              context.options[0] === 'fb'
                ? FB_PRETTIER_OPTIONS
                : context.options[0];
            const prettierRcOptions =
              prettier.resolveConfig && prettier.resolveConfig.sync
                ? prettier.resolveConfig.sync(context.getFilename())
                : null;
            const prettierOptions = Object.assign(
              {},
              prettierRcOptions,
              eslintPrettierOptions
            );

            const prettierSource = prettier.format(source, prettierOptions);
            if (source !== prettierSource) {
              const differences = generateDifferences(source, prettierSource);

              differences.forEach(difference => {
                switch (difference.operation) {
                  case OPERATION_INSERT:
                    reportInsert(
                      context,
                      difference.offset,
                      difference.insertText
                    );
                    break;
                  case OPERATION_DELETE:
                    reportDelete(
                      context,
                      difference.offset,
                      difference.deleteText
                    );
                    break;
                  case OPERATION_REPLACE:
                    reportReplace(
                      context,
                      difference.offset,
                      difference.deleteText,
                      difference.insertText
                    );
                    break;
                }
              });
            }
          }
        };
      }
    }
  }
};
<|endoftext|>


<commit_before>/**
 * Address search (geocoder).
 *
 * Recherche d'adresse (géocodage).
 */

/**
 * @param address The address to find.
 * @param callbackOk( longitude, latitude ) The code to call when address found.
 * @param callbackError( error_message ) The code to call when address not found or an error occured.
 */
function geocodage( address, callbackOk, callbackError )
{
  // TODO: automatically retrieving the protocol's scheme
  var http = 'http' ;

  address = address.replace(/\\("|\'|\\)/g, " ").trim();

  var asyncCalls = new Array();

  // async call to find the full address
  asyncCalls.push(
    $.get(http+'://nominatim.openstreetmap.org/search?q='+encodeURIComponent(address)+'&format=json')
  );

  if( found = address.match( /^\d+(.*)/i ) )
  {
    var address2 = found[1] ;
    // async call to find without address street number
    asyncCalls.push(
      $.get(http+'://nominatim.openstreetmap.org/search?q='+encodeURIComponent(address2)+'&format=json')
    );
  }

  $.when.apply( $, asyncCalls )
  .then( function( c1, c2 )
  {
    // All async calls done.
    if( typeof(c2) == 'string' && c1.length > 0 )
    {
      // case: only one query
      console.log("c1 found");
      callbackOk( c1[0].lon, c1[0].lat );
    }
    else if( typeof(c2) != 'string' && c1[0].length > 0 )
    {
      console.log("c1 found");
      callbackOk( c1[0][0].lon, c1[0][0].lat );
    }
    else if( typeof(c2) != 'string' && c2[0].length > 0 )
    {
      console.log("c2 found");
      callbackOk( c2[0][0].lon, c2[0][0].lat );
    }
    else
    {
      callbackError('not found');
    }

  });

};
<commit_msg>[bazar][geocoder] query http protocole #195 #196<commit_after>/**
 * Address search (geocoder).
 *
 * Recherche d'adresse (géocodage).
 */

/**
 * @param address The address to find.
 * @param callbackOk( longitude, latitude ) The code to call when address found.
 * @param callbackError( error_message ) The code to call when address not found or an error occured.
 */
function geocodage( address, callbackOk, callbackError )
{
  var http = window.location.protocol ;

  address = address.replace(/\\("|\'|\\)/g, " ").trim();

  var asyncCalls = new Array();

  // async call to find the full address
  asyncCalls.push(
    $.get(http+'//nominatim.openstreetmap.org/search?q='+encodeURIComponent(address)+'&format=json')
  );

  if( found = address.match( /^\d+(.*)/i ) )
  {
    var address2 = found[1] ;
    // async call to find without address street number
    asyncCalls.push(
      $.get(http+'//nominatim.openstreetmap.org/search?q='+encodeURIComponent(address2)+'&format=json')
    );
  }

  $.when.apply( $, asyncCalls )
  .then( function( c1, c2 )
  {
    // All async calls done.
    if( typeof(c2) == 'string' && c1.length > 0 )
    {
      // case: only one query
      console.log("c1 found");
      callbackOk( c1[0].lon, c1[0].lat );
    }
    else if( typeof(c2) != 'string' && c1[0].length > 0 )
    {
      console.log("c1 found");
      callbackOk( c1[0][0].lon, c1[0][0].lat );
    }
    else if( typeof(c2) != 'string' && c2[0].length > 0 )
    {
      console.log("c2 found");
      callbackOk( c2[0][0].lon, c2[0][0].lat );
    }
    else
    {
      callbackError('not found');
    }

  });

};
<|endoftext|>