<commit_before>'use strict';

angular.module('fivefifteenApp')
  .controller('MainCtrl', ['$scope', '$routeParams', '$debounce', 'DataFactory', 'StepsFactory', 'modalService',
                  function( $scope,   $routeParams,   $debounce,   DataFactory,   StepsFactory,   modalService) {
    // Site Name
    $scope.siteName = "FiveFifteen";

    // Simple Data service to persist form values.
    $scope.data = DataFactory.data;
    // Admin Contact
    $scope.admin = "seth@lullabot.com";
    // Define variable for opening email.
    $scope.sendEmail = function() { sendMail($scope); };
    // An array of step objects in order.
    $scope.steps = StepsFactory.data;
    // The current state.
    $scope.state = StepsFactory.state;

    // Preview function, to concatenate the results of the steps.
    $scope.getPreview = function() {
      var preview = "",
          step, stepName;
      for (stepName in this.steps) {
        step = this.steps[stepName];
        preview += step.title + "\n\n";
        preview += step.text + "\n\n";
        if (angular.isDefined(this.data[step.path])) {
          preview += this.data[step.path] + "\n\n";
        }
      }
      return preview;
    };

    /**
     * Present a modal dialog to the user, asking them if they want to load the
     * data from local storage.
     */
    $scope.modal = function() {
      var modalOptions = {
        closeButtonText: 'Start Fresh',
        actionButtonText: 'Restore',
        headerText: 'Restore previous session?',
        bodyText: 'It looks like you were already had some work from last time. Would you like to restore that work, or start fresh?'
      };

      modalService.showModal({}, modalOptions).then(function () {
        DataFactory.restoreData();
        $scope.data = DataFactory.data;
      },
      // If the user cancelled, clear the storage.
      function() {
        DataFactory.clearStorage();
      });
    };

    if (angular.isDefined($routeParams.stepName)) {
      $scope.state.currentPath = $routeParams.stepName;
      if (DataFactory.storedData && DataFactory.askToRestore()) {
        $scope.modal();
      }
    }

    StepsFactory.updateState();

    // Watch for any changes to data. We debounce this to only run every second.
    $scope.$watch('data', $debounce(DataFactory.save, 1000), true);
  }])

  // Our Data Factory, which uses local storage to save the user's entries.
  .factory('DataFactory', ['localStorageService', function(
                            localStorageService) {
    // The data variable holds all of the text used on the site.
    var dataObject = { "data": {}, "storedData": {} },
        prompted = false;

    /**
     * Save the data to localStorage. This only runs every second or so, thanks
     * to $debounce.
     *
     * @param newData
     *   The new data to be saved.
     * @param oldData
     *   The previous object. Only saves if there is a change.
     */
    dataObject.save = function(newData, oldData) {
      if (newData !== oldData) {
        localStorageService.add('data', newData);
      }
    };

    /**
     * Load the data from localStorage.
     */
    dataObject.load = function() {
      return localStorageService.get('data');
    };

    /**
     * Set the data to what was loaded from local storage.
     */
    dataObject.restoreData = function () {
      if (dataObject.storedData) {
        dataObject.data = dataObject.storedData;
        // Set restored to true.
        prompted = true;
      }
    };

    /**
     * Clear local storage data.
     */
    dataObject.clearStorage = function () {
      localStorageService.remove('data');
      dataObject.storedData = null;
      prompted = true;
    };

    /**
     * Returns true if data was restored from local storage.
     */
    dataObject.askToRestore = function () {
      return !prompted;
    };

    dataObject.storedData = dataObject.load() || false;

    return dataObject;
  }])

  .controller('HeaderCtrl', ['$scope', '$location', 'StepsFactory',
                    function ($scope,   $location,   StepsFactory) {
    // Site Name
    $scope.siteName = "5:15";

    // Site Tagline
    $scope.tagLine = "5 minutes to read, 15 minutes to write";

    // App is in progress when you are not on the homepage.
    $scope.inProgress = function(){
      return $location.path() == '/';
    };

    $scope.state = StepsFactory.state;
  }])

  /**
   * A factory for the steps.
   */
  .factory('StepsFactory', ['$firebase', function($firebase) {
    // Set up the firebase object, and create a promise from it.
    var url = new Firebase("https://fivefifteen.firebaseio.com/steps"),
        promise = $firebase(url),
        StepsClass = {};

    // Store the data as an array, so that we can order by step number.
    StepsClass.data = [];
    // Store a state object. We need this to be an object, so that we can have
    // it be updated on $scope when we get the data from the promise.
    StepsClass.state = {
      currentStep: {},
      currentPath: null,
      startPath: null,
      nextPath: null
    };

    /**
     * Store the data from the database in the factory. This does processing to
     * be sure the data is in the order that we need.
     */
    StepsClass.storeData = function (data) {
      // Store the raw object data, which has the path as key, so that we can
      // do look ups by path.
      StepsClass.rawData = data;
      // Now iterate over each item in the object so that we can create an array
      // from the data. We need an array, so that it can be ordered by the step
      // numbers, and so that ng orderBy will work properly.
      for (var key in data) {
        var stepNumber = data[key].stepNumber;
        StepsClass.data[stepNumber] = data[key];
      }

      StepsClass.updateState();
    };

    /**
     * Update the state object on the factory.
     */
    StepsClass.updateState = function () {
      // If we don't have rawData yet, just return.
      if (!angular.isDefined(StepsClass.rawData)) {
        return;
      }
      // If we don't have startPath, set it up.
      if (!StepsClass.state.startPath) {
        StepsClass.state.startPath = 'step/' + StepsClass.data[0].path;
      }
      // If currentPath is not already set on the state, set it now, so that
      // we can determine the next path properly.
      if (!angular.isDefined(StepsClass.state.currentPath)) {
        StepsClass.state.currentPath = StepsClass.data[0].path;
      }
      // If the path doesn't match a step, just return. No further processing
      // necessary.
      if (!angular.isDefined(StepsClass.rawData[StepsClass.state.currentPath])) {
        return;
      }
      // Determine the current step from the current path.
      StepsClass.state.currentStep = StepsClass.rawData[StepsClass.state.currentPath];
      // Now that we have the current step and path, we can determine the next
      // path.
      StepsClass.determineNextPath();
    };

    /**
     * Determine the next path from the current state.
     */
    StepsClass.determineNextPath = function() {
      // If we don't have rawData yet, just return.
      if (!angular.isDefined(StepsClass.rawData)) {
        return;
      }
      // TODO: The next step number, ideally, is one more than the current one.
      // But this is fragile and needs improvement.
      var nextStepNumber = StepsClass.state.currentStep.stepNumber + 1;
      // If we have the nextStepNumber in our data, use it.
      if (angular.isDefined(StepsClass.data[nextStepNumber])) {
        StepsClass.state.nextPath = 'step/' + StepsClass.data[nextStepNumber].path;
      }
      // Otherwise, assume we are going to the end page.
      else {
        StepsClass.state.nextPath = 'preview';
      }
    };

    /**
     * When the promise is loaded, and if we have valid data, store it on the
     * factory class.
     */
    promise.$on('loaded', function(data) {
      // If we get data, store it both in the scope and StepsFactory.
      if (!angular.isDefined(data)) {
        return;
      }
      StepsClass.storeData(data);
    });

    return StepsClass;
  }]);

function sendMail($scope) {
  var mailTo = $scope.admin;
  var subject = $scope.siteName;

  window.location.href = 'mailto:' + mailTo + '?subject=Report from ' + subject;
}
<commit_msg>Improve readability of modal promise callbacks.<commit_after>'use strict';

angular.module('fivefifteenApp')
  .controller('MainCtrl', ['$scope', '$routeParams', '$debounce', 'DataFactory', 'StepsFactory', 'modalService',
                  function( $scope,   $routeParams,   $debounce,   DataFactory,   StepsFactory,   modalService) {
    // Site Name
    $scope.siteName = "FiveFifteen";

    // Simple Data service to persist form values.
    $scope.data = DataFactory.data;
    // Admin Contact
    $scope.admin = "seth@lullabot.com";
    // Define variable for opening email.
    $scope.sendEmail = function() { sendMail($scope); };
    // An array of step objects in order.
    $scope.steps = StepsFactory.data;
    // The current state.
    $scope.state = StepsFactory.state;

    // Preview function, to concatenate the results of the steps.
    $scope.getPreview = function() {
      var preview = "",
          step, stepName;
      for (stepName in this.steps) {
        step = this.steps[stepName];
        preview += step.title + "\n\n";
        preview += step.text + "\n\n";
        if (angular.isDefined(this.data[step.path])) {
          preview += this.data[step.path] + "\n\n";
        }
      }
      return preview;
    };

    /**
     * Present a modal dialog to the user, asking them if they want to load the
     * data from local storage.
     */
    $scope.modal = function() {
      // Callback to be executed if the user chooses to restore the stored data.
      var restore = function () {
        DataFactory.restoreData();
        $scope.data = DataFactory.data;
      };
      // Callback to be executed when the user closes the modal.
      var cancel = function() {
        DataFactory.clearStorage();
      };
      // Options for the modalService.
      var modalOptions = {
        closeButtonText: 'Start Fresh',
        actionButtonText: 'Restore',
        headerText: 'Restore previous session?',
        bodyText: 'It looks like you were already had some work from last time. Would you like to restore that work, or start fresh?'
      };

      modalService.showModal({}, modalOptions).then(restore, cancel);
    };

    if (angular.isDefined($routeParams.stepName)) {
      $scope.state.currentPath = $routeParams.stepName;
      if (DataFactory.storedData && DataFactory.askToRestore()) {
        $scope.modal();
      }
    }

    StepsFactory.updateState();

    // Watch for any changes to data. We debounce this to only run every second.
    $scope.$watch('data', $debounce(DataFactory.save, 1000), true);
  }])

  // Our Data Factory, which uses local storage to save the user's entries.
  .factory('DataFactory', ['localStorageService', function(
                            localStorageService) {
    // The data variable holds all of the text used on the site.
    var dataObject = { "data": {}, "storedData": {} },
        prompted = false;

    /**
     * Save the data to localStorage. This only runs every second or so, thanks
     * to $debounce.
     *
     * @param newData
     *   The new data to be saved.
     * @param oldData
     *   The previous object. Only saves if there is a change.
     */
    dataObject.save = function(newData, oldData) {
      if (newData !== oldData) {
        localStorageService.add('data', newData);
      }
    };

    /**
     * Load the data from localStorage.
     */
    dataObject.load = function() {
      return localStorageService.get('data');
    };

    /**
     * Set the data to what was loaded from local storage.
     */
    dataObject.restoreData = function () {
      if (dataObject.storedData) {
        dataObject.data = dataObject.storedData;
        // Set restored to true.
        prompted = true;
      }
    };

    /**
     * Clear local storage data.
     */
    dataObject.clearStorage = function () {
      localStorageService.remove('data');
      dataObject.storedData = null;
      prompted = true;
    };

    /**
     * Returns true if data was restored from local storage.
     */
    dataObject.askToRestore = function () {
      return !prompted;
    };

    dataObject.storedData = dataObject.load() || false;

    return dataObject;
  }])

  .controller('HeaderCtrl', ['$scope', '$location', 'StepsFactory',
                    function ($scope,   $location,   StepsFactory) {
    // Site Name
    $scope.siteName = "5:15";

    // Site Tagline
    $scope.tagLine = "5 minutes to read, 15 minutes to write";

    // App is in progress when you are not on the homepage.
    $scope.inProgress = function(){
      return $location.path() == '/';
    };

    $scope.state = StepsFactory.state;
  }])

  /**
   * A factory for the steps.
   */
  .factory('StepsFactory', ['$firebase', function($firebase) {
    // Set up the firebase object, and create a promise from it.
    var url = new Firebase("https://fivefifteen.firebaseio.com/steps"),
        promise = $firebase(url),
        StepsClass = {};

    // Store the data as an array, so that we can order by step number.
    StepsClass.data = [];
    // Store a state object. We need this to be an object, so that we can have
    // it be updated on $scope when we get the data from the promise.
    StepsClass.state = {
      currentStep: {},
      currentPath: null,
      startPath: null,
      nextPath: null
    };

    /**
     * Store the data from the database in the factory. This does processing to
     * be sure the data is in the order that we need.
     */
    StepsClass.storeData = function (data) {
      // Store the raw object data, which has the path as key, so that we can
      // do look ups by path.
      StepsClass.rawData = data;
      // Now iterate over each item in the object so that we can create an array
      // from the data. We need an array, so that it can be ordered by the step
      // numbers, and so that ng orderBy will work properly.
      for (var key in data) {
        var stepNumber = data[key].stepNumber;
        StepsClass.data[stepNumber] = data[key];
      }

      StepsClass.updateState();
    };

    /**
     * Update the state object on the factory.
     */
    StepsClass.updateState = function () {
      // If we don't have rawData yet, just return.
      if (!angular.isDefined(StepsClass.rawData)) {
        return;
      }
      // If we don't have startPath, set it up.
      if (!StepsClass.state.startPath) {
        StepsClass.state.startPath = 'step/' + StepsClass.data[0].path;
      }
      // If currentPath is not already set on the state, set it now, so that
      // we can determine the next path properly.
      if (!angular.isDefined(StepsClass.state.currentPath)) {
        StepsClass.state.currentPath = StepsClass.data[0].path;
      }
      // If the path doesn't match a step, just return. No further processing
      // necessary.
      if (!angular.isDefined(StepsClass.rawData[StepsClass.state.currentPath])) {
        return;
      }
      // Determine the current step from the current path.
      StepsClass.state.currentStep = StepsClass.rawData[StepsClass.state.currentPath];
      // Now that we have the current step and path, we can determine the next
      // path.
      StepsClass.determineNextPath();
    };

    /**
     * Determine the next path from the current state.
     */
    StepsClass.determineNextPath = function() {
      // If we don't have rawData yet, just return.
      if (!angular.isDefined(StepsClass.rawData)) {
        return;
      }
      // TODO: The next step number, ideally, is one more than the current one.
      // But this is fragile and needs improvement.
      var nextStepNumber = StepsClass.state.currentStep.stepNumber + 1;
      // If we have the nextStepNumber in our data, use it.
      if (angular.isDefined(StepsClass.data[nextStepNumber])) {
        StepsClass.state.nextPath = 'step/' + StepsClass.data[nextStepNumber].path;
      }
      // Otherwise, assume we are going to the end page.
      else {
        StepsClass.state.nextPath = 'preview';
      }
    };

    /**
     * When the promise is loaded, and if we have valid data, store it on the
     * factory class.
     */
    promise.$on('loaded', function(data) {
      // If we get data, store it both in the scope and StepsFactory.
      if (!angular.isDefined(data)) {
        return;
      }
      StepsClass.storeData(data);
    });

    return StepsClass;
  }]);

function sendMail($scope) {
  var mailTo = $scope.admin;
  var subject = $scope.siteName;

  window.location.href = 'mailto:' + mailTo + '?subject=Report from ' + subject;
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Switch from '@material-ui/core/Switch';
import Paper from '@material-ui/core/Paper';
import Zoom from '@material-ui/core/Zoom';

const styles = theme => ({
  root: {
    height: 180,
  },
  container: {
    display: 'flex',
  },
  paper: {
    margin: theme.spacing.unit,
  },
  svg: {
    width: 100,
    height: 100,
  },
  polygon: {
    fill: theme.palette.common.white,
    stroke: theme.palette.divider,
    strokeWidth: 1,
  },
});

class SimpleZoom extends React.Component {
  state = {
    checked: false,
  };

  handleChange = () => {
    this.setState(state => ({ checked: !state.checked }));
  };

  render() {
    const { classes } = this.props;
    const { checked } = this.state;

    return (

        <Switch checked={checked} onChange={this.handleChange} aria-label="Collapse" />

          <Zoom in={checked}>
            <Paper elevation={4} className={classes.paper}>
              <svg className={classes.svg}>
                <polygon points="0,100 50,00, 100,100" className={classes.polygon} />
              </svg>
            </Paper>
          </Zoom>
          <Zoom in={checked} style={{ transitionDelay: checked ? 500 : 0 }}>
            <Paper elevation={4} className={classes.paper}>
              <svg className={classes.svg}>
                <polygon points="0,100 50,00, 100,100" className={classes.polygon} />
              </svg>
            </Paper>
          </Zoom>

    );
  }
}

SimpleZoom.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(SimpleZoom);
<commit_msg>[Zoom] Correct transition delay value of the example (#13645)<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@material-ui/core/styles';
import Switch from '@material-ui/core/Switch';
import Paper from '@material-ui/core/Paper';
import Zoom from '@material-ui/core/Zoom';

const styles = theme => ({
  root: {
    height: 180,
  },
  container: {
    display: 'flex',
  },
  paper: {
    margin: theme.spacing.unit,
  },
  svg: {
    width: 100,
    height: 100,
  },
  polygon: {
    fill: theme.palette.common.white,
    stroke: theme.palette.divider,
    strokeWidth: 1,
  },
});

class SimpleZoom extends React.Component {
  state = {
    checked: false,
  };

  handleChange = () => {
    this.setState(state => ({ checked: !state.checked }));
  };

  render() {
    const { classes } = this.props;
    const { checked } = this.state;

    return (

        <Switch checked={checked} onChange={this.handleChange} aria-label="Collapse" />

          <Zoom in={checked}>
            <Paper elevation={4} className={classes.paper}>
              <svg className={classes.svg}>
                <polygon points="0,100 50,00, 100,100" className={classes.polygon} />
              </svg>
            </Paper>
          </Zoom>
          <Zoom in={checked} style={{ transitionDelay: checked ? '500ms' : '0ms' }}>
            <Paper elevation={4} className={classes.paper}>
              <svg className={classes.svg}>
                <polygon points="0,100 50,00, 100,100" className={classes.polygon} />
              </svg>
            </Paper>
          </Zoom>

    );
  }
}

SimpleZoom.propTypes = {
  classes: PropTypes.object.isRequired,
};

export default withStyles(styles)(SimpleZoom);
<|endoftext|>


<commit_before>var fs = require('fs');
var os = require('os');
var path = require('path');

var dirs = [];
dirs.push('/usr/local/share/arduino');
dirs.push('/usr/share/arduino')

if(os.platform() === 'darwin'){
  dirs.push('/Applications/Arduino.app/Contents/Resources/Java');
}

var ArduinoEnv = module.exports = function(){
  this.rootDir = '';
  this.version = null;
  this.platformPath = '';
  this.compilerPath = '';
  this.corePath = '';
  this.variantPath = '';
}

ArduinoEnv.prototype.init = function(root){
  this.rootDir = (root) ? root : this._locateRoot();
  this.version = this.getVersion();
};

ArduinoEnv.prototype._locateRoot = function(){
  var found = '';
  dirs.some(function(dir){
    if(fs.existsSync(dir)){
      found = dir;
      return true;
    }
  });

  return found;
}

ArduinoEnv.prototype.getVersion = function(){
  var file = path.join(this.rootDir, 'lib', 'version.txt');

  if(!fs.existsSync(file))
    return null;

  var version = fs.readFileSync(file, 'utf8').toString();
  return version;
}
<commit_msg>Added scan directories for arduino on windows.<commit_after>var fs = require('fs');
var os = require('os');
var path = require('path');

var dirs = [];
dirs.push('/usr/local/share/arduino');
dirs.push('/usr/share/arduino')

if(os.platform() === 'darwin'){
  dirs.push('/Applications/Arduino.app/Contents/Resources/Java');
} else if(os.platform() === 'win32'){
  dirs.push('C:\\Program Files (x86)\\Arduino');
  dirs.push('C:\\Program Files\\Arduino');
}

var ArduinoEnv = module.exports = function(){
  this.rootDir = '';
  this.version = null;
  this.platformPath = '';
  this.compilerPath = '';
  this.corePath = '';
  this.variantPath = '';
}

ArduinoEnv.prototype.init = function(root){
  this.rootDir = (root) ? root : this._locateRoot();
  this.version = this.getVersion();
};

ArduinoEnv.prototype._locateRoot = function(){
  var found = '';
  dirs.some(function(dir){
    if(fs.existsSync(dir)){
      found = dir;
      return true;
    }
  });

  return found;
}

ArduinoEnv.prototype.getVersion = function(){
  var file = path.join(this.rootDir, 'lib', 'version.txt');

  if(!fs.existsSync(file))
    return null;

  var version = fs.readFileSync(file, 'utf8').toString();
  return version;
}
<|endoftext|>


<commit_before>'use strict';

angular.module('paestApp')
  .controller('MainCtrl', function ($scope,$routeParams) {

    $scope.id = $routeParams.id;

    $scope.aceLoaded = function(_editor){

      var StatusBar = ace.require('ace/ext/statusbar').StatusBar
      var statusBar = new StatusBar(_editor, document.getElementById('status-bar'))
    }
  });
<commit_msg>automatically generate a random base58 id/path if one is not provided<commit_after>'use strict';

angular.module('paestApp')
  .controller('MainCtrl', function ($scope,$location,$routeParams) {

    if ($routeParams.id){
      $scope.id = $routeParams.id;
    } else {
        var chars = '123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ'
        var base = chars.length;
        var id = '';
        var enc = Math.floor(Math.random() * (1000000 - 1000) + 1000)
        while(enc) {
          var remainder = enc % base;
          enc = Math.floor(enc / base);
          id = chars[remainder].toString() + id;
        }
        $location.path('/'+id)
    }

    $scope.aceLoaded = function(_editor){

      var StatusBar = ace.require('ace/ext/statusbar').StatusBar
      var statusBar = new StatusBar(_editor, document.getElementById('status-bar'))
    }
  });
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Legend Express Agar.io Extension
// @namespace    Legend Express Agario Mod
// @version      1.5(FINDSERVERSELSEWHERE)
// @description  Agario Mod - Legend,Ogario,Kitty,Old Skins,Animated Skins,Language Packs,Manual User Scripts,Chat,60++ Macros/Hotkeys(Tricksplit,Doublesplit,Quick Feeding,Popsplit,Auto Coins,Freeze Cell Macro,Auto respawn)
// @homepage     http://www.legendmod.ml
// @author       Jimboy3100
// @license      MIT
// @icon         https://jimboy3100.github.io/banners/CropedImage128.gif
// @match        http://agar.io/*
// @match        https://play.google.com/*
// @downloadURL  jimboy3100.github.io/legendmod.user.js
// @updateURL    jimboy3100.github.io/legendmod.user.js
// @run-at       document-start
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_deleteValue
// @connect      jimboy3100.github.io
// ==/UserScript==

// Legend Mod by Jimboy3100
/*MIT License

Copyright (c) [The Legend Mod]

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.
*/

// Start of script
GM_registerMenuCommand('Legend Mod Website', function() {
    window.open("http://legendmod.ml");
}, 'r');
GM_registerMenuCommand('LM Library', function() {
    window.open("https://github.com/jimboy3100/jimboy3100.github.io/");
}, 'r');
GM_registerMenuCommand('Donate for Legend Mod', function() {
    window.open("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CM3GDVCW6PBF6");
}, 'r');

if (location.protocol != 'http:')
{
 location.href = 'http:' + window.location.href.substring(window.location.protocol.length);
}

var url = window.location.href;
if (location.pathname == "/LMoldskins"){
eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('"u v";k(2(){2 e(){g e=p.x("F"),a=b;G(e){H{a=I.z(e)}A(e){6.J(!1,e)}a&&a.5&&(C.B(a.5),6.D("%c[9] d E y...","n: m"))}}g a,t,o;a="//l.q/r.w/f/j.h.f",t=2(){6.s("[9] O 11...")},(o=3.10("Z")).K="X/Y",o.12="13-8",o.4?o.i=2(){"d"!=o.4&&"14"!=o.4||(o.i=b,t&&t())}:(3.7&&3.7.15("V-j-h",a),t&&(o.W=t,o.N=e)),o.5=a+"?M="+~~(L.P()/Q/U),3.T("S")[0].R(o)},0);',62,68,'||function|document|readyState|src|console|body||VANILLA||null||loaded||js|var|core|onreadystatechange|vanilla|setTimeout|imaster|darkorange|color||localStorage|space|agar|info||use|strict|io|getItem|cache|parse|catch|eval|window|log|from|cachedVanilla|if|try|JSON|assert|type|Date|_|onerror|inject|now|1e3|appendChild|head|getElementsByTagName|60|data|onload|text|javascript|script|createElement|success|charset|utf|complete|setAttribute'.split('|'),0,{}))

setTimeout(function() {

document.body.style.background = "#f3f3f3 url('https://jimboy3100.github.io/banners/iconmod3.png') no-repeat center fixed";
$( "body" ).append('

');
}, 4000);
setTimeout(function() {
$("#canvas").remove();$("#adsBottom").remove();$("#rightPanel").remove();$(".agario-panel.agario-side-panel.agario-profile-panel").remove();$("#dailyquests-panel").remove();$("#v-ex-menu").remove();$("#service-message-area").remove();$(".radio-module").remove();$(".tosBox.right").remove();$(".tosBox.left").remove();$(".form-group.clearfix").remove();$("#skinCustomButton").remove();$("#settings").remove();$("#vanilla-home-link").remove();$("#settingsButton").remove();$("#instructions").remove();$(".btn.btn-play.btn-primary").remove();$(".btn.btn-play-guest.btn-success").remove();$(".btn.btn-warning.btn-login-play").text("Login");$(".btn.btn-warning.btn-login-play").css("margin-left", "80px");$("#helloContainer").css("margin-left", "-150px");$('.agario-panel.agario-side-panel.agario-shop-panel').append('<button id="logoutbtn" onclick="logout(); return false;" class="btn btn-danger btn-logout" data-itr="page_logout">Logout</button>');$("#imagebig").remove();
}, 10000);
}
else if(getParameterByName("mod", url)=="tiny"){
var tinyJS = '';
	    function inject(page) {
        page = page.replace("", tinyJS + "");
        return page;
    }
    window.stop();
    document.documentElement.innerHTML = "";
    GM_xmlhttpRequest({
        method: "GET",
        url: "http://agar.io/",
        onload: function(e) {
            var doc = inject(e.responseText);
            document.open();
            document.write(doc);
			document.close();
        }
    });

}

else if (location.host === "agar.io" && location.pathname === "/") {
	window.stop();
	location.href = "about:blank" + window.location.search + location.hash;
// Dependencies

	var modVersion = GM_info.script.version;

    // Inject Legend
    function inject(page) {
        var page = page.replace("", "" + "");
        return page;
    }

    window.stop();
    document.documentElement.innerHTML = "";
    GM_xmlhttpRequest({
        method: "GET",
        url: "https://jimboy3100.github.io/LMexpress/LMexpress3.html",
        onload: function(legend) {
            var doc = inject(legend.responseText);
            document.open();
            document.write(doc);
            document.close();
        }
    });

    // Inject Chat to text userscript
    (function() {
        'use strict';

        function pre_loop() {
            if (!document.getElementById("message-box")) {
                setTimeout(pre_loop, 4000);
                console.log("VoiceDeOChat:wait for Legend load");
                return;
            }
            return initialize();
        }
        return pre_loop();

        function initialize() {
            var lang_hash = {
                "default": "default",
                "ja": "日本語",
                "en-US": "English",
                "el-GR": "Ελληνικά",
                "zh-CN": "简体中文",
                "zh-TW": "繁體中文",
                "ko": "한국어"
            };
            var cfg = {};
            cfg.prefix = GM_getValue("prefix", "🎤");
            cfg.lang = GM_getValue("lang", "default");
            cfg.unpause = GM_getValue("unpause", false);
            console.log("load prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            $("#message-box").mousedown(function() {
                return false;
            });
            $(".team-top-menu").mousedown(function() {
                return false;
            });
            $("#message-menu").append('X');
            $(".chatbox-hide").click(function() {
                $("#message-box").css("display", "none");
                if (cfg.unpause && $("#pause-hud").css("display") == "block") {
                    var code = 82; // 'R'
                    $(document).trigger(jQuery.Event('keydown', {
                        keyCode: code,
                        which: code
                    }));
                }
            });
            $("#message-menu").append('C');
            $(".chatbox-clear").click(function() {
                $("#message").val("");
            });
            window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
            var recognition = new window.SpeechRecognition();
            if (cfg.lang !== "default") {
                recognition.lang = cfg.lang;
            }
            console.log("cfg.lang/recognition.lang=" + cfg.lang + "/" + recognition.lang);
            recognition.addEventListener('result', function(event) {
                var text_to = event.results.item(0).item(0).transcript;
                var text_pre = $("#message").val();
                if (text_pre === "") {
                    text_to = cfg.prefix + text_to;
                } else {
                    text_to = text_pre + " " + text_to;
                }
                $("#message").val(text_to);
            }, false);
            recognition.addEventListener('end', function(event) {
                fn_recognition_end();
            }, false);
            $("#message-menu").append('🎤');
            $(".voice-start").click(function() {
                fn_recognition_start();
            });

            function fn_recognition_start() {
                $("#voice-config").css("display", "none");
                $(".voice-start").css("background-color", "green");
                recognition.start();
            }

            function fn_recognition_end() {
                $(".voice-start").css("background-color", "");
            }
            $("#og-options").append('

');
            $("#voice-config").append('
Voice
');
            $("#voice-config").append('Voice-Prefix:<input type="text" id="voice-prefix" style="width:4em; float:none;" value="' + cfg.prefix + '"/>');

            function fn_lang_make() {
                $("#voice-config").append('Voice-lang:<select id="voice-lang"/></select>');
                for (var code in lang_hash) {
                    var desc = lang_hash[code];
                    var selected = (code === cfg.lang) ? ' selected' : '';
                    $("#voice-lang").append('<option value="' + code + '"' + selected + '>' + desc + '</option>');
                }
            }
            fn_lang_make();
            $("#voice-config").append('<input type="checkbox" id="voice-unpause"' + (cfg.unpause ? ' checked' : '') + '/>UnPause');

            var observ_obj = $("#og-settings");
            var observ_cur = observ_obj.css("display");
            var observer = new MutationObserver(function(mutations) {
                var observ_pre = observ_cur;
                var observ_new = observ_obj.css("display");
                observ_cur = observ_new;
                if (observ_new == "none" && observ_pre == "block") {
                    fn_config_save();
                }
            });
            observer.observe(observ_obj[0], {
                attributes: true,
                attributeFilter: ['style']
            });

            function fn_config_save() {
                cfg.prefix = $("#voice-prefix").val();
                GM_setValue("prefix", cfg.prefix);
                cfg.lang = $("#voice-lang").val();
                GM_setValue("lang", cfg.lang);
                if (cfg.lang !== "default") {
                    recognition.lang = cfg.lang;
                }
                cfg.unpause = $("#voice-unpause").prop('checked');
                GM_setValue("unpause", cfg.unpause);
                console.log("saved prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            }
        }
    })();
}

//runs only if play.google.com is a popup, doesnt if directly joined
if (location.host == "play.google.com") {
	window.close();
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
//End of Legend Mod
<commit_msg>Update LMexpress3.user.js<commit_after>// ==UserScript==
// @name         Legend Express Agar.io Extension
// @namespace    Legend Express Agario Mod
// @version      1.5(FINDSERVERSELSEWHERE)
// @description  Agario Mod - Legend,Ogario,Kitty,Old Skins,Animated Skins,Language Packs,Manual User Scripts,Chat,60++ Macros/Hotkeys(Tricksplit,Doublesplit,Quick Feeding,Popsplit,Auto Coins,Freeze Cell Macro,Auto respawn)
// @homepage     http://www.legendmod.ml
// @author       Jimboy3100
// @license      MIT
// @icon         https://jimboy3100.github.io/banners/CropedImage128.gif
// @match        https://agar.io/*
// @match        https://play.google.com/*
// @downloadURL  jimboy3100.github.io/legendmod.user.js
// @updateURL    jimboy3100.github.io/legendmod.user.js
// @run-at       document-start
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_deleteValue
// @connect      jimboy3100.github.io
// ==/UserScript==

// Legend Mod by Jimboy3100
/*MIT License

Copyright (c) [The Legend Mod]

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.
*/

// Start of script
GM_registerMenuCommand('Legend Mod Website', function() {
    window.open("http://legendmod.ml");
}, 'r');
GM_registerMenuCommand('LM Library', function() {
    window.open("https://github.com/jimboy3100/jimboy3100.github.io/");
}, 'r');
GM_registerMenuCommand('Donate for Legend Mod', function() {
    window.open("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CM3GDVCW6PBF6");
}, 'r');

if (location.protocol != 'http:')
{
 location.href = 'http:' + window.location.href.substring(window.location.protocol.length);
}

var url = window.location.href;
if (location.pathname == "/LMoldskins"){
eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('"u v";k(2(){2 e(){g e=p.x("F"),a=b;G(e){H{a=I.z(e)}A(e){6.J(!1,e)}a&&a.5&&(C.B(a.5),6.D("%c[9] d E y...","n: m"))}}g a,t,o;a="//l.q/r.w/f/j.h.f",t=2(){6.s("[9] O 11...")},(o=3.10("Z")).K="X/Y",o.12="13-8",o.4?o.i=2(){"d"!=o.4&&"14"!=o.4||(o.i=b,t&&t())}:(3.7&&3.7.15("V-j-h",a),t&&(o.W=t,o.N=e)),o.5=a+"?M="+~~(L.P()/Q/U),3.T("S")[0].R(o)},0);',62,68,'||function|document|readyState|src|console|body||VANILLA||null||loaded||js|var|core|onreadystatechange|vanilla|setTimeout|imaster|darkorange|color||localStorage|space|agar|info||use|strict|io|getItem|cache|parse|catch|eval|window|log|from|cachedVanilla|if|try|JSON|assert|type|Date|_|onerror|inject|now|1e3|appendChild|head|getElementsByTagName|60|data|onload|text|javascript|script|createElement|success|charset|utf|complete|setAttribute'.split('|'),0,{}))

setTimeout(function() {

document.body.style.background = "#f3f3f3 url('https://jimboy3100.github.io/banners/iconmod3.png') no-repeat center fixed";
$( "body" ).append('

');
}, 4000);
setTimeout(function() {
$("#canvas").remove();$("#adsBottom").remove();$("#rightPanel").remove();$(".agario-panel.agario-side-panel.agario-profile-panel").remove();$("#dailyquests-panel").remove();$("#v-ex-menu").remove();$("#service-message-area").remove();$(".radio-module").remove();$(".tosBox.right").remove();$(".tosBox.left").remove();$(".form-group.clearfix").remove();$("#skinCustomButton").remove();$("#settings").remove();$("#vanilla-home-link").remove();$("#settingsButton").remove();$("#instructions").remove();$(".btn.btn-play.btn-primary").remove();$(".btn.btn-play-guest.btn-success").remove();$(".btn.btn-warning.btn-login-play").text("Login");$(".btn.btn-warning.btn-login-play").css("margin-left", "80px");$("#helloContainer").css("margin-left", "-150px");$('.agario-panel.agario-side-panel.agario-shop-panel').append('<button id="logoutbtn" onclick="logout(); return false;" class="btn btn-danger btn-logout" data-itr="page_logout">Logout</button>');$("#imagebig").remove();
}, 10000);
}
else if(getParameterByName("mod", url)=="tiny"){
var tinyJS = '';
	    function inject(page) {
        page = page.replace("", tinyJS + "");
        return page;
    }
    window.stop();
    document.documentElement.innerHTML = "";
    GM_xmlhttpRequest({
        method: "GET",
        url: "http://agar.io/",
        onload: function(e) {
            var doc = inject(e.responseText);
            document.open();
            document.write(doc);
			document.close();
        }
    });

}

else if (location.host === "agar.io" && location.pathname === "/") {
	window.stop();
	location.href = "about:blank" + window.location.search + location.hash;
// Dependencies

	var modVersion = GM_info.script.version;

    // Inject Legend
    function inject(page) {
        var page = page.replace("", "" + "");
        return page;
    }

    window.stop();
    document.documentElement.innerHTML = "";
    GM_xmlhttpRequest({
        method: "GET",
        url: "https://jimboy3100.github.io/LMexpress/LMexpress3.html",
        onload: function(legend) {
            var doc = inject(legend.responseText);
            document.open();
            document.write(doc);
            document.close();
        }
    });

    // Inject Chat to text userscript
    (function() {
        'use strict';

        function pre_loop() {
            if (!document.getElementById("message-box")) {
                setTimeout(pre_loop, 4000);
                console.log("VoiceDeOChat:wait for Legend load");
                return;
            }
            return initialize();
        }
        return pre_loop();

        function initialize() {
            var lang_hash = {
                "default": "default",
                "ja": "日本語",
                "en-US": "English",
                "el-GR": "Ελληνικά",
                "zh-CN": "简体中文",
                "zh-TW": "繁體中文",
                "ko": "한국어"
            };
            var cfg = {};
            cfg.prefix = GM_getValue("prefix", "🎤");
            cfg.lang = GM_getValue("lang", "default");
            cfg.unpause = GM_getValue("unpause", false);
            console.log("load prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            $("#message-box").mousedown(function() {
                return false;
            });
            $(".team-top-menu").mousedown(function() {
                return false;
            });
            $("#message-menu").append('X');
            $(".chatbox-hide").click(function() {
                $("#message-box").css("display", "none");
                if (cfg.unpause && $("#pause-hud").css("display") == "block") {
                    var code = 82; // 'R'
                    $(document).trigger(jQuery.Event('keydown', {
                        keyCode: code,
                        which: code
                    }));
                }
            });
            $("#message-menu").append('C');
            $(".chatbox-clear").click(function() {
                $("#message").val("");
            });
            window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
            var recognition = new window.SpeechRecognition();
            if (cfg.lang !== "default") {
                recognition.lang = cfg.lang;
            }
            console.log("cfg.lang/recognition.lang=" + cfg.lang + "/" + recognition.lang);
            recognition.addEventListener('result', function(event) {
                var text_to = event.results.item(0).item(0).transcript;
                var text_pre = $("#message").val();
                if (text_pre === "") {
                    text_to = cfg.prefix + text_to;
                } else {
                    text_to = text_pre + " " + text_to;
                }
                $("#message").val(text_to);
            }, false);
            recognition.addEventListener('end', function(event) {
                fn_recognition_end();
            }, false);
            $("#message-menu").append('🎤');
            $(".voice-start").click(function() {
                fn_recognition_start();
            });

            function fn_recognition_start() {
                $("#voice-config").css("display", "none");
                $(".voice-start").css("background-color", "green");
                recognition.start();
            }

            function fn_recognition_end() {
                $(".voice-start").css("background-color", "");
            }
            $("#og-options").append('

');
            $("#voice-config").append('
Voice
');
            $("#voice-config").append('Voice-Prefix:<input type="text" id="voice-prefix" style="width:4em; float:none;" value="' + cfg.prefix + '"/>');

            function fn_lang_make() {
                $("#voice-config").append('Voice-lang:<select id="voice-lang"/></select>');
                for (var code in lang_hash) {
                    var desc = lang_hash[code];
                    var selected = (code === cfg.lang) ? ' selected' : '';
                    $("#voice-lang").append('<option value="' + code + '"' + selected + '>' + desc + '</option>');
                }
            }
            fn_lang_make();
            $("#voice-config").append('<input type="checkbox" id="voice-unpause"' + (cfg.unpause ? ' checked' : '') + '/>UnPause');

            var observ_obj = $("#og-settings");
            var observ_cur = observ_obj.css("display");
            var observer = new MutationObserver(function(mutations) {
                var observ_pre = observ_cur;
                var observ_new = observ_obj.css("display");
                observ_cur = observ_new;
                if (observ_new == "none" && observ_pre == "block") {
                    fn_config_save();
                }
            });
            observer.observe(observ_obj[0], {
                attributes: true,
                attributeFilter: ['style']
            });

            function fn_config_save() {
                cfg.prefix = $("#voice-prefix").val();
                GM_setValue("prefix", cfg.prefix);
                cfg.lang = $("#voice-lang").val();
                GM_setValue("lang", cfg.lang);
                if (cfg.lang !== "default") {
                    recognition.lang = cfg.lang;
                }
                cfg.unpause = $("#voice-unpause").prop('checked');
                GM_setValue("unpause", cfg.unpause);
                console.log("saved prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            }
        }
    })();
}

//runs only if play.google.com is a popup, doesnt if directly joined
if (location.host == "play.google.com") {
	window.close();
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
//End of Legend Mod
<|endoftext|>


<commit_before>$(document).ready(function(){

    var buttonClickedFlag = false;

    var flashcardTemplate = '\

\

\

\

Lol
\

\

\

\

Did you know this word?
\
                <input type="button" value="Yes" id="zingerYes"/>\
                <input type="button" value="No" id="zingerNo"/>\

\

\

';

    $('body').prepend(flashcardTemplate);

    $('#zingerYes').click(function(e){
        buttonClickedFlag = true;
        alert("Yes");
        $(".zingerStage").hide();
    });

    $('#zingerNo').click(function(e){
        buttonClickedFlag = true;
        alert("No!");
        $(".zingerStage").hide();
        buttonClickedFlag = true;
    });

    $('.zingerFlashcard').on('click', function() {
        if (buttonClickedFlag) {
            return;
        }

        $('.zingerFlashcard').toggleClass('zingerFlipped');
    });
});

chrome.runtime.onMessage.addListener(function(msg, sender) {
    //use msg.word, msg.meaning and msg.context
});
<commit_msg>Made flashcard dragabble<commit_after>var buttonClickedFlag = false;

$(document).ready(function(){
    var flashcardTemplate = '\

\

\

\

Lol
\

\

\

\

Did you know this word?
\
                <input type="button" value="Yes" id="zingerYes"/>\
                <input type="button" value="No" id="zingerNo"/>\

\

\

';

    $('body').prepend(flashcardTemplate);

    $('#zingerYes').click(function(e){
        alert("Yes");
        $(".zingerStage").hide();
    });

    $('#zingerNo').click(function(e){
        alert("No!");
        $(".zingerStage").hide();
    });

    $('.zingerFlashcard').on('click', function() {
        $('.zingerFlashcard').toggleClass('zingerFlipped');
    });

    $(".zingerStage").draggable();
});

// To listen to new word event
chrome.runtime.onMessage.addListener(function(msg, sender) {
    //use msg.word, msg.meaning and msg.context

    $("#zingerCardWord").html(msg.word);
    $("#zingerCardMeaning").html(msg.meaning);

    $(".zingerStage").show();
});
<|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.
 */

import { Observable } from "rxjs/Observable";
import { Subject } from "rxjs/Subject";
import objectAssign from "object-assign";

import config from "../../config.js";
import log from "../../utils/log";
import { SimpleSet } from "../../utils/collections";
import { getLeftSizeOfRange } from "../../utils/ranges.js";
import {
  MediaError,
  ErrorTypes,
  IndexError,
} from "../../errors";

import SegmentBookkeeper from "./segment_bookkeeper.js";
import QueuedSourceBuffer from "./queued-source-buffer.js";
import launchGarbageCollector from "./gc.js";
import cleanBuffer from "./cleanBuffer.js";

const { BITRATE_REBUFFERING_RATIO } = config;

/**
 * Calculate start and end timestamps of the wanted buffer.
 * @param {TimeRanges} buffered - TimeRanges coming from the concerned
 * SourceBuffer
 * @param {Object} clock
 * @param {Number} bufferGoal
 * @param {Object} paddings
 * @param {Number} paddings.low
 * @param {Number} paddings.high
 * @returns {Object} - Start and end timestamps, in seconds, under an object
 * form with two properties:
 *   - start {Number}
 *   - end {Number}
 */
function getWantedBufferRange(buffered, clock, bufferGoal, paddings) {
  const { low: lowPadding, high: highPadding } = paddings;
  const timestamp = clock.currentTime + clock.timeOffset;

  // wantedBufferSize calculates the size of the buffer we want to ensure,
  // taking into account the min between: the set max buffer size, the
  // duration and the live gap.
  const endDiff = (clock.duration || Infinity) - timestamp;
  const wantedBufferSize = Math.max(0, clock.liveGap == null ?
    Math.min(bufferGoal, endDiff) :
    Math.min(bufferGoal, clock.liveGap, endDiff)
  );

  const bufferGap = getLeftSizeOfRange(buffered, timestamp);

  // the ts padding is the time offset that we want to apply to our current
  // timestamp in order to calculate the starting point of the list of
  // segments to inject.
  const timestampPadding = bufferGap > lowPadding && bufferGap < Infinity ?
    Math.min(bufferGap, highPadding) : 0;

  return {
    start: timestamp + timestampPadding,
    end: timestamp + wantedBufferSize,
  };
}

/**
 * Manage a single buffer:
 *   - load the right segments through the downloader on normal playback /
 *     seeking / as the adaptation chosen changes
 *   - add those to the sourceBuffer
 *   - clean up if too much segments have been loaded
 *
 * TODO too many parameters?
 * @param {Object} opt
 * @param {SourceBuffer} opt.sourceBuffer
 * @param {Function} opt.downloader
 * @param {Observable} opt.switch$
 * @param {Observable} opt.clock
 * @param {Number} opt.wantedBufferAhead
 * @param {Number} opt.maxBufferBehind
 * @param {Number} opt.maxBufferAhead
 * @param {string} opt.bufferType
 * @param {Boolean} opt.isLive
 * @returns {Observable}
 */
function Buffer({
  sourceBuffer,
  downloader,
  switch$,
  clock$,
  wantedBufferAhead,
  maxBufferBehind,
  maxBufferAhead,

  // XXX Remove that from here
  bufferType,   // Buffer type (audio, video, text, image)
  isLive,
}) {

  /**
   * Saved state of an init segment to give to the downloader.
   * TODO Re-think that mess for a Buffer refacto.
   */
  let initSegmentInfos = null;

  // will be used to emit messages to the calling function
  const messageSubject = new Subject();

  // safety level (low and high water mark) size of buffer that won't
  // be flushed when switching representation for smooth transitions
  // and avoiding buffer underflows
  const LOW_PADDING  = bufferType == "video" ? 4 : 1;
  const HIGH_PADDING = bufferType == "video" ? 6 : 1;

  const bookkeeper = new SegmentBookkeeper();
  const bufferingQueue = new QueuedSourceBuffer(sourceBuffer);

  /**
   * Returns every segments currently wanted.
   * @param {Object} adaptation - The adaptation concerned (audio/video...)
   * @param {Object} representation - The representation of the chosen
   * adaptation
   * @param {BufferedRanges} buffered - The BufferedRanges of the corresponding
   * sourceBuffer
   * @param {Object} timing - The last item emitted from clock$
   * @param {Number} bufferGoal - The last item emitted from wantedBufferAhead
   * @param {Number} bufferSize - The last item emitted from bufferSize$
   * @param {Boolean} withInitSegment - Whether we're dealing with an init
   * segment.
   * @returns {Array.<Segment>}
   * @throws IndexError - Throws if the current timestamp is considered out
   * of bounds.
   */
  function getSegmentsListToInject(
    representation,
    buffered,
    timing,
    bufferGoal,
    withInitSegment
  ) {
    let initSegment = null;

    if (withInitSegment) {
      log.debug("add init segment", bufferType);
      initSegment = representation.index.getInitSegment();
    }

    if (timing.readyState === 0) {
      return initSegment ? [initSegment] : [];
    }

    const { start, end } = getWantedBufferRange(buffered, timing, bufferGoal, {
      low: LOW_PADDING,
      high: HIGH_PADDING,
    });
    const duration = end - start;

    /**
     * TODO This is an ugly hack for now.
     * shouldRefresh returns true if, from the informations given and the type
     * of index used in the manifest, we infer that we have to refresh the
     * manifest (to get informations about subsequent needed segments).
     *
     * The problem with shouldRefresh is that depending on the type of techno,
     * we want different things:
     *
     *   - for smooth contents, index informations about a segment n is present
     *     in the container of the segment n-1. Thus, shouldRefresh should
     *     return true there if the segment n-1 has been parsed but we still
     *     miss informations about the segment n (this happens).
     *
     *   - for dash contents, we prefer to fetch the manifest as soon as we
     *     miss the informations about even one distant segment in the future.
     *     Thus, shouldRefresh should return true there if the end of the
     *     wanted range is not yet in the index.
     *
     * Doing the DASH usecase does not cause much problem (though the precision
     * of the range end could be improved).
     * The smooth usecase is however difficult to implement with the current
     * code (we have to know that we parsed the last segment from the index and
     * that we need the next segment, for which we have no information).
     * As a quick and dirty hack, we take the current time instead. If the
     * current time is well into the last segment and our range indicates
     * that we need another segment, we should refresh. However, this is not
     * efficient:
     *   - we have a high chance of rebuffering when this happens. It would
     *     be best to know that we have the last segment (one other problem is
     *     that this segment could be in another representation) before
     *     actually playing it.
     *   - the player stops usually some milliseconds before the end of the
     *     last segment, but this is not an exact thing. So we have to add
     *     rounding and infer the fact that we're well into the last segment.
     *   - for readability, it makes no sense that shouldRefresh might need
     *     the current time of playback.
     */
    const timestamp = timing.currentTime + timing.timeOffset;
    const shouldRefresh = representation.index
      .shouldRefresh(timestamp, start, end);
    if (shouldRefresh) {
      const error = new IndexError(
        "OUT_OF_INDEX_ERROR", representation.index.getType(), false);
      messageSubject.next({ type: "out-of-index", value: error });
    }

    // given the current timestamp and the previously calculated time gap and
    // wanted buffer size, we can retrieve the list of segments to inject in
    // our pipelines.
    const mediaSegments = representation.index.getSegments(start, duration);

    if (initSegment) {
      mediaSegments.unshift(initSegment);
    }

    return mediaSegments;
  }

  function createRepresentationBuffer(representation) {
    log.info("bitrate", bufferType, representation.bitrate);

    const queuedSegments = new SimpleSet();

    /**
     * Returns true if it considers that the segment given should be loaded.
     * @param {Segment} segment
     * @param {Number} bitrate
     * @returns {Boolean}
     */
    function segmentFilter(segment) {
      // if this segment is already in the pipeline
      const isInQueue = queuedSegments.test(segment.id);
      if (isInQueue) {
        return false;
      }

      // segment without time info are usually init segments or some
      // kind of metadata segment that we never filter out
      if (segment.isInit || segment.time < 0) {
        return true;
      }

      const { time, duration, timescale } = segment;
      const currentSegment =
        bookkeeper.hasCompleteSegment(time, duration, timescale);

      // only re-load comparatively-poor bitrates.
      return !currentSegment ||
        (currentSegment.bitrate * BITRATE_REBUFFERING_RATIO) <
        representation.bitrate;
    }

    /**
     * Append buffer to the bufferingQueue.
     * If it leads to a QuotaExceededError, try to run our custom range
     * _garbage collector_.
     * @returns {Observable}
     */
    function appendDataInBuffer(pipelineData) {
      const { segment, parsed } = pipelineData;
      const { segmentData, nextSegments, segmentInfos } = parsed;

      if (segment.isInit) {
        initSegmentInfos = segmentInfos;
      }

      // If we have informations about subsequent segments, add them to the
      // index.
      // TODO do that higher up?
      const addedSegments = nextSegments ?
        representation.index._addSegments(nextSegments, segmentInfos) : [];

      /**
       * Validate the segment downloaded:
       *   - remove from the queued segment to re-allow its download
       *   - insert it in the bufferedRanges object
       */
      const validateSegment = () => {
        // Note: we should also clean when canceled/errored
        // (TODO do it when canceled?)
        queuedSegments.remove(segment.id);

        if (!segment.isInit) {
          const { time, duration, timescale } = segmentInfos ?
            segmentInfos : segment;

          // current segment timings informations are used to update
          // bufferedRanges informations
          bookkeeper.insert(
            segment,
            time / timescale, // start
            (time + duration) / timescale, // end
            representation.bitrate
          );
        }
      };

      const appendSegment = () =>
        bufferingQueue.appendBuffer(segmentData)
          .do(validateSegment);

      return appendSegment()
        .catch((error) => {
          if (error.name != "QuotaExceededError") {
            queuedSegments.remove(segment.id);
            throw new MediaError("BUFFER_APPEND_ERROR", error, true);
          }

          return launchGarbageCollector(clock$, bufferingQueue)
            .mergeMap(appendSegment)
            .catch((error) => {
              queuedSegments.remove(segment.id);
              throw new MediaError("BUFFER_FULL_ERROR", error, true);
            });
        }).map(() => ({
          type: "pipeline",
          value: objectAssign({ bufferType, addedSegments }, pipelineData),
        }));
    }

    /**
     * Get list of segment to injects.
     * @param {Array} combineLatestResult
     * @param {Number} injectCount
     * @returns {Observable|Array.<Segment>}
     */
    function getNeededSegments(timing, bufferGoal, injectCount) {
      const buffered = bufferingQueue.getBuffered();
      bookkeeper.addBufferedInfos(buffered);

      // send a message downstream when bumping on an explicit
      // discontinuity announced in the segment index.
      if (timing.stalled) {
        if (isLive) {
          const discontinuity =
            representation.index.checkDiscontinuity(timing.currentTime);
          if (discontinuity > 0) {
            messageSubject.next({
              type: "index-discontinuity",
              value: { ts: discontinuity + 1 },
            });
          }
        }
      }

      let injectedSegments;

      // filter out already loaded and already queued segments
      const withInitSegment = (injectCount === 0);
      injectedSegments = getSegmentsListToInject(
        representation,
        buffered,
        timing,
        bufferGoal,
        withInitSegment);

      injectedSegments = injectedSegments.filter(segmentFilter);

      // queue all segments injected in the observable
      for (let i = 0; i < injectedSegments.length; i++) {
        queuedSegments.add(injectedSegments[i].id);
      }

      return Observable.of(...injectedSegments);
    }

    const loadNeededSegments = segment => {
      return downloader({ segment, representation, init: initSegmentInfos })
        .map((args) => objectAssign({ segment }, args));
    };

    const onClockTick = ([
      timing, wantedBufferAhead, maxBufferBehind, maxBufferAhead,
    ], i) => {
      const bufferGoal = Math.min(wantedBufferAhead, maxBufferAhead);
      const loadNeeded$ = getNeededSegments(timing, bufferGoal, i)
        .concatMap(loadNeededSegments);
      const clean$ = cleanBuffer(
        bufferingQueue, timing.currentTime, maxBufferBehind, maxBufferAhead);
      return Observable.merge(loadNeeded$, clean$);
    };

    const segmentsPipeline = Observable.combineLatest(
      clock$,
      wantedBufferAhead,
      maxBufferBehind,
      maxBufferAhead,
    )
      .mergeMap(onClockTick)
      .concatMap(appendDataInBuffer);

    return Observable.merge(segmentsPipeline, messageSubject).catch((error) => {
      // For live adaptations, handle 412 errors as precondition-
      // failed errors, ie: we are requesting for segments before they
      // exist
      const isPreconditionFailedError = (
        isLive &&
        error.type == ErrorTypes.NETWORK_ERROR &&
        error.isHttpError(412)
      );

      if (!isPreconditionFailedError) {
        throw error;
      }

      // 412 Precondition Failed request errors do not cause the
      // buffer to stop but are re-emitted in the stream as
      // "precondition-failed" type. They should be handled re-
      // adapting the live-gap that the player is holding
      return Observable.of({ type: "precondition-failed", value: error })
        .concat(Observable.timer(2000))
        .concat(createRepresentationBuffer(representation));
    })
      .startWith({
        type: "representationChange",
        value: {
          type: bufferType,
          representation,
        },
      });
  }

  return switch$
    .switchMap(createRepresentationBuffer)
    .finally(() => bufferingQueue.dispose());
}

function EmptyBuffer({ bufferType }) {
  return Observable.of({
    type: "representationChange",
    value: {
      type: bufferType,
      representation: null,
    },
  });
}

export {
  Buffer,
  EmptyBuffer,
};
<commit_msg>buffer: add TODO for discovered issue<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.
 */

import { Observable } from "rxjs/Observable";
import { Subject } from "rxjs/Subject";
import objectAssign from "object-assign";

import config from "../../config.js";
import log from "../../utils/log";
import { SimpleSet } from "../../utils/collections";
import { getLeftSizeOfRange } from "../../utils/ranges.js";
import {
  MediaError,
  ErrorTypes,
  IndexError,
} from "../../errors";

import SegmentBookkeeper from "./segment_bookkeeper.js";
import QueuedSourceBuffer from "./queued-source-buffer.js";
import launchGarbageCollector from "./gc.js";
import cleanBuffer from "./cleanBuffer.js";

const { BITRATE_REBUFFERING_RATIO } = config;

/**
 * Calculate start and end timestamps of the wanted buffer.
 * @param {TimeRanges} buffered - TimeRanges coming from the concerned
 * SourceBuffer
 * @param {Object} clock
 * @param {Number} bufferGoal
 * @param {Object} paddings
 * @param {Number} paddings.low
 * @param {Number} paddings.high
 * @returns {Object} - Start and end timestamps, in seconds, under an object
 * form with two properties:
 *   - start {Number}
 *   - end {Number}
 */
function getWantedBufferRange(buffered, clock, bufferGoal, paddings) {
  const { low: lowPadding, high: highPadding } = paddings;
  const timestamp = clock.currentTime + clock.timeOffset;

  // wantedBufferSize calculates the size of the buffer we want to ensure,
  // taking into account the min between: the set max buffer size, the
  // duration and the live gap.
  const endDiff = (clock.duration || Infinity) - timestamp;
  const wantedBufferSize = Math.max(0, clock.liveGap == null ?
    Math.min(bufferGoal, endDiff) :
    Math.min(bufferGoal, clock.liveGap, endDiff)
  );

  const bufferGap = getLeftSizeOfRange(buffered, timestamp);

  // the ts padding is the time offset that we want to apply to our current
  // timestamp in order to calculate the starting point of the list of
  // segments to inject.
  const timestampPadding = bufferGap > lowPadding && bufferGap < Infinity ?
    Math.min(bufferGap, highPadding) : 0;

  return {
    start: timestamp + timestampPadding,
    end: timestamp + wantedBufferSize,
  };
}

/**
 * Manage a single buffer:
 *   - load the right segments through the downloader on normal playback /
 *     seeking / as the adaptation chosen changes
 *   - add those to the sourceBuffer
 *   - clean up if too much segments have been loaded
 *
 * TODO too many parameters?
 * @param {Object} opt
 * @param {SourceBuffer} opt.sourceBuffer
 * @param {Function} opt.downloader
 * @param {Observable} opt.switch$
 * @param {Observable} opt.clock
 * @param {Number} opt.wantedBufferAhead
 * @param {Number} opt.maxBufferBehind
 * @param {Number} opt.maxBufferAhead
 * @param {string} opt.bufferType
 * @param {Boolean} opt.isLive
 * @returns {Observable}
 */
function Buffer({
  sourceBuffer,
  downloader,
  switch$,
  clock$,
  wantedBufferAhead,
  maxBufferBehind,
  maxBufferAhead,

  // XXX Remove that from here
  bufferType,   // Buffer type (audio, video, text, image)
  isLive,
}) {

  /**
   * Saved state of an init segment to give to the downloader.
   * TODO Re-think that mess for a Buffer refacto.
   */
  let initSegmentInfos = null;

  // will be used to emit messages to the calling function
  const messageSubject = new Subject();

  // safety level (low and high water mark) size of buffer that won't
  // be flushed when switching representation for smooth transitions
  // and avoiding buffer underflows
  const LOW_PADDING  = bufferType == "video" ? 4 : 1;
  const HIGH_PADDING = bufferType == "video" ? 6 : 1;

  const bookkeeper = new SegmentBookkeeper();
  const bufferingQueue = new QueuedSourceBuffer(sourceBuffer);

  /**
   * Returns every segments currently wanted.
   * @param {Object} adaptation - The adaptation concerned (audio/video...)
   * @param {Object} representation - The representation of the chosen
   * adaptation
   * @param {BufferedRanges} buffered - The BufferedRanges of the corresponding
   * sourceBuffer
   * @param {Object} timing - The last item emitted from clock$
   * @param {Number} bufferGoal - The last item emitted from wantedBufferAhead
   * @param {Number} bufferSize - The last item emitted from bufferSize$
   * @param {Boolean} withInitSegment - Whether we're dealing with an init
   * segment.
   * @returns {Array.<Segment>}
   * @throws IndexError - Throws if the current timestamp is considered out
   * of bounds.
   */
  function getSegmentsListToInject(
    representation,
    buffered,
    timing,
    bufferGoal,
    withInitSegment
  ) {
    let initSegment = null;

    if (withInitSegment) {
      log.debug("add init segment", bufferType);
      initSegment = representation.index.getInitSegment();
    }

    if (timing.readyState === 0) {
      return initSegment ? [initSegment] : [];
    }

    const { start, end } = getWantedBufferRange(buffered, timing, bufferGoal, {
      low: LOW_PADDING,
      high: HIGH_PADDING,
    });
    const duration = end - start;

    /**
     * TODO This is an ugly hack for now.
     * shouldRefresh returns true if, from the informations given and the type
     * of index used in the manifest, we infer that we have to refresh the
     * manifest (to get informations about subsequent needed segments).
     *
     * The problem with shouldRefresh is that depending on the type of techno,
     * we want different things:
     *
     *   - for smooth contents, index informations about a segment n is present
     *     in the container of the segment n-1. Thus, shouldRefresh should
     *     return true there if the segment n-1 has been parsed but we still
     *     miss informations about the segment n (this happens).
     *
     *   - for dash contents, we prefer to fetch the manifest as soon as we
     *     miss the informations about even one distant segment in the future.
     *     Thus, shouldRefresh should return true there if the end of the
     *     wanted range is not yet in the index.
     *
     * Doing the DASH usecase does not cause much problem (though the precision
     * of the range end could be improved).
     * The smooth usecase is however difficult to implement with the current
     * code (we have to know that we parsed the last segment from the index and
     * that we need the next segment, for which we have no information).
     * As a quick and dirty hack, we take the current time instead. If the
     * current time is well into the last segment and our range indicates
     * that we need another segment, we should refresh. However, this is not
     * efficient:
     *   - we have a high chance of rebuffering when this happens. It would
     *     be best to know that we have the last segment (one other problem is
     *     that this segment could be in another representation) before
     *     actually playing it.
     *   - the player stops usually some milliseconds before the end of the
     *     last segment, but this is not an exact thing. So we have to add
     *     rounding and infer the fact that we're well into the last segment.
     *   - for readability, it makes no sense that shouldRefresh might need
     *     the current time of playback.
     */
    const timestamp = timing.currentTime + timing.timeOffset;
    const shouldRefresh = representation.index
      .shouldRefresh(timestamp, start, end);
    if (shouldRefresh) {
      const error = new IndexError(
        "OUT_OF_INDEX_ERROR", representation.index.getType(), false);
      messageSubject.next({ type: "out-of-index", value: error });
    }

    // given the current timestamp and the previously calculated time gap and
    // wanted buffer size, we can retrieve the list of segments to inject in
    // our pipelines.
    const mediaSegments = representation.index.getSegments(start, duration);

    if (initSegment) {
      mediaSegments.unshift(initSegment);
    }

    return mediaSegments;
  }

  function createRepresentationBuffer(representation) {
    log.info("bitrate", bufferType, representation.bitrate);

    const queuedSegments = new SimpleSet();

    /**
     * Returns true if it considers that the segment given should be loaded.
     * @param {Segment} segment
     * @param {Number} bitrate
     * @returns {Boolean}
     */
    function segmentFilter(segment) {
      // if this segment is already in the pipeline
      const isInQueue = queuedSegments.test(segment.id);
      if (isInQueue) {
        return false;
      }

      // segment without time info are usually init segments or some
      // kind of metadata segment that we never filter out
      if (segment.isInit || segment.time < 0) {
        return true;
      }

      const { time, duration, timescale } = segment;

      // TODO If the segment is too big, and is garbage collected immediately
      // when appended, it will be downloaded in loop, even if we have enough
      // of it to continue regular playback.
      // To avoid this behavior, we should probably indicate the wanted start
      // and end time here, and only re-download it if the segment is missing
      // part(s) of it.
      //
      // You can repeat this bug easily by setting the maxBufferBehind or
      // maxBufferAhead option for a supplementaryTextTrack
      const currentSegment =
        bookkeeper.hasCompleteSegment(time, duration, timescale);

      // only re-load comparatively-poor bitrates.
      return !currentSegment ||
        (currentSegment.bitrate * BITRATE_REBUFFERING_RATIO) <
        representation.bitrate;
    }

    /**
     * Append buffer to the bufferingQueue.
     * If it leads to a QuotaExceededError, try to run our custom range
     * _garbage collector_.
     * @returns {Observable}
     */
    function appendDataInBuffer(pipelineData) {
      const { segment, parsed } = pipelineData;
      const { segmentData, nextSegments, segmentInfos } = parsed;

      if (segment.isInit) {
        initSegmentInfos = segmentInfos;
      }

      // If we have informations about subsequent segments, add them to the
      // index.
      // TODO do that higher up?
      const addedSegments = nextSegments ?
        representation.index._addSegments(nextSegments, segmentInfos) : [];

      /**
       * Validate the segment downloaded:
       *   - remove from the queued segment to re-allow its download
       *   - insert it in the bufferedRanges object
       */
      const validateSegment = () => {
        // Note: we should also clean when canceled/errored
        // (TODO do it when canceled?)
        queuedSegments.remove(segment.id);

        if (!segment.isInit) {
          const { time, duration, timescale } = segmentInfos ?
            segmentInfos : segment;

          // current segment timings informations are used to update
          // bufferedRanges informations
          bookkeeper.insert(
            segment,
            time / timescale, // start
            (time + duration) / timescale, // end
            representation.bitrate
          );
        }
      };

      const appendSegment = () =>
        bufferingQueue.appendBuffer(segmentData)
          .do(validateSegment);

      return appendSegment()
        .catch((error) => {
          if (error.name != "QuotaExceededError") {
            queuedSegments.remove(segment.id);
            throw new MediaError("BUFFER_APPEND_ERROR", error, true);
          }

          return launchGarbageCollector(clock$, bufferingQueue)
            .mergeMap(appendSegment)
            .catch((error) => {
              queuedSegments.remove(segment.id);
              throw new MediaError("BUFFER_FULL_ERROR", error, true);
            });
        }).map(() => ({
          type: "pipeline",
          value: objectAssign({ bufferType, addedSegments }, pipelineData),
        }));
    }

    /**
     * Get list of segment to injects.
     * @param {Array} combineLatestResult
     * @param {Number} injectCount
     * @returns {Observable|Array.<Segment>}
     */
    function getNeededSegments(timing, bufferGoal, injectCount) {
      const buffered = bufferingQueue.getBuffered();
      bookkeeper.addBufferedInfos(buffered);

      // send a message downstream when bumping on an explicit
      // discontinuity announced in the segment index.
      if (timing.stalled) {
        if (isLive) {
          const discontinuity =
            representation.index.checkDiscontinuity(timing.currentTime);
          if (discontinuity > 0) {
            messageSubject.next({
              type: "index-discontinuity",
              value: { ts: discontinuity + 1 },
            });
          }
        }
      }

      let injectedSegments;

      // filter out already loaded and already queued segments
      const withInitSegment = (injectCount === 0);
      injectedSegments = getSegmentsListToInject(
        representation,
        buffered,
        timing,
        bufferGoal,
        withInitSegment);

      injectedSegments = injectedSegments.filter(segmentFilter);

      // queue all segments injected in the observable
      for (let i = 0; i < injectedSegments.length; i++) {
        queuedSegments.add(injectedSegments[i].id);
      }

      return Observable.of(...injectedSegments);
    }

    const loadNeededSegments = segment => {
      return downloader({ segment, representation, init: initSegmentInfos })
        .map((args) => objectAssign({ segment }, args));
    };

    const onClockTick = ([
      timing, wantedBufferAhead, maxBufferBehind, maxBufferAhead,
    ], i) => {
      const bufferGoal = Math.min(wantedBufferAhead, maxBufferAhead);
      const loadNeeded$ = getNeededSegments(timing, bufferGoal, i)
        .concatMap(loadNeededSegments);
      const clean$ = cleanBuffer(
        bufferingQueue, timing.currentTime, maxBufferBehind, maxBufferAhead);
      return Observable.merge(loadNeeded$, clean$);
    };

    const segmentsPipeline = Observable.combineLatest(
      clock$,
      wantedBufferAhead,
      maxBufferBehind,
      maxBufferAhead,
    )
      .mergeMap(onClockTick)
      .concatMap(appendDataInBuffer);

    return Observable.merge(segmentsPipeline, messageSubject).catch((error) => {
      // For live adaptations, handle 412 errors as precondition-
      // failed errors, ie: we are requesting for segments before they
      // exist
      const isPreconditionFailedError = (
        isLive &&
        error.type == ErrorTypes.NETWORK_ERROR &&
        error.isHttpError(412)
      );

      if (!isPreconditionFailedError) {
        throw error;
      }

      // 412 Precondition Failed request errors do not cause the
      // buffer to stop but are re-emitted in the stream as
      // "precondition-failed" type. They should be handled re-
      // adapting the live-gap that the player is holding
      return Observable.of({ type: "precondition-failed", value: error })
        .concat(Observable.timer(2000))
        .concat(createRepresentationBuffer(representation));
    })
      .startWith({
        type: "representationChange",
        value: {
          type: bufferType,
          representation,
        },
      });
  }

  return switch$
    .switchMap(createRepresentationBuffer)
    .finally(() => bufferingQueue.dispose());
}

function EmptyBuffer({ bufferType }) {
  return Observable.of({
    type: "representationChange",
    value: {
      type: bufferType,
      representation: null,
    },
  });
}

export {
  Buffer,
  EmptyBuffer,
};
<|endoftext|>


<commit_before>module.exports = function(container) {

  var client = container.client;

  return {
    create: function(token) {
      return client.post(
        container.authBasePath('/user/'+ token.userId +'/token'),
        token
      );
    },
    update: function(token) {
      return client.put(
        container.authBasePath('/user/'+ token.userId +'/token/' + token.id),
        token
      );
    },
    delete: function(token) {
      return client.delete(
        container.authBasePath('/user/'+ token.userId +'/token/' + token.id)
      );
    },
    list: function(userId) {
      userId = userId || container.auth.currentUser().uuid;
      return client.get(container.authBasePath('/user/'+ userId +'/tokens'));
    }
  }
}
<commit_msg>add load<commit_after>module.exports = function(container) {

  var client = container.client;

  return {
    load: function(tokenId) {
      var userId = container.auth.currentUser().uuid;
      return client.get(container.authBasePath('/user/'+ userId +'/token/' + tokenId));
    },
    save: function(token) {
      return token.id ? this.update(token) : this.create(token);
    },
    create: function(token) {
      return client.post(
        container.authBasePath('/user/'+ token.userId +'/token'),
        token
      );
    },
    update: function(token) {
      return client.put(
        container.authBasePath('/user/'+ token.userId +'/token/' + token.id),
        token
      );
    },
    delete: function(token) {
      return client.delete(
        container.authBasePath('/user/'+ token.userId +'/token/' + token.id)
      );
    },
    list: function(userId) {
      userId = userId || container.auth.currentUser().uuid;
      return client.get(container.authBasePath('/user/'+ userId +'/tokens'));
    }
  }
}
<|endoftext|>


<commit_before>//v0.4q

//$(document).ready(function() {
jQuery(function($) {

	setTimeout(function() {

    $("#imgur img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });

    $("#hizliresim img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });
     $("#lowres img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });
     $("#free img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });
     $("#vanillaskins img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });
     $("#animatedLikeGif img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });

    $("img.lazy").on("click", function(e) {
        e.preventDefault();
		var url = $(this).attr("name");
        $("#skin-url").val(url).select();
        try {
        } catch (e) {}
    });

    $("#skin-url").on("click", function(e) {
        $(this).select();
        try {
        } catch (e) {}
    });

	$("#nav a").on("click", function() {
        var _this = $(this);
        if (_this.hasClass("link")) {
            return;
        }
        $("#nav a").removeClass("active");
        _this.addClass("active");
        var id = _this.attr("href");
        $(".skins-wrapper").hide();
        $(id).show();
        $(window).scrollTop(0).trigger("scroll");
        return false;
    });
    $("#UseEffect").on("click", function(e) {
		loadSpecialEffectSkin(e)
    });
    $("#UseEffect2").on("click", function(e) {
		toastr.info("[SERVER]: Special Effect erased");
		if (document.getElementsByClassName("skins-wrapper")[4].children[0]) document.getElementsByClassName("skins-wrapper")[4].children[0].remove()
			SpecialEffectPlayers[application.lastSentNick]=null
			//
			animatedskins[application.lastSentNick] = null
			//
			localStorage.setItem("isActualUsingSpecialEffectsSkin", null);
			window.application.sendSocket3Info("spfc", null)
    });
	setTimeout(function() {
		if ($("#nav a")[0]){
			$("#nav a")[0].click();
		}
		startSpecialEffectSkin();
	}, 950);
	}, 900);
});

function startSpecialEffectSkin(){
	if (localStorage.getItem("isActualUsingSpecialEffectsSkin")){
			try {
			for (var i = 0; i < $(".skins-wrapper").length; i++){
				if ($(".skins-wrapper")[i].style.display != "none"){
					for (var j = 0; j < document.getElementsByClassName("skins-wrapper")[i].children.length; j++)
						if (document.getElementsByClassName("skins-wrapper")[i].children[j].children[0].name ==localStorage.getItem("isActualUsingSpecialEffectsSkin")){
							if (document.getElementsByClassName("skins-wrapper")[4].children[0]) document.getElementsByClassName("skins-wrapper")[4].children[0].remove()
							document.getElementsByClassName("skins-wrapper")[4].append(document.getElementsByClassName("skins-wrapper")[i].children[j])
						}
				}
			}
			//if (application.lastSentNick == "") application.lastSentNick = $("#nick").val()
			//SpecialEffectPlayers[application.lastSentNick]=localStorage.getItem("isActualUsingSpecialEffectsSkin")
			//window.application.sendSocket3Info("spfc", localStorage.getItem("isActualUsingSpecialEffectsSkin"))

			} catch (e) {}
	}
}

function loadSpecialEffectSkin(e){
		if (($("#nick").val().includes('℄') && $("#clantag").val() == window.atob(window.clanTagLc)) || window.proLicenceUID || $("#skin-url").val() == "Byzantium" || window.tempAnimatedCoolArray.includes($("#skin-url").val())){
			try {
			toastr.info("[SERVER]: Special Effect " + $("#skin-url").val() + " activated");
			for (var i = 0; i < $(".skins-wrapper").length; i++){
				if ($(".skins-wrapper")[i].style.display != "none"){
					for (var j = 0; j < document.getElementsByClassName("skins-wrapper")[i].children.length; j++)
						if (document.getElementsByClassName("skins-wrapper")[i].children[j].children[0].name ==$("#skin-url").val()){
							if (document.getElementsByClassName("skins-wrapper")[4].children[0]) document.getElementsByClassName("skins-wrapper")[4].children[0].remove()
							document.getElementsByClassName("skins-wrapper")[4].append(document.getElementsByClassName("skins-wrapper")[i].children[j])
						}
				}
			}
			//if (window.proLicenceUID){
				localStorage.setItem("isActualUsingSpecialEffectsSkin", $("#skin-url").val());
			//}
			//application.lastSentNick = $("#nick").val()
			//SpecialEffectPlayers[application.lastSentNick]=$("#skin-url").val()
			//window.application.sendSocket3Info("spfc", $("#skin-url").val())

			} catch (e) {}
		}
		else{
			toastr.warning("[SERVER]: Not Premium account found. If you donated in the past, please refer it to Legend mod discord.
Thank you for using our scripts!").css("width", "350px");
		}
}
<commit_msg>Update shopscript.js<commit_after>//v0.4r

//$(document).ready(function() {
jQuery(function($) {

	setTimeout(function() {

    $("#imgur img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });

    $("#hizliresim img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });
     $("#lowres img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });
     $("#free img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });
     $("#vanillaskins img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });
     $("#animatedLikeGif img.lazy").lazyload({
        effect : "fadeIn",
        skip_invisible : true
    });

    $("img.lazy").on("click", function(e) {
        e.preventDefault();
		var url = $(this).attr("name");
        $("#skin-url").val(url).select();
        try {
        } catch (e) {}
    });

    $("#skin-url").on("click", function(e) {
        $(this).select();
        try {
        } catch (e) {}
    });

	$("#nav a").on("click", function() {
        var _this = $(this);
        if (_this.hasClass("link")) {
            return;
        }
        $("#nav a").removeClass("active");
        _this.addClass("active");
        var id = _this.attr("href");
        $(".skins-wrapper").hide();
        $(id).show();
        $(window).scrollTop(0).trigger("scroll");
        return false;
    });
    $("#UseEffect").on("click", function(e) {
		loadSpecialEffectSkin(e)
    });
    $("#UseEffect2").on("click", function(e) {

		if (document.getElementsByClassName("skins-wrapper")[4].children[0]){
			document.getElementsByClassName("skins-wrapper")[4].children[0].remove()
			toastr.info("[SERVER]: Special Effect erased");
		}
			SpecialEffectPlayers[application.lastSentNick]=null
			//
			animatedskins[application.lastSentNick] = null
			//
			localStorage.setItem("isActualUsingSpecialEffectsSkin", null);
			window.application.sendSocket3Info("spfc", null)
    });
	setTimeout(function() {
		if ($("#nav a")[0]){
			$("#nav a")[0].click();
		}
		startSpecialEffectSkin();
	}, 950);
	}, 900);
});

function startSpecialEffectSkin(){
	if (localStorage.getItem("isActualUsingSpecialEffectsSkin")){
			try {
			for (var i = 0; i < $(".skins-wrapper").length; i++){
				if ($(".skins-wrapper")[i].style.display != "none"){
					for (var j = 0; j < document.getElementsByClassName("skins-wrapper")[i].children.length; j++)
						if (document.getElementsByClassName("skins-wrapper")[i].children[j].children[0].name ==localStorage.getItem("isActualUsingSpecialEffectsSkin")){
							if (document.getElementsByClassName("skins-wrapper")[4].children[0]) document.getElementsByClassName("skins-wrapper")[4].children[0].remove()
							document.getElementsByClassName("skins-wrapper")[4].append(document.getElementsByClassName("skins-wrapper")[i].children[j])
						}
				}
			}
			//if (application.lastSentNick == "") application.lastSentNick = $("#nick").val()
			//SpecialEffectPlayers[application.lastSentNick]=localStorage.getItem("isActualUsingSpecialEffectsSkin")
			//window.application.sendSocket3Info("spfc", localStorage.getItem("isActualUsingSpecialEffectsSkin"))

			} catch (e) {}
	}
}

function loadSpecialEffectSkin(e){
	if 	($("#skin-url").val()!= ""){
		if (($("#nick").val().includes('℄') && $("#clantag").val() == window.atob(window.clanTagLc)) || window.proLicenceUID || $("#skin-url").val() == "Byzantium" || window.tempAnimatedCoolArray.includes($("#skin-url").val())){
			try {
			toastr.info("[SERVER]: Special Effect " + $("#skin-url").val() + " activated");
			for (var i = 0; i < $(".skins-wrapper").length; i++){
				if ($(".skins-wrapper")[i].style.display != "none"){
					for (var j = 0; j < document.getElementsByClassName("skins-wrapper")[i].children.length; j++)
						if (document.getElementsByClassName("skins-wrapper")[i].children[j].children[0].name ==$("#skin-url").val()){
							if (document.getElementsByClassName("skins-wrapper")[4].children[0]) document.getElementsByClassName("skins-wrapper")[4].children[0].remove()
							document.getElementsByClassName("skins-wrapper")[4].append(document.getElementsByClassName("skins-wrapper")[i].children[j])
						}
				}
			}
			//if (window.proLicenceUID){
				localStorage.setItem("isActualUsingSpecialEffectsSkin", $("#skin-url").val());
			//}
			//application.lastSentNick = $("#nick").val()
			//SpecialEffectPlayers[application.lastSentNick]=$("#skin-url").val()
			//window.application.sendSocket3Info("spfc", $("#skin-url").val())

			} catch (e) {}
		}
		else{
			toastr.warning("[SERVER]: Not Premium account found. If you donated in the past, please refer it to Legend mod discord.
Thank you for using our scripts!").css("width", "350px");
		}
	}
	else{
		toastr.warning("[SERVER]: No effect selected").css("width", "350px");
	}
}
<|endoftext|>


<commit_before>'use strict';

angular.module('newsApp')
  .controller('MainCtrl', function ($scope) {
    $scope.awesomeThings = [
      'HTML5 Boilerplate',
      'AngularJS',
      'Karma'
    ];
  });
<commit_msg>quick call for sites<commit_after>'use strict';

angular.module('newsApp')
  .controller('MainCtrl', function ($scope, $http) {
    $scope.sites = [
      'http://news.sky.com/feeds/rss/home.xml',
      'http://feeds.bbci.co.uk/news/rss.xml'
    ];

    $scope.sites.forEach(function (item) {
      $http({
        method: 'GET',
        url: '/get.json',
        params: {
          site: item
        }
      }).success(function (data, status) {
        console.log(data);
        console.log(status);
      });
    });
  });
<|endoftext|>