<commit_before>/**
 The MIT License (MIT)

 Copyright (c) 2013 LiveFoundry Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 */

/**
 * @fileoverview
 * Single class source - contains definition of the AddLiveService class.
 *
 * @author Tadeusz Kozak
 * @date 6/5/13 2:49 PM
 */

(function () {
  'use strict';

  // Imports

  var $ = ADL.UI.$,
      $$, // Lazy init
      Log = ADL.Log;

  // Constants, enums
  var AVG_RTT_OK = 300,

      ConnHwItemStatus =
      {
        BAD:'invalid',
        WARN:'warning',
        OK:'valid',
        PENDING:'loading',
        SKIPPED:'skipped'
      },
      /**
       * How long the sample connection should last.
       */
          RTT_TEST_DURATION = 15000,

      CLOCK_MAP = {
        1:{warn:2500, ok:Number.MAX_VALUE},
        2:{warn:1700, ok:2500},
        3:{warn:1700, ok:2500},
//          Any 4 cores CPU will do the job
        4:{ok:0}
      },

      WARN_CPU_PATTERNS = [
        /Atom/, /Celeron/
      ],

      BAD_CPU_PATTERNS = [
        /Pentium III/,
        /Pentium II/
      ];

  // Scope variables
  var connHwTestOverallResult = ConnHwItemStatus.OK,
      scopeId,
      authDetails,
      responder,
      rtts = [],
      linkQualityConnDescr,
      terminated = false;

  function start(r, options) {
    terminated = false;
    $$ = ADL.UI.SetupAssistant.$$;
    authDetails = options.testConnDescr.authDetails;
    scopeId = options.testConnDescr.scopeId;
    linkQualityConnDescr = options.linkQualityConnDescr;
    responder = r;
    var listener = new ADL.AddLiveServiceListener();
    listener.onMediaConnTypeChanged = _onMediaConnTypeChanged;
    listener.onMediaStats = _onMediaStats;

//      Register the listener
    ADL.getService().addServiceListener(ADL.r(), listener);
    _testCpu();
    _initTestConn();
  }

  function terminate() {
    try {
      // It may fail if the cancel will be requested before the plug-in
      // installation - in this case ADL.getService() will return undefined.
      ADL.getService().disconnect(ADL.r(), scopeId);
    } catch (exc) {

    }
    terminated = true;
  }

  function _setConnHwTestStatus(newStatus) {
    if (connHwTestOverallResult === ConnHwItemStatus.BAD) {
      return;
    }
    if (newStatus === ConnHwItemStatus.OK) {
      return;
    }
    connHwTestOverallResult = newStatus;
  }

  function _testCpu() {
    if (terminated) {
      return;
    }
    Log.d('Testing the CPU');
    var $cpuTest = $$('.cpuTest');

    var onHostDetails = function (info) {

      var cpuStatus = _rateCPU(info);
      $cpuTest.find('.cpuInfo').text(info.brand_string);
      _setPartialResult($cpuTest, cpuStatus);

      Log.d('CPU Test complete');
      _setConnHwTestStatus(cpuStatus);
    }, onHostDetailsErr = function () {
      $cpuTest.hide();
      $$('.cpuErr').show();
      _setConnHwTestStatus(ConnHwItemStatus.WARN);
    };
    ADL.getService().getHostCpuDetails(ADL.r(onHostDetails, onHostDetailsErr));
  }

  function _rateCPU(info) {
    var cpuStatus = ConnHwItemStatus.BAD;
    if (CLOCK_MAP[info.cores] !== undefined) {
      if (info.clock > CLOCK_MAP[info.cores].ok) {
        cpuStatus = ConnHwItemStatus.OK;
      } else if (info.clock > CLOCK_MAP[info.cores].warn) {
        cpuStatus = ConnHwItemStatus.WARN;
      }
    } else if (info.cores > 4) {
      cpuStatus = ConnHwItemStatus.OK;
    }
    $.each(WARN_CPU_PATTERNS, function (i, pattern) {
      if (info.brand_string.match(pattern)) {
        cpuStatus = ConnHwItemStatus.WARN;
      }
    });

    $.each(BAD_CPU_PATTERNS, function (i, pattern) {
      if (info.brand_string.match(pattern)) {
        cpuStatus = ConnHwItemStatus.BAD;
      }
    });
    return cpuStatus;
  }

  function _initTestConn() {
    if (terminated) {
      return;
    }
    Log.d('Establishing RTT test connection');
    var connDescriptor = {
      scopeId:scopeId,
      authDetails:authDetails,
      publishVideo:false,
      publishAudio:true
    };
    ADL.getService().connect(ADL.r(_onConnected, _onConnErr), connDescriptor);
  }

  function _onConnected() {
    if (terminated) {
      ADL.getService().disconnect(ADL.r(), scopeId);
    }
    Log.d('RTT test connection established. Polling stats');
    _setPartialResult($$('.connTest'), ConnHwItemStatus.OK);
    ADL.getService().startMeasuringStatistics(ADL.r(), scopeId, 1);
    _testLinkQuality();
    setTimeout(_connAndRTTTestComplete, RTT_TEST_DURATION);
  }

  function _onConnErr() {
    Log.w('Failed to connect');

    _setPartialResult($$('.connTest'), ConnHwItemStatus.BAD);
    _failAllConnTests();
  }

  function _failAllConnTests() {
    $$('.connectivity-test').
        removeClass(ConnHwItemStatus.PENDING).
        addClass(ConnHwItemStatus.SKIPPED);

    // TODO
    $$('.connectingMsg').html('No Internet connection');
    _onConnectivityTestComplete();
  }

  function _connAndRTTTestComplete() {
    ADL.getService().disconnect(ADL.r(), scopeId);
    _testRTT();
  }

  function _testLinkQuality() {
    if (terminated) {
      return;
    }
    ADL.getService().networkTest(
        ADL.r(_onLinkQualityTestResult, _onLinkQualityTestError),
        linkQualityConnDescr);
  }

  function _onLinkQualityTestResult(qualityResult) {
    if (terminated) {
      return;
    }
    var testResult;

    if (qualityResult !== ADL.ConnectionQuality.FINE) {
      testResult = ConnHwItemStatus.WARN;
    } else {
      testResult = ConnHwItemStatus.OK;
    }
    _setPartialResult($$('.bandwithTest'), testResult);

    // TODO
    $$('.connectingMsg').html('Connection checked');
    _onConnectivityTestComplete();
  }

  function _onLinkQualityTestError() {
    _setPartialResult($$('.bandwithTest'), ConnHwItemStatus.WARN);

    // TODO
    $$('.connectingMsg').html('Connection checked');
    _onConnectivityTestComplete();
  }

  function _onConnectivityTestComplete() {
    if (terminated) {
      return;
    }
    if (connHwTestOverallResult === ConnHwItemStatus.OK) {
      $$('.goToPage5Btn').
          html('Next >').
          click(_complete);
    } else {
      $$('.goToPage5Btn').
          html('' +
          'I\'ll continue anyway')
          .click(_complete);
    }
    $$('.goToPage5Btn').parent().addClass('btn-holder');
    $$('.goToPage5Btn').next().removeClass();
  }

  function _onMediaStats(e) {
    if (e.mediaType === ADL.MediaType.AUDIO) {
      Log.d('Got media stats');
      rtts.push(e.stats.rtt);
    }
  }

  /**
   *
   * @param {ADL.MediaConnTypeChangedEvent}e
   */
  function _onMediaConnTypeChanged(e) {
    var $infoContainer,
        result;
    if (e.mediaType === ADL.MediaType.AUDIO) {
      $infoContainer = $$('.connTypeAudioTest');
    } else {
      $infoContainer = $$('.connTypeVideoTest');
    }
    switch (e.connectionType) {
      case ADL.ConnectionType.UDP_RELAY:
        result = ConnHwItemStatus.OK;
        break;
      case ADL.ConnectionType.TCP_RELAY:
        result = ConnHwItemStatus.WARN;
        break;
    }
    _setPartialResult($infoContainer, result);
  }

  function _testRTT() {
    var $infoContainer = $$('.distanceTest'),
        avgRtt = 0,
        result;

    $.each(rtts, function (i, rtt) {
      avgRtt += parseInt(rtt, 10);
    });
    avgRtt /= rtts.length;

    if (avgRtt > AVG_RTT_OK) {
      result = ConnHwItemStatus.WARN;
    } else {
      result = ConnHwItemStatus.OK;
      $infoContainer.find('.rttInfo').text(Math.floor(avgRtt));
    }
    _setPartialResult($infoContainer, result);
  }

  function _setPartialResult($container, result) {

    // If it's already bad - don't do anything
    if (connHwTestOverallResult !== ConnHwItemStatus.BAD) {

      // If it's ok - don't set it as it's the default value and we don't want
      // to go from warn to OK
      if (result !== ConnHwItemStatus.OK) {
        connHwTestOverallResult = result;
      }
    }
    $container.removeClass('loading').addClass(result);
  }

  function _complete() {
    responder.result();
  }

  ADL.UI.SAConnectivity = {
    start:start,
    terminate:terminate
  };

}());<commit_msg>Added i5 and i7 to list of whitelisted CPUs<commit_after>/**
 The MIT License (MIT)

 Copyright (c) 2013 LiveFoundry Inc.

 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the "Software"), to deal in
 the Software without restriction, including without limitation the rights to
 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
 the Software, and to permit persons to whom the Software is furnished to do so,
 subject to the following conditions:

 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 */

/**
 * @fileoverview
 * Single class source - contains definition of the AddLiveService class.
 *
 * @author Tadeusz Kozak
 * @date 6/5/13 2:49 PM
 */

(function () {
  'use strict';

  // Imports

  var $ = ADL.UI.$,
      $$, // Lazy init
      Log = ADL.Log;

  // Constants, enums
  var AVG_RTT_OK = 300,

      ConnHwItemStatus =
      {
        BAD:'invalid',
        WARN:'warning',
        OK:'valid',
        PENDING:'loading',
        SKIPPED:'skipped'
      },
      /**
       * How long the sample connection should last.
       */
          RTT_TEST_DURATION = 15000,

      CLOCK_MAP = {
        1:{warn:2500, ok:Number.MAX_VALUE},
        2:{warn:1700, ok:2500},
        3:{warn:1700, ok:2500},
//          Any 4 cores CPU will do the job
        4:{ok:0}
      },

  // Explicit CPU white and black listing
      WARN_CPU_PATTERNS = [
        /Atom/
      ],

      BAD_CPU_PATTERNS = [
        /Pentium III/,
        /Pentium II/
      ],

      OK_CPU_PATTERNS = [
        /i5/, // Intel core i5
        /i7/ // Intel core i7
      ];

  // Scope variables
  var connHwTestOverallResult = ConnHwItemStatus.OK,
      scopeId,
      authDetails,
      responder,
      rtts = [],
      linkQualityConnDescr,
      terminated = false;

  function start(r, options) {
    terminated = false;
    $$ = ADL.UI.SetupAssistant.$$;
    authDetails = options.testConnDescr.authDetails;
    scopeId = options.testConnDescr.scopeId;
    linkQualityConnDescr = options.linkQualityConnDescr;
    responder = r;
    var listener = new ADL.AddLiveServiceListener();
    listener.onMediaConnTypeChanged = _onMediaConnTypeChanged;
    listener.onMediaStats = _onMediaStats;

//      Register the listener
    ADL.getService().addServiceListener(ADL.r(), listener);
    _testCpu();
    _initTestConn();
  }

  function terminate() {
    try {
      // It may fail if the cancel will be requested before the plug-in
      // installation - in this case ADL.getService() will return undefined.
      ADL.getService().disconnect(ADL.r(), scopeId);
    } catch (exc) {

    }
    terminated = true;
  }

  function _setConnHwTestStatus(newStatus) {
    if (connHwTestOverallResult === ConnHwItemStatus.BAD) {
      return;
    }
    if (newStatus === ConnHwItemStatus.OK) {
      return;
    }
    connHwTestOverallResult = newStatus;
  }

  function _testCpu() {
    if (terminated) {
      return;
    }
    Log.d('Testing the CPU');
    var $cpuTest = $$('.cpuTest');

    var onHostDetails = function (info) {

      var cpuStatus = _rateCPU(info);
      $cpuTest.find('.cpuInfo').text(info.brand_string);
      _setPartialResult($cpuTest, cpuStatus);

      Log.d('CPU Test complete');
      _setConnHwTestStatus(cpuStatus);
    }, onHostDetailsErr = function () {
      $cpuTest.hide();
      $$('.cpuErr').show();
      _setConnHwTestStatus(ConnHwItemStatus.WARN);
    };
    ADL.getService().getHostCpuDetails(ADL.r(onHostDetails, onHostDetailsErr));
  }

  function _rateCPU(info) {
    var cpuStatus = ConnHwItemStatus.BAD;
    if (CLOCK_MAP[info.cores] !== undefined) {
      if (info.clock > CLOCK_MAP[info.cores].ok) {
        cpuStatus = ConnHwItemStatus.OK;
      } else if (info.clock > CLOCK_MAP[info.cores].warn) {
        cpuStatus = ConnHwItemStatus.WARN;
      }
    } else if (info.cores > 4) {
      cpuStatus = ConnHwItemStatus.OK;
    }
    $.each(WARN_CPU_PATTERNS, function (i, pattern) {
      if (info.brand_string.match(pattern)) {
        cpuStatus = ConnHwItemStatus.WARN;
      }
    });

    $.each(BAD_CPU_PATTERNS, function (i, pattern) {
      if (info.brand_string.match(pattern)) {
        cpuStatus = ConnHwItemStatus.BAD;
      }
    });
    $.each(OK_CPU_PATTERNS, function (i, pattern) {
      if (info.brand_string.match(pattern)) {
        cpuStatus = ConnHwItemStatus.OK;
      }
    });
    return cpuStatus;
  }

  function _initTestConn() {
    if (terminated) {
      return;
    }
    Log.d('Establishing RTT test connection');
    var connDescriptor = {
      scopeId:scopeId,
      authDetails:authDetails,
      publishVideo:false,
      publishAudio:true
    };
    ADL.getService().connect(ADL.r(_onConnected, _onConnErr), connDescriptor);
  }

  function _onConnected() {
    if (terminated) {
      ADL.getService().disconnect(ADL.r(), scopeId);
    }
    Log.d('RTT test connection established. Polling stats');
    _setPartialResult($$('.connTest'), ConnHwItemStatus.OK);
    ADL.getService().startMeasuringStatistics(ADL.r(), scopeId, 1);
    _testLinkQuality();
    setTimeout(_connAndRTTTestComplete, RTT_TEST_DURATION);
  }

  function _onConnErr() {
    Log.w('Failed to connect');

    _setPartialResult($$('.connTest'), ConnHwItemStatus.BAD);
    _failAllConnTests();
  }

  function _failAllConnTests() {
    $$('.connectivity-test').
        removeClass(ConnHwItemStatus.PENDING).
        addClass(ConnHwItemStatus.SKIPPED);

    // TODO
    $$('.connectingMsg').html('No Internet connection');
    _onConnectivityTestComplete();
  }

  function _connAndRTTTestComplete() {
    ADL.getService().disconnect(ADL.r(), scopeId);
    _testRTT();
  }

  function _testLinkQuality() {
    if (terminated) {
      return;
    }
    ADL.getService().networkTest(
        ADL.r(_onLinkQualityTestResult, _onLinkQualityTestError),
        linkQualityConnDescr);
  }

  function _onLinkQualityTestResult(qualityResult) {
    if (terminated) {
      return;
    }
    var testResult;

    if (qualityResult !== ADL.ConnectionQuality.FINE) {
      testResult = ConnHwItemStatus.WARN;
    } else {
      testResult = ConnHwItemStatus.OK;
    }
    _setPartialResult($$('.bandwithTest'), testResult);

    // TODO
    $$('.connectingMsg').html('Connection checked');
    _onConnectivityTestComplete();
  }

  function _onLinkQualityTestError() {
    _setPartialResult($$('.bandwithTest'), ConnHwItemStatus.WARN);

    // TODO
    $$('.connectingMsg').html('Connection checked');
    _onConnectivityTestComplete();
  }

  function _onConnectivityTestComplete() {
    if (terminated) {
      return;
    }
    if (connHwTestOverallResult === ConnHwItemStatus.OK) {
      $$('.goToPage5Btn').
          html('Next >').
          click(_complete);
    } else {
      $$('.goToPage5Btn').
          html('' +
          'I\'ll continue anyway')
          .click(_complete);
    }
    $$('.goToPage5Btn').parent().addClass('btn-holder');
    $$('.goToPage5Btn').next().removeClass();
  }

  function _onMediaStats(e) {
    if (e.mediaType === ADL.MediaType.AUDIO) {
      Log.d('Got media stats');
      rtts.push(e.stats.rtt);
    }
  }

  /**
   *
   * @param {ADL.MediaConnTypeChangedEvent}e
   */
  function _onMediaConnTypeChanged(e) {
    var $infoContainer,
        result;
    if (e.mediaType === ADL.MediaType.AUDIO) {
      $infoContainer = $$('.connTypeAudioTest');
    } else {
      $infoContainer = $$('.connTypeVideoTest');
    }
    switch (e.connectionType) {
      case ADL.ConnectionType.UDP_RELAY:
        result = ConnHwItemStatus.OK;
        break;
      case ADL.ConnectionType.TCP_RELAY:
        result = ConnHwItemStatus.WARN;
        break;
    }
    _setPartialResult($infoContainer, result);
  }

  function _testRTT() {
    var $infoContainer = $$('.distanceTest'),
        avgRtt = 0,
        result;

    $.each(rtts, function (i, rtt) {
      avgRtt += parseInt(rtt, 10);
    });
    avgRtt /= rtts.length;

    if (avgRtt > AVG_RTT_OK) {
      result = ConnHwItemStatus.WARN;
    } else {
      result = ConnHwItemStatus.OK;
      $infoContainer.find('.rttInfo').text(Math.floor(avgRtt));
    }
    _setPartialResult($infoContainer, result);
  }

  function _setPartialResult($container, result) {

    // If it's already bad - don't do anything
    if (connHwTestOverallResult !== ConnHwItemStatus.BAD) {

      // If it's ok - don't set it as it's the default value and we don't want
      // to go from warn to OK
      if (result !== ConnHwItemStatus.OK) {
        connHwTestOverallResult = result;
      }
    }
    $container.removeClass('loading').addClass(result);
  }

  function _complete() {
    responder.result();
  }

  ADL.UI.SAConnectivity = {
    start:start,
    terminate:terminate
  };

}());<|endoftext|>


<commit_before>'use strict';

module.exports = function($scope, $mdDialog, $mdToast, storage) {

	var angular = require('angular');
	var _ = require('underscore');

	var self = this;

	$scope.items = [
		// {name:'Bread', done: false},
		// {name:'Salmon', done: true},
		// {name:'Salad', done: false},
		// {name:'Milk', done: false},
		// {name:'Ham', done: false}
	];
	$scope.archivedItems = [
		// {name:'Tuna', done: false},
		// {name:'Tomato', done: false},
		// {name:'Yogurts', done: true},
		// {name:'Beer', done: true},
		// {name:'Pineapple juice', done: false},
		// {name:'Pizza', done: false},
		// {name:'Noodles', done: true},
		// {name:'Eggs', done: false},
		// {name:'Corn', done: true},
		// {name:'Chicken', done: true},
		// {name:'Pasta', done: false},
		// {name:'Cheese', done: false},
		// {name:'Fuet', done: false},
		// {name:'Kitchen tissue', done: false},
		// {name:'Wine', done: false},
		// {name:'Hot dogs', done: false},
		// {name:'Shower gel', done: false},
		// {name:'Shampoo', done: false},
		// {name:'Potatoes', done: false},
		// {name:'Deodorant', done: false},
		// {name:'Nutella', done: false},
		// {name:'Biscuits', done: false}
	];

	// Watch the list, and update the products every time it changes and it is needed
	$scope.$watch(function() {
		return self.list.name;
	}, function() {
		if (self.list.updateItems) {
			console.log(self.list.name + "  " + self.list.updateItems)
			storage.getAllItems(self.list.name, function(list) {
				$scope.$apply(function() {
					$scope.items = list.items;
					$scope.archivedItems = list.archive;
				});
			});
		}
	});

	$scope.addItem = function($event) {
		var DialogController = require('./new-list-dialog.js');
		var confirm = $mdDialog.show({
			controller: DialogController,
			controllerAs: "ctrl",
			templateUrl: './views/new-list-dialog.html',
			clickOutsideToClose: true,
			targetEvent: $event,
			ariaLabel: 'Item name',
			parent: angular.element(document.body),
			locals: {
				title: "Name the new item",
				label: "Item name",
				acceptBtn: "Add",
				initialName: "",
				uniques: [],
				autocompleteItems: _.pluck($scope.archivedItems, 'name')
			}
		})
		.then(function(result) {
			var newItem = result.trim();
			// Find if the item exists
			var findInLowerCase = function(item) {
				return item.name.toLowerCase() == newItem.toLowerCase();
			};
			var archivePos = _.findIndex($scope.archivedItems, findInLowerCase);
			var toastText = "Item added";

			// If item exists and is archived
			if (archivePos != -1) {
				// Move the item to pending
				var item = $scope.archivedItems.splice(archivePos, 1)[0];
				item.done = false;
				$scope.items.push(item);
				toastText = "Item moved from archive";
			}
			else {
				// If it is in the current list
				var itemPos = _.findIndex($scope.items, findInLowerCase);
				if (itemPos != -1) {
					// Tag the item as pending
					$scope.items[itemPos].done = false;
					toastText = "Item marked as undone";
				}
				// Otherwise add it to pending items
				else {
					var item = {name: newItem, done: false};
					$scope.items.push(item);
					storage.addItem(self.list.name, newItem, angular.noop);
				}
			}
			// Show toast
			var toast = $mdToast.simple()
				.textContent(toastText)
				.position('top right')
				.hideDelay(5000);
			$mdToast.show(toast);
		});
	};

	/**
	 *	Archives an item from the main list and shows a toast with an UNDO action.
	 *
	 * @param {int} $index The index of the item that must be retrieved
	 */
	$scope.archiveItem = function($index) {
		// Archive item
		var item = $scope.items.splice($index, 1)[0];
		$scope.archivedItems.unshift(item);
		// Show toast with undo
		var toast = $mdToast.simple()
			.textContent('Archived '+item.name)
			.position('top right')
			.hideDelay(5000)
			.action('UNDO')
			.highlightAction(true)
			.highlightClass('md-warn');
		$mdToast.show(toast).then(function(result) {
			if (result == 'ok') {
				// UNDO clicked: Rollback the change
				$scope.archivedItems.shift();
				$scope.items.splice($index, 0, item);
			}
			else {
				// Store the change
				storage.archiveItem(self.list.name, item.name, angular.noop);
			}
		});
	};

	/**
	 *	Retrieves an item from the archive back to the main list and shows a toast
	 *	with an UNDO action. Also marks the item as undone.
	 *
	 * @param {int} $index The index of the item that must be retrieved
	 */
	$scope.retrieveItem = function($index) {
		// Retrieve item and mark it as undone
		var item = $scope.archivedItems.splice($index, 1)[0];
		var done = item.done;
		item.done = false;
		$scope.items.push(item);
		// Show toast with undo
		var toast = $mdToast.simple()
			.textContent('Retrieved '+item.name)
			.position('top right')
			.hideDelay(5000)
			.action('UNDO')
			.highlightAction(true)
			.highlightClass('md-warn');
		$mdToast.show(toast).then(function(result) {
			if (result == 'ok') {
				// UNDO clicked: Rollback the change
				$scope.items.pop();
				item.done = done;
				$scope.archivedItems.splice($index, 0, item);
			}
			else {
				// Store the change
				storage.retrieveItem(self.list.name, item.name, angular.noop);
			}
		});
	};

	/**
	 *	Changes an item's status between done and not done.
	 *
	 * @param {int} $index The index of the item that must be changed
	 * @param {boolean} done The item's status before the change
	 */
	$scope.changeItemStatus = function($index, done) {
		// The next status will be the opposite of the one before the click
		var nextStatus = !done;
		// Change its status
		var item = $scope.items[$index];
		storage.changeItemStatus(self.list.name, item.name, nextStatus, angular.noop);
	};

	/**
	 *	Deletes an item from the specified list and shows a toast with an UNDO action.
	 *
	 * @param {int} $index The index of the item that must be deleted
	 * @param {string} sublist Either 'archive' or 'items' depending on which list
	 *	the item must be deleted from. Defaults to 'items'.
	 */
	$scope.deleteItem = function($index, sublist) {
		// Delete item
		var list = $scope.items;
		var isArchive = false;
		if (sublist == 'archive') {
			isArchive = true;
			list = $scope.archivedItems;
		}
		var item = list.splice($index, 1)[0];
		// Show toast with undo
		var toast = $mdToast.simple()
			.textContent('Deleted '+item.name)
			.position('top right')
			.hideDelay(5000)
			.action('UNDO')
			.highlightAction(true)
			.highlightClass('md-warn');
		$mdToast.show(toast).then(function(result) {
			if (result == 'ok') {
				list.splice($index, 0, item);
			}
			else {
				storage.deleteItem(self.list.name, item.name, isArchive, angular.noop);
			}
		});
	};
};<commit_msg>Fixed bug with toasts actions after the user has changed list.<commit_after>'use strict';

module.exports = function($scope, $mdDialog, $mdToast, storage) {

	var angular = require('angular');
	var _ = require('underscore');

	var self = this;

	$scope.items = [];
	$scope.archivedItems = [];

	// Watch the list, and update the products every time it changes and it is needed
	$scope.$watch(function() {
		return self.list.name;
	}, function() {
		if (self.list.updateItems) {
			console.log(self.list.name + "  " + self.list.updateItems)
			storage.getAllItems(self.list.name, function(list) {
				$scope.$apply(function() {
					$scope.items = list.items;
					$scope.archivedItems = list.archive;
				});
			});
		}
	});

	$scope.addItem = function($event) {
		var DialogController = require('./new-list-dialog.js');
		var confirm = $mdDialog.show({
			controller: DialogController,
			controllerAs: "ctrl",
			templateUrl: './views/new-list-dialog.html',
			clickOutsideToClose: true,
			targetEvent: $event,
			ariaLabel: 'Item name',
			parent: angular.element(document.body),
			locals: {
				title: "Name the new item",
				label: "Item name",
				acceptBtn: "Add",
				initialName: "",
				uniques: [],
				autocompleteItems: _.pluck($scope.archivedItems, 'name')
			}
		})
		.then(function(result) {
			var newItem = result.trim();
			// Find if the item exists
			var findInLowerCase = function(item) {
				return item.name.toLowerCase() == newItem.toLowerCase();
			};
			var archivePos = _.findIndex($scope.archivedItems, findInLowerCase);
			var toastText = "Item added";

			// If item exists and is archived
			if (archivePos != -1) {
				// Move the item to pending
				var item = $scope.archivedItems.splice(archivePos, 1)[0];
				item.done = false;
				$scope.items.push(item);
				toastText = "Item moved from archive";
			}
			else {
				// If it is in the current list
				var itemPos = _.findIndex($scope.items, findInLowerCase);
				if (itemPos != -1) {
					// Tag the item as pending
					$scope.items[itemPos].done = false;
					toastText = "Item marked as undone";
				}
				// Otherwise add it to pending items
				else {
					var item = {name: newItem, done: false};
					$scope.items.push(item);
					storage.addItem(self.list.name, newItem, angular.noop);
				}
			}
			// Show toast
			var toast = $mdToast.simple()
				.textContent(toastText)
				.position('top right')
				.hideDelay(5000);
			$mdToast.show(toast);
		});
	};

	/**
	 *	Archives an item from the main list and shows a toast with an UNDO action.
	 *
	 * @param {int} $index The index of the item that must be retrieved
	 */
	$scope.archiveItem = function($index) {
		// Archive item
		var item = $scope.items.splice($index, 1)[0];
		$scope.archivedItems.unshift(item);
		// Show toast with undo
		var listName = self.list.name; // Keep it in case the user changes list
		var toast = $mdToast.simple()
			.textContent('Archived '+item.name)
			.position('top right')
			.hideDelay(5000)
			.action('UNDO')
			.highlightAction(true)
			.highlightClass('md-warn');
		$mdToast.show(toast).then(function(result) {
			if (result == 'ok') {
				// UNDO clicked: Rollback the change
				$scope.archivedItems.shift();
				$scope.items.splice($index, 0, item);
			}
			else {
				// Store the change
				storage.archiveItem(listName, item.name, angular.noop);
			}
		});
	};

	/**
	 *	Retrieves an item from the archive back to the main list and shows a toast
	 *	with an UNDO action. Also marks the item as undone.
	 *
	 * @param {int} $index The index of the item that must be retrieved
	 */
	$scope.retrieveItem = function($index) {
		// Retrieve item and mark it as undone
		var item = $scope.archivedItems.splice($index, 1)[0];
		var done = item.done;
		item.done = false;
		$scope.items.push(item);
		// Show toast with undo
		var listName = self.list.name; // Keep it in case the user changes list
		var toast = $mdToast.simple()
			.textContent('Retrieved '+item.name)
			.position('top right')
			.hideDelay(5000)
			.action('UNDO')
			.highlightAction(true)
			.highlightClass('md-warn');
		$mdToast.show(toast).then(function(result) {
			if (result == 'ok') {
				// UNDO clicked: Rollback the change
				$scope.items.pop();
				item.done = done;
				$scope.archivedItems.splice($index, 0, item);
			}
			else {
				// Store the change
				storage.retrieveItem(listName, item.name, angular.noop);
			}
		});
	};

	/**
	 *	Changes an item's status between done and not done.
	 *
	 * @param {int} $index The index of the item that must be changed
	 * @param {boolean} done The item's status before the change
	 */
	$scope.changeItemStatus = function($index, done) {
		// The next status will be the opposite of the one before the click
		var nextStatus = !done;
		// Change its status
		var item = $scope.items[$index];
		storage.changeItemStatus(self.list.name, item.name, nextStatus, angular.noop);
	};

	/**
	 *	Deletes an item from the specified list and shows a toast with an UNDO action.
	 *
	 * @param {int} $index The index of the item that must be deleted
	 * @param {string} sublist Either 'archive' or 'items' depending on which list
	 *	the item must be deleted from. Defaults to 'items'.
	 */
	$scope.deleteItem = function($index, sublist) {
		// Delete item
		var list = $scope.items;
		var isArchive = false;
		if (sublist == 'archive') {
			isArchive = true;
			list = $scope.archivedItems;
		}
		var item = list.splice($index, 1)[0];
		// Show toast with undo
		var listName = self.list.name; // Keep it in case the user changes list
		var toast = $mdToast.simple()
			.textContent('Deleted '+item.name)
			.position('top right')
			.hideDelay(5000)
			.action('UNDO')
			.highlightAction(true)
			.highlightClass('md-warn');
		$mdToast.show(toast).then(function(result) {
			if (result == 'ok') {
				list.splice($index, 0, item);
			}
			else {
				storage.deleteItem(listName, item.name, isArchive, angular.noop);
			}
		});
	};

};<|endoftext|>


<commit_before>var module = angular.module('filters', []),
    webutil = require('../util/web'),
    Amount = ripple.Amount,
    Base = ripple.Base;

var iso4217 = require('../data/iso4217');

/**
 * Format a ripple.Amount.
 *
 * If the parameter is a number, the number is treated the relative
 */
module.filter('rpamount', function () {
  return function (input, opts) {
    if ("number" === typeof opts) {
      opts = {
        rel_min_precision: opts
      };
    } else if ("object" !== typeof opts) {
      opts = {};
    }

    if (!input) return "n/a";

    if (opts.xrp_human && input === ("" + parseInt(input, 10))) {
      input = input + ".0";
    }

    var amount = Amount.from_json(input);
    if (!amount.is_valid()) return "n/a";

    // Currency default precision
    var currency = iso4217[amount.currency().to_json()];
    var cdp = ("undefined" !== typeof currency) ? currency[1] : 4;

    // Certain formatting options are relative to the currency default precision
    if ("number" === typeof opts.rel_precision) {
      opts.precision = cdp + opts.rel_precision;
    }
    if ("number" === typeof opts.rel_min_precision) {
      opts.min_precision = cdp + opts.rel_min_precision;
    }

    // If no precision is given, we'll default to max precision.
    if ("number" !== typeof opts.precision) {
      opts.precision = 16;
    }

    // But we will cut off after five significant decimals
    if ("number" !== typeof opts.max_sig_digits) {
      opts.max_sig_digits = 5;
    }

    var out = amount.to_human(opts);

    return out;
  };
});

/**
 * Get the currency from an Amount.
 */
module.filter('rpcurrency', function () {
  return function (input) {
    if (!input) return "";

    var amount = Amount.from_json(input);
    return amount.currency().to_json();
  };
});

/**
 * Get the currency issuer.
 */
module.filter('rpissuer', function () {
  return function (input) {
    if (!input) return "";

    var amount = Amount.from_json(input);
    return amount.issuer().to_json();
  };
});

/**
 * Get the full currency name from an Amount.
 */
module.filter('rpcurrencyfull', ['$rootScope', function ($scope) {
  return function (input) {
    if (!input) return "";

    var amount = Amount.from_json(input);
    var currency = $.grep($scope.currencies, function(e){ return e.value == amount.currency().to_json(); })[0];

    if (currency) {
      return currency.name;
    } else {
      return amount.currency().to_json();
    }
  };
}]);

/**
 * Calculate a ratio of two Amounts.
 */
module.filter('rpamountratio', function () {
  return function (numerator, denominator) {
    try {
      return Amount.from_json(numerator).ratio_human(denominator);
    } catch (err) {
      return Amount.NaN();
    }
  };
});

/**
 * Calculate the sum of two Amounts.
 */
module.filter('rpamountadd', function () {
  return function (a, b) {
    try {
      b = Amount.from_json(b);
      if (b.is_zero()) return a;
      return Amount.from_json(a).add(b);
    } catch (err) {
      return Amount.NaN();
    }
  };
});
/**
 * Calculate the difference of two Amounts.
 */
module.filter('rpamountsubtract', function () {
  return function (a, b) {
    try {
      return Amount.from_json(a).subtract(b);
    } catch (err) {
      return Amount.NaN();
    }
  };
});

/**
 * Angular filter for Moment.js.
 *
 * Displays a timestamp as "x minutes ago".
 */
module.filter('rpfromnow', function () {
  return function (input) {
    return moment(input).fromNow();
  };
});

/**
 * Show contact name or short address
 */
module.filter('rpcontactname', ['$rootScope', function ($scope) {
  return function (address) {
    address = address ? ""+address : "";

    var contact = webutil.getContact($scope.userBlob.data.contacts, address);

    if (!contact) {
      return "" + address.substring(0,7) + "…";
    }

    return contact.name;
  };
}]);

module.filter('rpcontactnamefull', ['$rootScope', function ($scope) {
  return function (address) {
    address = address ? ""+address : "";
    var contact = webutil.getContact($scope.userBlob.data.contacts, address);

    if (!contact) {
      return "" + address;
    }

    return contact.name;
  };
}]);

module.filter('rponlycontactname', ['$rootScope', function ($scope) {
  return function (address) {
    address = address ? ""+address : "";

    var contact = webutil.getContact($scope.userBlob.data.contacts, address);

    if (contact) {
      return contact.name;
    }
  };
}]);

/**
 * Masks a string like so: •••••.
 *
 * The number of the bullets will correspond to the length of the string.
 */
module.filter('rpmask', function () {
  return function (pass) {
    pass = ""+pass;
    return Array(pass.length+1).join("•");
  };
});

/**
 * Crops a string to len characters
 *
 * The number of the bullets will correspond to the length of the string.
 */
module.filter('rptruncate', function () {
  return function (str, len) {
    return str ? str.slice(0, len) : '';
  };
});

/**
 * Format a file size.
 *
 * Based on code by aioobe @ StackOverflow.
 * @see http://stackoverflow.com/questions/3758606
 */
module.filter('rpfilesize', function () {
  function number_format( number, decimals, dec_point, thousands_sep ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +     bugfix by: Michael White (http://crestidg.com)
    // +     bugfix by: Benjamin Lupton
    // +     bugfix by: Allan Jensen (http://www.winternet.no)
    // +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // *     example 1: number_format(1234.5678, 2, '.', '');
    // *     returns 1: 1234.57

    var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
    var d = dec_point === undefined ? "," : dec_point;
    var t = thousands_sep === undefined ? "." : thousands_sep, s = n < 0 ? "-" : "";
    var i = parseInt(n = Math.abs(+n || 0).toFixed(c), 10) + "", j = (j = i.length) > 3 ? j % 3 : 0;

    return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
  }

  // SI (International System of Units)
  // e.g. 1000 bytes = 1 kB
  var unit = 1000;
  var prefixes = "kMGTPE";
  var common = "B";

  // Binary system
  // e.g. 1024 bytes = 1 KiB
  //var unit = 1024
  //var prefixes = "KMGTPE";
  //var common = "iB";

  return function (str) {
    var bytes = +str;
    if (bytes < unit) return bytes + " B";
    var exp = Math.floor(Math.log(bytes) / Math.log(unit));
    var pre = " "+prefixes[exp-1] + common;
    return number_format(bytes / Math.pow(unit, exp), 2, '.', '')+pre;
  };
});

/**
 * Uppercase the first letter.
 */
module.filter('rpucfirst', function () {
  return function (str) {
    str = ""+str;
    return str.charAt(0).toUpperCase() + str.slice(1);
  };
});

/**
 * Something similar to javascript for loop
 *
 * Usage
 * Example1 : ng-repeat="n in [20] | rprange"
 * Example2 : ng-repeat="n in [10, 35] | rprange"
 */
module.filter('rprange', function() {
  return function(input) {
    var lowBound, highBound;
    switch (input.length) {
      case 1:
        lowBound = 0;
        highBound = parseInt(input[0], 10) - 1;
        break;
      case 2:
        lowBound = parseInt(input[0], 10);
        highBound = parseInt(input[1], 10);
        break;
      default:
        return input;
    }
    var result = [];
    for (var i = lowBound; i <= highBound; i++)
      result.push(i);
    return result;
  };
});

module.filter('rpaddressorigin', function() {
  return function(recipient) {
    return !isNaN(Base.decode_check([0, 5], recipient, 'bitcoin')) ? 'bitcoin' : 'ripple';
  };
});
<commit_msg>test1<commit_after>var module = angular.module('filters', []),
    webutil = require('../util/web'),
    Amount = ripple.Amount,
    Base = ripple.Base;

var iso4217 = require('../data/iso4217');

/**
 * Format a ripple.Amount.
 *
 * If the parameter is a number, the number is treated the relative
 */
module.filter('rpamount', function () {
  return function (input, opts) {
    if ("number" === typeof opts) {
      opts = {
        rel_min_precision: opts
      };
    } else if ("object" !== typeof opts) {
      opts = {};
    }

    if (!input) return "n/a";

    if (opts.xrp_human && input === ("" + parseInt(input, 10))) {
      input = input + ".0";
    }

    var amount = Amount.from_json(input);
    if (!amount.is_valid()) return "n/a";

    // Currency default precision
    var currency = iso4217[amount.currency().to_json()];
    var cdp = ("undefined" !== typeof currency) ? currency[1] : 4;

    // Certain formatting options are relative to the currency default precision
    if ("number" === typeof opts.rel_precision) {
      opts.precision = cdp + opts.rel_precision;
    }
    if ("number" === typeof opts.rel_min_precision) {
      opts.min_precision = cdp + opts.rel_min_precision;
    }

    // If no precision is given, we'll default to max precision.
    if ("number" !== typeof opts.precision) {
      opts.precision = 16;
    }

    // But we will cut off after five significant decimals
    if ("number" !== typeof opts.max_sig_digits) {
      opts.max_sig_digits = 5;
    }

    var out = amount.to_human(opts);

    return out;
  };
});

/**
 * Get the currency from an Amount.
 */
module.filter('rpcurrency', function () {
  return function (input) {
    if (!input) return "";

    var amount = Amount.from_json(input);
    return amount.currency().to_json();
  };
});

/**
 * Get the currency issuer.
 */
module.filter('rpissuer', function () {
  return function (input) {
    if (!input) return "";

    var amount = Amount.from_json(input);
    return amount.issuer().to_json();
  };
});

/**
 * Get the full currency name from an Amount.
 */
module.filter('rpcurrencyfull', ['$rootScope', function ($scope) {
  return function (input) {
    if (!input) return "";

    var amount = Amount.from_json(input);
    var currency = $.grep($scope.currencies, function(e){ return e.value == amount.currency().to_json(); })[0];

    if (currency) {
      return currency.name;
    } else {
      return amount.currency().to_json();
    }
  };
}]);

/**
 * Calculate a ratio of two Amounts.
 */
module.filter('rpamountratio', function () {
  return function (numerator, denominator) {
    try {
      return Amount.from_json(numerator).ratio_human(denominator);
    } catch (err) {
      return Amount.NaN();
    }
  };
});

/**
 * Calculate the sum of two Amounts.
 */
module.filter('rpamountadd', function () {
  return function (a, b) {
    try {
      b = Amount.from_json(b);
      if (b.is_zero()) return a;
      return Amount.from_json(a).add(b);
    } catch (err) {
      return Amount.NaN();
    }
  };
});
/**
 * Calculate the difference of two Amounts.
 */
module.filter('rpamountsubtract', function () {
  return function (a, b) {
    try {
      return Amount.from_json(a).subtract(b);
    } catch (err) {
      return Amount.NaN();
    }
  };
});

/**
 * Angular filter for Moment.js.
 *
 * Displays a timestamp as "x minutes ago".
 */
module.filter('rpfromnow', function () {
  return function (input) {
    return moment(input).fromNow();
  };
});

/**
 * Show contact name or short address
 */
module.filter('rpcontactname', ['$rootScope', function ($scope) {
  return function (address) {
    address = address ? ""+address : "";

    var contact = webutil.getContact($scope.userBlob.data.contacts, address);

    if (!contact) {
      return "" + address.substring(0,7) + "…";
    }

    return contact.name;
  };
}]);

module.filter('rpcontactnamefull', ['$rootScope', function ($scope) {
  return function (address) {
    address = address ? ""+address : "";
    var contact = webutil.getContact($scope.userBlob.data.contacts, address);

    if (!contact) {
      return "" + address;
    }

    return contact.name;
  };
}]);

module.filter('rponlycontactname', ['$rootScope', function ($scope) {
  return function (address) {
    address = address ? ""+address : "";

    var contact = webutil.getContact($scope.userBlob.data.contacts, address);

    if (contact) {
      return contact.name;
    }
  };
}]);

/**
 * Masks a string like so: •••••.
 *
 * The number of the bullets will correspond to the length of the string.
 */
module.filter('rpmask', function () {
  return function (pass) {
    pass = ""+pass;
    return Array(pass.length+1).join("•");
  };
});

/**
 * Crops a string to len characters
 *
 * The number of the bullets will correspond to the length of the string.
 */
module.filter('rptruncate', function () {
  return function (str, len) {
    return str ? str.slice(0, len) : '';
  };
});

/**
 * Format a file size.
 *
 * Based on code by aioobe @ StackOverflow.
 * @see http://stackoverflow.com/questions/3758606
 */
module.filter('rpfilesize', function () {
  function number_format( number, decimals, dec_point, thousands_sep ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // +     bugfix by: Michael White (http://crestidg.com)
    // +     bugfix by: Benjamin Lupton
    // +     bugfix by: Allan Jensen (http://www.winternet.no)
    // +    revised by: Jonas Raoni Soares Silva (http://www.jsfromhell.com)
    // *     example 1: number_format(1234.5678, 2, '.', '');
    // *     returns 1: 1234.57

    var n = number, c = isNaN(decimals = Math.abs(decimals)) ? 2 : decimals;
    var d = dec_point === undefined ? "," : dec_point;
    var t = thousands_sep === undefined ? "." : thousands_sep, s = n < 0 ? "-" : "";
    var i = parseInt(n = Math.abs(+n || 0).toFixed(c), 10) + "", j = (j = i.length) > 3 ? j % 3 : 0;

    return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
  }

  // SI (International System of Units)
  // e.g. 1000 bytes = 1 kB
  var unit = 1000;
  var prefixes = "kMGTPE";
  var common = "B";

  // Binary system
  // e.g. 1024 bytes = 1 KiB
  //var unit = 1024
  //var prefixes = "KMGTPE";
  //var common = "iB";

  return function (str) {
    var bytes = +str;
    if (bytes < unit) return bytes + " B";
    var exp = Math.floor(Math.log(bytes) / Math.log(unit));
    var pre = " "+prefixes[exp-1] + common;
    return number_format(bytes / Math.pow(unit, exp), 2, '.', '')+pre;
  };
});

/**
 * Uppercase the first letter.
 */
module.filter('rpucfirst', function () {
  return function (str) {
    str = ""+str;
    return str.charAt(0).toUpperCase() + str.slice(1);
  };
});

/**
 * Something similar to javascript for loop
 *
 * Usage
 * Example1 : ng-repeat="n in [20] | rprange"
 * Example2 : ng-repeat="n in [10, 35] | rprange"
 */
module.filter('rprange', function() {
  return function(input) {
    var lowBound, highBound;
    switch (input.length) {
      case 1:
        lowBound = 0;
        highBound = parseInt(input[0], 10) - 1;
        break;
      case 2:
        lowBound = parseInt(input[0], 10);
        highBound = parseInt(input[1], 10);
        break;
      default:
        return input;
    }
    var result = [];
    for (var i = lowBound; i <= highBound; i++)
      result.push(i);
    return result;
  };
});

module.filter('rpaddressorigin', function() {
  return function(recipient) {
    return !isNaN(Base.decode_check([0, 5], recipient, 'bitcoin')) ? 'bitcoin' : 'latcoin';
  };
});
<|endoftext|>


<commit_before>/**
 * Member photo swapping behavior.
 */

const Vue = require('vue/dist/vue.common')

const members = new Vue({
  el: '#section-members',
  delimiters: ['#{', '}'],
  data: {
    started: true,
    members: [
      { name: 'recidive', image: '/images/members/1.jpg' },
      { name: 'handrus', image: '/images/members/2.jpg' },
      { name: 'italo', image: '/images/members/3.jpg' },
      { name: 'anderson', image: '/images/members/4.jpg' },
      { name: 'mari', image: '/images/members/5.jpg' },
      { name: 'reva', image: '/images/members/6.jpg' },
      { name: 'lucas', image: '/images/members/7.jpg' },
      { name: 'joseph', image: '/images/members/8.jpg' },
      { name: 'celso', image: '/images/members/9.jpg' },
      { name: 'becker', image: '/images/members/10.jpg' },
      { name: 'mario', image: '/images/members/11.jpg' },
      { name: 'sebas', image: '/images/members/12.jpg' },
      { name: 'ban', image: '/images/members/13.jpg' },
      { name: 'rafa', image: '/images/members/14.jpg' },
      { name: 'denis', image: '/images/members/15.jpg' },
      { name: 'helal', image: '/images/members/16.jpg' },
    ]
  },
  methods: {
    swipe: function (member) {
      const index = this.members.indexOf(member)
      const result = shuffle(this.members).filter(curr => curr !== member)
      result.splice(index, 0, member)

      this.members = result
    }
  }
})

function shuffle (array) {
  let counter = array.length;

  // While there are elements in the array
  while (counter > 0) {
    // Pick a random index
    let index = Math.floor(Math.random() * counter);

    // Decrease counter by 1
    counter--;

    // And swap the last element with it
    let temp = array[counter];
    array[counter] = array[index];
    array[index] = temp;
  }

  return array;
}
<commit_msg>Updated photo-swipe lib to fit the members section updates.<commit_after>/**
 * Member photo swapping behavior.
 */

const Vue = require('vue/dist/vue.common')

const members = new Vue({
  el: '#section-members',
  delimiters: ['#{', '}'],
  data: {
    started: true,
    members: [
      { name: 'recidive', image: '/images/members/1.jpg' },
      { name: 'italo', image: '/images/members/3.jpg' },
      { name: 'anderson', image: '/images/members/4.jpg' },
      { name: 'mari', image: '/images/members/5.jpg' },
      { name: 'reva', image: '/images/members/6.jpg' },
      { name: 'lucas', image: '/images/members/7.jpg' },
      { name: 'joseph', image: '/images/members/8.jpg' },
      { name: 'celso', image: '/images/members/9.jpg' },
      { name: 'becker', image: '/images/members/10.jpg' },
      { name: 'sebas', image: '/images/members/12.jpg' },
      { name: 'ban', image: '/images/members/13.jpg' },
      { name: 'rafa', image: '/images/members/14.jpg' },
      { name: 'helal', image: '/images/members/16.jpg' },
      { name: 'marcos', image: '/images/members/17.jpg' },
      { name: 'recidive', image: '/images/members/1.jpg' },
      { name: 'italo', image: '/images/members/3.jpg' },
    ]
  },
  methods: {
    swipe: function (member) {
      const index = this.members.indexOf(member)
      const result = shuffle(this.members).filter(curr => curr !== member)
      result.splice(index, 0, member)

      this.members = result
    }
  }
})

function shuffle (array) {
  let counter = array.length;

  // While there are elements in the array
  while (counter > 0) {
    // Pick a random index
    let index = Math.floor(Math.random() * counter);

    // Decrease counter by 1
    counter--;

    // And swap the last element with it
    let temp = array[counter];
    array[counter] = array[index];
    array[index] = temp;
  }

  return array;
}
<|endoftext|>


<commit_before>const log = require('../log');
const utils = require('../utils');

/**
 * Validate visually complete `<form>` or specific field in it.
 *
 * @function external:"jQuery.fn".vulcanval
 *
 * @param  {String} validate - With value `'validate'`.
 * @param  {String} [fieldName] - Only limite validation to the field.
 * @return {external:jQuery} The same jQuery object.
 */
const validate = function (fieldName) {
  'use strict';

  const settings = this.data('vv-settings');

  if (fieldName) {
    const field = utils.find(settings.fields, f => f.name === fieldName);
    if (!field) log.error(`field "${fieldName}" not found`);
    field.$el.trigger('vv-change');
    field.$el.trigger('focus');
  } else {

    let invalid;
    let first = true;

    settings.fields.forEach(function (field) {

      if (!field.$el) return;

      invalid = field.$el.vulcanval('inspect', field.name);

      if (invalid) {
        field.$el.trigger('vv-change');
        if (first) {
          first = false;
          field.$el.trigger('focus');
        }
      }
    });
  }

  return this;
};

module.exports = validate;
<commit_msg>fix: plugin validate<commit_after>const log = require('../log');
const utils = require('../utils');

/**
 * Validate visually complete `<form>` or specific field in it.
 *
 * @function external:"jQuery.fn".vulcanval
 *
 * @param  {String} validate - With value `'validate'`.
 * @param  {String} [fieldName] - Only limite validation to the field.
 * @return {external:jQuery} The same jQuery object.
 */
const validate = function (fieldName) {
  'use strict';

  const settings = this.data('vv-settings');

  if (fieldName) {
    const field = utils.find(settings.fields, f => f.name === fieldName);
    if (!field) log.error(`field "${fieldName}" not found`);
    field.$el.trigger('vv-change');
    field.$el.trigger('focus');
  } else {

    let invalid;
    let first = true;

    settings.fields.forEach(function (field) {

      if (!field.$el) return;

      field.$el.trigger('vv-change');

      invalid = field.$el.vulcanval('inspect', field.name);

      if (invalid && first) {
        first = false;
        field.$el.trigger('focus');
      }
    });
  }

  return this;
};

module.exports = validate;
<|endoftext|>


<commit_before>// ==========================================================================
// YouTube plugin
// ==========================================================================

import ui from '../ui';
import { createElement, replaceElement, toggleClass } from '../utils/elements';
import { triggerEvent } from '../utils/events';
import fetch from '../utils/fetch';
import is from '../utils/is';
import loadImage from '../utils/loadImage';
import loadScript from '../utils/loadScript';
import { extend } from '../utils/objects';
import { format, generateId } from '../utils/strings';
import { setAspectRatio } from '../utils/style';

// Parse YouTube ID from URL
function parseId(url) {
    if (is.empty(url)) {
        return null;
    }

    const regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
    return url.match(regex) ? RegExp.$2 : url;
}

// Set playback state and trigger change (only on actual change)
function assurePlaybackState(play) {
    if (play && !this.embed.hasPlayed) {
        this.embed.hasPlayed = true;
    }
    if (this.media.paused === play) {
        this.media.paused = !play;
        triggerEvent.call(this, this.media, play ? 'play' : 'pause');
    }
}

const youtube = {
    setup() {
        // Add embed class for responsive
        toggleClass(this.elements.wrapper, this.config.classNames.embed, true);

        // Set aspect ratio
        setAspectRatio.call(this);

        // Setup API
        if (is.object(window.YT) && is.function(window.YT.Player)) {
            youtube.ready.call(this);
        } else {
            // Load the API
            loadScript(this.config.urls.youtube.sdk).catch(error => {
                this.debug.warn('YouTube API failed to load', error);
            });

            // Setup callback for the API
            // YouTube has it's own system of course...
            window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];

            // Add to queue
            window.onYouTubeReadyCallbacks.push(() => {
                youtube.ready.call(this);
            });

            // Set callback to process queue
            window.onYouTubeIframeAPIReady = () => {
                window.onYouTubeReadyCallbacks.forEach(callback => {
                    callback();
                });
            };
        }
    },

    // Get the media title
    getTitle(videoId) {
        // Try via undocumented API method first
        // This method disappears now and then though...
        // https://github.com/sampotts/plyr/issues/709
        if (is.function(this.embed.getVideoData)) {
            const { title } = this.embed.getVideoData();

            if (is.empty(title)) {
                this.config.title = title;
                ui.setTitle.call(this);
                return;
            }
        }

        // Or via Google API
        const key = this.config.keys.google;
        if (is.string(key) && !is.empty(key)) {
            const url = format(this.config.urls.youtube.api, videoId, key);

            fetch(url)
                .then(result => {
                    if (is.object(result)) {
                        this.config.title = result.items[0].snippet.title;
                        ui.setTitle.call(this);
                    }
                })
                .catch(() => {});
        }
    },

    // API ready
    ready() {
        const player = this;

        // Ignore already setup (race condition)
        const currentId = player.media.getAttribute('id');
        if (!is.empty(currentId) && currentId.startsWith('youtube-')) {
            return;
        }

        // Get the source URL or ID
        let source = player.media.getAttribute('src');

        // Get from <div> if needed
        if (is.empty(source)) {
            source = player.media.getAttribute(this.config.attributes.embed.id);
        }

        // Replace the <iframe> with a <div> due to YouTube API issues
        const videoId = parseId(source);
        const id = generateId(player.provider);

        // Get poster, if already set
        const { poster } = player;

        // Replace media element
        const container = createElement('div', { id, poster });
        player.media = replaceElement(container, player.media);

        // Id to poster wrapper
        const posterSrc = format => `https://i.ytimg.com/vi/${videoId}/${format}default.jpg`;

        // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
        loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
            .catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
            .catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
            .then(image => ui.setPoster.call(player, image.src))
            .then(posterSrc => {
                // If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
                if (!posterSrc.includes('maxres')) {
                    player.elements.poster.style.backgroundSize = 'cover';
                }
            })
            .catch(() => {});

        const config = player.config.youtube;

        // Setup instance
        // https://developers.google.com/youtube/iframe_api_reference
        player.embed = new window.YT.Player(id, {
            videoId,
            host: config.noCookie ? 'https://www.youtube-nocookie.com' : undefined,
            playerVars: extend(
                {},
                {
                    autoplay: player.config.autoplay ? 1 : 0, // Autoplay
                    hl: player.config.hl, // iframe interface language
                    controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported
                    disablekb: 1, // Disable keyboard as we handle it
                    playsinline: !player.config.fullscreen.iosNative ? 1 : 0, // Allow iOS inline playback
                    // Captions are flaky on YouTube
                    cc_load_policy: player.captions.active ? 1 : 0,
                    cc_lang_pref: player.config.captions.language,
                    // Tracking for stats
                    widget_referrer: window ? window.location.href : null,
                },
                config,
            ),
            events: {
                onError(event) {
                    // YouTube may fire onError twice, so only handle it once
                    if (!player.media.error) {
                        const code = event.data;
                        // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError
                        const message =
                            {
                                2: 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.',
                                5: 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.',
                                100: 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.',
                                101: 'The owner of the requested video does not allow it to be played in embedded players.',
                                150: 'The owner of the requested video does not allow it to be played in embedded players.',
                            }[code] || 'An unknown error occured';

                        player.media.error = { code, message };

                        triggerEvent.call(player, player.media, 'error');
                    }
                },
                onPlaybackRateChange(event) {
                    // Get the instance
                    const instance = event.target;

                    // Get current speed
                    player.media.playbackRate = instance.getPlaybackRate();

                    triggerEvent.call(player, player.media, 'ratechange');
                },
                onReady(event) {
                    // Bail if onReady has already been called. See issue #1108
                    if (is.function(player.media.play)) {
                        return;
                    }
                    // Get the instance
                    const instance = event.target;

                    // Get the title
                    youtube.getTitle.call(player, videoId);

                    // Create a faux HTML5 API using the YouTube API
                    player.media.play = () => {
                        assurePlaybackState.call(player, true);
                        instance.playVideo();
                    };

                    player.media.pause = () => {
                        assurePlaybackState.call(player, false);
                        instance.pauseVideo();
                    };

                    player.media.stop = () => {
                        instance.stopVideo();
                    };

                    player.media.duration = instance.getDuration();
                    player.media.paused = true;

                    // Seeking
                    player.media.currentTime = 0;
                    Object.defineProperty(player.media, 'currentTime', {
                        get() {
                            return Number(instance.getCurrentTime());
                        },
                        set(time) {
                            // If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
                            if (player.paused && !player.embed.hasPlayed) {
                                player.embed.mute();
                            }

                            // Set seeking state and trigger event
                            player.media.seeking = true;
                            triggerEvent.call(player, player.media, 'seeking');

                            // Seek after events sent
                            instance.seekTo(time);
                        },
                    });

                    // Playback speed
                    Object.defineProperty(player.media, 'playbackRate', {
                        get() {
                            return instance.getPlaybackRate();
                        },
                        set(input) {
                            instance.setPlaybackRate(input);
                        },
                    });

                    // Volume
                    let { volume } = player.config;
                    Object.defineProperty(player.media, 'volume', {
                        get() {
                            return volume;
                        },
                        set(input) {
                            volume = input;
                            instance.setVolume(volume * 100);
                            triggerEvent.call(player, player.media, 'volumechange');
                        },
                    });

                    // Muted
                    let { muted } = player.config;
                    Object.defineProperty(player.media, 'muted', {
                        get() {
                            return muted;
                        },
                        set(input) {
                            const toggle = is.boolean(input) ? input : muted;
                            muted = toggle;
                            instance[toggle ? 'mute' : 'unMute']();
                            triggerEvent.call(player, player.media, 'volumechange');
                        },
                    });

                    // Source
                    Object.defineProperty(player.media, 'currentSrc', {
                        get() {
                            return instance.getVideoUrl();
                        },
                    });

                    // Ended
                    Object.defineProperty(player.media, 'ended', {
                        get() {
                            return player.currentTime === player.duration;
                        },
                    });

                    // Get available speeds
                    player.options.speed = instance.getAvailablePlaybackRates();

                    // Set the tabindex to avoid focus entering iframe
                    if (player.supported.ui) {
                        player.media.setAttribute('tabindex', -1);
                    }

                    triggerEvent.call(player, player.media, 'timeupdate');
                    triggerEvent.call(player, player.media, 'durationchange');

                    // Reset timer
                    clearInterval(player.timers.buffering);

                    // Setup buffering
                    player.timers.buffering = setInterval(() => {
                        // Get loaded % from YouTube
                        player.media.buffered = instance.getVideoLoadedFraction();

                        // Trigger progress only when we actually buffer something
                        if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {
                            triggerEvent.call(player, player.media, 'progress');
                        }

                        // Set last buffer point
                        player.media.lastBuffered = player.media.buffered;

                        // Bail if we're at 100%
                        if (player.media.buffered === 1) {
                            clearInterval(player.timers.buffering);

                            // Trigger event
                            triggerEvent.call(player, player.media, 'canplaythrough');
                        }
                    }, 200);

                    // Rebuild UI
                    setTimeout(() => ui.build.call(player), 50);
                },
                onStateChange(event) {
                    // Get the instance
                    const instance = event.target;

                    // Reset timer
                    clearInterval(player.timers.playing);

                    const seeked = player.media.seeking && [1, 2].includes(event.data);

                    if (seeked) {
                        // Unset seeking and fire seeked event
                        player.media.seeking = false;
                        triggerEvent.call(player, player.media, 'seeked');
                    }

                    // Handle events
                    // -1   Unstarted
                    // 0    Ended
                    // 1    Playing
                    // 2    Paused
                    // 3    Buffering
                    // 5    Video cued
                    switch (event.data) {
                        case -1:
                            // Update scrubber
                            triggerEvent.call(player, player.media, 'timeupdate');

                            // Get loaded % from YouTube
                            player.media.buffered = instance.getVideoLoadedFraction();
                            triggerEvent.call(player, player.media, 'progress');

                            break;

                        case 0:
                            assurePlaybackState.call(player, false);

                            // YouTube doesn't support loop for a single video, so mimick it.
                            if (player.media.loop) {
                                // YouTube needs a call to `stopVideo` before playing again
                                instance.stopVideo();
                                instance.playVideo();
                            } else {
                                triggerEvent.call(player, player.media, 'ended');
                            }

                            break;

                        case 1:
                            // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
                            if (player.media.paused && !player.embed.hasPlayed) {
                                player.media.pause();
                            } else {
                                assurePlaybackState.call(player, true);

                                triggerEvent.call(player, player.media, 'playing');

                                // Poll to get playback progress
                                player.timers.playing = setInterval(() => {
                                    triggerEvent.call(player, player.media, 'timeupdate');
                                }, 50);

                                // Check duration again due to YouTube bug
                                // https://github.com/sampotts/plyr/issues/374
                                // https://code.google.com/p/gdata-issues/issues/detail?id=8690
                                if (player.media.duration !== instance.getDuration()) {
                                    player.media.duration = instance.getDuration();
                                    triggerEvent.call(player, player.media, 'durationchange');
                                }
                            }

                            break;

                        case 2:
                            // Restore audio (YouTube starts playing on seek if the video hasn't been played yet)
                            if (!player.muted) {
                                player.embed.unMute();
                            }
                            assurePlaybackState.call(player, false);

                            break;

                        default:
                            break;
                    }

                    triggerEvent.call(player, player.elements.container, 'statechange', false, {
                        code: event.data,
                    });
                },
            },
        });
    },
};

export default youtube;
<commit_msg>fixed setting youtube host for non-https case<commit_after>// ==========================================================================
// YouTube plugin
// ==========================================================================

import ui from '../ui';
import { createElement, replaceElement, toggleClass } from '../utils/elements';
import { triggerEvent } from '../utils/events';
import fetch from '../utils/fetch';
import is from '../utils/is';
import loadImage from '../utils/loadImage';
import loadScript from '../utils/loadScript';
import { extend } from '../utils/objects';
import { format, generateId } from '../utils/strings';
import { setAspectRatio } from '../utils/style';

// Parse YouTube ID from URL
function parseId(url) {
    if (is.empty(url)) {
        return null;
    }

    const regex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|&v=)([^#&?]*).*/;
    return url.match(regex) ? RegExp.$2 : url;
}

// Set playback state and trigger change (only on actual change)
function assurePlaybackState(play) {
    if (play && !this.embed.hasPlayed) {
        this.embed.hasPlayed = true;
    }
    if (this.media.paused === play) {
        this.media.paused = !play;
        triggerEvent.call(this, this.media, play ? 'play' : 'pause');
    }
}

function useHttp() {
    return !window.location.href.includes('https://');
}

function getYoutubeHost(config) {
    let host;

    if (config.noCookie) {
        host = 'https://www.youtube-nocookie.com';
    } else {
        host = useHttp() ? 'http://www.youtube.com' : undefined;
    }

    return host;
}

const youtube = {
    setup() {
        // Add embed class for responsive
        toggleClass(this.elements.wrapper, this.config.classNames.embed, true);

        // Set aspect ratio
        setAspectRatio.call(this);

        // Setup API
        if (is.object(window.YT) && is.function(window.YT.Player)) {
            youtube.ready.call(this);
        } else {
            // Load the API
            loadScript(this.config.urls.youtube.sdk).catch(error => {
                this.debug.warn('YouTube API failed to load', error);
            });

            // Setup callback for the API
            // YouTube has it's own system of course...
            window.onYouTubeReadyCallbacks = window.onYouTubeReadyCallbacks || [];

            // Add to queue
            window.onYouTubeReadyCallbacks.push(() => {
                youtube.ready.call(this);
            });

            // Set callback to process queue
            window.onYouTubeIframeAPIReady = () => {
                window.onYouTubeReadyCallbacks.forEach(callback => {
                    callback();
                });
            };
        }
    },

    // Get the media title
    getTitle(videoId) {
        // Try via undocumented API method first
        // This method disappears now and then though...
        // https://github.com/sampotts/plyr/issues/709
        if (is.function(this.embed.getVideoData)) {
            const { title } = this.embed.getVideoData();

            if (is.empty(title)) {
                this.config.title = title;
                ui.setTitle.call(this);
                return;
            }
        }

        // Or via Google API
        const key = this.config.keys.google;
        if (is.string(key) && !is.empty(key)) {
            const url = format(this.config.urls.youtube.api, videoId, key);

            fetch(url)
                .then(result => {
                    if (is.object(result)) {
                        this.config.title = result.items[0].snippet.title;
                        ui.setTitle.call(this);
                    }
                })
                .catch(() => {});
        }
    },

    // API ready
    ready() {
        const player = this;

        // Ignore already setup (race condition)
        const currentId = player.media.getAttribute('id');
        if (!is.empty(currentId) && currentId.startsWith('youtube-')) {
            return;
        }

        // Get the source URL or ID
        let source = player.media.getAttribute('src');

        // Get from <div> if needed
        if (is.empty(source)) {
            source = player.media.getAttribute(this.config.attributes.embed.id);
        }

        // Replace the <iframe> with a <div> due to YouTube API issues
        const videoId = parseId(source);
        const id = generateId(player.provider);

        // Get poster, if already set
        const { poster } = player;

        // Replace media element
        const container = createElement('div', { id, poster });
        player.media = replaceElement(container, player.media);

        // Id to poster wrapper
        const posterSrc = format => `https://i.ytimg.com/vi/${videoId}/${format}default.jpg`;

        // Check thumbnail images in order of quality, but reject fallback thumbnails (120px wide)
        loadImage(posterSrc('maxres'), 121) // Higest quality and unpadded
            .catch(() => loadImage(posterSrc('sd'), 121)) // 480p padded 4:3
            .catch(() => loadImage(posterSrc('hq'))) // 360p padded 4:3. Always exists
            .then(image => ui.setPoster.call(player, image.src))
            .then(posterSrc => {
                // If the image is padded, use background-size "cover" instead (like youtube does too with their posters)
                if (!posterSrc.includes('maxres')) {
                    player.elements.poster.style.backgroundSize = 'cover';
                }
            })
            .catch(() => {});

        const config = player.config.youtube;

        // Setup instance
        // https://developers.google.com/youtube/iframe_api_reference
        player.embed = new window.YT.Player(id, {
            videoId,
            host: getYoutubeHost(config),
            playerVars: extend(
                {},
                {
                    autoplay: player.config.autoplay ? 1 : 0, // Autoplay
                    hl: player.config.hl, // iframe interface language
                    controls: player.supported.ui ? 0 : 1, // Only show controls if not fully supported
                    disablekb: 1, // Disable keyboard as we handle it
                    playsinline: !player.config.fullscreen.iosNative ? 1 : 0, // Allow iOS inline playback
                    // Captions are flaky on YouTube
                    cc_load_policy: player.captions.active ? 1 : 0,
                    cc_lang_pref: player.config.captions.language,
                    // Tracking for stats
                    widget_referrer: window ? window.location.href : null,
                },
                config,
            ),
            events: {
                onError(event) {
                    // YouTube may fire onError twice, so only handle it once
                    if (!player.media.error) {
                        const code = event.data;
                        // Messages copied from https://developers.google.com/youtube/iframe_api_reference#onError
                        const message =
                            {
                                2: 'The request contains an invalid parameter value. For example, this error occurs if you specify a video ID that does not have 11 characters, or if the video ID contains invalid characters, such as exclamation points or asterisks.',
                                5: 'The requested content cannot be played in an HTML5 player or another error related to the HTML5 player has occurred.',
                                100: 'The video requested was not found. This error occurs when a video has been removed (for any reason) or has been marked as private.',
                                101: 'The owner of the requested video does not allow it to be played in embedded players.',
                                150: 'The owner of the requested video does not allow it to be played in embedded players.',
                            }[code] || 'An unknown error occured';

                        player.media.error = { code, message };

                        triggerEvent.call(player, player.media, 'error');
                    }
                },
                onPlaybackRateChange(event) {
                    // Get the instance
                    const instance = event.target;

                    // Get current speed
                    player.media.playbackRate = instance.getPlaybackRate();

                    triggerEvent.call(player, player.media, 'ratechange');
                },
                onReady(event) {
                    // Bail if onReady has already been called. See issue #1108
                    if (is.function(player.media.play)) {
                        return;
                    }
                    // Get the instance
                    const instance = event.target;

                    // Get the title
                    youtube.getTitle.call(player, videoId);

                    // Create a faux HTML5 API using the YouTube API
                    player.media.play = () => {
                        assurePlaybackState.call(player, true);
                        instance.playVideo();
                    };

                    player.media.pause = () => {
                        assurePlaybackState.call(player, false);
                        instance.pauseVideo();
                    };

                    player.media.stop = () => {
                        instance.stopVideo();
                    };

                    player.media.duration = instance.getDuration();
                    player.media.paused = true;

                    // Seeking
                    player.media.currentTime = 0;
                    Object.defineProperty(player.media, 'currentTime', {
                        get() {
                            return Number(instance.getCurrentTime());
                        },
                        set(time) {
                            // If paused and never played, mute audio preventively (YouTube starts playing on seek if the video hasn't been played yet).
                            if (player.paused && !player.embed.hasPlayed) {
                                player.embed.mute();
                            }

                            // Set seeking state and trigger event
                            player.media.seeking = true;
                            triggerEvent.call(player, player.media, 'seeking');

                            // Seek after events sent
                            instance.seekTo(time);
                        },
                    });

                    // Playback speed
                    Object.defineProperty(player.media, 'playbackRate', {
                        get() {
                            return instance.getPlaybackRate();
                        },
                        set(input) {
                            instance.setPlaybackRate(input);
                        },
                    });

                    // Volume
                    let { volume } = player.config;
                    Object.defineProperty(player.media, 'volume', {
                        get() {
                            return volume;
                        },
                        set(input) {
                            volume = input;
                            instance.setVolume(volume * 100);
                            triggerEvent.call(player, player.media, 'volumechange');
                        },
                    });

                    // Muted
                    let { muted } = player.config;
                    Object.defineProperty(player.media, 'muted', {
                        get() {
                            return muted;
                        },
                        set(input) {
                            const toggle = is.boolean(input) ? input : muted;
                            muted = toggle;
                            instance[toggle ? 'mute' : 'unMute']();
                            triggerEvent.call(player, player.media, 'volumechange');
                        },
                    });

                    // Source
                    Object.defineProperty(player.media, 'currentSrc', {
                        get() {
                            return instance.getVideoUrl();
                        },
                    });

                    // Ended
                    Object.defineProperty(player.media, 'ended', {
                        get() {
                            return player.currentTime === player.duration;
                        },
                    });

                    // Get available speeds
                    player.options.speed = instance.getAvailablePlaybackRates();

                    // Set the tabindex to avoid focus entering iframe
                    if (player.supported.ui) {
                        player.media.setAttribute('tabindex', -1);
                    }

                    triggerEvent.call(player, player.media, 'timeupdate');
                    triggerEvent.call(player, player.media, 'durationchange');

                    // Reset timer
                    clearInterval(player.timers.buffering);

                    // Setup buffering
                    player.timers.buffering = setInterval(() => {
                        // Get loaded % from YouTube
                        player.media.buffered = instance.getVideoLoadedFraction();

                        // Trigger progress only when we actually buffer something
                        if (player.media.lastBuffered === null || player.media.lastBuffered < player.media.buffered) {
                            triggerEvent.call(player, player.media, 'progress');
                        }

                        // Set last buffer point
                        player.media.lastBuffered = player.media.buffered;

                        // Bail if we're at 100%
                        if (player.media.buffered === 1) {
                            clearInterval(player.timers.buffering);

                            // Trigger event
                            triggerEvent.call(player, player.media, 'canplaythrough');
                        }
                    }, 200);

                    // Rebuild UI
                    setTimeout(() => ui.build.call(player), 50);
                },
                onStateChange(event) {
                    // Get the instance
                    const instance = event.target;

                    // Reset timer
                    clearInterval(player.timers.playing);

                    const seeked = player.media.seeking && [1, 2].includes(event.data);

                    if (seeked) {
                        // Unset seeking and fire seeked event
                        player.media.seeking = false;
                        triggerEvent.call(player, player.media, 'seeked');
                    }

                    // Handle events
                    // -1   Unstarted
                    // 0    Ended
                    // 1    Playing
                    // 2    Paused
                    // 3    Buffering
                    // 5    Video cued
                    switch (event.data) {
                        case -1:
                            // Update scrubber
                            triggerEvent.call(player, player.media, 'timeupdate');

                            // Get loaded % from YouTube
                            player.media.buffered = instance.getVideoLoadedFraction();
                            triggerEvent.call(player, player.media, 'progress');

                            break;

                        case 0:
                            assurePlaybackState.call(player, false);

                            // YouTube doesn't support loop for a single video, so mimick it.
                            if (player.media.loop) {
                                // YouTube needs a call to `stopVideo` before playing again
                                instance.stopVideo();
                                instance.playVideo();
                            } else {
                                triggerEvent.call(player, player.media, 'ended');
                            }

                            break;

                        case 1:
                            // Restore paused state (YouTube starts playing on seek if the video hasn't been played yet)
                            if (player.media.paused && !player.embed.hasPlayed) {
                                player.media.pause();
                            } else {
                                assurePlaybackState.call(player, true);

                                triggerEvent.call(player, player.media, 'playing');

                                // Poll to get playback progress
                                player.timers.playing = setInterval(() => {
                                    triggerEvent.call(player, player.media, 'timeupdate');
                                }, 50);

                                // Check duration again due to YouTube bug
                                // https://github.com/sampotts/plyr/issues/374
                                // https://code.google.com/p/gdata-issues/issues/detail?id=8690
                                if (player.media.duration !== instance.getDuration()) {
                                    player.media.duration = instance.getDuration();
                                    triggerEvent.call(player, player.media, 'durationchange');
                                }
                            }

                            break;

                        case 2:
                            // Restore audio (YouTube starts playing on seek if the video hasn't been played yet)
                            if (!player.muted) {
                                player.embed.unMute();
                            }
                            assurePlaybackState.call(player, false);

                            break;

                        default:
                            break;
                    }

                    triggerEvent.call(player, player.elements.container, 'statechange', false, {
                        code: event.data,
                    });
                },
            },
        });
    },
};

export default youtube;
<|endoftext|>


<commit_before>define(function () {
  // Turkish
  return {
    errorLoading: function (){
      return "Sonuç yüklenemedi";
    },
    inputTooLong: function (args) {
      var overChars = args.input.length - args.maximum;

      var message = overChars + ' karakter daha girmelisiniz';

      return message;
    },
    inputTooShort: function (args) {
      var remainingChars = args.minimum - args.input.length;

      var message = 'En az ' + remainingChars + ' karakter daha girmelisiniz';

      return message;
    },
    loadingMore: function () {
      return 'Daha fazla…';
    },
    maximumSelected: function (args) {
      var message = 'Sadece ' + args.maximum + ' seçim yapabilirsiniz';

      return message;
    },
    noResults: function () {
      return 'Sonuç bulunamadı';
    },
    searching: function () {
      return 'Aranıyor…';
    }
  };
});
<commit_msg>Corrected linting issue in Turkish translation<commit_after>define(function () {
  // Turkish
  return {
    errorLoading: function (){
      return 'Sonuç yüklenemedi';
    },
    inputTooLong: function (args) {
      var overChars = args.input.length - args.maximum;

      var message = overChars + ' karakter daha girmelisiniz';

      return message;
    },
    inputTooShort: function (args) {
      var remainingChars = args.minimum - args.input.length;

      var message = 'En az ' + remainingChars + ' karakter daha girmelisiniz';

      return message;
    },
    loadingMore: function () {
      return 'Daha fazla…';
    },
    maximumSelected: function (args) {
      var message = 'Sadece ' + args.maximum + ' seçim yapabilirsiniz';

      return message;
    },
    noResults: function () {
      return 'Sonuç bulunamadı';
    },
    searching: function () {
      return 'Aranıyor…';
    }
  };
});
<|endoftext|>