<commit_before>$('.result img').click(function() {
	$('.result img').removeClass('animate');
	$(this).addClass('animate');
});

var inProgress = [false, -2, ['zappos', 'tjmaxx', 'macys'], 'blah', 0];
var ajaxInterval;
var itemID;
var vendorName;

$(document).ready(function () {
        itemID = getURLParameter('itemID');
        vendorName = getURLParameter('vendor');
        inProgress[3] = vendorName;
        ajaxInterval = setInterval( ajaxCalls, 1000 );
});

// CREDIT: http://stackoverflow.com/questions/1403888/get-url-parameter-with-javascript-or-jquery
var getURLParameter = function(name) {
    return decodeURI(
        (RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
    );
}

var ajaxCalls = function () {
        console.log(inProgress[0]);
        if ( !inProgress[0] )
        {
                if ( inProgress[1] == -2 )
                {
                        inProgress[0] = true;
                        inProgress[1] = ( inProgress[2][0] == inProgress[3] )?0:-1;

                        getAjaxData( inProgress[3] );
                }
                else if ( inProgress[1] < 2 )
                {

                        inProgress[0] = true;
                        inProgress[1] += 1;

                        var vendor = inProgress[2][inProgress[1]];

                        if ( vendor != inProgress[3] )
                        {
                                getAjaxData(vendor);
                        }
                        else // if ( vendor == inProgress[3] )
                        {
                                if ( inProgress[1] != 0 )
                                {
                                        inProgress[0] = false;
                                        return;
                                }
                                else
                                {
                                        console.log('get ajax');
                                        getAjaxData(vendor);
                                }
                        }
                }
                else
                {
                        clearInterval(ajaxInterval);
                }
        }
}

var getAjaxData = function ( vendor ) {

        console.log(inProgress[0] + ' --- ' + inProgress[1] + ' --- ' + vendor + ' --- ' + inProgress[3] + ' --- ' + inProgress[4]);

        var url = "http://localhost:8080/widget/vendor/" + vendor + "/itemId/" + itemID; // + "?callback=data";
        $.ajax({
                type: "GET",
                url: url,
                //data: null,
                dataType: "json",
                success: function (data) {
                                //alert( data[0].imageUrl );
                                inProgress[4] += 1;
                                insertVendor( vendor, data );
                                inProgress[0] = false;
                        }
        });
}

var insertVendor = function ( vendorName, data ) {

                var vendorSection = $('.vendor' + inProgress[4]);
                innerHTML =
                '
 ' +
                    '
' +
                        '
' +
                            vendorName +
                        '
' +
                    '
' +
                    '
';

                $.each( data, function ( i, val )
                {
                        if ( i < 4 )
                        {
                                innerHTML +=
                                '
' +
                                    '
Brand Name' +
                                        '' +
                                            val.productName +
                                        '' +
                                    '
' +
                                    '
' +
                                        val.price +
                                        '' +
                                            val.salePrice +
                                        '' +
                                    '
' +
                                    '

' +
                                    '' +
                                '
';
                        }
                });

                innerHTML += '

';

                vendorSection.append(innerHTML);

        }
<commit_msg>removed extraneous section tag<commit_after>$('.result img').click(function() {
	$('.result img').removeClass('animate');
	$(this).addClass('animate');
});

var inProgress = [false, -2, ['zappos', 'tjmaxx', 'macys'], 'blah', 0];
var ajaxInterval;
var itemID;
var vendorName;

$(document).ready(function () {
        itemID = getURLParameter('itemID');
        vendorName = getURLParameter('vendor');
        inProgress[3] = vendorName;
        ajaxInterval = setInterval( ajaxCalls, 1000 );
});

// CREDIT: http://stackoverflow.com/questions/1403888/get-url-parameter-with-javascript-or-jquery
var getURLParameter = function(name) {
    return decodeURI(
        (RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
    );
}

var ajaxCalls = function () {
        console.log(inProgress[0]);
        if ( !inProgress[0] )
        {
                if ( inProgress[1] == -2 )
                {
                        inProgress[0] = true;
                        inProgress[1] = ( inProgress[2][0] == inProgress[3] )?0:-1;

                        getAjaxData( inProgress[3] );
                }
                else if ( inProgress[1] < 2 )
                {

                        inProgress[0] = true;
                        inProgress[1] += 1;

                        var vendor = inProgress[2][inProgress[1]];

                        if ( vendor != inProgress[3] )
                        {
                                getAjaxData(vendor);
                        }
                        else
                        {
                                if ( inProgress[1] != 0 )
                                {
                                        inProgress[0] = false;
                                        return;
                                }
                                else
                                {
                                        getAjaxData(vendor);
                                }
                        }
                }
                else
                {
                        clearInterval(ajaxInterval);
                }
        }
}

var getAjaxData = function ( vendor ) {

        console.log(inProgress[0] + ' --- ' + inProgress[1] + ' --- ' + vendor + ' --- ' + inProgress[3] + ' --- ' + inProgress[4]);

        var url = "http://localhost:8080/widget/vendor/" + vendor + "/itemId/" + itemID; // + "?callback=data";
        $.ajax({
                type: "GET",
                url: url,
                //data: null,
                dataType: "json",
                success: function (data) {
                                //alert( data[0].imageUrl );
                                inProgress[4] += 1;
                                insertVendor( vendor, data );
                                inProgress[0] = false;
                        }
        });
}

var insertVendor = function ( vendorName, data ) {

                var vendorSection = $('.vendor' + inProgress[4]);
                innerHTML =
                //'
 ' +
                    '
' +
                        '
' +
                            vendorName +
                        '
' +
                    '
' +
                    '
';

                $.each( data, function ( i, val )
                {
                        if ( i < 4 )
                        {
                                innerHTML +=
                                '
' +
                                    '
Brand Name' +
                                        '' +
                                            val.productName +
                                        '' +
                                    '
' +
                                    '
' +
                                        val.price +
                                        '' +
                                            val.salePrice +
                                        '' +
                                    '
' +
                                    '

' +
                                    '' +
                                '
';
                        }
                });

                innerHTML += '
<';

                vendorSection.append(innerHTML);

        }
<|endoftext|>


<commit_before>$(document).ready(function(){
	var turn=0;
	var userChoice;
	var computerChoice;
	var gameReady=false;
	var gameOver=false;
	function clickResponse(){
		$("#X").hide();
		$("#O").hide();
		$("h2").html("Play!");
		$("h2").css("margin-bottom", "43px");
		gameReady=true;
	}
	$("#X").click(function(){
		userChoice="X";
		computerChoice="O";
		clickResponse();
		});
	$("#O").click(function(){
		userChoice="O";
		computerChoice="X";
		clickResponse();

	})
	var options=["top-left","top-center","top-right",
				"center-left","center-center","center-right",
				"bottom-left","bottom-center","bottom-right"];
	//EASY VERSION-uses random choices
	$(".square").click(function(){
		if (($(this).hasClass("unclickable")==false)&&gameReady==true){
		$(this).html(userChoice);
		$(this).addClass("unclickable");
		$(this).addClass("user");
		turn++;
		if (turn<8){
					computerResponse();
	}
		findWinner();
		if (turn==9){
			var status=$("h2").html();
			if (status!=="Player has won!"&&status!=="Computer has won!"){
				$("h2").html("Cat's Game!");
					setTimeout(function(){
						window.location.reload();
					}, 3000);
			}
		}
	}

	});

	function computerResponse(){
		var compSel=Math.ceil(Math.random() * (9)-1);
		while($("#"+(options[compSel])).hasClass("unclickable")){
			compSel=Math.ceil(Math.random() * (9)-1);
		}
		$("#"+(options[compSel])).html(computerChoice);
		$("#"+(options[compSel])).addClass("unclickable").addClass("computer");
		turn++;

	}
	function findWinner(){
		var playerArray=[0,0,0,0,0,0,0,0];
		var compArray=[0,0,0,0,0,0,0,0];
		var topVictory="#top-left, #top-center, #top-right";
		var centerVictory="#center-left, #center-center, #center-right";
		var bottomVictory="#bottom-left, #bottom-center, #bottom-right";
		var leftVerticalVictory="#top-left, #center-left, #bottom-left";
		var centerVerticalVictory="#top-center, #center-center, #bottom-center";
		var rightVerticalVictory="#top-right, #center-right, #bottom-right";
		var diagonalLeftRight="#top-left, #center-center, #bottom-right";
		var diagonalRightLeft="#top-right, #center-center, #bottom-left";
		var vicArr=[topVictory,centerVictory,bottomVictory,leftVerticalVictory,centerVerticalVictory,
		rightVerticalVictory,diagonalLeftRight,diagonalRightLeft];

		function winner(className, controller, arraySlot, condition){
		$(condition).each(function(){

			if($(this).hasClass(className)){
				arraySlot++;
				if (arraySlot==3){
					gameOver=true;
					$("h2").html(controller+" has won!");
					setTimeout(function(){
						window.location.reload();
					}, 3000);
				}
			}});
		}

		for (var i=0;i<vicArr.length;i++){
			var cond=vicArr[i];
			winner("user", "Player",playerArray[i], cond);
			winner("computer", "Computer",compArray[i], cond);

		}
	}

});<commit_msg>Debug the javascript<commit_after>$(document).ready(function(){
	var turn=0;
	var userChoice;
	var computerChoice;
	var gameReady=false;
	var gameOver=false;
	function clickResponse(){
		$("#X").hide();
		$("#O").hide();
		$("h2").html("Play!");
		$("h2").css("margin-bottom", "43px");
		gameReady=true;
	}
	$("#X").click(function(){
		userChoice="X";
		computerChoice="O";
		clickResponse();
		});
	$("#O").click(function(){
		userChoice="O";
		computerChoice="X";
		clickResponse();

	})
	var options=["top-left","top-center","top-right",
				"center-left","center-center","center-right",
				"bottom-left","bottom-center","bottom-right"];
	//EASY VERSION-uses random choices
	$(".square").click(function(){
		if (($(this).hasClass("unclickable")==false)&&gameReady==true){
		$(this).html(userChoice);
		$(this).addClass("unclickable");
		$(this).addClass("user");
		turn++;
		findWinner();
		if (turn<8&&gameOver==false){
					computerResponse();
	}
		findWinner();
		if (turn==9){
			var status=$("h2").html();
			if (status!=="Player has won!"&&status!=="Computer has won!"){
				$("h2").html("Cat's Game!");
					setTimeout(function(){
						window.location.reload();
					}, 3000);
			}
		}
	}

	});

	function computerResponse(){
		var compSel=Math.ceil(Math.random() * (9)-1);
		while($("#"+(options[compSel])).hasClass("unclickable")){
			compSel=Math.ceil(Math.random() * (9)-1);
		}
		$("#"+(options[compSel])).html(computerChoice);
		$("#"+(options[compSel])).addClass("unclickable").addClass("computer");
		turn++;
	}
	function hardComputerResponse(){
		//turn 2

		//turn 4

		//turn 6

		//turn 8

	}
	function findWinner(){
		var playerArray=[0,0,0,0,0,0,0,0];
		var compArray=[0,0,0,0,0,0,0,0];
		var topVictory="#top-left, #top-center, #top-right";
		var centerVictory="#center-left, #center-center, #center-right";
		var bottomVictory="#bottom-left, #bottom-center, #bottom-right";
		var leftVerticalVictory="#top-left, #center-left, #bottom-left";
		var centerVerticalVictory="#top-center, #center-center, #bottom-center";
		var rightVerticalVictory="#top-right, #center-right, #bottom-right";
		var diagonalLeftRight="#top-left, #center-center, #bottom-right";
		var diagonalRightLeft="#top-right, #center-center, #bottom-left";
		var vicArr=[topVictory,centerVictory,bottomVictory,leftVerticalVictory,centerVerticalVictory,
		rightVerticalVictory,diagonalLeftRight,diagonalRightLeft];

		function winner(className, controller, arraySlot, condition){
		$(condition).each(function(){

			if($(this).hasClass(className)){
				arraySlot++;
				if (arraySlot==3){
					gameOver=true;
					$("h2").html(controller+" has won!");
					setTimeout(function(){
						window.location.reload();
					}, 3000);
				}
			}});
		}
		for (var i=0;i<vicArr.length;i++){
			var cond=vicArr[i];
			winner("computer", "Computer",compArray[i], cond);
			winner("user", "Player",playerArray[i], cond);
		}
	}
});<|endoftext|>


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

const { Subscription } = require("rxjs/Subscription");
const { BehaviorSubject } = require("rxjs/BehaviorSubject");
const { combineLatest } = require("rxjs/observable/combineLatest");
const { only } = require("../utils/rx-utils");
const { findBetterMatchIndex } = require("../utils/languages");

const AverageBitrate = require("./average-bitrate");

const DEFAULTS = {
  defaultLanguage: {
    language: "fra",
    audioDescription: false,
  },
  defaultSubtitle: null,
  // default buffer size in seconds
  defaultBufferSize: 30,
  // buffer threshold ratio used as a lower bound
  // margin to find the suitable representation
  defaultBufferThreshold: 0.3,
  initVideoBitrate: 0,
  initAudioBitrate: 0,
  maxVideoBitrate: Infinity,
  maxAudioBitrate: Infinity,
};

/**
 * Simple find function implementation.
 * @param {Array} array
 * @param {Function} predicate - The predicate. Will take as arguments:
 *   1. the current array element
 *   2. the array index
 *   3. the entire array
 * @returns {*} - null if not found
 */
function find(array, predicate) {
  for (let i = 0; i < array.length; i++) {
    if (predicate(array[i], i, array) === true) {
      return array[i];
    }
  }
  return null;
}

/**
 * Returns val if x is either not a Number type or inferior or equal to 0.
 * @param {Number} [x]
 * @param {*} val
 * @returns {*}
 */
function def(x, val) {
  return typeof x == "number" && x > 0 ? x : val;
}

/**
 * Get closest bitrate lower or equal to the bitrate wanted when the threshold
 * is equal to 0. You can add a security margin by setting the threshold between
 * 0 and 1.
 * @param {Array.<Number>} bitrates - all available bitrates.
 * @param {Number} btr - a chosen bitrate
 * @param {Number} [treshold=0]
 * @returns {Number}
 */
function getClosestBitrate(bitrates, btr, threshold=0) {
  for (let i = bitrates.length - 1; i >= 0; i--) {
    if ((bitrates[i] / btr) <= (1 - threshold)) {
      return bitrates[i];
    }
  }
  return bitrates[0];
}

/**
 * Get the bitrate from the first representation which has a width >= to the
 * width wanted.
 * Returns Infinity if not found.
 * @param {Array.<Object>} reps - The representations array
 * @param {Number} width
 * @returns {Number}
 */
function getClosestDisplayBitrate(reps, width) {
  const rep = find(reps, (r) => r.width >= width);
  if (rep) {
    return rep.bitrate;
  } else {
    return Infinity;
  }
}

/**
 * Find first adaptation with the corresponding language.
 * @param {Array.<Object>} adaptations
 * @param {string} lang
 * @returns {Object|null}
 */
function findAdaptationByLang(adaptations, lang) {
  const langs = adaptations.map(a => a.lang);

  const index = findBetterMatchIndex(langs, lang);
  if (index >= 0) {
    return adaptations[index];
  }
  return null;
}

/**
 * @param {Array.<Object>} adaptations
 * @param {string} lang
 * @param {Boolean} [audioDescription=false]
 * @returns {Object|null}
 */
function findAudioAdaptation(adaptations, lang, audioDescription = false) {
  const filteredAdaptations = adaptations.filter(adaptation =>
    adaptation.audioDescription == audioDescription
  );
  return findAdaptationByLang(filteredAdaptations, lang);
}

/**
 * @param {Array.<Object>} adaptations
 * @param {string} lang
 * @param {Boolean} [closedCaption=false]
 * @returns {Object|null}
 */
function findTextAdaptation(adaptations, lang, closedCaption = false) {
  const filteredAdaptations = adaptations.filter(adaptation =>
    adaptation.closedCaption == closedCaption
  );
  return findAdaptationByLang(filteredAdaptations, lang);
}

/**
 * Filter the given observable/array to only keep the item with the selected
 * type.
 * @param {Observable|Array.<Object>} stream
 * @param {string} selectedType
 * @returns {Observable|Array.<Object>}
 */
function filterByType(stream, selectedType) {
  return stream.filter(({ type }) => type === selectedType);
}

module.exports = function(metrics, deviceEvents, options={}) {
  Object.keys(options).forEach(key =>
    options[key] === undefined && delete options[key]
  );

  const {
    defaultLanguage,
    defaultSubtitle,
    defaultBufferSize,
    defaultBufferThreshold,
    initVideoBitrate,
    initAudioBitrate,
    maxVideoBitrate,
    maxAudioBitrate,
    limitVideoWidth,
    throttleWhenHidden,
  } = Object.assign({}, DEFAULTS, options);

  const { videoWidth, inBackground } = deviceEvents;

  const $languages = new BehaviorSubject(defaultLanguage);
  const $subtitles = new BehaviorSubject(defaultSubtitle);

  const $averageBitrates = {
    audio: new BehaviorSubject(initAudioBitrate),
    video: new BehaviorSubject(initVideoBitrate),
  };

  const averageBitratesConns = [
    AverageBitrate(filterByType(metrics, "audio"), { alpha: 0.6 })
      .multicast($averageBitrates.audio),
    AverageBitrate(filterByType(metrics, "video"), { alpha: 0.6 })
      .multicast($averageBitrates.video),
  ];

  let conns = new Subscription();
  averageBitratesConns.forEach((a) => conns.add(a.connect()));

  const $usrBitrates = {
    audio: new BehaviorSubject(Infinity),
    video: new BehaviorSubject(Infinity),
  };

  const $maxBitrates = {
    audio: new BehaviorSubject(maxAudioBitrate),
    video: new BehaviorSubject(maxVideoBitrate),
  };

  const $bufSizes = {
    audio: new BehaviorSubject(defaultBufferSize),
    video: new BehaviorSubject(defaultBufferSize),
    text:  new BehaviorSubject(defaultBufferSize),
  };

  /**
   * Returns an Observable emitting:
   *   - first, the current audio adaption
   *   - the new one each time it changes
   * @param {Array.<Object>} adaptations - The available audio adaptations
   * objects.
   * @returns {Observable}
   */
  function audioAdaptationChoice(adaptations) {
    return $languages.distinctUntilChanged()
      .map(({ language, audioDescription }) =>
        findAudioAdaptation(
          adaptations,
          language,
          audioDescription
        ) || adaptations[0]
      );
  }

  /**
   * Returns an Observable emitting:
   *   - first, the current text adaption
   *   - the new one each time it changes
   * @param {Array.<Object>} adaptations - The available text adaptations
   * objects.
   * @returns {Observable}
   */
  function textAdaptationChoice(adaptations) {
    return $subtitles.distinctUntilChanged()
      .map(arg =>
        arg ?  findTextAdaptation(
          adaptations,
          arg.language,
          arg.closedCaption
        ) : null
      );
  }

  /**
   * Get the current and new adaptations each time it changes for all
   * types.
   * Mostly useful for audio languages and text subtitles to know which one
   * to choose first and when it changes.
   * @param {string} type - The adaptation type
   * @param {Array.<Object>} adaptations
   * @returns {Observable}
   */
  function getAdaptationsChoice(type, adaptations) {
    if (type == "audio") {
      return audioAdaptationChoice(adaptations);
    }

    if (type == "text") {
      return textAdaptationChoice(adaptations);
    }

    return only(adaptations[0]);
  }

  /**
   * Returns an object containing two observables:
   *   - representations: the chosen best representation for the adaptation
   *     (correlated from the user, max and average bitrates)
   *   - bufferSizes: the bufferSize chosen
   * @param {Object} adaptation
   * @returns {Object}
   */
  function getBufferAdapters(adaptation) {
    const { type, bitrates, representations } = adaptation;

    let representationsObservable;
    if (representations.length > 1) {
      const usrBitrates = $usrBitrates[type];
      let maxBitrates = $maxBitrates[type];

      const avrBitrates = $averageBitrates[type]
        .map((avrBitrate, count) => {
          // no threshold for the first value of the average bitrate
          // stream corresponding to the selected initial video bitrate
          let bufThreshold;
          if (count === 0) {
            bufThreshold = 0;
          } else {
            bufThreshold = defaultBufferThreshold;
          }

          return getClosestBitrate(bitrates, avrBitrate, bufThreshold);
        })
        .distinctUntilChanged()
        .debounceTime(2000)
        .startWith(getClosestBitrate(bitrates, $averageBitrates[type].getValue(), 0));

      if (type == "video") {
        const maxBitrateUpdatesObs = [maxBitrates];

        if (limitVideoWidth) {
          maxBitrateUpdatesObs.push(videoWidth);
        }

        if (throttleWhenHidden) {
          maxBitrateUpdatesObs.push(inBackground);
        }

        // To compute the bitrate upper-bound for video
        // representations we need to combine multiple stream:
        //   - user-based maximum bitrate (subject)
        //   - maximum based on the video element width
        //   - maximum based on the application visibility (background tab)
        maxBitrates = combineLatest(...maxBitrateUpdatesObs)
          .map((bitrate, width, isHidden) => {
            if (isHidden) {
              return bitrates[0];
            }

            const closestDisplayBitrate = getClosestDisplayBitrate(representations, width);
            if (closestDisplayBitrate < bitrate) {
              return closestDisplayBitrate;
            }

            return bitrate;
          });
      }

      representationsObservable = combineLatest(
        usrBitrates,
        maxBitrates,
        avrBitrates,
        (usr, max, avr) => {
          let btr;
          if (usr < Infinity) {
            btr = usr;
          } else if (max < Infinity) {
            btr = Math.min(max, avr);
          } else {
            btr = avr;
          }
          return find(representations, (rep) => rep.bitrate === getClosestBitrate(bitrates, btr));
        })
        .distinctUntilChanged((a, b) => a.id === b.id);
    }
    else { // representations.length <= 1
      representationsObservable = only(representations[0]);
    }

    return {
      representations: representationsObservable,
      bufferSizes: $bufSizes[type] || new BehaviorSubject(defaultBufferSize),
    };
  }

  return {
    setLanguage(lng) { $languages.next(lng); },
    setSubtitle(sub) { $subtitles.next(sub); },
    getLanguage() { return $languages.getValue(); },
    getSubtitle() { return $subtitles.getValue(); },

    getAverageBitrates() { return $averageBitrates; },

    getAudioMaxBitrate() { return $maxBitrates.audio.getValue(); },
    getVideoMaxBitrate() { return $maxBitrates.video.getValue(); },
    getAudioBufferSize() { return $bufSizes.audio.getValue(); },
    getVideoBufferSize() { return $bufSizes.video.getValue(); },

    setAudioBitrate(x)    { $usrBitrates.audio.next(def(x, Infinity)); },
    setVideoBitrate(x)    { $usrBitrates.video.next(def(x, Infinity)); },
    setAudioMaxBitrate(x) { $maxBitrates.audio.next(def(x, Infinity)); },
    setVideoMaxBitrate(x) { $maxBitrates.video.next(def(x, Infinity)); },
    setAudioBufferSize(x) { $bufSizes.audio.next(def(x, defaultBufferSize)); },
    setVideoBufferSize(x) { $bufSizes.video.next(def(x, defaultBufferSize)); },

    getBufferAdapters,
    getAdaptationsChoice,

    unsubscribe() {
      if (conns) {
        conns.unsubscribe();
        conns = null;
      }
    },
  };
};
<commit_msg>device-events: fix typo and logic<commit_after>/**
 * Copyright 2015 CANAL+ Group
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

const { Subscription } = require("rxjs/Subscription");
const { BehaviorSubject } = require("rxjs/BehaviorSubject");
const { combineLatest } = require("rxjs/observable/combineLatest");
const { only } = require("../utils/rx-utils");
const { findBetterMatchIndex } = require("../utils/languages");

const AverageBitrate = require("./average-bitrate");

const DEFAULTS = {
  defaultLanguage: {
    language: "fra",
    audioDescription: false,
  },
  defaultSubtitle: null,
  // default buffer size in seconds
  defaultBufferSize: 30,
  // buffer threshold ratio used as a lower bound
  // margin to find the suitable representation
  defaultBufferThreshold: 0.3,
  initVideoBitrate: 0,
  initAudioBitrate: 0,
  maxVideoBitrate: Infinity,
  maxAudioBitrate: Infinity,
};

/**
 * Simple find function implementation.
 * @param {Array} array
 * @param {Function} predicate - The predicate. Will take as arguments:
 *   1. the current array element
 *   2. the array index
 *   3. the entire array
 * @returns {*} - null if not found
 */
function find(array, predicate) {
  for (let i = 0; i < array.length; i++) {
    if (predicate(array[i], i, array) === true) {
      return array[i];
    }
  }
  return null;
}

/**
 * Returns val if x is either not a Number type or inferior or equal to 0.
 * @param {Number} [x]
 * @param {*} val
 * @returns {*}
 */
function def(x, val) {
  return typeof x == "number" && x > 0 ? x : val;
}

/**
 * Get closest bitrate lower or equal to the bitrate wanted when the threshold
 * is equal to 0. You can add a security margin by setting the threshold between
 * 0 and 1.
 * @param {Array.<Number>} bitrates - all available bitrates.
 * @param {Number} btr - a chosen bitrate
 * @param {Number} [treshold=0]
 * @returns {Number}
 */
function getClosestBitrate(bitrates, btr, threshold=0) {
  for (let i = bitrates.length - 1; i >= 0; i--) {
    if ((bitrates[i] / btr) <= (1 - threshold)) {
      return bitrates[i];
    }
  }
  return bitrates[0];
}

/**
 * Get the bitrate from the first representation which has a width >= to the
 * width wanted.
 * Returns Infinity if not found.
 * @param {Array.<Object>} reps - The representations array
 * @param {Number} width
 * @returns {Number}
 */
function getClosestDisplayBitrate(reps, width) {
  const rep = find(reps, (r) => r.width >= width);
  if (rep) {
    return rep.bitrate;
  } else {
    return Infinity;
  }
}

/**
 * Find first adaptation with the corresponding language.
 * @param {Array.<Object>} adaptations
 * @param {string} lang
 * @returns {Object|null}
 */
function findAdaptationByLang(adaptations, lang) {
  const langs = adaptations.map(a => a.lang);

  const index = findBetterMatchIndex(langs, lang);
  if (index >= 0) {
    return adaptations[index];
  }
  return null;
}

/**
 * @param {Array.<Object>} adaptations
 * @param {string} lang
 * @param {Boolean} [audioDescription=false]
 * @returns {Object|null}
 */
function findAudioAdaptation(adaptations, lang, audioDescription = false) {
  const filteredAdaptations = adaptations.filter(adaptation =>
    adaptation.audioDescription == audioDescription
  );
  return findAdaptationByLang(filteredAdaptations, lang);
}

/**
 * @param {Array.<Object>} adaptations
 * @param {string} lang
 * @param {Boolean} [closedCaption=false]
 * @returns {Object|null}
 */
function findTextAdaptation(adaptations, lang, closedCaption = false) {
  const filteredAdaptations = adaptations.filter(adaptation =>
    adaptation.closedCaption == closedCaption
  );
  return findAdaptationByLang(filteredAdaptations, lang);
}

/**
 * Filter the given observable/array to only keep the item with the selected
 * type.
 * @param {Observable|Array.<Object>} stream
 * @param {string} selectedType
 * @returns {Observable|Array.<Object>}
 */
function filterByType(stream, selectedType) {
  return stream.filter(({ type }) => type === selectedType);
}

module.exports = function(metrics, deviceEvents, options={}) {
  Object.keys(options).forEach(key =>
    options[key] === undefined && delete options[key]
  );

  const {
    defaultLanguage,
    defaultSubtitle,
    defaultBufferSize,
    defaultBufferThreshold,
    initVideoBitrate,
    initAudioBitrate,
    maxVideoBitrate,
    maxAudioBitrate,
    limitVideoWidth,
    throttleWhenHidden,
  } = Object.assign({}, DEFAULTS, options);

  const { videoWidth, inBackground } = deviceEvents;

  const $languages = new BehaviorSubject(defaultLanguage);
  const $subtitles = new BehaviorSubject(defaultSubtitle);

  const $averageBitrates = {
    audio: new BehaviorSubject(initAudioBitrate),
    video: new BehaviorSubject(initVideoBitrate),
  };

  const averageBitratesConns = [
    AverageBitrate(filterByType(metrics, "audio"), { alpha: 0.6 })
      .multicast($averageBitrates.audio),
    AverageBitrate(filterByType(metrics, "video"), { alpha: 0.6 })
      .multicast($averageBitrates.video),
  ];

  let conns = new Subscription();
  averageBitratesConns.forEach((a) => conns.add(a.connect()));

  const $usrBitrates = {
    audio: new BehaviorSubject(Infinity),
    video: new BehaviorSubject(Infinity),
  };

  const $maxBitrates = {
    audio: new BehaviorSubject(maxAudioBitrate),
    video: new BehaviorSubject(maxVideoBitrate),
  };

  const $bufSizes = {
    audio: new BehaviorSubject(defaultBufferSize),
    video: new BehaviorSubject(defaultBufferSize),
    text:  new BehaviorSubject(defaultBufferSize),
  };

  /**
   * Returns an Observable emitting:
   *   - first, the current audio adaption
   *   - the new one each time it changes
   * @param {Array.<Object>} adaptations - The available audio adaptations
   * objects.
   * @returns {Observable}
   */
  function audioAdaptationChoice(adaptations) {
    return $languages.distinctUntilChanged()
      .map(({ language, audioDescription }) =>
        findAudioAdaptation(
          adaptations,
          language,
          audioDescription
        ) || adaptations[0]
      );
  }

  /**
   * Returns an Observable emitting:
   *   - first, the current text adaption
   *   - the new one each time it changes
   * @param {Array.<Object>} adaptations - The available text adaptations
   * objects.
   * @returns {Observable}
   */
  function textAdaptationChoice(adaptations) {
    return $subtitles.distinctUntilChanged()
      .map(arg =>
        arg ?  findTextAdaptation(
          adaptations,
          arg.language,
          arg.closedCaption
        ) : null
      );
  }

  /**
   * Get the current and new adaptations each time it changes for all
   * types.
   * Mostly useful for audio languages and text subtitles to know which one
   * to choose first and when it changes.
   * @param {string} type - The adaptation type
   * @param {Array.<Object>} adaptations
   * @returns {Observable}
   */
  function getAdaptationsChoice(type, adaptations) {
    if (type == "audio") {
      return audioAdaptationChoice(adaptations);
    }

    if (type == "text") {
      return textAdaptationChoice(adaptations);
    }

    return only(adaptations[0]);
  }

  /**
   * Returns an object containing two observables:
   *   - representations: the chosen best representation for the adaptation
   *     (correlated from the user, max and average bitrates)
   *   - bufferSizes: the bufferSize chosen
   * @param {Object} adaptation
   * @returns {Object}
   */
  function getBufferAdapters(adaptation) {
    const { type, bitrates, representations } = adaptation;

    let representationsObservable;
    if (representations.length > 1) {
      const usrBitrates = $usrBitrates[type];
      let maxBitrates = $maxBitrates[type];

      const avrBitrates = $averageBitrates[type]
        .map((avrBitrate, count) => {
          // no threshold for the first value of the average bitrate
          // stream corresponding to the selected initial video bitrate
          let bufThreshold;
          if (count === 0) {
            bufThreshold = 0;
          } else {
            bufThreshold = defaultBufferThreshold;
          }

          return getClosestBitrate(bitrates, avrBitrate, bufThreshold);
        })
        .distinctUntilChanged()
        .debounceTime(2000)
        .startWith(getClosestBitrate(bitrates, $averageBitrates[type].getValue(), 0));

      if (type == "video") {
        // To compute the bitrate upper-bound for video
        // representations we need to combine multiple stream:
        //   - user-based maximum bitrate (subject)
        //   - maximum based on the video element width
        //   - maximum based on the application visibility (background tab)
        maxBitrates = combineLatest([maxBitrates, videoWidth, inBackground])
          .map(([maxSetBitrate, width, isHidden]) => {
            if (throttleWhenHidden && isHidden) {
              return bitrates[0];
            }

            const maxUsableBitrate = limitVideoWidth ?
              getClosestDisplayBitrate(representations, width) :
              bitrates[bitrates.length - 1];

            return Math.min(maxUsableBitrate, maxSetBitrate);
          });
      }

      representationsObservable = combineLatest(
        usrBitrates,
        maxBitrates,
        avrBitrates,
        (usr, max, avr) => {
          let btr;
          if (usr < Infinity) {
            btr = usr;
          } else if (max < Infinity) {
            btr = Math.min(max, avr);
          } else {
            btr = avr;
          }
          return find(representations, (rep) => rep.bitrate === getClosestBitrate(bitrates, btr));
        })
        .distinctUntilChanged((a, b) => a.id === b.id);
    }
    else { // representations.length <= 1
      representationsObservable = only(representations[0]);
    }

    return {
      representations: representationsObservable,
      bufferSizes: $bufSizes[type] || new BehaviorSubject(defaultBufferSize),
    };
  }

  return {
    setLanguage(lng) { $languages.next(lng); },
    setSubtitle(sub) { $subtitles.next(sub); },
    getLanguage() { return $languages.getValue(); },
    getSubtitle() { return $subtitles.getValue(); },

    getAverageBitrates() { return $averageBitrates; },

    getAudioMaxBitrate() { return $maxBitrates.audio.getValue(); },
    getVideoMaxBitrate() { return $maxBitrates.video.getValue(); },
    getAudioBufferSize() { return $bufSizes.audio.getValue(); },
    getVideoBufferSize() { return $bufSizes.video.getValue(); },

    setAudioBitrate(x)    { $usrBitrates.audio.next(def(x, Infinity)); },
    setVideoBitrate(x)    { $usrBitrates.video.next(def(x, Infinity)); },
    setAudioMaxBitrate(x) { $maxBitrates.audio.next(def(x, Infinity)); },
    setVideoMaxBitrate(x) { $maxBitrates.video.next(def(x, Infinity)); },
    setAudioBufferSize(x) { $bufSizes.audio.next(def(x, defaultBufferSize)); },
    setVideoBufferSize(x) { $bufSizes.video.next(def(x, defaultBufferSize)); },

    getBufferAdapters,
    getAdaptationsChoice,

    unsubscribe() {
      if (conns) {
        conns.unsubscribe();
        conns = null;
      }
    },
  };
};
<|endoftext|>


<commit_before>console.log('main.js connected')

//stores shuffled_board[idx] when clicking tiles
var memory_values = [];
//counts how many tiles are flipped
var tiles_flipped = 0;
//empty board to be shuffled
var board = ['1','1','2','2','3','3','4','4','5','5','6','6','7','7','8','8','9','9'];
//current player1/2 to be changed after each turn
var currentPlayer = 'player1'
//keep track of score for each
var player_Score = 'player1_Score'
//tiles from HTML
var boardEl = $('.tiles');
console.log (boardEl);
//initial score to be updated
var player1_Score = 0;
var player2_Score = 0;
//winner to be updated
var winner = '';
//Stores current matched or unmatched information
var matchStore = '';
//Stores last 2 clicked IDs
var id_memory = [];
//check if game is on (used for un/clickable function)
var gameOn = true;

//shuffle images

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;
  while (0 !== currentIndex) {

    randomIndex = Math.floor(Math.random()*currentIndex);
    currentIndex -= 1;

    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;

  }

  return array;
}

//shuffle board

var shuffled_board = shuffle(board);

//Event Listener (For Loop)

var userClicksCard = function(event) {
  var idx = parseInt(this.id);
  if($(this).hasClass('tilesF')) {
    return;
    console.log('rejected')
  } else if($(this).hasClass('tiles')) {
    $(this).removeClass().addClass('tilesF')
    $(this).css('background-image', "url(css/img/sc" + shuffled_board[idx] + ".png" + ")");
    console.log('card flipped up');
    tiles_flipped ++;
    memory_values.push(shuffled_board[idx]);
    id_memory.push(this.id);
    match();
    getWinner();

  }
};

for(var i = 0; i < boardEl.length; i++) {
  boardEl[i].addEventListener('click', userClicksCard);
}

//changes player turn

function changeTurn() {
  if (currentPlayer == 'player1') {
    currentPlayer = 'player2';
    player_Score = 'player2_Score';
    setTimeout(function() {$('.arrow').css('background-image', 'url(css/img/compassR.png)');}, 1000);
    console.log('player2')
  } else {
     currentPlayer = 'player1';
     player_Score = 'player1_Score';
     setTimeout(function() {$('.arrow').css('background-image', 'url(css/img/compassL.png)');}, 1000);
     console.log('player1')
  }
}

//card flipback mechanism to be used for setTimeout within match()
function flipBack() {

  $('#'+id_memory[0]).removeAttr('style').removeClass().addClass('tiles');
  $('#'+id_memory[1]).removeAttr('style').removeClass().addClass('tiles');
  id_memory = [];
  console.log('flipback happened')
};

//check if there is any match
function match() {
  if(currentPlayer === 'player1') {
    if(memory_values[1] === undefined) {
      matchStore = '';
      console.log('one more');
    } else if (memory_values[0] === memory_values[1]) {
      console.log('match');
      matchStore = "matched";
      player1_Score++
      $('#player1_Score').html(player1_Score);
      memory_values = [];
      id_memory = [];
      $('.tiles').attr('disabled', 'disabled');
      setTimeout(function() {
      $('.tiles').removeAttr('disabled');
      }, 1000);
      changeTurn();
    } else if (memory_values[0] !== memory_values[1]){
      console.log('no match');
      matchStore = "unmatched";
      setTimeout(flipBack, 1000);
      tiles_flipped-=2;
      memory_values = [];
      $('.tiles').attr('disabled', 'disabled');
      setTimeout(function() {
      $('.tiles').removeAttr('disabled');
      }, 1000);
      changeTurn();
    }
  } else if(currentPlayer === 'player2') {
      if(memory_values[1] === undefined) {
      matchStore = '';
      console.log('one more');
    } else if (memory_values[0] === memory_values[1]) {
      console.log('match');
      matchStore = 'matched';
      player2_Score++
      $('#player2_Score').html(player2_Score);
      memory_values = [];
      id_memory = [];
      $('.tiles').attr('disabled', 'disabled');
      setTimeout(function() {
      $('.tiles').removeAttr('disabled');
      }, 1000);
      changeTurn();
    } else if (memory_values[0] !== memory_values[1]){
      console.log('no match');
      matchStore = "unmatched";
      setTimeout(flipBack, 1000);
      tiles_flipped-=2;
      memory_values = [];
      $('.tiles').attr('disabled', 'disabled');
      setTimeout(function() {
      $('.tiles').removeAttr('disabled');
      }, 1000);
      changeTurn();
    }
  }
};

//reset function
  function reset(){
    for(var i = 0; i < boardEl.length; i++) {
      shuffle(board);
      setTimeout(function() {$('.tilesF').removeClass().addClass('tiles').css('background-image', 'url(css/img/scb.png)');}, 1000);
      tiles_flipped = 0;
      player1_Score = 0;
      player2_Score = 0;
      $('#player1_Score').html(0);
      $('#player2_Score').html(0);
    }
  };

//get winner

function getWinner() {
  if(tiles_flipped < 18) {
    return;
  } else if(tiles_flipped === 18) {
    if(player1_Score > player2_Score) {
      winner = "Soul Calibur";
      reset();
      console.log('P1 WIN');
      window.alert("Soul Calibur Wins");
    } else if(player2_Score > player1_Score) {
      winner = "Soul Edge";
      reset();
      console.log('P2 WIN');
      window.alert("Soul Edge Wins");
    } else {
      winner = "Tie";
      reset();
      console.log('Tie');
      window.alert("Tie");
    }
  }
};

//Audio Player

var audio;
var playlist;
var tracks;
var current;
var shuffled_playlist = shuffle($('#playlist'))

init();
function init(){
    current = 0;
    audio = $('#audio');
    playlist = $('#playlist');
    tracks = playlist.find('li a');
    len = tracks.length - 1;
    audio[0].volume = 1;
    audio[0].play();
    playlist.find('a').click(function(e){
        e.preventDefault();
        link = $(this);
        current = link.parent().index();
        run(link, audio[0]);
    });
    audio[0].addEventListener('ended',function(e){
        current++;
        if(current == len){
            current = 0;
            link = playlist.find('a')[0];
        }else{
            link = playlist.find('a')[current];
        }
        run($(link),audio[0]);
    });
}

function run(link, player){
        player.src = link.attr('href');
        par = link.parent();
        par.addClass('active').siblings().removeClass('active');
        audio[0].load();
        audio[0].play();
}

<commit_msg>UI/UX change<commit_after>console.log('main.js connected')

//stores shuffled_board[idx] when clicking tiles
var memory_values = [];
//counts how many tiles are flipped
var tiles_flipped = 0;
//empty board to be shuffled
var board = ['1','1','2','2','3','3','4','4','5','5','6','6','7','7','8','8','9','9'];
//current player1/2 to be changed after each turn
var currentPlayer = 'player1'
//keep track of score for each
var player_Score = 'player1_Score'
//tiles from HTML
var boardEl = $('.tiles');
console.log (boardEl);
//initial score to be updated
var player1_Score = 0;
var player2_Score = 0;
//winner to be updated
var winner = '';
//Stores current matched or unmatched information
var matchStore = '';
//Stores last 2 clicked IDs
var id_memory = [];
//check if game is on (used for un/clickable function)
var gameOn = true;

//shuffle images

function shuffle(array) {
  var currentIndex = array.length, temporaryValue, randomIndex;
  while (0 !== currentIndex) {

    randomIndex = Math.floor(Math.random()*currentIndex);
    currentIndex -= 1;

    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;

  }

  return array;
}

//shuffle board

var shuffled_board = shuffle(board);

//Event Listener (For Loop)

var userClicksCard = function(event) {
  var idx = parseInt(this.id);
  if($(this).hasClass('tilesF')) {
    return;
    console.log('rejected')
  } else if($(this).hasClass('tiles')) {
    $(this).removeClass().addClass('tilesF')
    $(this).css('background-image', "url(css/img/sc" + shuffled_board[idx] + ".png" + ")");
    console.log('card flipped up');
    tiles_flipped ++;
    memory_values.push(shuffled_board[idx]);
    id_memory.push(this.id);
    match();
    getWinner();

  }
};

for(var i = 0; i < boardEl.length; i++) {
  boardEl[i].addEventListener('click', userClicksCard);
}

//changes player turn

function changeTurn() {
  if (currentPlayer == 'player1') {
    currentPlayer = 'player2';
    player_Score = 'player2_Score';
    setTimeout(function() {$('.arrow').css('background-image', 'url(css/img/compassR.png)');}, 500);
    console.log('player2')
  } else {
     currentPlayer = 'player1';
     player_Score = 'player1_Score';
     setTimeout(function() {$('.arrow').css('background-image', 'url(css/img/compassL.png)');}, 500);
     console.log('player1')
  }
}

//card flipback mechanism to be used for setTimeout within match()
function flipBack() {

  $('#'+id_memory[0]).removeAttr('style').removeClass().addClass('tiles');
  $('#'+id_memory[1]).removeAttr('style').removeClass().addClass('tiles');
  id_memory = [];
  console.log('flipback happened')
};

//check if there is any match
function match() {
  if(currentPlayer === 'player1') {
    if(memory_values[1] === undefined) {
      matchStore = '';
      console.log('one more');
    } else if (memory_values[0] === memory_values[1]) {
      console.log('match');
      matchStore = "matched";
      player1_Score++
      $('#player1_Score').html(player1_Score);
      memory_values = [];
      id_memory = [];
      $('.tiles').attr('disabled', 'disabled');
      setTimeout(function() {
      $('.tiles').removeAttr('disabled');
      }, 500);
      changeTurn();
    } else if (memory_values[0] !== memory_values[1]){
      console.log('no match');
      matchStore = "unmatched";
      setTimeout(flipBack, 500);
      tiles_flipped-=2;
      memory_values = [];
      $('.tiles').attr('disabled', 'disabled');
      setTimeout(function() {
      $('.tiles').removeAttr('disabled');
      }, 500);
      changeTurn();
    }
  } else if(currentPlayer === 'player2') {
      if(memory_values[1] === undefined) {
      matchStore = '';
      console.log('one more');
    } else if (memory_values[0] === memory_values[1]) {
      console.log('match');
      matchStore = 'matched';
      player2_Score++
      $('#player2_Score').html(player2_Score);
      memory_values = [];
      id_memory = [];
      $('.tiles').attr('disabled', 'disabled');
      setTimeout(function() {
      $('.tiles').removeAttr('disabled');
      }, 500);
      changeTurn();
    } else if (memory_values[0] !== memory_values[1]){
      console.log('no match');
      matchStore = "unmatched";
      setTimeout(flipBack, 500);
      tiles_flipped-=2;
      memory_values = [];
      $('.tiles').attr('disabled', 'disabled');
      setTimeout(function() {
      $('.tiles').removeAttr('disabled');
      }, 500);
      changeTurn();
    }
  }
};

//reset function
  function reset(){
    for(var i = 0; i < boardEl.length; i++) {
      shuffle(board);
      setTimeout(function() {$('.tilesF').removeClass().addClass('tiles').css('background-image', 'url(css/img/scb.png)');}, 500);
      tiles_flipped = 0;
      player1_Score = 0;
      player2_Score = 0;
      $('#player1_Score').html(0);
      $('#player2_Score').html(0);
    }
  };

//get winner

function getWinner() {
  if(tiles_flipped < 18) {
    return;
  } else if(tiles_flipped === 18) {
    if(player1_Score > player2_Score) {
      winner = "Soul Calibur";
      reset();
      console.log('P1 WIN');
      window.alert("Soul Calibur Wins");
    } else if(player2_Score > player1_Score) {
      winner = "Soul Edge";
      reset();
      console.log('P2 WIN');
      window.alert("Soul Edge Wins");
    } else {
      winner = "Tie";
      reset();
      console.log('Tie');
      window.alert("Tie");
    }
  }
};

//Audio Player

var audio;
var playlist;
var tracks;
var current;
var shuffled_playlist = shuffle($('#playlist'))

init();
function init(){
    current = 0;
    audio = $('#audio');
    playlist = $('#playlist');
    tracks = playlist.find('li a');
    len = tracks.length - 1;
    audio[0].volume = 1;
    audio[0].play();
    playlist.find('a').click(function(e){
        e.preventDefault();
        link = $(this);
        current = link.parent().index();
        run(link, audio[0]);
    });
    audio[0].addEventListener('ended',function(e){
        current++;
        if(current == len){
            current = 0;
            link = playlist.find('a')[0];
        }else{
            link = playlist.find('a')[current];
        }
        run($(link),audio[0]);
    });
}

function run(link, player){
        player.src = link.attr('href');
        par = link.parent();
        par.addClass('active').siblings().removeClass('active');
        audio[0].load();
        audio[0].play();
}

<|endoftext|>


<commit_before>'use strict';

document.addEventListener("DOMContentLoaded", function() {
    var clicker = document.querySelector("#clicker"),
        searchBox = document.querySelector("#search");

    function searchReveal() {
        console.log("searchReveal function firing!");
        searchBox.classList.toggle("reveal");
    }

    clicker.onclick = searchReveal;
})
<commit_msg>Added comments to JS and started to build out AJAX call for search results<commit_after>'use strict';

document.addEventListener("DOMContentLoaded", function() {

    //Event listener to reveal search field on magnifying glass click
    var clicker = document.querySelector("#clicker"),
        searchBox = document.querySelector("#search");

    function searchReveal() {
        searchBox.classList.toggle("reveal");
    }

    clicker.onclick = searchReveal;
    //End search field click event code

    //AJAX call and response callback
    var searchTxt = document.querySelector("#search");

    function getResults() {
        console.log(searchTxt.value);
        //AJAX code goes here...
    }

    searchTxt.onchange = getResults;

})
<|endoftext|>


<commit_before>
function debounce(func, wait) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      timeout = null;
      func.apply(context, args);
    }, wait || 300);
  };
};

//--------------------------------------------------------------------------------
// location prompt
//--------------------------------------------------------------------------------

$(function() {
  var locationMarker = $('#request-location');
  var locationOffset = parseInt(locationMarker.data('offset') || 0);

  function checkScroll(e)
  {
    if ($(window).scrollTop() > locationMarker.offset().top - locationOffset) {
      askLocation();
      $(window).off('scroll', checkScroll);
    }
  }

  function askLocation()
  {
    if (!("geolocation" in navigator)) {
      return;
    }

    navigator.geolocation.getCurrentPosition(function(position) {
      $.ajax({
        url: "http://legislators-locator.herokuapp.com/",
        jsonp: "callback",
        dataType: "jsonp",
        data: {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        },
        // work with the response
        success: renderLegislators
      });
    }, function() {
      // :TODO:
      console.error("Geo fail");
    });
  }

  checkScroll();
  $(window).on('scroll', checkScroll);
});

// ----------------- LEGISLATORS CALL ----------------------------

var legislatorTemplate = $('#legislator-template').html();

var renderLegislators = function(legislators) {
  _.each(legislators, function (legislator) {
    $('.legislators').append(_.template(legislatorTemplate, legislator));
  })
};

// ----------------- FORM SUBMISSION ----------------------

$('.postcode-lookup').on('submit', function(ev){
  $('.postcode-steps').fadeOut(400);
  var postcode = $('input', $(ev.currentTarget)).val();
  $.ajax({
    url: "http://legislators-locator.herokuapp.com/",
    jsonp: "callback",
    dataType: "jsonp",
    data: {
        postcode: postcode
    },
    // work with the response
    success: function( response ) {
        renderLegislators(response);
        console.log( response ); // server response
    }
  });
  return false;
});

// ----------------- POP OVERS ----------------------------

$('.metric').popover({
  trigger: 'hover',
  container: 'body',
  placement: 'top'
});

$('.support img').popover({
  trigger: 'hover',
  container: 'body',
  placement: 'top'
});
$('.contact li').popover({
  trigger: 'hover',
  container: 'body',
  placement: 'top'
});

// ----------------- MODALS ----------------------------
$('body').on('click', '.contact .call-action', function (e) {
  var legislatorId = $(e.currentTarget).parents('.legislator').attr('data-legislator-id');
  var legislator = legislators[legislatorId];
  var callModalTemplate = $('#call-modal-template').html();
  $('#call-modal-container').html(_.template(callModalTemplate, legislator));
  $('#call-modal-container .modal').modal();
});

$('body').on('click', '.contact .email-action', function (e) {
  var legislatorId = $(e.currentTarget).parents('.legislator').attr('data-legislator-id');
  var legislator = legislators[legislatorId];
  var emailModalTemplate = $('#email-modal-template').html();
  $('#email-modal-container').html(_.template(emailModalTemplate, legislator));
  $('#email-modal-container .modal').modal();
  $('#email-modal').modal();
});
<commit_msg>fix checkScroll firing twice<commit_after>
function debounce(func, wait) {
  var timeout;
  return function() {
    var context = this, args = arguments;
    clearTimeout(timeout);
    timeout = setTimeout(function() {
      timeout = null;
      func.apply(context, args);
    }, wait || 300);
  };
};

//--------------------------------------------------------------------------------
// location prompt
//--------------------------------------------------------------------------------

$(function() {
  var locationMarker = $('#request-location');
  var locationOffset = parseInt(locationMarker.data('offset') || 0);

  function checkScroll(e)
  {
    if ($(window).scrollTop() > locationMarker.offset().top - locationOffset) {
      askLocation();
      $(window).off('scroll', checkScroll);
    }
  }

  function askLocation()
  {
    if (!("geolocation" in navigator)) {
      return;
    }

    navigator.geolocation.getCurrentPosition(function(position) {
      $.ajax({
        url: "http://legislators-locator.herokuapp.com/",
        jsonp: "callback",
        dataType: "jsonp",
        data: {
          lat: position.coords.latitude,
          lng: position.coords.longitude
        },
        // work with the response
        success: renderLegislators
      });
    }, function() {
      // :TODO:
      console.error("Geo fail");
    });
  }

  $(window).on('scroll', checkScroll);
  checkScroll();
});

// ----------------- LEGISLATORS CALL ----------------------------

var legislatorTemplate = $('#legislator-template').html();

var renderLegislators = function(legislators) {
  _.each(legislators, function (legislator) {
    $('.legislators').append(_.template(legislatorTemplate, legislator));
  })
};

// ----------------- FORM SUBMISSION ----------------------

$('.postcode-lookup').on('submit', function(ev){
  $('.postcode-steps').fadeOut(400);
  var postcode = $('input', $(ev.currentTarget)).val();
  $.ajax({
    url: "http://legislators-locator.herokuapp.com/",
    jsonp: "callback",
    dataType: "jsonp",
    data: {
        postcode: postcode
    },
    // work with the response
    success: function( response ) {
        renderLegislators(response);
        console.log( response ); // server response
    }
  });
  return false;
});

// ----------------- POP OVERS ----------------------------

$('.metric').popover({
  trigger: 'hover',
  container: 'body',
  placement: 'top'
});

$('.support img').popover({
  trigger: 'hover',
  container: 'body',
  placement: 'top'
});
$('.contact li').popover({
  trigger: 'hover',
  container: 'body',
  placement: 'top'
});

// ----------------- MODALS ----------------------------
$('body').on('click', '.contact .call-action', function (e) {
  var legislatorId = $(e.currentTarget).parents('.legislator').attr('data-legislator-id');
  var legislator = legislators[legislatorId];
  var callModalTemplate = $('#call-modal-template').html();
  $('#call-modal-container').html(_.template(callModalTemplate, legislator));
  $('#call-modal-container .modal').modal();
});

$('body').on('click', '.contact .email-action', function (e) {
  var legislatorId = $(e.currentTarget).parents('.legislator').attr('data-legislator-id');
  var legislator = legislators[legislatorId];
  var emailModalTemplate = $('#email-modal-template').html();
  $('#email-modal-container').html(_.template(emailModalTemplate, legislator));
  $('#email-modal-container .modal').modal();
  $('#email-modal').modal();
});
<|endoftext|>


<commit_before>// License: MIT (Expat)

"use strict";

function begin_authorization() {
    document.getElementById("sign_in").style.display = "none";
    document.getElementById("content").style.display = "none";
    document.getElementById("auth").style.display = "flex";
    return false;
}

function authorized_user() {
    document.getElementById("sign_in").remove();
    document.getElementById("sign_out").style.display = "inline-block";
    document.getElementById("user_name").style.display = "inline-block";
    document.getElementById("user_avatar").style.display = "inline-block";
    document.getElementById("auth").remove();
}

function unauthorized_user() {
    document.getElementById("sign_in").style.display = "inline-block";
    document.getElementById("sign_out").remove();
    document.getElementById("user_name").remove();
    email_is_unknown();
    not_admin();
}

function admin() {
    document.getElementById("settings_page").style.display = "inline-block";
}

function not_admin() {
    document.getElementById("settings_page").remove();
}

function email_is_unknown() {
    document.getElementById("user_avatar").remove();
}

function sign_out() {
    $.post("?ajax=sign_out");
    return true;
}

function store_user_name() {
    localStorage.setItem("user_name", $("#input_user_name").val());
}

function document_postprocessing() {
    if ($("#input_user_name")) {
        $("#input_user_name").val(localStorage.getItem("user_name"));
    }
}

function show_auth_error() {
    document.getElementById("auth_error").style.display = "table";
}

function close_auth_error() {
    document.getElementById("auth_error").style.display = "none";
    document.getElementById("input_user_name").focus();
    document.getElementById("input_user_name").scrollIntoView();
}

function force_password_update() {
    var currentUrl = $("#sign_out").find("a").attr("href");
    var redirectTo = $("#user_name").find("a").attr("href") + "/security";
    if (currentUrl !== redirectTo) {
        localStorage.redirect_to = currentUrl;
        localStorage.force_pass_update = true;
        location.href = redirectTo;
    }
}

$(document).on("click", "#close_auth_error", close_auth_error);
$(document).on("click", "#sign_in *", begin_authorization);
$(document).on("click", "#sign_out *", sign_out);
$(document).on("submit", "#auth_form", store_user_name);
$(document).ready(document_postprocessing);

<commit_msg>Tiny cosmetic change in authorization form.<commit_after>// License: MIT (Expat)

"use strict";

function begin_authorization() {
    document.getElementById("sign_in").style.display = "none";
    document.getElementById("content").style.display = "none";
    document.getElementById("auth").style.display = "flex";
    return false;
}

function authorized_user() {
    document.getElementById("sign_in").remove();
    document.getElementById("sign_out").style.display = "inline-block";
    document.getElementById("user_name").style.display = "inline-block";
    document.getElementById("user_avatar").style.display = "inline-block";
    document.getElementById("auth").remove();
}

function unauthorized_user() {
    document.getElementById("sign_in").style.display = "inline-block";
    document.getElementById("sign_out").remove();
    document.getElementById("user_name").remove();
    email_is_unknown();
    not_admin();
}

function admin() {
    document.getElementById("settings_page").style.display = "inline-block";
}

function not_admin() {
    document.getElementById("settings_page").remove();
}

function email_is_unknown() {
    document.getElementById("user_avatar").remove();
}

function sign_out() {
    $.post("?ajax=sign_out");
    return true;
}

function store_user_name() {
    localStorage.setItem("user_name", $("#input_user_name").val());
    $("#button_submit_auth_form").css("cursor", "wait");
}

function document_postprocessing() {
    if ($("#input_user_name")) {
        $("#input_user_name").val(localStorage.getItem("user_name"));
    }
}

function show_auth_error() {
    document.getElementById("auth_error").style.display = "table";
}

function close_auth_error() {
    document.getElementById("auth_error").style.display = "none";
    document.getElementById("input_user_name").focus();
    document.getElementById("input_user_name").scrollIntoView();
}

function force_password_update() {
    var currentUrl = $("#sign_out").find("a").attr("href");
    var redirectTo = $("#user_name").find("a").attr("href") + "/security";
    if (currentUrl !== redirectTo) {
        localStorage.redirect_to = currentUrl;
        localStorage.force_pass_update = true;
        location.href = redirectTo;
    }
}

$(document).on("click", "#close_auth_error", close_auth_error);
$(document).on("click", "#sign_in *", begin_authorization);
$(document).on("click", "#sign_out *", sign_out);
$(document).on("submit", "#auth_form", store_user_name);
$(document).ready(document_postprocessing);

<|endoftext|>


<commit_before>var app = {
  init : function() {
    app.current = null;
    app.autoplay = false;
    app.autoplay_timer = null;

    var opt = {
      center: new google.maps.LatLng(50.037643, 8.562409), zoom: 15,
      mapTypeId: google.maps.MapTypeId.SATELLITE,
      disableDefaultUI: true, mapTypeControl: false, navigationControl: false, disableDoubleClickZoom: false,
      draggable: false, scrollwheel: false, streetViewControl: false,
      backgroundColor: '#000000'};
    app.map = new google.maps.Map($('#map')[0],opt);

    app.static_airports = [
      new Airport(["EDDF","Frankfurt am Main International Airport","L","49.9984","8.49708","50.0458","8.58698","DE","Frankfurt-am-Main"]),
      new Airport(["OMDB","Dubai International Airport","L","25.2433","55.347","25.2665","55.3815","AE","Dubai"]),
      new Airport(["KSFO","San Francisco International Airport","L","37.6068","-122.393","37.6287","-122.357","US","San Francisco"])
    ];
    app.airports = [];
    $.get("data/data.csv", function(data) {
      var lines = data.split(/\r\n|\n/);
      for (var i=1; i<lines.length; i++)
      {
        var data = lines[i].split(',');
        if (data.length == 9)
        {
          app.airports.push(new Airport(data));
        }
      }
    });

    // setup event handlers
    google.maps.event.addListener(app.map, 'click', function(event) {
      app.track("control", "map-click");
      app.loadRandomAirport();
    });

    google.maps.event.addDomListener(window, 'resize', function() {
      google.maps.event.trigger(app.map, 'resize');
      app.fitMap();
    });

    $('#control-info').click(function() {
      app.track("control", "info");
      app.openInfoOverlay();
      });
    $('#control-google-maps').click(function() {
      app.openGoogleMaps();
      });
    $('#control-random').click(function() {
      app.track("control", "random");
      app.loadRandomAirport();
      });
    $('#control-play').click(function() {
      app.track("control", "play");
      app.toggleAutoPlay();
      });

    app.loadRandomAirport();
  },

  load : function(code) {
    for (var index = 0; index < app.airports.length; ++index) {
      if (app.airports[index].get_code() != code) {
        continue;
      }

      app.current = app.airports[index];
      app.updateLabel();
      app.fitMap();
      break;
    }
  },

  fitMap : function() {
    if (!app.current) {
      return;
    }
    app.map.setCenter(app.current.get_pos());
    if (app.current.get_bounds().getNorthEast().equals(app.current.get_bounds().getSouthWest())) {
      app.map.setZoom(app.current.get_zoom());
    } else {
      app.map.fitBounds(app.current.get_bounds());
    }
  },

  toggleAutoPlay : function () {
    if (app.autoplay) {
      clearInterval(app.autoplay_timer);
      app.autoplay = true;
      $('#control-play > i').removeClass('fa-pause').addClass('fa-play');
    } else {
      app.autoplay = true;
      $('#control-play > i').removeClass('fa-play').addClass('fa-pause');
      app.autoplay_interval = setInterval(function() { app.loadRandomAirport(); }, 60 * 1000);
    }
  },

  openGoogleMaps : function() {
    app.track("control", "google-maps", "airport", app.current.get_label());
    window.open(app.current.get_google_maps_url(), '_blank');
  },

  openInfoOverlay : function() {
    $('#controls').fadeOut(1000);
    $('#label').fadeOut(1000);
    $('#info-overlay').fadeIn(1000);
    $('#info-overlay button').click(function(){
      app.closeInfoOverlay();
    });
  },

  closeInfoOverlay : function() {
    $('#info-overlay').fadeOut(1000);
    $('#controls').fadeIn(1000);
    $('#label').fadeIn(1000);
  },

  updateLabel : function() {
    $('#label').html(app.current.get_label());
    $('#location').html(app.current.get_location_name());
  },

  loadRandomAirport : function() {
    if (app.airports.length > 0) {
      var index =  Math.floor(Math.random() * app.airports.length);
      app.current = app.airports[index];
    } else if (app.static_airports.length > 0) {
      var index =  Math.floor(Math.random() * app.static_airports.length);
      app.current = app.static_airports[index];
    } else {
      return;
    }

    $('#container').prepend($('#map').clone(false).attr('id','map-buffer'));
    google.maps.event.addListenerOnce(app.map, 'bounds_changed', function(){
      setTimeout(function(){
        $('#map-buffer').fadeOut(1000, function(){
          $(this).remove();
          app.updateLabel();
          });
        }, 2000);
      });
    setTimeout(function(){
      $('#map-buffer').remove();
      app.updateLabel();
    }, 3000);

    app.fitMap();
  },

  track : function(category,action,label,value) {
    if(_gaq) _gaq.push(['_trackEvent', category, action, label, value]);
  }
};

var _gaq = _gaq || [];

$(document).ready(function(){
  app.init();

  _gaq.push(['_setAccount', 'UA-27729857-5']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
});
<commit_msg>added better tracking<commit_after>var app = {
  init : function() {
    app.current = null;
    app.autoplay = false;
    app.autoplay_timer = null;

    var opt = {
      center: new google.maps.LatLng(50.037643, 8.562409), zoom: 15,
      mapTypeId: google.maps.MapTypeId.SATELLITE,
      disableDefaultUI: true, mapTypeControl: false, navigationControl: false, disableDoubleClickZoom: false,
      draggable: false, scrollwheel: false, streetViewControl: false,
      backgroundColor: '#000000'};
    app.map = new google.maps.Map($('#map')[0],opt);

    app.static_airports = [
      new Airport(["EDDF","Frankfurt am Main International Airport","L","49.9984","8.49708","50.0458","8.58698","DE","Frankfurt-am-Main"]),
      new Airport(["OMDB","Dubai International Airport","L","25.2433","55.347","25.2665","55.3815","AE","Dubai"]),
      new Airport(["KSFO","San Francisco International Airport","L","37.6068","-122.393","37.6287","-122.357","US","San Francisco"])
    ];
    app.airports = [];
    $.get("data/data.csv", function(data) {
      var lines = data.split(/\r\n|\n/);
      for (var i=1; i<lines.length; i++)
      {
        var data = lines[i].split(',');
        if (data.length == 9)
        {
          app.airports.push(new Airport(data));
        }
      }
    });

    // setup event handlers
    google.maps.event.addListener(app.map, 'click', function(event) {
      app.track("map", "click");
      app.loadRandomAirport();
    });

    google.maps.event.addDomListener(window, 'resize', function() {
      google.maps.event.trigger(app.map, 'resize');
      app.fitMap();
    });

    $('#control-info').click(function() {
      app.track("control", "info");
      app.openInfoOverlay();
      });
    $('#control-google-maps').click(function() {
      app.openGoogleMaps();
      });
    $('#control-random').click(function() {
      app.track("control", "random");
      app.loadRandomAirport();
      });
    $('#control-play').click(function() {
      app.track("control", "play");
      app.toggleAutoPlay();
      });

    app.loadRandomAirport();
  },

  load : function(code) {
    for (var index = 0; index < app.airports.length; ++index) {
      if (app.airports[index].get_code() != code) {
        continue;
      }

      app.current = app.airports[index];
      app.updateLabel();
      app.fitMap();
      break;
    }
  },

  fitMap : function() {
    if (!app.current) {
      return;
    }
    app.map.setCenter(app.current.get_pos());
    if (app.current.get_bounds().getNorthEast().equals(app.current.get_bounds().getSouthWest())) {
      app.map.setZoom(app.current.get_zoom());
    } else {
      app.map.fitBounds(app.current.get_bounds());
    }
  },

  toggleAutoPlay : function () {
    if (app.autoplay) {
      clearInterval(app.autoplay_timer);
      app.autoplay = true;
      $('#control-play > i').removeClass('fa-pause').addClass('fa-play');
    } else {
      app.autoplay = true;
      $('#control-play > i').removeClass('fa-play').addClass('fa-pause');
      app.autoplay_interval = setInterval(function() {
        app.track("autoplay", "load");
        app.loadRandomAirport();
        }, 60 * 1000);
    }
  },

  openGoogleMaps : function() {
    app.track("control", "google-maps", "airport", app.current.get_label());
    window.open(app.current.get_google_maps_url(), '_blank');
  },

  openInfoOverlay : function() {
    $('#controls').fadeOut(1000);
    $('#label').fadeOut(1000);
    $('#info-overlay').fadeIn(1000);
    $('#info-overlay button').click(function(){
      app.closeInfoOverlay();
    });
  },

  closeInfoOverlay : function() {
    $('#info-overlay').fadeOut(1000);
    $('#controls').fadeIn(1000);
    $('#label').fadeIn(1000);
  },

  updateLabel : function() {
    $('#label').html(app.current.get_label());
    $('#location').html(app.current.get_location_name());
  },

  loadRandomAirport : function() {
    if (app.airports.length > 0) {
      var index =  Math.floor(Math.random() * app.airports.length);
      app.current = app.airports[index];
    } else if (app.static_airports.length > 0) {
      var index =  Math.floor(Math.random() * app.static_airports.length);
      app.current = app.static_airports[index];
    } else {
      return;
    }

    $('#container').prepend($('#map').clone(false).attr('id','map-buffer'));
    google.maps.event.addListenerOnce(app.map, 'bounds_changed', function(){
      setTimeout(function(){
        $('#map-buffer').fadeOut(1000, function(){
          $(this).remove();
          app.updateLabel();
          });
        }, 2000);
      });
    setTimeout(function(){
      $('#map-buffer').remove();
      app.updateLabel();
    }, 3000);

    app.fitMap();
  },

  track : function(category,action,label,value) {
    if(_gaq) _gaq.push(['_trackEvent', category, action, label, value]);
  }
};

var _gaq = _gaq || [];

$(document).ready(function(){
  app.init();

  _gaq.push(['_setAccount', 'UA-27729857-5']);
  _gaq.push(['_trackPageview']);

  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
});
<|endoftext|>