<commit_before>/* Runs when the page finishes loading */
$(function() {
    //set css for the meme itself
    $('#meme-container').css(memeContainerCSS);
    $('#meme-text').css(memeTextCSS);
    $('#meme-image').css(memeImageCSS);

    $('#create_button').click(onClickCreate);
});

function onClickCreate() {
    var memeTextArea = document.getElementById('meme-text-input');
    var memeImageInput = document.getElementById('meme-image-input');
    var missingWarning = document.getElementById('missing-warning');

    //checks if both an image and text are present
    if(memeImageInput.files[0] && memeTextArea.value) {
        var memeImage = memeImageInput.files[0];
        var memeText = memeTextArea.value;
        missingWarning.style.display = "none";

        var reader = new FileReader();
        reader.onload = function () {
            createMemeAfterImageIsURI(memeText, reader);
        };
        reader.readAsDataURL(memeImage);
    }
    else {
         missingWarning.style.display = "block";
    }
}

function setMemeHTML(memeText, memeImageDataURI) {
    return new Promise(function (resolve, reject) {
        document.getElementById('meme-text').innerHTML = memeText;

        var imageContainer = document.getElementById('meme-image');
        imageContainer.onload = function() {
            $(imageContainer).css({"width" : "480px", "height": "auto"});
            resolve();
        };
        imageContainer.src = memeImageDataURI;
    });
}

function createMemeAfterImageIsURI(memeText, reader) {
    var memeImageDataURI = reader.result;
    var memeContainer = document.getElementById('meme-container');

    setMemeHTML(memeText, memeImageDataURI).then(function() {
        //get the size of the canvas
        var canvasWidth = Math.floor($(memeContainer).outerWidth());
        var canvasHeight = Math.floor($(memeContainer).outerHeight());

        //make canvas element
        var canvas = document.createElement("canvas");
        canvas.width = canvasWidth;
        canvas.height = canvasHeight;
        var ctx = canvas.getContext('2d');

        //paint background white to prevent png transparency
        ctx.fillStyle = 'white';
        ctx.fillRect(0, 0, canvasWidth, canvasHeight);

        /* Call dom2canvas with html we created */
        var htmlElement = memeContainer.cloneNode(true);
        htmlElement.style.display = "block";

        dom2canvas(htmlElement, canvas).then(function(canvas) {
            var memeSrc = canvas.toDataURL("image/jpeg");

            var downloadContent = document.getElementById('download-content');
            var downloadButton = document.getElementById('download-meme-button');
            var downloadMemeImage = document.getElementById('meme');

            downloadButton.href = memeSrc;
            downloadButton.download = 'meme_' + Date.now();
            downloadMemeImage.src = memeSrc;

            if(downloadContent.style.display == "none") {
                downloadContent.style.display = "block";
            }
        });
    });
}

var memeTextCSS = {"font-family" : "Helvetica Neue,Helvetica,Arial,sans-serif",
                "margin": "5px 10px 0px 10px",
                "font-size" : "28px",
                "line-height" : "30px",
                "font-weight" : "300",
                "letter-spacing" : ".01em",
                "color" : "#292f33",
                "width" : "480px"
            };

var memeImageCSS = {"border-radius": "5px",
                "margin": "10px auto",
                "position": "relative",
                "display" : "block",
                "overflow": "hidden",
                "vertical-align": "top"
            };

var memeContainerCSS = {"background-color" : "#fff",
                        "width" : "500px",
                        "overflow": "hidden"
                    };<commit_msg>Now processes image and text before 'create' is clicked.<commit_after>/* Runs when the page finishes loading */
$(function() {
    //set css for the meme itself
    $('#meme-container').css(memeContainerCSS);
    $('#meme-text').css(memeTextCSS);
    $('#meme-image').css(memeImageCSS);

    var imageURIPromise;
    $('#meme-text-input').focusout(onTextInputDone);
    $('#meme-image-input').change(function(event) {
        imageURIPromise = new Promise(function(resolve, reject) {
            onImageUploaded(resolve, reject, event);
        });
    });
    $('#create_button').click(function (event) {
        onClickCreate(imageURIPromise);
    });
});

function onTextInputDone(event) {
    document.getElementById('meme-text').innerHTML = event.target.value;
}

function onImageUploaded(resolve, reject, event) {
    var imageContainer = document.getElementById('meme-image');
    var reader = new FileReader();
    reader.onload = function () {
        imageContainer.onload = function() {
            resolve();
        };
        imageContainer.src = reader.result;
    };
    reader.readAsDataURL(event.target.files[0]);
}

function onClickCreate(imagePromise) {
    var memeTextArea = document.getElementById('meme-text-input');
    var memeImageInput = document.getElementById('meme-image-input');
    var missingWarning = document.getElementById('missing-warning');

    //checks if both an image and text are present
    if(memeImageInput.files[0] && memeTextArea.value) {
        missingWarning.style.display = "none";
        imagePromise.then(createMeme);
    }
    else {
         missingWarning.style.display = "block";
    }
}

function createMeme() {
    var memeContainer = document.getElementById('meme-container');

    //get the size of the canvas
    var canvasWidth = Math.floor($(memeContainer).outerWidth());
    var canvasHeight = Math.floor($(memeContainer).outerHeight());

    //make canvas element
    var canvas = document.createElement("canvas");
    canvas.width = canvasWidth;
    canvas.height = canvasHeight;
    var ctx = canvas.getContext('2d');

    //paint background white to prevent png transparency
    ctx.fillStyle = 'white';
    ctx.fillRect(0, 0, canvasWidth, canvasHeight);

    /* Call dom2canvas with html we created */
    var htmlElement = memeContainer.cloneNode(true);
    htmlElement.style.display = "block";

    dom2canvas(htmlElement, canvas).then(function(canvas) {
        var memeSrc = canvas.toDataURL("image/jpeg");

        var downloadContent = document.getElementById('download-content');
        var downloadButton = document.getElementById('download-meme-button');
        var downloadMemeImage = document.getElementById('meme');

        downloadButton.href = memeSrc;
        downloadButton.download = 'meme_' + Date.now();
        downloadMemeImage.src = memeSrc;

        if(downloadContent.style.display == "none") {
            downloadContent.style.display = "block";
        }
    });
}

var memeTextCSS = {"font-family" : "Helvetica Neue,Helvetica,Arial,sans-serif",
                "margin": "5px 10px 0px 10px",
                "font-size" : "28px",
                "line-height" : "30px",
                "font-weight" : "300",
                "letter-spacing" : ".01em",
                "color" : "#292f33",
                "width" : "480px"
            };

var memeImageCSS = {"border-radius": "5px",
                "margin": "10px auto",
                "position": "relative",
                "display" : "block",
                "overflow": "hidden",
                "vertical-align": "top",
                "width" : "480px",
                "height": "auto"
            };

var memeContainerCSS = {"background-color" : "#fff",
                        "width" : "500px",
                        "overflow": "hidden"
                    };<|endoftext|>


<commit_before>"use strict"; /*jslint indent: 2 */ /*globals $, _, EventEmitter */
// prereqs: underscore.js, jquery.js, EventEmitter
var Preloader = (function() {
  var el = function(tagName, attributes, opts) {
    /** el: create a new DOM element, using given tag and attributes.
    1. Appending each of `opts.children` [Node] as child nodes.
    2. Next, appending `opts.text` String as a text node.
    3. Finally, appending it to `opts.parent` Node if provided.
    */
    var element = document.createElement(tagName);
    // attributes is an object
    if (attributes) {
      for (var name in attributes) {
        element.setAttribute(name, attributes[name]);
      }
    }
    // text is a string
    if (opts) {
      if (opts.children) {
        for (var i = 0, l = opts.children.length; i < l; i++) {
          element.appendChild(opts.children[i]);
        }
      }
      if (opts.text) {
        var text_node = document.createTextNode(opts.text);
        element.appendChild(text_node);
      }
      if (opts.parent) {
        parent.appendChild(element);
      }
    }
    return element;
  };

  var templates = {
    video: function(c) {
      return '<video width="640" height="360" id="' + c.id + '" style="display: none" autobuffer preload="auto">' +
        '<source type="video/mp4" src="' + c.url + '">' +
      '</video>';
    },
    audio: function(c) {
      return '<audio id="' + c.id + '" style="display: none" autobuffer preload="auto">' +
        '<source src="' + c.url + '">' +
      '</audio>';
    },
    image: function(c) {
      return '';
    }
  };

  function diffs(xs) {
    /** returns a list of length (xs.length - 1), of the deltas between each pair of xs, e.g.:
    diffs([25, 10, 5, 2, 1]) = [15, 5, 3, 1]
    diffs([1, 2, 4, 8, 16, 32, 64]) = [-1, -2, -4, -8, -16, -32]
    Returns [] if xs is empty or has only one element.
    */
    var ys = [];
    for (var i = 0; i < xs.length - 1; i++) {
      ys.push(xs[i] - xs[i + 1]);
    }
    return ys;
  }

  function sum(xs) {
    var y = 0;
    for (var i = 0; i < xs.length; i++) y += xs[i];
    return y;
  }

  function time() {
    return (new Date()).getTime();
  }

  function guessType(url) {
    if (url.match(/\.(mp4|m4v)$/)) {
      return 'video';
    }
    else if (url.match(/\.(mp3|wav)$/)) {
      return 'audio';
    }
    else {
      return 'image';
    }
  }

  var Resource = function(url) {
    /** new Resource: preloads a url, guessing the type from the url.

    Resources do not know about other resources -- they aren't chained.

    emits 'error' if the resource 404s or times out.
    emits 'progress' periodically while the resource is loading with the current
        ratio of progress (between 0 and 1). It may emit multiple 'progress' events
        with the same value.
    emits 'finish' when the resource has completed preloading and is ready to display.
        when this is emitted, resource.complete will be true.
    */
    EventEmitter.call(this);
    this.url = url;
    this.id = url.replace(/\W/g, '');
    this.type = guessType(url); // one of 'video', 'audio', or 'image'
    this.$element = null;
    this.complete = false;
  };
  Resource.prototype = Object.create(EventEmitter.prototype);
  Resource.prototype.constructor = Resource;
  Resource.prototype.abort = function() {
    if (this.$element) {
      // only do the weird media cancellation hack for videos
      if (this.type == 'video') {
        this.$element.children('source').attr('src', '');
        var media = this.$element[0];
        if (media && media.load) media.load();
      }
      // abruptly and rudely remove the whole element from the dom.
      this.$element.remove();
      this.$element = null;
    }
  };
  Resource.prototype.insert = function(container, rush) {
    var self = this;
    var ctx = {url: this.url, id: this.id};
    var html = templates[this.type](ctx);

    // attach the element so we can detach it later in abort if needed
    this.$element = $(html).appendTo(container);
    var media = this.$element[0];
    var started = time();

    var done = function(err) {
      // like an internal callback
      if (err) {
        self.emit('error', err);
      }
      else {
        self.complete = true;
        self.emit('finish');
      }
    };

    // begin monitoring process, setting up a loop with varying timeouts
    var buffered_record = [];
    (function watch() {
      if (!self.$element) {
        // type: 'ElementError'
        return done(new Error('Resource aborted, element removed.'));
      }
      if (!media) {
        // type: 'MediaError'
        return done(new Error('Media cannot be found for the url.'));
      }

      var buffered_length = 0;
      var completed = 0;

      if (self.type == 'image') {
        if (media.complete) {
          completed = 1.0;
        }
      }
      else {
        if (media.buffered && media.buffered.length > 0) {
          buffered_length = media.buffered.end(0);
        }
        buffered_record.push(buffered_length);

        // media.duration might be NaN, probably when it hasn't loaded yet
        if (!isNaN(media.duration)) {
          completed = buffered_length / media.duration;
        }
      }

      var elapsed = time() - started;
      var last_10_diff_sum = sum(diffs(buffered_record.slice(-10)));
      self.emit('progress', completed);

      if (completed > 0.99) {
        // close enough, normal completion
        done();
      }
      else if (rush) {
        if (elapsed > Preloader.timeouts.rush && last_10_diff_sum < 1 && completed > 0.5) {
          // sometimes Chrome doesn't feel like loading the whole movie. Okay, fine.
          done();
        }
        else {
          setTimeout(watch, 250);
        }
      }
      else if (elapsed > Preloader.timeouts.zero && last_10_diff_sum < 1 && completed > 0.5) {
        // it seems that Chrome isn't ever going to preload the whole media
        done();
      }
      else if (elapsed > Preloader.timeouts.slow && buffered_length === 0) {
        // simply can't find it all, probably a 404
        done(new Error('Cannot find or load media.'));
      }
      else if (elapsed > Preloader.timeouts.slow && last_10_diff_sum < 0.01) {
        // give up
        done();
      }
      else if (elapsed > Preloader.timeouts.hard) {
        done();
      }
      else {
        setTimeout(watch, 250);
      }
    })();
  };
  Resource.prototype.ready = function(callback) {
    /** ready: call this when the resource finishes loading, or immediately,
    if it is already completely loaded.

    `callback`: function(Error | null)
    */
    if (this.complete) return callback();

    this.on('finish', callback);
  };

  var NullLogger = function() {};
  NullLogger.prototype.error = NullLogger.prototype.warn = NullLogger.prototype.info = NullLogger.prototype.debug = function() {};

  var Preloader = function(options) {
    /** new Preloader: create a new preloader helper, specifying where in the
    DOM it should put loading elements.

    Emits 'finish' events

    `options`: Object
        `container`: DOM Element Node (optional)
        `logger`: logging object (optional)
        `urls`: List of urls to preload (optional)
        `paused`: initial state (defaults to true)
    */
    EventEmitter.call(this);

    // this.resources is a list of Resource objects
    this.resources = [];

    // set option defaults
    var opts = _.extend({}, Preloader.defaults, options);
    // container may be null, but the default won't be created until one is needed
    this.container = opts.container;
    this.logger = opts.logger;
    this.paused = opts.paused;

    if (opts.urls) {
      this.add.apply(this, opts.urls);
    }
  };
  Preloader.defaults = {
    logger: new NullLogger(),
    paused: true
  };
  Preloader.timeouts = {
    // in seconds
    rush: 2000,
    zero: 5000,
    slow: 20000,
    hard: 50000
  };
  Preloader.prototype = Object.create(EventEmitter.prototype);
  Preloader.prototype.constructor = Preloader;
  Preloader.prototype.getContainer = function() {
    if (this.container === undefined) {
      // if no container is provided, create new node at the end of the document to hold the elements.
      this.container = el('div', {style: "display: none"}, {parent: document.body});
    }
    return this.container;
  };
  Preloader.prototype.setContainer = function(container) {
    if (this.container) {
      // first move over children from the current container
      while (this.container.firstChild) {
        container.appendChild(this.container.firstChild);
      }
    }
    this.container = container;
  };
  Preloader.prototype.add = function(url1 /*, url2, ...*/) {
    // each url, on loading, will be stuck in the dom, in a hidden div.
    // keyed by their santized urls as element ids, i.e. url.replace(/\W/g, '')
    var urls = Array.prototype.slice.call(arguments, 0);
    this.logger.debug('Preloader.add: adding', urls.length, 'urls:', urls);
    for (var i = 0, l = urls.length; i < l; i++) {
      var url = urls[i];
      if (!this.findResource(url)) {
        this.resources.push(new Resource(url));
      }
    }
    this.loop();
  };
  Preloader.prototype.findResource = function(url) {
    for (var i = 0, l = this.resources.length; i < l; i++) {
      if (this.resources[i].url == url) {
        return this.resources[i];
      }
    }
  };
  Preloader.prototype.currentResource = function() {
    /** currentResource: iterate through resources and return the first one that is not complete.
    The returned resource may not have even started.
    Returns null when all resources have already been loaded.
    */
    for (var i = 0, l = this.resources.length; i < l; i++) {
      var resource = this.resources[i];
      if (!resource.complete) {
        return resource;
      }
    }
  };
  Preloader.prototype.pause = function() {
    /** pause: pause the preloader, but don't abort the current load */
    this.logger.debug('Preloader.pause');
    this.paused = true;
  };
  Preloader.prototype.abort = function() {
    /** abort: pause the preloader and abort the current load */
    this.logger.debug('Preloader.abort');
    // if we haven't loaded everything yet, find the current resource and abort it
    var current_resource = this.currentResource();
    if (current_resource) current_resource.abort();
  };
  Preloader.prototype.resume = function() {
    this.logger.debug('Preloader.resume (was previously ' + (this.paused ? '' : 'not ') + 'paused)');
    this.paused = false;
    this.loop();
  };
  Preloader.prototype.loop = function() {
    // this can be called multiple times without ill effect
    if (this.paused) {
      return this.logger.debug('Preloader.loop (paused)');
    }

    var current_resource = this.currentResource();
    if (!current_resource) {
      this.emit('finish');
      this.logger.debug('Preloader.loop (no more resources)');
      return;
    }

    if (current_resource.$element) {
      this.logger.debug('Preloader.loop (in-progress: ' + current_resource.url + ')');
    }
    else {
      var self = this;
      current_resource.insert(this.getContainer(), false);
      this.logger.debug('Preloader.loop (inserted: ' + current_resource.url + ')');
      current_resource.ready(function(err) {
        if (err) self.logger.error('Resource error: ' + err.toString());
        self.loop();
      });
    }
  };
  Preloader.prototype.load = function(url, callback) {
    /** preloader.load(): look for the resource with the given url in the
    existing resources, or add it if it does not already exist.

    Does not abort any other resource load that might be going on.

    `url`: String
    `callback`: function(Error | null, jQuery element | null)
    */
    this.logger.debug('Preloader.load: url=', url);
    var resource = this.findResource(url);
    var self = this;

    if (!resource) {
      resource = new Resource(url);
      this.resources.push(resource);
    }

    if (!resource.$element) {
      // rush: true
      resource.insert(this.getContainer(), true);
    }
    resource.ready(function(err) {
      if (err) self.logger.error('Resource error: ' + err);
      callback(err, resource.$element);
    });
    return resource;
  };

  return Preloader;
})();
<commit_msg>Let more things be movies and let the browser figure out which kind (works in Firefox/Chrome just fine(<commit_after>"use strict"; /*jslint indent: 2 */ /*globals $, _, EventEmitter */
// prereqs: underscore.js, jquery.js, EventEmitter
var Preloader = (function() {
  var el = function(tagName, attributes, opts) {
    /** el: create a new DOM element, using given tag and attributes.
    1. Appending each of `opts.children` [Node] as child nodes.
    2. Next, appending `opts.text` String as a text node.
    3. Finally, appending it to `opts.parent` Node if provided.
    */
    var element = document.createElement(tagName);
    // attributes is an object
    if (attributes) {
      for (var name in attributes) {
        element.setAttribute(name, attributes[name]);
      }
    }
    // text is a string
    if (opts) {
      if (opts.children) {
        for (var i = 0, l = opts.children.length; i < l; i++) {
          element.appendChild(opts.children[i]);
        }
      }
      if (opts.text) {
        var text_node = document.createTextNode(opts.text);
        element.appendChild(text_node);
      }
      if (opts.parent) {
        parent.appendChild(element);
      }
    }
    return element;
  };

  var templates = {
    video: function(c) {
      return '<video id="' + c.id + '" style="display: none" autobuffer preload="auto">' +
        '<source src="' + c.url + '">' +
      '</video>';
    },
    audio: function(c) {
      return '<audio id="' + c.id + '" style="display: none" autobuffer preload="auto">' +
        '<source src="' + c.url + '">' +
      '</audio>';
    },
    image: function(c) {
      return '';
    }
  };

  function diffs(xs) {
    /** returns a list of length (xs.length - 1), of the deltas between each pair of xs, e.g.:
    diffs([25, 10, 5, 2, 1]) = [15, 5, 3, 1]
    diffs([1, 2, 4, 8, 16, 32, 64]) = [-1, -2, -4, -8, -16, -32]
    Returns [] if xs is empty or has only one element.
    */
    var ys = [];
    for (var i = 0; i < xs.length - 1; i++) {
      ys.push(xs[i] - xs[i + 1]);
    }
    return ys;
  }

  function sum(xs) {
    var y = 0;
    for (var i = 0; i < xs.length; i++) y += xs[i];
    return y;
  }

  function time() {
    return (new Date()).getTime();
  }

  function guessType(url) {
    if (url.match(/\.(mp4|m4v|mpg|webm)$/)) {
      return 'video';
    }
    else if (url.match(/\.(mp3|wav)$/)) {
      return 'audio';
    }
    else {
      return 'image';
    }
  }

  var Resource = function(url) {
    /** new Resource: preloads a url, guessing the type from the url.

    Resources do not know about other resources -- they aren't chained.

    emits 'error' if the resource 404s or times out.
    emits 'progress' periodically while the resource is loading with the current
        ratio of progress (between 0 and 1). It may emit multiple 'progress' events
        with the same value.
    emits 'finish' when the resource has completed preloading and is ready to display.
        when this is emitted, resource.complete will be true.
    */
    EventEmitter.call(this);
    this.url = url;
    this.id = url.replace(/\W/g, '');
    this.type = guessType(url); // one of 'video', 'audio', or 'image'
    this.$element = null;
    this.complete = false;
  };
  Resource.prototype = Object.create(EventEmitter.prototype);
  Resource.prototype.constructor = Resource;
  Resource.prototype.abort = function() {
    if (this.$element) {
      // only do the weird media cancellation hack for videos
      if (this.type == 'video') {
        this.$element.children('source').attr('src', '');
        var media = this.$element[0];
        if (media && media.load) media.load();
      }
      // abruptly and rudely remove the whole element from the dom.
      this.$element.remove();
      this.$element = null;
    }
  };
  Resource.prototype.insert = function(container, rush) {
    var self = this;
    var ctx = {url: this.url, id: this.id};
    var html = templates[this.type](ctx);

    // attach the element so we can detach it later in abort if needed
    this.$element = $(html).appendTo(container);
    var media = this.$element[0];
    var started = time();

    var done = function(err) {
      // like an internal callback
      if (err) {
        self.emit('error', err);
      }
      else {
        self.complete = true;
        self.emit('finish');
      }
    };

    // begin monitoring process, setting up a loop with varying timeouts
    var buffered_record = [];
    (function watch() {
      if (!self.$element) {
        // type: 'ElementError'
        return done(new Error('Resource aborted, element removed.'));
      }
      if (!media) {
        // type: 'MediaError'
        return done(new Error('Media cannot be found for the url.'));
      }

      var buffered_length = 0;
      var completed = 0;

      if (self.type == 'image') {
        if (media.complete) {
          completed = 1.0;
        }
      }
      else {
        if (media.buffered && media.buffered.length > 0) {
          buffered_length = media.buffered.end(0);
        }
        buffered_record.push(buffered_length);

        // media.duration might be NaN, probably when it hasn't loaded yet
        if (!isNaN(media.duration)) {
          completed = buffered_length / media.duration;
        }
      }

      var elapsed = time() - started;
      var last_10_diff_sum = sum(diffs(buffered_record.slice(-10)));
      self.emit('progress', completed);

      if (completed > 0.99) {
        // close enough, normal completion
        done();
      }
      else if (rush) {
        if (elapsed > Preloader.timeouts.rush && last_10_diff_sum < 1 && completed > 0.5) {
          // sometimes Chrome doesn't feel like loading the whole movie. Okay, fine.
          done();
        }
        else {
          setTimeout(watch, 250);
        }
      }
      else if (elapsed > Preloader.timeouts.zero && last_10_diff_sum < 1 && completed > 0.5) {
        // it seems that Chrome isn't ever going to preload the whole media
        done();
      }
      else if (elapsed > Preloader.timeouts.slow && buffered_length === 0) {
        // simply can't find it all, probably a 404
        done(new Error('Cannot find or load media.'));
      }
      else if (elapsed > Preloader.timeouts.slow && last_10_diff_sum < 0.01) {
        // give up
        done();
      }
      else if (elapsed > Preloader.timeouts.hard) {
        done();
      }
      else {
        setTimeout(watch, 250);
      }
    })();
  };
  Resource.prototype.ready = function(callback) {
    /** ready: call this when the resource finishes loading, or immediately,
    if it is already completely loaded.

    `callback`: function(Error | null)
    */
    if (this.complete) return callback();

    this.on('finish', callback);
  };

  var NullLogger = function() {};
  NullLogger.prototype.error = NullLogger.prototype.warn = NullLogger.prototype.info = NullLogger.prototype.debug = function() {};

  var Preloader = function(options) {
    /** new Preloader: create a new preloader helper, specifying where in the
    DOM it should put loading elements.

    Emits 'finish' events

    `options`: Object
        `container`: DOM Element Node (optional)
        `logger`: logging object (optional)
        `urls`: List of urls to preload (optional)
        `paused`: initial state (defaults to true)
    */
    EventEmitter.call(this);

    // this.resources is a list of Resource objects
    this.resources = [];

    // set option defaults
    var opts = _.extend({}, Preloader.defaults, options);
    // container may be null, but the default won't be created until one is needed
    this.container = opts.container;
    this.logger = opts.logger;
    this.paused = opts.paused;

    if (opts.urls) {
      this.add.apply(this, opts.urls);
    }
  };
  Preloader.defaults = {
    logger: new NullLogger(),
    paused: true
  };
  Preloader.timeouts = {
    // in seconds
    rush: 2000,
    zero: 5000,
    slow: 20000,
    hard: 50000
  };
  Preloader.prototype = Object.create(EventEmitter.prototype);
  Preloader.prototype.constructor = Preloader;
  Preloader.prototype.getContainer = function() {
    if (this.container === undefined) {
      // if no container is provided, create new node at the end of the document to hold the elements.
      this.container = el('div', {style: "display: none"}, {parent: document.body});
    }
    return this.container;
  };
  Preloader.prototype.setContainer = function(container) {
    if (this.container) {
      // first move over children from the current container
      while (this.container.firstChild) {
        container.appendChild(this.container.firstChild);
      }
    }
    this.container = container;
  };
  Preloader.prototype.add = function(url1 /*, url2, ...*/) {
    // each url, on loading, will be stuck in the dom, in a hidden div.
    // keyed by their santized urls as element ids, i.e. url.replace(/\W/g, '')
    var urls = Array.prototype.slice.call(arguments, 0);
    this.logger.debug('Preloader.add: adding', urls.length, 'urls:', urls);
    for (var i = 0, l = urls.length; i < l; i++) {
      var url = urls[i];
      if (!this.findResource(url)) {
        this.resources.push(new Resource(url));
      }
    }
    this.loop();
  };
  Preloader.prototype.findResource = function(url) {
    for (var i = 0, l = this.resources.length; i < l; i++) {
      if (this.resources[i].url == url) {
        return this.resources[i];
      }
    }
  };
  Preloader.prototype.currentResource = function() {
    /** currentResource: iterate through resources and return the first one that is not complete.
    The returned resource may not have even started.
    Returns null when all resources have already been loaded.
    */
    for (var i = 0, l = this.resources.length; i < l; i++) {
      var resource = this.resources[i];
      if (!resource.complete) {
        return resource;
      }
    }
  };
  Preloader.prototype.pause = function() {
    /** pause: pause the preloader, but don't abort the current load */
    this.logger.debug('Preloader.pause');
    this.paused = true;
  };
  Preloader.prototype.abort = function() {
    /** abort: pause the preloader and abort the current load */
    this.logger.debug('Preloader.abort');
    // if we haven't loaded everything yet, find the current resource and abort it
    var current_resource = this.currentResource();
    if (current_resource) current_resource.abort();
  };
  Preloader.prototype.resume = function() {
    this.logger.debug('Preloader.resume (was previously ' + (this.paused ? '' : 'not ') + 'paused)');
    this.paused = false;
    this.loop();
  };
  Preloader.prototype.loop = function() {
    // this can be called multiple times without ill effect
    if (this.paused) {
      return this.logger.debug('Preloader.loop (paused)');
    }

    var current_resource = this.currentResource();
    if (!current_resource) {
      this.emit('finish');
      this.logger.debug('Preloader.loop (no more resources)');
      return;
    }

    if (current_resource.$element) {
      this.logger.debug('Preloader.loop (in-progress: ' + current_resource.url + ')');
    }
    else {
      var self = this;
      current_resource.insert(this.getContainer(), false);
      this.logger.debug('Preloader.loop (inserted: ' + current_resource.url + ')');
      current_resource.ready(function(err) {
        if (err) self.logger.error('Resource error: ' + err.toString());
        self.loop();
      });
    }
  };
  Preloader.prototype.load = function(url, callback) {
    /** preloader.load(): look for the resource with the given url in the
    existing resources, or add it if it does not already exist.

    Does not abort any other resource load that might be going on.

    `url`: String
    `callback`: function(Error | null, jQuery element | null)
    */
    this.logger.debug('Preloader.load: url=', url);
    var resource = this.findResource(url);
    var self = this;

    if (!resource) {
      resource = new Resource(url);
      this.resources.push(resource);
    }

    if (!resource.$element) {
      // rush: true
      resource.insert(this.getContainer(), true);
    }
    resource.ready(function(err) {
      if (err) self.logger.error('Resource error: ' + err);
      callback(err, resource.$element);
    });
    return resource;
  };

  return Preloader;
})();
<|endoftext|>


<commit_before>function genUni() {
	var code = prompt("Generate Unicode Character:");
	$('#code').val($('#code').val() + String.fromCharCode(parseInt(code)));
	updateByteCount();
};

function getByteCount(s) {
	return s.length;
}

function t(s){for(var i=0;i<s.length;i++){console.log(s.charCodeAt(i));}}

function updateByteCount() {
	var c = $('#code').val();
	var byteCount = getByteCount(c);
	var charCount = c.length;
	var s = byteCount + " bytes and " + charCount + " chars long.";
	$('#byteCount').html(s);
}

function getStrippedCode() {
	var stripped = $('#code').val();
	$('#stripped').html(
			'Stripped code: ' + stripped + ' Byte count: '
					+ getByteCount(stripped));
}

var string = false;
var codeBlock = false;

function getExplanation() {
	$('#explanation').html('');
	var code = $('#code').val();
	for (var x = 0, c = ''; c = code.charAt(x); x++) {
        if(c === '"') {
            string = !string;
        }
        else if(c === '`') {
            codeBlock = !codeBlock;
        }
		var original = $('#explanation').html();
		$('#explanation').html(
				original
						+ " "
                        + codeBlock?'    ':''
                        + string?'':explanations[c.charCodeAt()]
								+ "\r\n");
	}

}

function updateUtils() {
	updateByteCount();
	getStrippedCode();
	getExplanation();
}

updateUtils();

$(document).ready(
		function() {
			$("#permalink").click(
					function() {
						var code = $.param({
							code : $('#code').val(),
							input : $('#input').val()
						});
						prompt("Permalink:", "http://"
								+ window.location.hostname + "/link/" + code);
						window.location.pathname = "/link/" + code;
					});
			$('#code').on('input propertychange paste', function() {
				updateUtils();
			});
		});<commit_msg>fix explanations?<commit_after>function genUni() {
	var code = prompt("Generate Unicode Character:");
	$('#code').val($('#code').val() + String.fromCharCode(parseInt(code)));
	updateByteCount();
};

function getByteCount(s) {
    var count = 0, stringLength = s.length;
    s = String(s || "");
    for (var i = 0; i < stringLength; i++) {
        var partCount = encodeURI(s[i]).split("%").length;
        count += partCount == 1 ? 1 : partCount - 1;
    }
    return count;
}

function t(s){for(var i=0;i<s.length;i++){console.log(s.charCodeAt(i));}}

function updateByteCount() {
	var c = $('#code').val();
	var byteCount = getByteCount(c);
	var charCount = c.length;
	var s = byteCount + " bytes and " + charCount + " chars long.";
	$('#byteCount').html(s);
}

function getStrippedCode() {
	var stripped = $('#code').val();
	$('#stripped').html(
			'Stripped code: ' + stripped + ' Byte count: '
					+ getByteCount(stripped));
}

var string = false;
var codeBlock = false;

function getExplanation() {
	$('#explanation').html('');
	var code = $('#code').val();
    var explain = '';
    var indent = '   ';
	for (var x = 0, c = ''; c = code.charAt(x); x++) {
        if(c === '"') {
            string = !string;
        } else if(c === '`') {
            codeBlock = !codeBlock;
        }
        if(string) {
            explain = '';
        } else {
            explain = explanations[c.charCodeAt()]
        }
        if(codeBlock) {
            indent = '    ';
        } else {
            indent = '';
        }
		var original = $('#explanation').html();
		$('#explanation').html(
				original
						+ " "
                        + indent
                        + explain
								+ "\r\n");
	}

}

function updateUtils() {
	updateByteCount();
	getStrippedCode();
	getExplanation();
}

updateUtils();

$(document).ready(
		function() {
			$("#permalink").click(
					function() {
						var code = $.param({
							code : $('#code').val(),
							input : $('#input').val()
						});
						prompt("Permalink:", "http://"
								+ window.location.hostname + "/link/" + code);
						window.location.pathname = "/link/" + code;
					});
			$('#code').on('input propertychange paste', function() {
				updateUtils();
			});
		});<|endoftext|>


<commit_before>//from adapter.js
/*global RTCPeerConnection getUserMedia attachMediaStream
  reattachMediaStream webrtcDetectedBrowser webrtcDetectedVersion
  RTCSessionDescription RTCIceCandidate*/

"use strict";

var chatphraseIceServers = [
  {"url": "stun:stun.vline.com"}
  ,{"url": "stun:stun.l.google.com:19302"}
  ,{
      url: 'turn:numb.viagenie.ca',
      username: 'ice@chatphrase.com',
      credential: 'yovipletskickit'
  }
];

// The base of the URLs to check the initial offers from.
var chatphraseOffersBase = "/signal/offers/";

//phrase: the slugified phrase to connect to.
//cbs: The callbacks to send to the UI/system on various events/hooks.
function chatphraseSignaling (slugPhrase, cbs) {
  cbs = cbs || {};
  var iface = {
    on: cbs
  };

  function xhrPostJson(url, body, cb, opts) {
    opts = opts || {};
    var rq = new XMLHttpRequest();
    rq.onreadystatechange = function () {
      if (rq.readyState == 4) {
        return cb(rq.status, rq.responseText,
          rq.getResponseHeader('Location'));
      }
    };
    rq.onerror = function(e){cb(null,e)};
    rq.open("POST", url);
    if (opts.timeout) {
      rq.timeout = opts.timeout;
      rq.ontimeout = opts.ontimeout;
    }
    // NOTE: the type is text/json and not application/json because I'm
    // too lazy and paranoid to do things right on the server.
    // (It's currently only designed to parse the body when it's a
    // text/ type... eek.)
    // This should be fixed at some point down the line, for instance,
    // once caress is updated with Content-Type saving.
    rq.setRequestHeader("Content-Type", "text/json; charset=utf-8");
    rq.send(JSON.stringify(body));
  }

  function xhrGetJson(url, cb, opts) {
    opts = opts || {};
    var rq = new XMLHttpRequest();
    function handleEnd() {
    }
    rq.onreadystatechange = function () {
      if (rq.readyState == 4) {
        var body;
        try {
          body = JSON.parse(rq.responseText);
        } catch(e) {
          body = rq.responseText;
        }
        return cb(rq.status, body,
          rq.getResponseHeader('Location'), rq.getResponseHeader('Etag'));
      }
    };
    rq.onerror = function(e){cb(null,e)};
    rq.open("GET", url);
    if (opts.timeout) {
      rq.timeout = opts.timeout;
      rq.ontimeout = opts.ontimeout;
    }
    if (opts.ourtag){
      rq.setRequestHeader("If-None-Match", opts.ourtag);
    }
    rq.send();
  }

  // The RTCPeerConnection.
  var pc;
  // The path we GET to listen on / POST updates to.
  var signalPath;
  // The index of the current message we're asking for.
  var pollPoint = 0;
  // The local stream, for restarting.
  var localStream;

  //stream: the stream object from getUserMedia.
  iface.start = function start(stream) {

    if (stream) localStream = stream;

    // Re-initialize our outside state variables
    signalPath = undefined;

    pc = new RTCPeerConnection({
      "iceServers": chatphraseIceServers},

      // DTLS-SRTP is required by the current WebRTC standard.
      // Versions of Chrome before 31 don't do DTLS-SRTP by default
      // (due to an inefficient certificate generation scheme or something),
      // so you need to explicitly request it to be able to interoperate
      // with other implementations (like Firefox).

      // This is less relevant since Chrome 31 went stable in
      // mid-November 2013, but it doesn't hurt anything to keep it around,
      // at least for a while.
      {optional:[{DtlsSrtpKeyAgreement: true}]});

    // Add our stream to the connection
    pc.addStream(localStream);

    // Add a listener for the stream from the other end
    pc.onaddstream = onAddStream;

    // Add our ICE listener
    pc.onicecandidate = onIceCandidate;

    getOffer();
  };

  function getOffer() {
    var endpoint = chatphraseOffersBase + slugPhrase;

    xhrGetJson(endpoint, beginConnection);

    function beginConnection(status,body,location) {
      if (status == 200) {

        // mark that we've got the initial content, and will want to start
        // asking for ICE messages
        ++pollPoint;

        // Set the remote offer and move on to answer it back
        pc.setRemoteDescription(new RTCSessionDescription(body),
          answerOffer(location), onError);
      // If there's no current offer
      } else if (status == 404) {
        // Create the offer
        pc.createOffer(setLocalAndPost(endpoint), onError, {
          mandatory: {
            OfferToReceiveAudio: true,
            OfferToReceiveVideo: true },
          optional: []});
      } else if(status) {
        onError(new Error(
          "Got status "+status+" from "+endpoint+": "+body));
      } else {
        onError(body);
      }
    }
  }

  function answerOffer(location) {
    return function(){
      pc.createAnswer(setLocalAndPost(location), onError, {
        mandatory: {},
        optional: []});
    };
  }

  function setLocalAndPost(location) {
    return function(desc) {
      pc.setLocalDescription(desc, function(){
        xhrPostJson(location, desc, continueFromPost, onError);
      }, onError);
    };
  }

  function continueFromPost(status, body, location) {

    function poll() {
      // continue polling
      xhrGetJson(location + '/' + pollPoint + '?side=down', respondToPoll);
    }

    // Ignore the "nulLocation" parameter, we never expect to get it.
    function respondToPoll(status, body, nulLocation, etag) {

      //if there's no change or no body yet
      if (status == 204 || status == 304) {
        //continue polling
        poll();

      // if there's a new body
      } else if (status == 200) {
        // If we've been awaiting the initial remote description
        if (pollPoint == 0) {
          // update our peerconnection with the new remote description,
          // then continue polling
          ++pollPoint;
          return pc.setRemoteDescription(new RTCSessionDescription(body),
            poll, onError);
        // If we're waiting for ICE candidate updates
        } else {
          // Advance the poll position to the next item
          ++pollPoint;
          // If this is an ICE candidate and not the message saying that the
          // candidates have finished
          if (body) {
            // Add the ICE candidate and continue polling for the next one

            // TODO: Fix this to use callbacks once
            // https://code.google.com/p/webrtc/issues/detail?id=2338
            // is fixed (*shakes fist at Google*)
            pc.addIceCandidate(new RTCIceCandidate(body));
            return poll();

          // If the message was "null", that's our cue to stop polling, we're
          // not going to get any more messages.
          } else {

            // Nonetheless, we're going to keep polling for now, because our
            // GET calls are the heartbeats that refresh the TTL on our OWN
            // POST endpoint due to the way caress is currently configured.
            // This could be fixed to be less dysfunctional down the line:
            // it'll probably happen after caress is updated to use Lua scripts
            // for transactions.
            return poll();
          }
        }

      // if the body is gone (not found, because we don't special-case them)
      } else if (status == 404) {
        // fire the event for that
        return cbs.remoteSignalLost && cbs.remoteSignalLost();

      // if there was some unexpected status
      } else if (status) {
        // report it as an error
        return onError(new Error (
          "Got status " + status + " while polling " + location
            + ": " + body));

      // if there was an error in the XHR (no status)
      } else {
        // report it
        return onError(body);
      }
    }

    // If the signal endpoint was created
    if (status == 201) {
      // Export the path we've just been given for POSTing updates to
      signalPath = location;
      // Start polling
      return poll();

    // If we're colliding or the endpoint is missing
    // (the endpoint goes missing when someone else answers an offer first)
    } else if (status == 303 || status == 404) {
      // Re-get the offer
      return getOffer();

    } else if (status) {
      return onError(new Error (
        "Got status " + status + " posting session: " + body));

    } else {
      return onError(body);
    }

  }

  function onError(err) {
    return cbs.error && cbs.error(err);
  }

  function onAddStream(evt) {
    return cbs.remoteStream && cbs.remoteStream(evt.stream);
  }

  function onIceCandidate(evt) {
    //if the server is ready to receive our updates
    if (signalPath) {
      // Update our session description with the new ICE candidates
      xhrPostJson(signalPath+'?side=up', evt.candidate,
        function (status,body) {
          if (!status) {
            onError(body);
          } else if (status >= 500) {
            onError(new Error(
              'Got status ' + status + ' updating SDP: ' + body));
          }
        });
    }
  }

  return iface;
}<commit_msg>Queue candidate messages when waiting for a response<commit_after>//from adapter.js
/*global RTCPeerConnection getUserMedia attachMediaStream
  reattachMediaStream webrtcDetectedBrowser webrtcDetectedVersion
  RTCSessionDescription RTCIceCandidate*/

"use strict";

var chatphraseIceServers = [
  {"url": "stun:stun.vline.com"}
  ,{"url": "stun:stun.l.google.com:19302"}
  ,{
      url: 'turn:numb.viagenie.ca',
      username: 'ice@chatphrase.com',
      credential: 'yovipletskickit'
  }
];

// The base of the URLs to check the initial offers from.
var chatphraseOffersBase = "/signal/offers/";

//phrase: the slugified phrase to connect to.
//cbs: The callbacks to send to the UI/system on various events/hooks.
function chatphraseSignaling (slugPhrase, cbs) {
  cbs = cbs || {};
  var iface = {
    on: cbs
  };

  function xhrPostJson(url, body, cb, opts) {
    opts = opts || {};
    var rq = new XMLHttpRequest();
    rq.onreadystatechange = function () {
      if (rq.readyState == 4) {
        return cb(rq.status, rq.responseText,
          rq.getResponseHeader('Location'));
      }
    };
    rq.onerror = function(e){cb(null,e)};
    rq.open("POST", url);
    if (opts.timeout) {
      rq.timeout = opts.timeout;
      rq.ontimeout = opts.ontimeout;
    }
    // NOTE: the type is text/json and not application/json because I'm
    // too lazy and paranoid to do things right on the server.
    // (It's currently only designed to parse the body when it's a
    // text/ type... eek.)
    // This should be fixed at some point down the line, for instance,
    // once caress is updated with Content-Type saving.
    rq.setRequestHeader("Content-Type", "text/json; charset=utf-8");
    rq.send(JSON.stringify(body));
  }

  function xhrGetJson(url, cb, opts) {
    opts = opts || {};
    var rq = new XMLHttpRequest();
    function handleEnd() {
    }
    rq.onreadystatechange = function () {
      if (rq.readyState == 4) {
        var body;
        try {
          body = JSON.parse(rq.responseText);
        } catch(e) {
          body = rq.responseText;
        }
        return cb(rq.status, body,
          rq.getResponseHeader('Location'), rq.getResponseHeader('Etag'));
      }
    };
    rq.onerror = function(e){cb(null,e)};
    rq.open("GET", url);
    if (opts.timeout) {
      rq.timeout = opts.timeout;
      rq.ontimeout = opts.ontimeout;
    }
    if (opts.ourtag){
      rq.setRequestHeader("If-None-Match", opts.ourtag);
    }
    rq.send();
  }

  // The RTCPeerConnection.
  var pc;
  // The path we GET to listen on / POST updates to.
  var signalPath;
  // Queued ICE candidates to send.
  var localIceQueue = [];
  // Whether we're currently draining the ICE queue
  // (for concurrency control purposes).
  var drainingIceQueue = false;
  // The index of the current message we're asking for.
  var pollPoint = 0;
  // The local stream, for restarting.
  var localStream;

  //stream: the stream object from getUserMedia.
  iface.start = function start(stream) {

    // TODO: destroy existing PeerConnection, if any

    if (stream) localStream = stream;

    // Reinitialize our outside state variables
    signalPath = undefined;
    pollPoint = 0;
    localIceQueue.length = 0;
    drainingIceQueue = false;

    pc = new RTCPeerConnection({
      "iceServers": chatphraseIceServers},

      // DTLS-SRTP is required by the current WebRTC standard.
      // Versions of Chrome before 31 don't do DTLS-SRTP by default
      // (due to an inefficient certificate generation scheme or something),
      // so you need to explicitly request it to be able to interoperate
      // with other implementations (like Firefox).

      // This is less relevant since Chrome 31 went stable in
      // mid-November 2013, but it doesn't hurt anything to keep it around,
      // at least for a while.
      {optional:[{DtlsSrtpKeyAgreement: true}]});

    // Add our stream to the connection
    pc.addStream(localStream);

    // Add a listener for the stream from the other end
    pc.onaddstream = onAddStream;

    // Add our ICE listener
    pc.onicecandidate = onIceCandidate;

    getOffer();
  };

  function getOffer() {
    var endpoint = chatphraseOffersBase + slugPhrase;

    xhrGetJson(endpoint, beginConnection);

    function beginConnection(status,body,location) {
      if (status == 200) {

        // mark that we've got the initial content, and will want to start
        // asking for ICE messages
        ++pollPoint;

        // Set the remote offer and move on to answer it back
        pc.setRemoteDescription(new RTCSessionDescription(body),
          answerOffer(location), onError);
      // If there's no current offer
      } else if (status == 404) {
        // Create the offer
        pc.createOffer(setLocalAndPost(endpoint), onError, {
          mandatory: {
            OfferToReceiveAudio: true,
            OfferToReceiveVideo: true },
          optional: []});
      } else if(status) {
        onError(new Error(
          "Got status "+status+" from "+endpoint+": "+body));
      } else {
        onError(body);
      }
    }
  }

  function answerOffer(location) {
    return function(){
      pc.createAnswer(setLocalAndPost(location), onError, {
        mandatory: {},
        optional: []});
    };
  }

  function setLocalAndPost(location) {
    return function(desc) {
      pc.setLocalDescription(desc, function(){
        xhrPostJson(location, desc, continueFromPost, onError);
      }, onError);
    };
  }

  function continueFromPost(status, body, location) {

    function poll() {
      // continue polling
      xhrGetJson(location + '/' + pollPoint + '?side=down', respondToPoll);
    }

    // Ignore the "nulLocation" parameter, we never expect to get it.
    function respondToPoll(status, body, nulLocation, etag) {

      //if there's no change or no body yet
      if (status == 204 || status == 304) {
        //continue polling
        poll();

      // if there's a new body
      } else if (status == 200) {
        // If we've been awaiting the initial remote description
        if (pollPoint == 0) {
          // update our peerconnection with the new remote description,
          // then continue polling
          ++pollPoint;
          return pc.setRemoteDescription(new RTCSessionDescription(body),
            poll, onError);
        // If we're waiting for ICE candidate updates
        } else {
          // Advance the poll position to the next item
          ++pollPoint;
          // If this is an ICE candidate and not the message saying that the
          // candidates have finished
          if (body) {
            // Add the ICE candidate and continue polling for the next one

            // TODO: Fix this to use callbacks once
            // https://code.google.com/p/webrtc/issues/detail?id=2338
            // is fixed (*shakes fist at Google*)
            pc.addIceCandidate(new RTCIceCandidate(body));
            return poll();

          // If the message was "null", that's our cue to stop polling, we're
          // not going to get any more messages.
          } else {

            // Nonetheless, we're going to keep polling for now, because our
            // GET calls are the heartbeats that refresh the TTL on our OWN
            // POST endpoint due to the way caress is currently configured.
            // This could be fixed to be less dysfunctional down the line:
            // it'll probably happen after caress is updated to use Lua scripts
            // for transactions.
            return poll();
          }
        }

      // if the body is gone (not found, because we don't special-case them)
      } else if (status == 404) {
        // fire the event for that
        return cbs.remoteSignalLost && cbs.remoteSignalLost();

      // if there was some unexpected status
      } else if (status) {
        // report it as an error
        return onError(new Error (
          "Got status " + status + " while polling " + location
            + ": " + body));

      // if there was an error in the XHR (no status)
      } else {
        // report it
        return onError(body);
      }
    }

    // If the signal endpoint was created
    if (status == 201) {
      // Export the path we've just been given for POSTing updates to
      signalPath = location;

      // Unless we've somehow already started sending our queued candidates
      // before this point (if that's even possible)
      if (!drainingIceQueue) {
        // POST any updates we've queued up
        drainIceQueue();
      }

      // Start polling
      return poll();

    // If we're colliding or the endpoint is missing
    // (the endpoint goes missing when someone else answers an offer first)
    } else if (status == 303 || status == 404) {
      // Re-get the offer
      return getOffer();

    } else if (status) {
      return onError(new Error (
        "Got status " + status + " posting session: " + body));

    } else {
      return onError(body);
    }

  }

  function onError(err) {
    return cbs.error && cbs.error(err);
  }

  function onAddStream(evt) {
    return cbs.remoteStream && cbs.remoteStream(evt.stream);
  }

  function drainIceQueue() {
    if (localIceQueue.length > 0) {
      drainingIceQueue = true;
      return xhrPostJson(signalPath + '?side=up', localIceQueue.shift(),
        function (status,body) {
          if (status == 200 || status == 201) {
            return drainIceQueue();
          } else if (!status) {
            return onError(body);

          } else if (status >= 500) {
            return onError(new Error(
              'Got status ' + status + ' updating SDP: ' + body));

          } else if (status >= 400) {
            // All the 400s mean we've basically somehow timed out
            return cbs.remoteSignalLost && cbs.remoteSignalLost();

          // We have no idea how to handle 1xx or 3xx codes
          } else {
            return onError(new Error(
              'Got status ' + status + ' updating SDP: ' + body));
          }
        });
    } else {
      drainingIceQueue = false;
      return;
    }
  }

  function sendIceCandidate(candidate) {
    // Add this to the current list of candidates to push
    localIceQueue.push(candidate);

    // If we're ready and not currently sending candidates
    if (signalPath && !drainingIceQueue) {
      // Start sending candidates
      return drainIceQueue();
    }
  }

  function onIceCandidate(evt) {
    return sendIceCandidate(evt.candidate);
  }

  return iface;
}<|endoftext|>


<commit_before>/**
 * Video Club modile.
 */
_debug('1!!!!!!!!!!!!!!');
(function(){

    //stb.ajax_loader = 'http://bb2.sandbox/stalker_portal/server/load.php'

    /* VCLUB */
    function vclub_constructor(){

        this.layer_name = 'vclub';

        this.row_blocks  = ['hd', 'sd', 'fav', 'lock', 'name', 'today', 'yestarday', 'week_and_more'];

        this.load_params = {
            'type'   : 'vod',
            'action' : 'get_ordered_list'
        };

        this.superclass = Layer.prototype;

        this.category_alias = '';

        this.sort_menu = {};

        this.search_box = {};

        this.view_menu = {};

        this.row_callback_timer;
        this.row_callback_timeout = 1000;

        this.password_input = new password_input({"parent" : this});
        this.password_input.bind();

        this.series_switch = new series_switch({"parent" : this});
        this.series_switch.bind();

        this.load_genres = function(alias){

            alias = alias || '';

            _debug('vclub.load_genres', alias);

            stb.load(
                {
                    "type"      : "vod",
                    "action"    : "get_genres_by_category_alias",
                    "cat_alias" : alias
                },
                function(result){
                    _debug('callback categories');

                    this.sidebar.fill_items("genre", result);
                },
                this
            )
        };

        this.load_years = function(category_id){
            _debug('vclub.load_years');

            stb.load(
                {
                    "type"     : "vod",
                    "action"   : "get_years",
                    "category" : category_id
                },
                function(result){
                    _debug('callback years');

                    this.sidebar.fill_items("years", result);
                },
                this
            )
        };

        this.load_abc = function(){
            _debug('vclub.load_abc');

            stb.load(
                {
                    "type"   : "vod",
                    "action" : "get_abc"
                },
                function(result){
                    _debug('callback abc');

                    this.sidebar.fill_items("abc", result);
                },
                this
            )
        };

        this._show = function(category){

            _debug('vclub.show');

            this.load_params['category'] = category.id;

            try{
                this.sort_menu.action();

                this.superclass.show.call(this);

                this.load_abc();
                this.load_genres(category.alias);
                this.load_years(category.id);
            }catch(e){
                _debug(e);
            }
        };

        /*this.show = function(category){

            _debug('vclub.show');

            this.load_params['category'] = category.id;

            try{
                this.sort_menu.action();

                this.superclass.show.call(this);

                this.load_abc();
                this.load_genres(category.alias);
                this.load_years(category.id);
            }catch(e){
                _debug(e);
            }
        };*/

        this.hide = function(do_not_reset){

            _debug('vclub.hide');

            if(!do_not_reset){
                this.search_box && this.search_box.reset && this.search_box.reset();
            }

            this.search_box.on && this.search_box.hide && this.search_box.hide();
            this.sort_menu.on && this.sort_menu.hide && this.sort_menu.hide();
            this.view_menu.on && this.view_menu.hide && this.view_menu.hide();

            this.info.on && this.info.hide && this.info.hide();
            this.password_input.on && this.password_input.hide && this.password_input.hide();
            this.series_switch.on && this.series_switch.hide && this.series_switch.hide();

            this.superclass.hide.call(this, do_not_reset);
        };

        this.init_sort_menu = function(map, options){
            this.sort_menu = new bottom_menu(this, options);
            this.sort_menu.init(map);
            this.sort_menu.bind();
        };

        this.sort_menu_switcher = function(){
            if (this.sort_menu && this.sort_menu.on){
                this.sort_menu.hide();
            }else{
                this.sort_menu.show();
            }
        };

        this.init_search_box = function(options){
            this.search_box = new search_box(this, options);
            this.search_box.init();
            this.search_box.bind();
        };

        this.search_box_switcher = function(){
            if (this.search_box && this.search_box.on){
                this.search_box.hide();
            }else{
                this.search_box.show();
            }
        };

        this.init_view_menu = function(map, options){
            this.view_menu = new bottom_menu(this, options);
            this.view_menu.init(map);
            this.view_menu.bind();
        };

        this.view_switcher = function(){
            if (this.view_menu && this.view_menu.on){
                this.view_menu.hide();
            }else{
                this.view_menu.show();
            }
        };

        this.fill_short_info = function(item){
            _debug('fill_short_info');

            //item.name
            //item.o_name
            //item.year
            //item.director
            //item.screenshot_uri
            //item.genres_str

            this.short_info_box.innerHTML = 'Жанр: ' + item.genres_str + '
Год: ' + item.year + ' Время: ' + item.time + ' мин.
Режиссер: ' + item.director;
            this.screenshot_box.innerHTML = '';
        };

        this.init_short_info = function(){
            this.info_box = create_block_element('', this.main_container);

            this.short_info_box = create_block_element('vclub_info_box', this.info_box);
            this.screenshot_box = create_block_element('vclub_screenshot_box', this.info_box);
        };

        this.shift_row_callback = function(item){

            window.clearTimeout(this.row_callback_timer);

            var self = this;

            this.row_callback_timer = window.setTimeout(function(){

                self.fill_short_info(item);

            },
            this.row_callback_timeout);
        };

        this.set_middle_container = function(){

            this.superclass.set_middle_container.apply(this);

            this.fill_short_info(this.data_items[this.cur_row]);

        };

        this.handling_block = function(data, row_items, block_name){

            var passive_blocks = ['today_block', 'yestarday_block', 'week_and_more_block'];
            var active_blocks  = ['active_today_block', 'active_yestarday_block', 'active_week_and_more_block'];

            var block_obj = row_items[block_name+'_block']

            if (data === 1){
                if (block_obj.isHidden()){
                    block_obj.show();
                }
            }else if (data === 0 || typeof(data) == "undefined"){
                if (!block_obj.isHidden()){
                    block_obj.hide();

                    if (passive_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '0';
                    }else if (active_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '25px';
                    }
                }
            }else{
                if (block_obj.isHidden()){
                    block_obj.show();

                    if (passive_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '150px';
                    }else if (active_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '175px';
                    }

                }
                block_obj.innerHTML = data;
            }
        };

        this.init_info = function(){
            this.info = new vclub_info(this);
            this.info.init();
            this.info.bind();

            this.full_info_switch.bind(key.RIGHT, this).bind(key.INFO, this);

            var color_buttons = this.buttons_bar.cloneNode(true);

            color_buttons.addClass('disabled_all_buttons');

            this.info.dom_obj.appendChild(color_buttons);
        };

        this.full_info_switch = function(){
            _debug('full_info_switch');

            if (this.info && this.info.on){
                this.on = true;
                this.info.hide();
            }else{
                this.on = false;
                this.info.show(this.data_items[this.cur_row]);
            }
        };

        this.bind = function(){
            this.superclass.bind.apply(this);

            this.check_for_pass.bind(key.OK, this);

            (function(){
                this.hide();
                main_menu.show();
            }).bind(key.EXIT, this).bind(key.LEFT, this).bind(key.MENU, this);
        };

        this.check_for_pass = function(){
            _debug('vclub.check_for_play');

            _debug('lock', this.data_items[this.cur_row].lock);

            if (this.data_items[this.cur_row].lock){
                var self = this;

                this.password_input.callback = function(){
                    self.check_for_series();
                }

                this.password_input.show();
            }else{
                this.check_for_series();
            }
        };

        this.check_for_series = function(){
            _debug('vclub.check_for_series');

            if (this.data_items[this.cur_row].series.length > 0){

                var self = this;

                this.series_switch.callback = function(series){
                    _debug('series', series);
                    self.data_items[self.cur_row].cur_series = series;
                    self.play();
                }

                this.series_switch.show(this.data_items[this.cur_row].series, this.data_items[this.cur_row].cur_series);
            }else{
                this.play();
            }
        };

        this.play = function(){
            _debug('vclub.play');

            var self = this;

            stb.player.on_create_link = function(result){
                _debug('vclub.on_create_link', result);

                if (result.error == 'limit'){
                    stb.notice.show('Количество подключений ограничено.
Попробуйте позже');
                }else if(result.error == 'nothing_to_play'){
                    stb.notice.show('Файл отсутствует');
                }else if(result.error == 'link_fault'){
                    stb.notice.show('Ошибка сервера');
                }else{

                    if (this.info.on){
                        this.info.hide();
                    }

                    self.hide(true);

                    stb.player.prev_layer = self;
                    stb.player.need_show_info = 1;
                    stb.player.play_now(result.cmd);
                }
            }

            stb.player.play(this.data_items[this.cur_row]);
        };
    }

    vclub_constructor.prototype = new Layer();

    var vclub = new vclub_constructor();

    vclub.bind();
    vclub.init();

    vclub.init_short_info();

    vclub.set_wide_container();

    vclub.init_left_ear('ears_back');
    vclub.init_right_ear('ears_movie');

    vclub.init_color_buttons([
        {"label" : "ОТОБРАЖЕНИЕ", "cmd" : vclub.view_switcher},
        {"label" : "СОРТИРОВКА", "cmd" : vclub.sort_menu_switcher},
        {"label" : "ПОИСК", "cmd" : vclub.search_box_switcher},
        {"label" : "ВЫБОРКА", "cmd" : vclub.sidebar_switcher}
    ]);

    vclub.init_info();

    vclub.init_sidebar();

    vclub.sidebar.init_items("abc", {"header" : "ПО БУКВЕ", "width" : 26, "align" : "center"});
    vclub.sidebar.init_items("genre",  {"header" : "ПО ЖАНРУ", "width" : 95});
    vclub.sidebar.init_items("years",  {"header" : "ПО ГОДУ", "width" : 35});

    vclub.sidebar.bind();

    vclub.init_sort_menu(
        [
            {"label" : "по имени", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'name'; this.parent.load_params.hd = false}},
            {"label" : "по добавлению", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'added'; this.parent.load_params.hd = false}},
            {"label" : "по популярности", "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'top'; this.parent.load_params.hd = false}},
            {"label" : "только HD", "cmd" : function(){this.parent.load_params.sortby = 'name'; this.parent.load_params.fav = false; this.parent.load_params.hd = true}},
            {"label" : "только избранное", "cmd" : function(){this.parent.load_params.sortby = 'name'; this.parent.load_params.fav = true; this.parent.load_params.hd = false}}
        ],
        {
            "offset_x" : 217
        }
    );

    vclub.init_search_box(
        {
            "offset_x" : 323
        }
    );

    vclub.init_view_menu(
        [
            {"label" : "список", "cmd" : function(){this.parent.set_wide_container()}},
            {"label" : "список с инфо", "cmd" : function(){this.parent.set_middle_container()}}
        ],
        {
            "offset_x" : 27,
            "need_reset_load_data" : false,
            "need_update_header"   : false
        }
    );

    vclub.init_header_path('ВИДЕО КЛУБ');

    vclub.sidebar.dependency    = [vclub.sort_menu, vclub.search_box, vclub.view_menu];
    vclub.sort_menu.dependency  = [vclub.sidebar, vclub.search_box, vclub.view_menu];
    vclub.search_box.dependency = [vclub.sidebar, vclub.sort_menu, vclub.view_menu];
    vclub.view_menu.dependency  = [vclub.sidebar, vclub.sort_menu, vclub.search_box];

    vclub.hide();

    module.vclub = vclub;
    /* END VCLUB */

    /* Integrate vclub in main menu */
    stb.load(
        {
            "type"   : "vod",
            "action" : "get_categories"
        },
        function(result){
            _debug('callback categories');

            var categories = result;

            var map = [];

            for(var i=0; i<categories.length; i++){
                map.push(

                {
                    "title" : categories[i].title,
                    "cmd"   : (function(category){

                        return function(){
                            _debug('alias', category.alias);

                            main_menu.hide();
                            module.vclub._show(category);
                        }

                    })(categories[i]),
                }

                );
            }

            main_menu.add('ВИДЕОКЛУБ', map, 'i/mm_ico_video.png');

            loader.next();
        },
        this
    )

})();
_debug('2!!!!!!!!!!!!!!');

//loader.next();<commit_msg>"All words replaced with variable"<commit_after>/**
 * Video Club modile.
 */
_debug('1!!!!!!!!!!!!!!');
(function(){

    //stb.ajax_loader = 'http://bb2.sandbox/stalker_portal/server/load.php'

    /* VCLUB */
    function vclub_constructor(){

        this.layer_name = 'vclub';

        this.row_blocks  = ['hd', 'sd', 'fav', 'lock', 'name', 'today', 'yestarday', 'week_and_more'];

        this.load_params = {
            'type'   : 'vod',
            'action' : 'get_ordered_list'
        };

        this.superclass = Layer.prototype;

        this.category_alias = '';

        this.sort_menu = {};

        this.search_box = {};

        this.view_menu = {};

        this.row_callback_timer;
        this.row_callback_timeout = 1000;

        this.password_input = new password_input({"parent" : this});
        this.password_input.bind();

        this.series_switch = new series_switch({"parent" : this});
        this.series_switch.bind();

        this.load_genres = function(alias){

            alias = alias || '';

            _debug('vclub.load_genres', alias);

            stb.load(
                {
                    "type"      : "vod",
                    "action"    : "get_genres_by_category_alias",
                    "cat_alias" : alias
                },
                function(result){
                    _debug('callback categories');

                    this.sidebar.fill_items("genre", result);
                },
                this
            )
        };

        this.load_years = function(category_id){
            _debug('vclub.load_years');

            stb.load(
                {
                    "type"     : "vod",
                    "action"   : "get_years",
                    "category" : category_id
                },
                function(result){
                    _debug('callback years');

                    this.sidebar.fill_items("years", result);
                },
                this
            )
        };

        this.load_abc = function(){
            _debug('vclub.load_abc');

            stb.load(
                {
                    "type"   : "vod",
                    "action" : "get_abc"
                },
                function(result){
                    _debug('callback abc');

                    this.sidebar.fill_items("abc", result);
                },
                this
            )
        };

        this._show = function(category){

            _debug('vclub.show');

            this.load_params['category'] = category.id;

            try{
                this.sort_menu.action();

                this.superclass.show.call(this);

                this.load_abc();
                this.load_genres(category.alias);
                this.load_years(category.id);
            }catch(e){
                _debug(e);
            }
        };

        /*this.show = function(category){

            _debug('vclub.show');

            this.load_params['category'] = category.id;

            try{
                this.sort_menu.action();

                this.superclass.show.call(this);

                this.load_abc();
                this.load_genres(category.alias);
                this.load_years(category.id);
            }catch(e){
                _debug(e);
            }
        };*/

        this.hide = function(do_not_reset){

            _debug('vclub.hide');

            if(!do_not_reset){
                this.search_box && this.search_box.reset && this.search_box.reset();
            }

            this.search_box.on && this.search_box.hide && this.search_box.hide();
            this.sort_menu.on && this.sort_menu.hide && this.sort_menu.hide();
            this.view_menu.on && this.view_menu.hide && this.view_menu.hide();

            this.info.on && this.info.hide && this.info.hide();
            this.password_input.on && this.password_input.hide && this.password_input.hide();
            this.series_switch.on && this.series_switch.hide && this.series_switch.hide();

            this.superclass.hide.call(this, do_not_reset);
        };

        this.init_sort_menu = function(map, options){
            this.sort_menu = new bottom_menu(this, options);
            this.sort_menu.init(map);
            this.sort_menu.bind();
        };

        this.sort_menu_switcher = function(){
            if (this.sort_menu && this.sort_menu.on){
                this.sort_menu.hide();
            }else{
                this.sort_menu.show();
            }
        };

        this.init_search_box = function(options){
            this.search_box = new search_box(this, options);
            this.search_box.init();
            this.search_box.bind();
        };

        this.search_box_switcher = function(){
            if (this.search_box && this.search_box.on){
                this.search_box.hide();
            }else{
                this.search_box.show();
            }
        };

        this.init_view_menu = function(map, options){
            this.view_menu = new bottom_menu(this, options);
            this.view_menu.init(map);
            this.view_menu.bind();
        };

        this.view_switcher = function(){
            if (this.view_menu && this.view_menu.on){
                this.view_menu.hide();
            }else{
                this.view_menu.show();
            }
        };

        this.fill_short_info = function(item){
            _debug('fill_short_info');

            //item.name
            //item.o_name
            //item.year
            //item.director
            //item.screenshot_uri
            //item.genres_str

            this.short_info_box.innerHTML = '' + word['vclub_genre'] + ': ' + item.genres_str + '
' + word['vclub_year'] + ': ' + item.year + ' ' + word['vclub_length'] + ': ' + item.time + ' ' + word['vclub_minutes'] + '.
' + word['vclub_director'] + ': ' + item.director;
            this.screenshot_box.innerHTML = '';
        };

        this.init_short_info = function(){
            this.info_box = create_block_element('', this.main_container);

            this.short_info_box = create_block_element('vclub_info_box', this.info_box);
            this.screenshot_box = create_block_element('vclub_screenshot_box', this.info_box);
        };

        this.shift_row_callback = function(item){

            window.clearTimeout(this.row_callback_timer);

            var self = this;

            this.row_callback_timer = window.setTimeout(function(){

                self.fill_short_info(item);

            },
            this.row_callback_timeout);
        };

        this.set_middle_container = function(){

            this.superclass.set_middle_container.apply(this);

            this.fill_short_info(this.data_items[this.cur_row]);

        };

        this.handling_block = function(data, row_items, block_name){

            var passive_blocks = ['today_block', 'yestarday_block', 'week_and_more_block'];
            var active_blocks  = ['active_today_block', 'active_yestarday_block', 'active_week_and_more_block'];

            var block_obj = row_items[block_name+'_block']

            if (data === 1){
                if (block_obj.isHidden()){
                    block_obj.show();
                }
            }else if (data === 0 || typeof(data) == "undefined"){
                if (!block_obj.isHidden()){
                    block_obj.hide();

                    if (passive_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '0';
                    }else if (active_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '25px';
                    }
                }
            }else{
                if (block_obj.isHidden()){
                    block_obj.show();

                    if (passive_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '150px';
                    }else if (active_blocks.indexOf(block_obj.className) >= 0){
                        row_items['name_block'].style.marginRight = '175px';
                    }

                }
                block_obj.innerHTML = data;
            }
        };

        this.init_info = function(){
            this.info = new vclub_info(this);
            this.info.init();
            this.info.bind();

            this.full_info_switch.bind(key.RIGHT, this).bind(key.INFO, this);

            var color_buttons = this.buttons_bar.cloneNode(true);

            color_buttons.addClass('disabled_all_buttons');

            this.info.dom_obj.appendChild(color_buttons);
        };

        this.full_info_switch = function(){
            _debug('full_info_switch');

            if (this.info && this.info.on){
                this.on = true;
                this.info.hide();
            }else{
                this.on = false;
                this.info.show(this.data_items[this.cur_row]);
            }
        };

        this.bind = function(){
            this.superclass.bind.apply(this);

            this.check_for_pass.bind(key.OK, this);

            (function(){
                this.hide();
                main_menu.show();
            }).bind(key.EXIT, this).bind(key.LEFT, this).bind(key.MENU, this);
        };

        this.check_for_pass = function(){
            _debug('vclub.check_for_play');

            _debug('lock', this.data_items[this.cur_row].lock);

            if (this.data_items[this.cur_row].lock){
                var self = this;

                this.password_input.callback = function(){
                    self.check_for_series();
                }

                this.password_input.show();
            }else{
                this.check_for_series();
            }
        };

        this.check_for_series = function(){
            _debug('vclub.check_for_series');

            if (this.data_items[this.cur_row].series.length > 0){

                var self = this;

                this.series_switch.callback = function(series){
                    _debug('series', series);
                    self.data_items[self.cur_row].cur_series = series;
                    self.play();
                }

                this.series_switch.show(this.data_items[this.cur_row].series, this.data_items[this.cur_row].cur_series);
            }else{
                this.play();
            }
        };

        this.play = function(){
            _debug('vclub.play');

            var self = this;

            stb.player.on_create_link = function(result){
                _debug('vclub.on_create_link', result);

                if (result.error == 'limit'){
                    stb.notice.show(word['player_limit_notice']);
                }else if(result.error == 'nothing_to_play'){
                    stb.notice.show(word['player_file_missing']);
                }else if(result.error == 'link_fault'){
                    stb.notice.show(word['player_server_error']);
                }else{

                    if (this.info.on){
                        this.info.hide();
                    }

                    self.hide(true);

                    stb.player.prev_layer = self;
                    stb.player.need_show_info = 1;
                    stb.player.play_now(result.cmd);
                }
            }

            stb.player.play(this.data_items[this.cur_row]);
        };
    }

    vclub_constructor.prototype = new Layer();

    var vclub = new vclub_constructor();

    vclub.bind();
    vclub.init();

    vclub.init_short_info();

    vclub.set_wide_container();

    vclub.init_left_ear('ears_back');
    vclub.init_right_ear('ears_movie');

    vclub.init_color_buttons([
        {"label" : word['vclub_view'], "cmd" : vclub.view_switcher},
        {"label" : word['vclub_sort'], "cmd" : vclub.sort_menu_switcher},
        {"label" : word['vclub_search'], "cmd" : vclub.search_box_switcher},
        {"label" : word['vclub_sampling'], "cmd" : vclub.sidebar_switcher}
    ]);

    vclub.init_info();

    vclub.init_sidebar();

    vclub.sidebar.init_items("abc", {"header" : word['vclub_by_letter'], "width" : 26, "align" : "center"});
    vclub.sidebar.init_items("genre",  {"header" : word['vclub_by_genre'], "width" : 95});
    vclub.sidebar.init_items("years",  {"header" : word['vclub_by_year'], "width" : 35});

    vclub.sidebar.bind();

    vclub.init_sort_menu(
        [
            {"label" : word['vclub_by_title'], "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'name'; this.parent.load_params.hd = false}},
            {"label" : word['vclub_by_addtime'], "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'added'; this.parent.load_params.hd = false}},
            {"label" : word['vclub_top'], "cmd" : function(){this.parent.load_params.fav = false; this.parent.load_params.sortby = 'top'; this.parent.load_params.hd = false}},
            {"label" : word['vclub_only_hd'], "cmd" : function(){this.parent.load_params.sortby = 'name'; this.parent.load_params.fav = false; this.parent.load_params.hd = true}},
            {"label" : word['vclub_only_favorite'], "cmd" : function(){this.parent.load_params.sortby = 'name'; this.parent.load_params.fav = true; this.parent.load_params.hd = false}}
        ],
        {
            "offset_x" : 217
        }
    );

    vclub.init_search_box(
        {
            "offset_x" : 323
        }
    );

    vclub.init_view_menu(
        [
            {"label" : word['vclub_list'], "cmd" : function(){this.parent.set_wide_container()}},
            {"label" : word['vclub_list_w_info'], "cmd" : function(){this.parent.set_middle_container()}}
        ],
        {
            "offset_x" : 27,
            "need_reset_load_data" : false,
            "need_update_header"   : false
        }
    );

    vclub.init_header_path(word['vclub_title']);

    vclub.sidebar.dependency    = [vclub.sort_menu, vclub.search_box, vclub.view_menu];
    vclub.sort_menu.dependency  = [vclub.sidebar, vclub.search_box, vclub.view_menu];
    vclub.search_box.dependency = [vclub.sidebar, vclub.sort_menu, vclub.view_menu];
    vclub.view_menu.dependency  = [vclub.sidebar, vclub.sort_menu, vclub.search_box];

    vclub.hide();

    module.vclub = vclub;
    /* END VCLUB */

    /* Integrate vclub in main menu */
    stb.load(
        {
            "type"   : "vod",
            "action" : "get_categories"
        },
        function(result){
            _debug('callback categories');

            var categories = result;

            var map = [];

            for(var i=0; i<categories.length; i++){
                map.push(

                {
                    "title" : categories[i].title,
                    "cmd"   : (function(category){

                        return function(){
                            _debug('alias', category.alias);

                            main_menu.hide();
                            module.vclub._show(category);
                        }

                    })(categories[i]),
                }

                );
            }

            main_menu.add(word['vclub_title'], map, 'i/mm_ico_video.png');

            loader.next();
        },
        this
    )

})();
_debug('2!!!!!!!!!!!!!!');

//loader.next();<|endoftext|>