<commit_before>var loadImages = function(dataPath, groupName, pictureName){
	var groupName = groupName || 'picture';
		pictureName = pictureName || 'picture';

	function loadImages(imgAmount){
		var fileManager = [NSFileManager defaultManager];
		var scriptPath = sketch.scriptPath;
		var pluginFolder = scriptPath.match(/Plugins\/([\w -])*/)[0] + "/";
		var sketchPluginsPath = scriptPath.replace(/Plugins([\w \/ -])*.sketchplugin$/, "");
		var imagesPath =  sketchPluginsPath + pluginFolder + dataPath;
		var imagesFileNames = [fileManager contentsOfDirectoryAtPath:imagesPath error:nil];
		var imageCount = [imagesFileNames count] -1;
		var selectedPaths = [];

		if(imgAmount > imageCount){ //Load images in sequential order
			while(imgAmount--) {
				var index = Math.floor(Math.random() * imageCount);
				do {
					index = index >= imageCount ? 0 : index + 1;
					var fileName = imagesFileNames[index];
					var filePath = imagesPath + fileName;
				} while(![fileManager fileExistsAtPath: filePath] || fileName == '.DS_Store')

				selectedPaths.push(filePath);
			}
		}
		else{	//Load unique images
			while(imgAmount--) {
				do {
					var index = Math.floor(Math.random() * imageCount);
					var fileName = imagesFileNames[index];
					var filePath = imagesPath + fileName;
					var match = selectedPaths.filter(function(selectedPath){return filePath == selectedPath;});
				} while(fileName == '.DS_Store' || ![fileManager fileExistsAtPath: filePath] || match.length >= 1);
				selectedPaths.push(filePath);
			}
		}

		return selectedPaths.map(function(imagePath){
			if ([fileManager fileExistsAtPath: imagePath]) {
				var image = [[NSImage alloc] initWithContentsOfFile:imagePath];
				return image;
			}
		})
	}

	function main(){
		var allLayers = [[doc currentPage] layers],
			imagesCollection = loadImages([selection count] + 1);

		for(var i = 0; i < [selection count]; i++){
			var layer = selection[i];
            if([layer class] == MSShapeGroup){
                var image = imagesCollection[i];
                var fill = layer.style().fills().firstObject();
                fill.setFillType(4);
                if(tools.minorVersion() >= 1){
					layer.style().fills().firstObject().setImage(MSImageData.alloc().initWithImage_convertColorSpace(image, false));
					layer.style().fills().firstObject().setImage(MSImageData.alloc().initWithImage_convertColorSpace(image, false));
                }
                else{
                	layer.style().fills().firstObject().setPatternImage( image );
                }
                layer.style().fills().firstObject().setPatternFillType(1);
            }
		}

		if([selection count] == 0) [doc showMessage:'Select at least one vector shape'];;

		tools.checkPluginUpdate();
	}
	main();
}

<commit_msg>image fix<commit_after>var loadImages = function(dataPath, groupName, pictureName){
	var groupName = groupName || 'picture';
		pictureName = pictureName || 'picture';

	function loadImages(imgAmount){
		var fileManager = [NSFileManager defaultManager];
		var scriptPath = sketch.scriptPath;
		var pluginFolder = scriptPath.match(/Plugins\/([\w -])*/)[0] + "/";
		var sketchPluginsPath = scriptPath.replace(/Plugins([\w \/ -])*.sketchplugin$/, "");
		var imagesPath =  sketchPluginsPath + pluginFolder + dataPath;
		var imagesFileNames = [fileManager contentsOfDirectoryAtPath:imagesPath error:nil];
		var imageCount = [imagesFileNames count] -1;
		var selectedPaths = [];

		if(imgAmount > imageCount){ //Load images in sequential order
			while(imgAmount--) {
				var index = Math.floor(Math.random() * imageCount);
				do {
					index = index >= imageCount ? 0 : index + 1;
					var fileName = imagesFileNames[index];
					var filePath = imagesPath + fileName;
				} while(![fileManager fileExistsAtPath: filePath] || fileName == '.DS_Store')

				selectedPaths.push(filePath);
			}
		}
		else{	//Load unique images
			while(imgAmount--) {
				do {
					var index = Math.floor(Math.random() * imageCount);
					var fileName = imagesFileNames[index];
					var filePath = imagesPath + fileName;
					var match = selectedPaths.filter(function(selectedPath){return filePath == selectedPath;});
				} while(fileName == '.DS_Store' || ![fileManager fileExistsAtPath: filePath] || match.length >= 1);
				selectedPaths.push(filePath);
			}
		}

		return selectedPaths.map(function(imagePath){
			if ([fileManager fileExistsAtPath: imagePath]) {
				var image = [[NSImage alloc] initWithContentsOfFile:imagePath];
				return image;
			}
		})
	}

	function main(){
		var allLayers = [[doc currentPage] layers],
			imagesCollection = loadImages([selection count] + 1);

		for(var i = 0; i < [selection count]; i++){
			var layer = selection[i];
            if([layer class] == MSShapeGroup){
                var image = imagesCollection[i];
                var fill = layer.style().fills().firstObject();
                fill.setFillType(4);
                if(tools.minorVersion() >= 1){
					layer.style().fills().firstObject().setImage(MSImageData.alloc().initWithImage_convertColorSpace(image, false));
					layer.style().fills().firstObject().setPatternFillType(1);
                }
                else{
                	layer.style().fills().firstObject().setImage(MSImageData.alloc().initWithImage_convertColorSpace(image, false));
                }
                layer.style().fills().firstObject().setPatternFillType(1);
            }
		}

		if([selection count] == 0) [doc showMessage:'Select at least one vector shape'];;

		tools.checkPluginUpdate();
	}
	main();
}

<|endoftext|>


<commit_before>var locations = [
  { name: 'Tim Brownawell', origin: 'Fulton, MO', latitude: 38.86517, longitude: -91.98643, slack_handle: "tbrownaw" },
  { name: 'wayne bills', origin: 'northaven, tn', latitude: 35.26507, longitude: -90.04078 },
  { name: 'Brad Montgomery', origin: 'Lepanto, AR', latitude: 35.61046, longitude: -90.33114, company: "Tennessee Data Commons", slack_handle: "bkmontgomery"},
  { name: 'Stephen Bramlett', origin: 'memphis, tn', latitude: 35.2243923520236, longitude: -90.00089585781097, company: 'Semmes Murphey Clinic', slack_handle: "sbramlett"  },
  { name: 'Eric Terpstra', origin: 'Kellogg, IA', latitude: 41.776711, longitude:-92.964886, slack_handle: "eterps" },
  { name: 'josh lewis', origin: 'rogersville, mo', latitude: 37.110618, longitude: -93.053759 },
  { name: 'Daniel Pritchett', origin: 'Dothan, AL', latitude: 31.2290238, longitude: -85.4766258, slack_handle: "dpritchett" },
  { name: 'Joe Ferguson', origin: 'memphis, tn', latitude: 35.2246054, longitude: -90.0001485 },
  { name: 'David Hiltenbrand', origin: 'Pine Bluff, AR', latitude: 34.231984, longitude: -92.135550 },
  { name: 'Ismael Alonso', origin: 'Valladolid, ES-VA', latitude: 41.6519094, longitude: -4.730486 },
  { name: 'Collin Barrett', origin: 'Kalamazoo, MI', latitude: 42.271161, longitude: -85.660178 },
  { name: 'Claudio Donndelinger', origin: 'Tucson, AZ', latitude: 32.2274179, longitude: -110.9604492 },
  { name: 'Jason Myers', origin: 'memphis, tn', latitude: 35.143839,longitude: -89.944866, slack_handle: "syliddar"  },
  { name: 'Daniel Soskel', origin: 'Salt Lake City, UT', latitude: 40.7762692, longitude: -112.2006695, slack_handle: "meltheous" },
  { name: 'Mike Cochran', origin: 'Memphis, TN', latitude: 35.15497509873826, longitude: -90.01109898090363, slack_handle: 'vongrippen' },
  { name: 'Forrest Williams', origin: 'Memphis, TN', latitude: 35.036800, longitude: -89.823446, slack_handle: 'serroft' }
];
<commit_msg>Add gpspake<commit_after>var locations = [
  { name: 'Tim Brownawell', origin: 'Fulton, MO', latitude: 38.86517, longitude: -91.98643, slack_handle: "tbrownaw" },
  { name: 'wayne bills', origin: 'northaven, tn', latitude: 35.26507, longitude: -90.04078 },
  { name: 'Brad Montgomery', origin: 'Lepanto, AR', latitude: 35.61046, longitude: -90.33114, company: "Tennessee Data Commons", slack_handle: "bkmontgomery"},
  { name: 'Stephen Bramlett', origin: 'memphis, tn', latitude: 35.2243923520236, longitude: -90.00089585781097, company: 'Semmes Murphey Clinic', slack_handle: "sbramlett"  },
  { name: 'Eric Terpstra', origin: 'Kellogg, IA', latitude: 41.776711, longitude:-92.964886, slack_handle: "eterps" },
  { name: 'josh lewis', origin: 'rogersville, mo', latitude: 37.110618, longitude: -93.053759 },
  { name: 'Daniel Pritchett', origin: 'Dothan, AL', latitude: 31.2290238, longitude: -85.4766258, slack_handle: "dpritchett" },
  { name: 'Joe Ferguson', origin: 'memphis, tn', latitude: 35.2246054, longitude: -90.0001485 },
  { name: 'David Hiltenbrand', origin: 'Pine Bluff, AR', latitude: 34.231984, longitude: -92.135550 },
  { name: 'Ismael Alonso', origin: 'Valladolid, ES-VA', latitude: 41.6519094, longitude: -4.730486 },
  { name: 'Collin Barrett', origin: 'Kalamazoo, MI', latitude: 42.271161, longitude: -85.660178 },
  { name: 'Claudio Donndelinger', origin: 'Tucson, AZ', latitude: 32.2274179, longitude: -110.9604492 },
  { name: 'Jason Myers', origin: 'memphis, tn', latitude: 35.143839,longitude: -89.944866, slack_handle: "syliddar"  },
  { name: 'Daniel Soskel', origin: 'Salt Lake City, UT', latitude: 40.7762692, longitude: -112.2006695, slack_handle: "meltheous" },
  { name: 'Mike Cochran', origin: 'Memphis, TN', latitude: 35.15497509873826, longitude: -90.01109898090363, slack_handle: 'vongrippen' },
  { name: 'Forrest Williams', origin: 'Memphis, TN', latitude: 35.036800, longitude: -89.823446, slack_handle: 'serroft' },
  ( name: 'George Spake', origin: Memphis, TN, latitude: 35.1182222, longitude: -90.0053115, slack_handle: 'gpspake' }
];
<|endoftext|>


<commit_before>var locations = [
  { name: 'Tim Brownawell', origin: 'Fulton, MO', latitude: 38.86517, longitude: -91.98643, slack_handle: "tbrownaw" },
  { name: 'wayne bills', origin: 'northaven, tn', latitude: 35.26507, longitude: -90.04078 },
  { name: 'brad montgomery', origin: 'lepanto, ar', latitude: 35.61046, longitude: -90.33114, slack_handle: "bkmontgomery"},
  { name: 'Stephen Bramlett', origin: 'memphis, tn', latitude: 35.2243923520236, longitude: -90.00089585781097, company: 'Semmes Murphey Clinic', slack_handle: "sbramlett"  },
  { name: 'Eric Terpstra', origin: 'Kellogg, IA', latitude: 41.776711, longitude:-92.964886, slack_handle: "eterps" },
  { name: 'josh lewis', origin: 'rogersville, mo', latitude: 37.110618, longitude: -93.053759 },
  { name: 'Daniel Pritchett', origin: 'Dothan, AL', latitude: 31.2290238, longitude: -85.4766258, slack_handle: "dpritchett" },
  { name: 'Joe Ferguson', origin: 'memphis, tn', latitude: 35.2246054, longitude: -90.0001485 },
  { name: 'David Hiltenbrand', origin: 'Pine Bluff, AR', latitude: 34.231984, longitude: -92.135550 },
  { name: 'Ismael Alonso', origin: 'Valladolid, ES-VA', latitude: 41.6519094, longitude: -4.730486 },
  { name: 'Collin Barrett', origin: 'Kalamazoo, MI', latitude: 42.271161, longitude: -85.660178 },
  { name: 'Claudio Donndelinger', origin: 'Tucson, AZ', latitude: 32.2274179, longitude: -110.9604492 },
  { name: 'Jason Myers', origin: 'memphis, tn', latitude: 35.143839,longitude: -89.944866, slack_handle: "syliddar"  },
  { name: 'Daniel Soskel', origin: 'Salt Lake City, UT', latitude: 40.7762692, longitude: -112.2006695, slack_handle: "meltheous" },
  { name: 'Mike Cochran', origin: 'Memphis, TN', latitude: 35.15497509873826, longitude: -90.01109898090363, slack_handle: 'vongrippen' }
];
<commit_msg>add my company<commit_after>var locations = [
  { name: 'Tim Brownawell', origin: 'Fulton, MO', latitude: 38.86517, longitude: -91.98643, slack_handle: "tbrownaw" },
  { name: 'wayne bills', origin: 'northaven, tn', latitude: 35.26507, longitude: -90.04078 },
  { name: 'Brad Montgomery', origin: 'Lepanto, AR', latitude: 35.61046, longitude: -90.33114, company: "Tennessee Data Commons", slack_handle: "bkmontgomery"},
  { name: 'Stephen Bramlett', origin: 'memphis, tn', latitude: 35.2243923520236, longitude: -90.00089585781097, company: 'Semmes Murphey Clinic', slack_handle: "sbramlett"  },
  { name: 'Eric Terpstra', origin: 'Kellogg, IA', latitude: 41.776711, longitude:-92.964886, slack_handle: "eterps" },
  { name: 'josh lewis', origin: 'rogersville, mo', latitude: 37.110618, longitude: -93.053759 },
  { name: 'Daniel Pritchett', origin: 'Dothan, AL', latitude: 31.2290238, longitude: -85.4766258, slack_handle: "dpritchett" },
  { name: 'Joe Ferguson', origin: 'memphis, tn', latitude: 35.2246054, longitude: -90.0001485 },
  { name: 'David Hiltenbrand', origin: 'Pine Bluff, AR', latitude: 34.231984, longitude: -92.135550 },
  { name: 'Ismael Alonso', origin: 'Valladolid, ES-VA', latitude: 41.6519094, longitude: -4.730486 },
  { name: 'Collin Barrett', origin: 'Kalamazoo, MI', latitude: 42.271161, longitude: -85.660178 },
  { name: 'Claudio Donndelinger', origin: 'Tucson, AZ', latitude: 32.2274179, longitude: -110.9604492 },
  { name: 'Jason Myers', origin: 'memphis, tn', latitude: 35.143839,longitude: -89.944866, slack_handle: "syliddar"  },
  { name: 'Daniel Soskel', origin: 'Salt Lake City, UT', latitude: 40.7762692, longitude: -112.2006695, slack_handle: "meltheous" },
  { name: 'Mike Cochran', origin: 'Memphis, TN', latitude: 35.15497509873826, longitude: -90.01109898090363, slack_handle: 'vongrippen' }
];
<|endoftext|>


<commit_before>import log from 'logger';
import User from 'models/user';
import Raven from 'raven';

class Me extends User {
    fetch() {
        this.$api('me.get_me', {}, this.on_user_fetched);
        return this;
    }

    update(data, on_success, on_error) {
        this.$api('me.update_me', {payload: JSON.stringify(data)}, on_success, on_error);
    }

    on_user_fetched(response) {
        Raven.setUserContext({
            id: response.obj.id,
            email: response.obj.email,
            slug: response.obj.slug,
            fullname: `${response.obj.first_name} ${response.obj.last_name}`,
            is_authenticated: true,
            is_anonymous: false
        });
        this.on_fetched(response);
    }
}

var me = new Me();

export default me.fetch();
<commit_msg>Declare current user to Sentry only if enabled<commit_after>import User from 'models/user';
import Raven from 'raven';
import config from 'config';

class Me extends User {
    fetch() {
        this.$api('me.get_me', {}, this.on_user_fetched);
        return this;
    }

    update(data, on_success, on_error) {
        this.$api('me.update_me', {payload: JSON.stringify(data)}, on_success, on_error);
    }

    on_user_fetched(response) {
        if (config.sentry) {
            Raven.setUserContext({
                id: response.obj.id,
                email: response.obj.email,
                slug: response.obj.slug,
                fullname: `${response.obj.first_name} ${response.obj.last_name}`,
                is_authenticated: true,
                is_anonymous: false
            });
        }
        this.on_fetched(response);
    }
}

const me = new Me();

export default me.fetch();
<|endoftext|>


<commit_before>/* ========================================================================
 * Bootstrap: offcanvas.js v3.1.3
 * http://jasny.github.io/bootstrap/javascript/#offcanvas
 * ========================================================================
 * Copyright 2013-2014 Arnold Daniels
 *
 * 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.
 * ======================================================================== */

+function ($) { "use strict";

  // OFFCANVAS PUBLIC CLASS DEFINITION
  // =================================

  var OffCanvas = function (element, options) {
    this.$element = $(element)
    this.options  = $.extend({}, OffCanvas.DEFAULTS, options)
    this.state    = null
    this.placement = null

    if (this.options.recalc) {
      this.calcClone()
      $(window).on('resize', $.proxy(this.recalc, this))
    }

    if (this.options.autohide && !this.options.modal)
      $(document).on('click', $.proxy(this.autohide, this))

    if (this.options.toggle) this.toggle()

    if (this.options.disablescrolling) {
        this.options.disableScrolling = this.options.disablescrolling
        delete this.options.disablescrolling
    }
  }

  OffCanvas.DEFAULTS = {
    toggle: true,
    placement: 'auto',
    autohide: true,
    recalc: true,
    disableScrolling: true,
    modal: false
  }

  OffCanvas.prototype.offset = function () {
    switch (this.placement) {
      case 'left':
      case 'right':  return this.$element.outerWidth()
      case 'top':
      case 'bottom': return this.$element.outerHeight()
    }
  }

  OffCanvas.prototype.calcPlacement = function () {
    if (this.options.placement !== 'auto') {
        this.placement = this.options.placement
        return
    }

    if (!this.$element.hasClass('in')) {
      this.$element.css('visiblity', 'hidden !important').addClass('in')
    }

    var horizontal = $(window).width() / this.$element.width()
    var vertical = $(window).height() / this.$element.height()

    var element = this.$element
    function ab(a, b) {
      if (element.css(b) === 'auto') return a
      if (element.css(a) === 'auto') return b

      var size_a = parseInt(element.css(a), 10)
      var size_b = parseInt(element.css(b), 10)

      return size_a > size_b ? b : a
    }

    this.placement = horizontal >= vertical ? ab('left', 'right') : ab('top', 'bottom')

    if (this.$element.css('visibility') === 'hidden !important') {
      this.$element.removeClass('in').css('visiblity', '')
    }
  }

  OffCanvas.prototype.opposite = function (placement) {
    switch (placement) {
      case 'top':    return 'bottom'
      case 'left':   return 'right'
      case 'bottom': return 'top'
      case 'right':  return 'left'
    }
  }

  OffCanvas.prototype.getCanvasElements = function() {
    // Return a set containing the canvas plus all fixed elements
    var canvas = this.options.canvas ? $(this.options.canvas) : this.$element

    var fixed_elements = canvas.find('*').filter(function() {
      return $(this).css('position') === 'fixed'
    }).not(this.options.exclude)

    return canvas.add(fixed_elements)
  }

  OffCanvas.prototype.slide = function (elements, offset, callback) {
    // Use jQuery animation if CSS transitions aren't supported
    if (!$.support.transition) {
      var anim = {}
      anim[this.placement] = "+=" + offset
      return elements.animate(anim, 350, callback)
    }

    var placement = this.placement
    var opposite = this.opposite(placement)

    elements.each(function() {
      if ($(this).css(placement) !== 'auto')
        $(this).css(placement, (parseInt($(this).css(placement), 10) || 0) + offset)

      if ($(this).css(opposite) !== 'auto')
        $(this).css(opposite, (parseInt($(this).css(opposite), 10) || 0) - offset)
    })

    this.$element
      .one($.support.transition.end, callback)
      .emulateTransitionEnd(350)
  }

  OffCanvas.prototype.disableScrolling = function() {
    var bodyWidth = $('body').width()
    var prop = 'padding-right'

    if ($('body').data('offcanvas-style') === undefined) {
      $('body').data('offcanvas-style', $('body').attr('style') || '')
    }

    $('body').css('overflow', 'hidden')

    if ($('body').width() > bodyWidth) {
      var padding = parseInt($('body').css(prop), 10) + $('body').width() - bodyWidth

      setTimeout(function() {
        $('body').css(prop, padding)
      }, 1)
    }
    //disable scrolling on mobiles (they ignore overflow:hidden)
    $('body').on('touchmove.bs', function(e) {
      e.preventDefault();
    });
  }

  OffCanvas.prototype.enableScrolling = function() {
    $('body').off('touchmove.bs');
  }

  OffCanvas.prototype.show = function () {
    if (this.state) return

    var startEvent = $.Event('show.bs.offcanvas')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    this.state = 'slide-in'
    this.calcPlacement();

    var elements = this.getCanvasElements()
    var placement = this.placement
    var opposite = this.opposite(placement)
    var offset = this.offset()

    if (elements.index(this.$element) !== -1) {
      $(this.$element).data('offcanvas-style', $(this.$element).attr('style') || '')
      this.$element.css(placement, -1 * offset)
      this.$element.css(placement); // Workaround: Need to get the CSS property for it to be applied before the next line of code
    }

    elements.addClass('canvas-sliding').each(function() {
      if ($(this).data('offcanvas-style') === undefined) $(this).data('offcanvas-style', $(this).attr('style') || '')
      if ($(this).css('position') === 'static') $(this).css('position', 'relative')
      if (($(this).css(placement) === 'auto' || $(this).css(placement) === '0px') &&
          ($(this).css(opposite) === 'auto' || $(this).css(opposite) === '0px')) {
        $(this).css(placement, 0)
      }
    })

    if (this.options.disableScrolling) this.disableScrolling()
    if (this.options.modal) this.toggleBackdrop()

    var complete = function () {
      if (this.state != 'slide-in') return

      this.state = 'slid'

      elements.removeClass('canvas-sliding').addClass('canvas-slid')
      this.$element.trigger('shown.bs.offcanvas')
    }

    setTimeout($.proxy(function() {
      this.$element.addClass('in')
      this.slide(elements, offset, $.proxy(complete, this))
    }, this), 1)
  }

  OffCanvas.prototype.hide = function (fast) {
    if (this.state !== 'slid') return

    var startEvent = $.Event('hide.bs.offcanvas')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    this.state = 'slide-out'

    var elements = $('.canvas-slid')
    var placement = this.placement
    var offset = -1 * this.offset()

    var complete = function () {
      if (this.state != 'slide-out') return

      this.state = null
      this.placement = null

      this.$element.removeClass('in')

      elements.removeClass('canvas-sliding')
      elements.add(this.$element).add('body').each(function() {
        $(this).attr('style', $(this).data('offcanvas-style')).removeData('offcanvas-style')
      })

      this.$element.trigger('hidden.bs.offcanvas')
    }

    if (this.options.disableScrolling) this.enableScrolling()
    if (this.options.modal) this.toggleBackdrop()

    elements.removeClass('canvas-slid').addClass('canvas-sliding')

    setTimeout($.proxy(function() {
      this.slide(elements, offset, $.proxy(complete, this))
    }, this), 1)
  }

  OffCanvas.prototype.toggle = function () {
    if (this.state === 'slide-in' || this.state === 'slide-out') return
    this[this.state === 'slid' ? 'hide' : 'show']()
  }

  OffCanvas.prototype.toggleBackdrop = function (callback) {
    callback = callback || $.noop;
    if (this.state == 'slide-in') {
      var doAnimate = $.support.transition;

      this.$backdrop = $('<div class="modal-backdrop fade" />')
      .insertAfter(this.$element);

      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow

      this.$backdrop.addClass('in')
      this.$backdrop.on('click.bs', $.proxy(this.autohide, this))

      doAnimate ?
        this.$backdrop
        .one($.support.transition.end, callback)
        .emulateTransitionEnd(150) :
        callback()
    } else if (this.state == 'slide-out' && this.$backdrop) {
      this.$backdrop.removeClass('in');
      $('body').off('touchmove.bs');
      var self = this;
      if ($.support.transition) {
        this.$backdrop
          .one($.support.transition.end, function() {
            self.$backdrop.remove();
            callback()
            self.$backdrop = null;
          })
        .emulateTransitionEnd(150);
      } else {
        this.$backdrop.remove();
        this.$backdrop = null;
        callback();
      }
    } else if (callback) {
      callback()
    }
  }

  OffCanvas.prototype.calcClone = function() {
    this.$calcClone = this.$element.clone()
      .html('')
      .addClass('offcanvas-clone').removeClass('in')
      .appendTo($('body'))
  }

  OffCanvas.prototype.recalc = function () {
    if (this.$calcClone.css('display') === 'none' || (this.state !== 'slid' && this.state !== 'slide-in')) return

    this.state = null
    this.placement = null
    var elements = this.getCanvasElements()

    this.$element.removeClass('in')

    elements.removeClass('canvas-slid')
    elements.add(this.$element).add('body').each(function() {
      $(this).attr('style', $(this).data('offcanvas-style')).removeData('offcanvas-style')
    })
  }

  OffCanvas.prototype.autohide = function (e) {
    if ($(e.target).closest(this.$element).length === 0) this.hide()
  }

  // OFFCANVAS PLUGIN DEFINITION
  // ==========================

  var old = $.fn.offcanvas

  $.fn.offcanvas = function (option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.offcanvas')
      var options = $.extend({}, OffCanvas.DEFAULTS, $this.data(), typeof option === 'object' && option)

      if (!data) $this.data('bs.offcanvas', (data = new OffCanvas(this, options)))
      if (typeof option === 'string') data[option]()
    })
  }

  $.fn.offcanvas.Constructor = OffCanvas

  // OFFCANVAS NO CONFLICT
  // ====================

  $.fn.offcanvas.noConflict = function () {
    $.fn.offcanvas = old
    return this
  }

  // OFFCANVAS DATA-API
  // =================

  $(document).on('click.bs.offcanvas.data-api', '[data-toggle=offcanvas]', function (e) {
    var $this   = $(this), href
    var target  = $this.attr('data-target')
        || e.preventDefault()
        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
    var $canvas = $(target)
    var data    = $canvas.data('bs.offcanvas')
    var option  = data ? 'toggle' : $this.data()

    e.stopPropagation()

    if (data) data.toggle()
      else $canvas.offcanvas(option)
  })

}(window.jQuery);
<commit_msg>Allow touching in the offcanvas area<commit_after>/* ========================================================================
 * Bootstrap: offcanvas.js v3.1.3
 * http://jasny.github.io/bootstrap/javascript/#offcanvas
 * ========================================================================
 * Copyright 2013-2014 Arnold Daniels
 *
 * 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.
 * ======================================================================== */

+function ($) { "use strict";

  // OFFCANVAS PUBLIC CLASS DEFINITION
  // =================================

  var OffCanvas = function (element, options) {
    this.$element = $(element)
    this.options  = $.extend({}, OffCanvas.DEFAULTS, options)
    this.state    = null
    this.placement = null

    if (this.options.recalc) {
      this.calcClone()
      $(window).on('resize', $.proxy(this.recalc, this))
    }

    if (this.options.autohide && !this.options.modal)
      $(document).on('click', $.proxy(this.autohide, this))

    if (this.options.toggle) this.toggle()

    if (this.options.disablescrolling) {
        this.options.disableScrolling = this.options.disablescrolling
        delete this.options.disablescrolling
    }
  }

  OffCanvas.DEFAULTS = {
    toggle: true,
    placement: 'auto',
    autohide: true,
    recalc: true,
    disableScrolling: true,
    modal: false
  }

  OffCanvas.prototype.offset = function () {
    switch (this.placement) {
      case 'left':
      case 'right':  return this.$element.outerWidth()
      case 'top':
      case 'bottom': return this.$element.outerHeight()
    }
  }

  OffCanvas.prototype.calcPlacement = function () {
    if (this.options.placement !== 'auto') {
        this.placement = this.options.placement
        return
    }

    if (!this.$element.hasClass('in')) {
      this.$element.css('visiblity', 'hidden !important').addClass('in')
    }

    var horizontal = $(window).width() / this.$element.width()
    var vertical = $(window).height() / this.$element.height()

    var element = this.$element
    function ab(a, b) {
      if (element.css(b) === 'auto') return a
      if (element.css(a) === 'auto') return b

      var size_a = parseInt(element.css(a), 10)
      var size_b = parseInt(element.css(b), 10)

      return size_a > size_b ? b : a
    }

    this.placement = horizontal >= vertical ? ab('left', 'right') : ab('top', 'bottom')

    if (this.$element.css('visibility') === 'hidden !important') {
      this.$element.removeClass('in').css('visiblity', '')
    }
  }

  OffCanvas.prototype.opposite = function (placement) {
    switch (placement) {
      case 'top':    return 'bottom'
      case 'left':   return 'right'
      case 'bottom': return 'top'
      case 'right':  return 'left'
    }
  }

  OffCanvas.prototype.getCanvasElements = function() {
    // Return a set containing the canvas plus all fixed elements
    var canvas = this.options.canvas ? $(this.options.canvas) : this.$element

    var fixed_elements = canvas.find('*').filter(function() {
      return $(this).css('position') === 'fixed'
    }).not(this.options.exclude)

    return canvas.add(fixed_elements)
  }

  OffCanvas.prototype.slide = function (elements, offset, callback) {
    // Use jQuery animation if CSS transitions aren't supported
    if (!$.support.transition) {
      var anim = {}
      anim[this.placement] = "+=" + offset
      return elements.animate(anim, 350, callback)
    }

    var placement = this.placement
    var opposite = this.opposite(placement)

    elements.each(function() {
      if ($(this).css(placement) !== 'auto')
        $(this).css(placement, (parseInt($(this).css(placement), 10) || 0) + offset)

      if ($(this).css(opposite) !== 'auto')
        $(this).css(opposite, (parseInt($(this).css(opposite), 10) || 0) - offset)
    })

    this.$element
      .one($.support.transition.end, callback)
      .emulateTransitionEnd(350)
  }

  OffCanvas.prototype.disableScrolling = function() {
    var bodyWidth = $('body').width()
    var prop = 'padding-right'

    if ($('body').data('offcanvas-style') === undefined) {
      $('body').data('offcanvas-style', $('body').attr('style') || '')
    }

    $('body').css('overflow', 'hidden')

    if ($('body').width() > bodyWidth) {
      var padding = parseInt($('body').css(prop), 10) + $('body').width() - bodyWidth

      setTimeout(function() {
        $('body').css(prop, padding)
      }, 1)
    }
    //disable scrolling on mobiles (they ignore overflow:hidden)
    $('body').on('touchmove.bs', function(e) {
      if (!$(event.target).closest('.offcanvas').length)
        e.preventDefault();
    });
  }

  OffCanvas.prototype.enableScrolling = function() {
    $('body').off('touchmove.bs');
  }

  OffCanvas.prototype.show = function () {
    if (this.state) return

    var startEvent = $.Event('show.bs.offcanvas')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    this.state = 'slide-in'
    this.calcPlacement();

    var elements = this.getCanvasElements()
    var placement = this.placement
    var opposite = this.opposite(placement)
    var offset = this.offset()

    if (elements.index(this.$element) !== -1) {
      $(this.$element).data('offcanvas-style', $(this.$element).attr('style') || '')
      this.$element.css(placement, -1 * offset)
      this.$element.css(placement); // Workaround: Need to get the CSS property for it to be applied before the next line of code
    }

    elements.addClass('canvas-sliding').each(function() {
      if ($(this).data('offcanvas-style') === undefined) $(this).data('offcanvas-style', $(this).attr('style') || '')
      if ($(this).css('position') === 'static') $(this).css('position', 'relative')
      if (($(this).css(placement) === 'auto' || $(this).css(placement) === '0px') &&
          ($(this).css(opposite) === 'auto' || $(this).css(opposite) === '0px')) {
        $(this).css(placement, 0)
      }
    })

    if (this.options.disableScrolling) this.disableScrolling()
    if (this.options.modal) this.toggleBackdrop()

    var complete = function () {
      if (this.state != 'slide-in') return

      this.state = 'slid'

      elements.removeClass('canvas-sliding').addClass('canvas-slid')
      this.$element.trigger('shown.bs.offcanvas')
    }

    setTimeout($.proxy(function() {
      this.$element.addClass('in')
      this.slide(elements, offset, $.proxy(complete, this))
    }, this), 1)
  }

  OffCanvas.prototype.hide = function (fast) {
    if (this.state !== 'slid') return

    var startEvent = $.Event('hide.bs.offcanvas')
    this.$element.trigger(startEvent)
    if (startEvent.isDefaultPrevented()) return

    this.state = 'slide-out'

    var elements = $('.canvas-slid')
    var placement = this.placement
    var offset = -1 * this.offset()

    var complete = function () {
      if (this.state != 'slide-out') return

      this.state = null
      this.placement = null

      this.$element.removeClass('in')

      elements.removeClass('canvas-sliding')
      elements.add(this.$element).add('body').each(function() {
        $(this).attr('style', $(this).data('offcanvas-style')).removeData('offcanvas-style')
      })

      this.$element.trigger('hidden.bs.offcanvas')
    }

    if (this.options.disableScrolling) this.enableScrolling()
    if (this.options.modal) this.toggleBackdrop()

    elements.removeClass('canvas-slid').addClass('canvas-sliding')

    setTimeout($.proxy(function() {
      this.slide(elements, offset, $.proxy(complete, this))
    }, this), 1)
  }

  OffCanvas.prototype.toggle = function () {
    if (this.state === 'slide-in' || this.state === 'slide-out') return
    this[this.state === 'slid' ? 'hide' : 'show']()
  }

  OffCanvas.prototype.toggleBackdrop = function (callback) {
    callback = callback || $.noop;
    if (this.state == 'slide-in') {
      var doAnimate = $.support.transition;

      this.$backdrop = $('<div class="modal-backdrop fade" />')
      .insertAfter(this.$element);

      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow

      this.$backdrop.addClass('in')
      this.$backdrop.on('click.bs', $.proxy(this.autohide, this))

      doAnimate ?
        this.$backdrop
        .one($.support.transition.end, callback)
        .emulateTransitionEnd(150) :
        callback()
    } else if (this.state == 'slide-out' && this.$backdrop) {
      this.$backdrop.removeClass('in');
      $('body').off('touchmove.bs');
      var self = this;
      if ($.support.transition) {
        this.$backdrop
          .one($.support.transition.end, function() {
            self.$backdrop.remove();
            callback()
            self.$backdrop = null;
          })
        .emulateTransitionEnd(150);
      } else {
        this.$backdrop.remove();
        this.$backdrop = null;
        callback();
      }
    } else if (callback) {
      callback()
    }
  }

  OffCanvas.prototype.calcClone = function() {
    this.$calcClone = this.$element.clone()
      .html('')
      .addClass('offcanvas-clone').removeClass('in')
      .appendTo($('body'))
  }

  OffCanvas.prototype.recalc = function () {
    if (this.$calcClone.css('display') === 'none' || (this.state !== 'slid' && this.state !== 'slide-in')) return

    this.state = null
    this.placement = null
    var elements = this.getCanvasElements()

    this.$element.removeClass('in')

    elements.removeClass('canvas-slid')
    elements.add(this.$element).add('body').each(function() {
      $(this).attr('style', $(this).data('offcanvas-style')).removeData('offcanvas-style')
    })
  }

  OffCanvas.prototype.autohide = function (e) {
    if ($(e.target).closest(this.$element).length === 0) this.hide()
  }

  // OFFCANVAS PLUGIN DEFINITION
  // ==========================

  var old = $.fn.offcanvas

  $.fn.offcanvas = function (option) {
    return this.each(function () {
      var $this   = $(this)
      var data    = $this.data('bs.offcanvas')
      var options = $.extend({}, OffCanvas.DEFAULTS, $this.data(), typeof option === 'object' && option)

      if (!data) $this.data('bs.offcanvas', (data = new OffCanvas(this, options)))
      if (typeof option === 'string') data[option]()
    })
  }

  $.fn.offcanvas.Constructor = OffCanvas

  // OFFCANVAS NO CONFLICT
  // ====================

  $.fn.offcanvas.noConflict = function () {
    $.fn.offcanvas = old
    return this
  }

  // OFFCANVAS DATA-API
  // =================

  $(document).on('click.bs.offcanvas.data-api', '[data-toggle=offcanvas]', function (e) {
    var $this   = $(this), href
    var target  = $this.attr('data-target')
        || e.preventDefault()
        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
    var $canvas = $(target)
    var data    = $canvas.data('bs.offcanvas')
    var option  = data ? 'toggle' : $this.data()

    e.stopPropagation()

    if (data) data.toggle()
      else $canvas.offcanvas(option)
  })

}(window.jQuery);
<|endoftext|>


<commit_before>

// ready

var u = new FrontEndUtils();

$(document).ready(function(){

   setup_utils();

   setup_interaccion();

   scrollToTarget();

   $(window).trigger('resize');

   // $('#header nav.menu').addClass('small-9');

});

var resizing = false;
$(window).resize(function() {
   if( ! resizing ) {
      resizing = setTimeout(function(){
         do_resize();
         resizing = false;
      }, 150)
   }
})

function do_resize() {

   u.vcenter();
   u.shareW();
   u.sameMaxH( $('.sameMaxH') );

   if( $(window).width() <= 1024 ) {
      if( ! $('#avisos-destacados').hasClass('antes') ) {

         $('#avisos-destacados').detach().insertBefore('#area_contenidos')
         $('#avisos-destacados').addClass('antes')

      }

      if( $('#header nav').hasClass('large') ) {

         $('#header nav').removeClass('large').detach().appendTo('#offCanvasRight');

      }

   } else {

      if( $('#avisos-destacados').hasClass('antes') ) {

         $('#avisos-destacados').detach().insertAfter('#area_contenidos')
         $('#avisos-destacados').removeClass('antes')

      }

      if( ! $('#offCanvasRight nav').hasClass('large') ) {

         $('#offCanvasRight nav').addClass('large').detach().appendTo('#header');

      }

      $('#offCanvasRight').foundation('close');

   }

}

function setup_utils() {

   //vcenter
   u.vcenter();
   u.shareW();

   //imgLiquid
   $(".imgLiquidFill").imgLiquid();
   $('.imgLiquid.imgLiquidNoFill').imgLiquid({
      fill:false
   });

   // lineup slider
   $('#lineup_galeria').slick({
      dots: false,
      arrows: true,
      infinite: true,
      speed: 500,
      // fade: true,
      centerMode: true,
      centerPadding: '7vw',
      autoplay: true,
      autoplaySpeed: 3000,
      // cssEase: 'swing',
      slidesToShow: 1,
      slidesToScroll: 1,
      lazyLoad: 'ondemand',
      responsive: [

         {
            breakpoint: 768,
            settings: {
               centerPadding: '1vw',
            }
         }
      ]
   });

   // mapa
   if( $('#festival-map').length > 0 )
      initMap();

}

function setup_interaccion() {

   $('a[href*="#"]:not([href="#"])').click(function() {

      var targetId = $(this).attr('href');
      var target = $(targetId);

      if ( target.length > 0 ) {

         var offsetY = target.offset().top - $('#header').height();

         $('html,body').animate({
            scrollTop: offsetY
         }, 1000);

      }

      return false;

   });

   $('a').click(function(){
      var targetID = getParameterByName('scrollTo', $(this).attr('href') );
      if( targetID && $('#'+targetID ).length ) {
         scrollToTarget( $(this).attr('href') );
         return false;
      }
   })

   $('#festival-boletos-compra input').val(1);

   $('#festival-boletos-compra input').change(function(){
      $('#festival-boletos-compra button').html("Compra "+$(this).val());
   });

   $('#festival-boletos-compra a').click(function(e){
      var preventa_id = "56";
      var cantidad = $('#festival-boletos-compra input').val();

      // clear_cart();
      add_to_cart( preventa_id, function( key ){

         currentKey = key;
         set_cart_item_quantity( key, cantidad , function( result ) {

            setTimeout(function(){
               window.location = $(this).attr('href');
            },1000)
         } );
       })

       e.preventDefault();
       e.stopPropagation();
   })

}

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, " "));
}

function scrollToTarget( url ) {

   var scrollToId = getParameterByName( 'scrollTo', url );

   if( scrollToId != null ) {

      var targetId = '#' + scrollToId;
      var target = $(targetId);

      if ( target.length > 0 ) {

         var offsetY = target.offset().top - $('#header').height();

         $('html,body').animate({
            scrollTop: offsetY
         }, 1000);

      }

   }

}

//mapa
var latLong = {lat: 19.4538898, lng: -99.2192209};
function initMap() {
   var mapDiv = document.getElementById('festival-map');

      // if ( mapDiv.length > 0 ) {

      var map = new google.maps.Map(mapDiv, {
         zoom: 14,
         center: latLong,
         // mapTypeId: google.maps.MapTypeId.ROADMAP,
         scrollwheel: false,
         navigationControl: true,
         mapTypeControl: true,
         draggable: true
      });
      var marker = new google.maps.Marker({
         position: latLong,
         map: map,
         title: 'Off Limits Festival'
      });
   // }
};

function add_to_cart( id, callback ) {
	var ajaxData = {

		type: 'post',
		url: ol_ajax.ajaxurl,
		dataType: 'json',
		data: {
			action: 'add_to_cart',
			id: id
		},
		success: function(key){

         if( typeof(callback) != "undefined" ) {
				callback( key );
			}

		}

	};

	$.ajax(ajaxData);

}

function set_cart_item_quantity( key, quantity, callback ) {

	var ajaxData = {

		type: 'post',
		url: ol_ajax.ajaxurl,
		dataType: 'json',
		data: {
			action: 'set_cart_item_quantity',
			key: key,
			quantity: parseInt( quantity )
		},
		success: function(result){

			if( typeof(callback) != "undefined" )
				callback( result )

		}

	};

	$.ajax( ajaxData );

}

function clear_cart() {

	var ajaxData = {

		type: 'post',
		url: ol_ajax.ajaxurl,
		dataType: 'json',
		data: {
			action: 'clear_cart'
		},
		success: function() {

		}

	};

	$.ajax(ajaxData);

}
<commit_msg>ajustes boletos<commit_after>

// ready

var u = new FrontEndUtils();

$(document).ready(function(){

   setup_utils();

   setup_interaccion();

   scrollToTarget();

   $(window).trigger('resize');

   // $('#header nav.menu').addClass('small-9');

});

var resizing = false;
$(window).resize(function() {
   if( ! resizing ) {
      resizing = setTimeout(function(){
         do_resize();
         resizing = false;
      }, 150)
   }
})

function do_resize() {

   u.vcenter();
   u.shareW();
   u.sameMaxH( $('.sameMaxH') );

   if( $(window).width() <= 1024 ) {
      if( ! $('#avisos-destacados').hasClass('antes') ) {

         $('#avisos-destacados').detach().insertBefore('#area_contenidos')
         $('#avisos-destacados').addClass('antes')

      }

      if( $('#header nav').hasClass('large') ) {

         $('#header nav').removeClass('large').detach().appendTo('#offCanvasRight');

      }

   } else {

      if( $('#avisos-destacados').hasClass('antes') ) {

         $('#avisos-destacados').detach().insertAfter('#area_contenidos')
         $('#avisos-destacados').removeClass('antes')

      }

      if( ! $('#offCanvasRight nav').hasClass('large') ) {

         $('#offCanvasRight nav').addClass('large').detach().appendTo('#header');

      }

      $('#offCanvasRight').foundation('close');

   }

}

function setup_utils() {

   //vcenter
   u.vcenter();
   u.shareW();

   //imgLiquid
   $(".imgLiquidFill").imgLiquid();
   $('.imgLiquid.imgLiquidNoFill').imgLiquid({
      fill:false
   });

   // lineup slider
   $('#lineup_galeria').slick({
      dots: false,
      arrows: true,
      infinite: true,
      speed: 500,
      // fade: true,
      centerMode: true,
      centerPadding: '7vw',
      autoplay: true,
      autoplaySpeed: 3000,
      // cssEase: 'swing',
      slidesToShow: 1,
      slidesToScroll: 1,
      lazyLoad: 'ondemand',
      responsive: [

         {
            breakpoint: 768,
            settings: {
               centerPadding: '1vw',
            }
         }
      ]
   });

   // mapa
   if( $('#festival-map').length > 0 )
      initMap();

}

function setup_interaccion() {

   $('a[href*="#"]:not([href="#"])').click(function() {

      var targetId = $(this).attr('href');
      var target = $(targetId);

      if ( target.length > 0 ) {

         var offsetY = target.offset().top - $('#header').height();

         $('html,body').animate({
            scrollTop: offsetY
         }, 1000);

      }

      return false;

   });

   $('a').click(function(){
      var targetID = getParameterByName('scrollTo', $(this).attr('href') );
      if( targetID && $('#'+targetID ).length ) {
         scrollToTarget( $(this).attr('href') );
         return false;
      }
   })

   $('#festival-boletos-compra input').val(1);

   $('#festival-boletos-compra input').change(function(){
      $('#festival-boletos-compra button').html("Compra "+$(this).val());
   });

   $('#festival-boletos-compra a').click(function(e){
      var preventa_id = "56";
      var cantidad = $('#festival-boletos-compra input').val();
      var link = $(this);
      // clear_cart();
      add_to_cart( preventa_id, function( key ){

         currentKey = key;
         set_cart_item_quantity( key, cantidad , function( result ) {

            setTimeout(function(){
               window.location = link.attr('href');
            },1000)
         } );
       })

       e.preventDefault();
       e.stopPropagation();
   })

}

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, " "));
}

function scrollToTarget( url ) {

   var scrollToId = getParameterByName( 'scrollTo', url );

   if( scrollToId != null ) {

      var targetId = '#' + scrollToId;
      var target = $(targetId);

      if ( target.length > 0 ) {

         var offsetY = target.offset().top - $('#header').height();

         $('html,body').animate({
            scrollTop: offsetY
         }, 1000);

      }

   }

}

//mapa
var latLong = {lat: 19.4538898, lng: -99.2192209};
function initMap() {
   var mapDiv = document.getElementById('festival-map');

      // if ( mapDiv.length > 0 ) {

      var map = new google.maps.Map(mapDiv, {
         zoom: 14,
         center: latLong,
         // mapTypeId: google.maps.MapTypeId.ROADMAP,
         scrollwheel: false,
         navigationControl: true,
         mapTypeControl: true,
         draggable: true
      });
      var marker = new google.maps.Marker({
         position: latLong,
         map: map,
         title: 'Off Limits Festival'
      });
   // }
};

function add_to_cart( id, callback ) {
	var ajaxData = {

		type: 'post',
		url: ol_ajax.ajaxurl,
		dataType: 'json',
		data: {
			action: 'add_to_cart',
			id: id
		},
		success: function(key){

         if( typeof(callback) != "undefined" ) {
				callback( key );
			}

		}

	};

	$.ajax(ajaxData);

}

function set_cart_item_quantity( key, quantity, callback ) {

	var ajaxData = {

		type: 'post',
		url: ol_ajax.ajaxurl,
		dataType: 'json',
		data: {
			action: 'set_cart_item_quantity',
			key: key,
			quantity: parseInt( quantity )
		},
		success: function(result){

			if( typeof(callback) != "undefined" )
				callback( result )

		}

	};

	$.ajax( ajaxData );

}

function clear_cart() {

	var ajaxData = {

		type: 'post',
		url: ol_ajax.ajaxurl,
		dataType: 'json',
		data: {
			action: 'clear_cart'
		},
		success: function() {

		}

	};

	$.ajax(ajaxData);

}
<|endoftext|>


<commit_before>var pDiv = document.createElement("div");
pDiv.setAttribute("onclick", "return window;");
p = pDiv.onclick();

var $ = p.$;
var currentTrackId = "";
var settings;
var storedTrackInfo = {};
var recordsWithArtInCss = {};

////////////////////////////Enums

var lastfmStatus = {
	SCROBBLING_DISABLED: -1,
	UNSENT: 0,
	PLAYING_SENT: 1,
	WAITING_FOR_SCROBBLING: 2,
	SCROBBLED: 3
}

////////////////////////////

function urlEncodeCharacter(c) {
	return '%' + c.charCodeAt(0).toString(16);
}

function urlEncode(s) {
    return encodeURIComponent( s ).replace( /\%20/g, '+' ).replace( /[!'()*~]/g, urlEncodeCharacter );
}

function getUser(id) {
	var user = undefined;
	for(var i = 0; i < p.room.users.length; i++) {
		if(p.room.users[i].id == id) {
			user = p.room.users[i];
		}
	}
	return user;
}

function newTrack(id) {
	var track = p.room.tracks[id];
	var user = getUser(track.userId);
	var trackData = {
		id: id,
		filename: track.upload.originalFilename
	};
	if(user != undefined) {
		trackData.user = user.name;
	}
	if(track.metadata.artist != undefined && track.metadata.title != undefined) {
		trackData.title = track.metadata.title;
		trackData.artist = track.metadata.artist;
		trackData.album = track.metadata.album;
	}
	chrome.extension.sendRequest({type: "newtrack", track: trackData}, function(response) {});
}

function showSettings() {
	$("#addons_lightbox_dimmer").show();
	$("#addons_lightbox_dimmer").click(hideSettings);
	$("#addons_settings").show();
}

function hideSettings() {
	$("#addons_lightbox_dimmer").hide();
	$("#addons_lightbox_dimmer").unbind('click');
	$("#addons_settings").hide();
}

function saveSettings() {
	settings = {};
	settings.hidechat = document.getElementById("addons_settings_hidechat").checked;
	settings.showuploader = document.getElementById("addons_settings_showuploader").checked;
	settings.albumart = document.getElementById("addons_settings_albumart").checked;
	settings.twitterusernamelinks = document.getElementById("addons_settings_twitterusernamelinks").checked;

	settings.scrobble = document.getElementById("addons_settings_scrobble").checked;
	settings.showscrobblestatus = document.getElementById("addons_settings_showscrobblestatus").checked;
	settings.lastfmlink = document.getElementById("addons_settings_lastfmlink").checked;
	settings.showlastfmlovebutton = document.getElementById("addons_settings_showlastfmlovebutton").checked;

	chrome.extension.sendRequest({type: "savesettings", settings:settings}, function(response) {});
	hideSettings();
	updateAllTrackData();
	applyChatHidden();
	removeRecordImagesIfNecessary();
	removeTwitterLinksIfNecessary();
}

function loadSettings() {
	chrome.extension.sendRequest({type: "getsettings"}, function(newSettings) {
		document.getElementById("addons_settings_hidechat").checked = newSettings.hidechat;
		document.getElementById("addons_settings_showuploader").checked = newSettings.showuploader;
		document.getElementById("addons_settings_albumart").checked = newSettings.albumart;
		document.getElementById("addons_settings_twitterusernamelinks").checked = newSettings.twitterusernamelinks;

		document.getElementById("addons_settings_scrobble").checked = newSettings.scrobble;
		document.getElementById("addons_settings_showscrobblestatus").checked = newSettings.showscrobblestatus;
		document.getElementById("addons_settings_lastfmlink").checked = newSettings.lastfmlink;
		document.getElementById("addons_settings_showlastfmlovebutton").checked = newSettings.showlastfmlovebutton;

		settings = newSettings;
		applyChatHidden();
	});
}

function showChangelog() {
	$("#addons_lightbox_dimmer").show();
	$("#addons_lightbox_dimmer").click(hideChangelog);
	$("#addons_changelog").show();
}

function hideChangelog() {
	$("#addons_lightbox_dimmer").hide();
	$("#addons_lightbox_dimmer").unbind('click');
	$("#addons_changelog").hide();
}

// The log in box is different from other pop ups. Clicking outside this box should not cancel it.
function showLastFmLogin() {
	$("#addons_lightbox_dimmer").show();
	$("#addons_lastfmlogin").show();
}

function hideLastFmLogin() {
	$("#addons_lightbox_dimmer").hide();
	$("#addons_lastfmlogin").hide();
}

function sendLastFmLogin() {
	var login = {};
	login.username = $("#addons_lastfm_username").val();
	login.password = $("#addons_lastfm_password").val();
	$("#addons_lastfm_password").val("");
	chrome.extension.sendRequest({type: "lastfmlogin", login:login}, function(response) {});
	hideLastFmLogin();
}

function dontDoLastFmLogin() {
	settings.scrobble = false;
	document.getElementById("addons_settings_scrobble").checked = false;
	settings.showlastfmlovebutton = false;
	document.getElementById("addons_settings_showlastfmlovebutton").checked = false;

	chrome.extension.sendRequest({type: "savesettings", settings:settings}, function(response) {});
	updateAllTrackData();
	hideLastFmLogin();
}

function processMessage(request, sender, sendResponse) {
	if(request.type == "lastfmloginneeded") {
		if(request.lastfmUsername && $("#addons_lastfm_username").val() == "") {
			$("#addons_lastfm_username").val(request.lastfmUsername);
		}
		showLastFmLogin();
		sendResponse({});
	} else if(request.type = "updatedtrackinfo") {
		storedTrackInfo[request.id] = request.info;
		sendResponse({});
	}
}

function checkForNewTrack() {
	if(p.room.nowPlaying != undefined && currentTrackId != p.room.nowPlaying) {
		newTrack(p.room.nowPlaying);
		currentTrackId = p.room.nowPlaying;
	}
}

function buttonHtml(url, imagename, titleText) {
	return '';
}

function resizedImage(width, url) {
	return "http://resizer.co?w="+ width +"&img=" + urlEncode(url);
}

function fetchTrackInfo(trackId) {
	chrome.extension.sendRequest({type: "gettrackinfo", id:trackId}, function(response) {
		if(response != undefined) {
			storedTrackInfo[trackId] = response;
		}
	});
}

function updateAllTrackData() {
	$("div.addons_trackdata").each(function(index) {
		var trackId = this.id.substring(16);
		updateSingleTrackData(trackId, $(this));
	});
}

function updateSingleTrackData(trackId, el) {
	if(!el) {
		el = $("div#addon_trackdata_"+ trackId);
	}
	var track = p.room.tracks[trackId];
	var trackDataHtml = "";

	var trackInfo = storedTrackInfo[trackId];
	if(trackInfo) {
		if(trackInfo.albumArt && trackInfo.albumArt != "none") {
			setRecordImage(trackId, resizedImage(190, trackInfo.albumArt));
		}
		if(settings.showuploader) {
			var user = trackInfo.user;
			if(user != undefined && user != "") {
				if(settings.twitterusernamelinks) {
					var twitterUrl = "http://www.twitter.com/"+ user;
					trackDataHtml += '
Uploaded by '+ user +'
';
				} else {
					trackDataHtml += '
Uploaded by '+ user +'
';
				}
			} else {
				trackDataHtml += '
Uploader has now left the room
';
			}
		}
		if(settings.lastfmlink && trackInfo.lastfmurl && trackInfo.lastfmurl != "none") {
			trackDataHtml += buttonHtml(trackInfo.lastfmurl, chrome.extension.getURL("lastfm_button.png"), "See this track on Last.fm.");
		}
		if(settings.showscrobblestatus && trackInfo.lastfmstatus) {
			var imagePath = "";
			var titleText = "";
			if(trackInfo.lastfmstatus == lastfmStatus.UNSENT || trackInfo.lastfmstatus == lastfmStatus.PLAYING_SENT || trackInfo.lastfmstatus == lastfmStatus.WAITING_FOR_SCROBBLING) {
				imagePath = "notscrobbled.png";
				titleText = "This track has not been scrobbled yet. This will usually happen when the track finishes playing."
			} else if(trackInfo.lastfmstatus == lastfmStatus.SCROBBLED) {
				imagePath = "scrobbled.png";
				titleText = "This track has been scrobbled."
			}
			if(imagePath != "") {
				trackDataHtml += ''
			}
		}
		if(settings.showlastfmlovebutton && !trackInfo.lastfmloved && track.metadata.title) {
			trackDataHtml += ''
		}

	} else {
		fetchTrackInfo(trackId);
	}

	el.html(trackDataHtml);
	if(settings.showlastfmlovebutton) {
		el.find("a.addons_lastfm_lovebutton").click(function() {
			setTrackLoved(trackId, track.metadata.title, track.metadata.artist);
			$(this).hide();
		});
	}
}

function applyChatHidden() {
	var styleNode = $("style#addons_css_hidechat");
	if(settings.hidechat && !styleNode.length) {
		styleNode = document.createElement("style");
		$(styleNode).attr("type", "text/css")
			.attr("id", "addons_css_hidechat")
			.append("div.annotation {display: none;}");
		$("head").append(styleNode);
	} else if(!settings.hidechat && styleNode.length) {
		styleNode.remove();
	}
}

function removeRecordImagesIfNecessary() {
	var styleNode = $("style#addons_css_records");
	if(!settings.albumart && styleNode.length) {
		styleNode.remove();
		recordsWithArtInCss = {};
	}
}

function setRecordImage(trackId, url) {
	if(settings.albumart && !recordsWithArtInCss[trackId]) {
		var styleNode = $("style#addons_css_records");
		if(!styleNode.length) {
			styleNode = document.createElement("style");
			styleNode = $(styleNode);
			styleNode.attr("type", "text/css")
				.attr("id", "addons_css_records");
			$("head").append(styleNode);
		}
		styleNode.append("div#record-"+ trackId +" div.record {background-image: url("+ url + ");} ");
		recordsWithArtInCss[trackId] = true;
	}
}

function setTrackLoved(trackId, title, artist) {
	chrome.extension.sendRequest({type: "settrackloved", id:trackId, title: title, artist: artist}, function(response) {});
}

function addTrackDataDiv(html, track, opt_userP) {
	var dataDiv = "

";

	var jHtml = $(html);
	jHtml.find("div.description").append(dataDiv);
	html = $('
').append(jHtml.clone()).remove().html();

	return html;
}

function linkifyTwitterNames() {
	if(settings.twitterusernamelinks) {
		$(".username:not(.addons_username), li.user span.name:not(.addons_username)").each(function(index){
			$(this).addClass("addons_username");
			var username = this.innerHTML;
			this.dataset.username = username;
			var twitterUrl = "http://www.twitter.com/"+ username;
			this.innerHTML = "" + username + "";
		});
	}
}

function removeTwitterLinksIfNecessary() {
	if(!settings.twitterusernamelinks) {
		$(".username.addons_username, span.name.addons_username").each(function(index){
			$(this).removeClass("addons_username");
			this.innerHTML = this.dataset.username;
		});
	}
}

function pulse() {
	checkForNewTrack();
	linkifyTwitterNames();
}

function slowPulse() {
	updateAllTrackData();
}

function init() {
	$("body").append("

");
	chrome.extension.sendRequest({type: "gethtml", url:"popups.html"}, function(response) {
		$("#addons").html(response);

		$("#addons_settings_save").click(saveSettings);
		$("#addons_settings_cancel").click(hideSettings);
		$("#addons_changelog_close").click(hideChangelog);

		loadSettings();

		$("#addons_lastfm_button").click(sendLastFmLogin);
		$("#addons_lastfm_cancel").click(dontDoLastFmLogin);
	});

	$("#sponsor").before("

");
	chrome.extension.sendRequest({type: "gethtml", url:"links.html"}, function(response) {
		$("#addons_links").html(response);
		$("#addons_settings_link").click(showSettings);
		$("#addons_changelog_link").click(showChangelog);
	});

	if(!p.viz.recordHtmlOriginal) {
		p.viz.recordHtmlOriginal = p.viz.recordHtml;
		p.viz.recordHtmlMods = [];

		p.viz.recordHtml = function(track, opt_userP) {
			var html = p.viz.recordHtmlOriginal(track, opt_userP);
			html = addTrackDataDiv(html, track, opt_userP);
			return html;
		};
	}

	setInterval(pulse, 1000);
	setInterval(slowPulse, 3000);
	chrome.extension.onRequest.addListener(processMessage);
}

init();<commit_msg>Override element level display:block; on chat comments. Closes #10.<commit_after>var pDiv = document.createElement("div");
pDiv.setAttribute("onclick", "return window;");
p = pDiv.onclick();

var $ = p.$;
var currentTrackId = "";
var settings;
var storedTrackInfo = {};
var recordsWithArtInCss = {};

////////////////////////////Enums

var lastfmStatus = {
	SCROBBLING_DISABLED: -1,
	UNSENT: 0,
	PLAYING_SENT: 1,
	WAITING_FOR_SCROBBLING: 2,
	SCROBBLED: 3
}

////////////////////////////

function urlEncodeCharacter(c) {
	return '%' + c.charCodeAt(0).toString(16);
}

function urlEncode(s) {
    return encodeURIComponent( s ).replace( /\%20/g, '+' ).replace( /[!'()*~]/g, urlEncodeCharacter );
}

function getUser(id) {
	var user = undefined;
	for(var i = 0; i < p.room.users.length; i++) {
		if(p.room.users[i].id == id) {
			user = p.room.users[i];
		}
	}
	return user;
}

function newTrack(id) {
	var track = p.room.tracks[id];
	var user = getUser(track.userId);
	var trackData = {
		id: id,
		filename: track.upload.originalFilename
	};
	if(user != undefined) {
		trackData.user = user.name;
	}
	if(track.metadata.artist != undefined && track.metadata.title != undefined) {
		trackData.title = track.metadata.title;
		trackData.artist = track.metadata.artist;
		trackData.album = track.metadata.album;
	}
	chrome.extension.sendRequest({type: "newtrack", track: trackData}, function(response) {});
}

function showSettings() {
	$("#addons_lightbox_dimmer").show();
	$("#addons_lightbox_dimmer").click(hideSettings);
	$("#addons_settings").show();
}

function hideSettings() {
	$("#addons_lightbox_dimmer").hide();
	$("#addons_lightbox_dimmer").unbind('click');
	$("#addons_settings").hide();
}

function saveSettings() {
	settings = {};
	settings.hidechat = document.getElementById("addons_settings_hidechat").checked;
	settings.showuploader = document.getElementById("addons_settings_showuploader").checked;
	settings.albumart = document.getElementById("addons_settings_albumart").checked;
	settings.twitterusernamelinks = document.getElementById("addons_settings_twitterusernamelinks").checked;

	settings.scrobble = document.getElementById("addons_settings_scrobble").checked;
	settings.showscrobblestatus = document.getElementById("addons_settings_showscrobblestatus").checked;
	settings.lastfmlink = document.getElementById("addons_settings_lastfmlink").checked;
	settings.showlastfmlovebutton = document.getElementById("addons_settings_showlastfmlovebutton").checked;

	chrome.extension.sendRequest({type: "savesettings", settings:settings}, function(response) {});
	hideSettings();
	updateAllTrackData();
	applyChatHidden();
	removeRecordImagesIfNecessary();
	removeTwitterLinksIfNecessary();
}

function loadSettings() {
	chrome.extension.sendRequest({type: "getsettings"}, function(newSettings) {
		document.getElementById("addons_settings_hidechat").checked = newSettings.hidechat;
		document.getElementById("addons_settings_showuploader").checked = newSettings.showuploader;
		document.getElementById("addons_settings_albumart").checked = newSettings.albumart;
		document.getElementById("addons_settings_twitterusernamelinks").checked = newSettings.twitterusernamelinks;

		document.getElementById("addons_settings_scrobble").checked = newSettings.scrobble;
		document.getElementById("addons_settings_showscrobblestatus").checked = newSettings.showscrobblestatus;
		document.getElementById("addons_settings_lastfmlink").checked = newSettings.lastfmlink;
		document.getElementById("addons_settings_showlastfmlovebutton").checked = newSettings.showlastfmlovebutton;

		settings = newSettings;
		applyChatHidden();
	});
}

function showChangelog() {
	$("#addons_lightbox_dimmer").show();
	$("#addons_lightbox_dimmer").click(hideChangelog);
	$("#addons_changelog").show();
}

function hideChangelog() {
	$("#addons_lightbox_dimmer").hide();
	$("#addons_lightbox_dimmer").unbind('click');
	$("#addons_changelog").hide();
}

// The log in box is different from other pop ups. Clicking outside this box should not cancel it.
function showLastFmLogin() {
	$("#addons_lightbox_dimmer").show();
	$("#addons_lastfmlogin").show();
}

function hideLastFmLogin() {
	$("#addons_lightbox_dimmer").hide();
	$("#addons_lastfmlogin").hide();
}

function sendLastFmLogin() {
	var login = {};
	login.username = $("#addons_lastfm_username").val();
	login.password = $("#addons_lastfm_password").val();
	$("#addons_lastfm_password").val("");
	chrome.extension.sendRequest({type: "lastfmlogin", login:login}, function(response) {});
	hideLastFmLogin();
}

function dontDoLastFmLogin() {
	settings.scrobble = false;
	document.getElementById("addons_settings_scrobble").checked = false;
	settings.showlastfmlovebutton = false;
	document.getElementById("addons_settings_showlastfmlovebutton").checked = false;

	chrome.extension.sendRequest({type: "savesettings", settings:settings}, function(response) {});
	updateAllTrackData();
	hideLastFmLogin();
}

function processMessage(request, sender, sendResponse) {
	if(request.type == "lastfmloginneeded") {
		if(request.lastfmUsername && $("#addons_lastfm_username").val() == "") {
			$("#addons_lastfm_username").val(request.lastfmUsername);
		}
		showLastFmLogin();
		sendResponse({});
	} else if(request.type = "updatedtrackinfo") {
		storedTrackInfo[request.id] = request.info;
		sendResponse({});
	}
}

function checkForNewTrack() {
	if(p.room.nowPlaying != undefined && currentTrackId != p.room.nowPlaying) {
		newTrack(p.room.nowPlaying);
		currentTrackId = p.room.nowPlaying;
	}
}

function buttonHtml(url, imagename, titleText) {
	return '';
}

function resizedImage(width, url) {
	return "http://resizer.co?w="+ width +"&img=" + urlEncode(url);
}

function fetchTrackInfo(trackId) {
	chrome.extension.sendRequest({type: "gettrackinfo", id:trackId}, function(response) {
		if(response != undefined) {
			storedTrackInfo[trackId] = response;
		}
	});
}

function updateAllTrackData() {
	$("div.addons_trackdata").each(function(index) {
		var trackId = this.id.substring(16);
		updateSingleTrackData(trackId, $(this));
	});
}

function updateSingleTrackData(trackId, el) {
	if(!el) {
		el = $("div#addon_trackdata_"+ trackId);
	}
	var track = p.room.tracks[trackId];
	var trackDataHtml = "";

	var trackInfo = storedTrackInfo[trackId];
	if(trackInfo) {
		if(trackInfo.albumArt && trackInfo.albumArt != "none") {
			setRecordImage(trackId, resizedImage(190, trackInfo.albumArt));
		}
		if(settings.showuploader) {
			var user = trackInfo.user;
			if(user != undefined && user != "") {
				if(settings.twitterusernamelinks) {
					var twitterUrl = "http://www.twitter.com/"+ user;
					trackDataHtml += '
Uploaded by '+ user +'
';
				} else {
					trackDataHtml += '
Uploaded by '+ user +'
';
				}
			} else {
				trackDataHtml += '
Uploader has now left the room
';
			}
		}
		if(settings.lastfmlink && trackInfo.lastfmurl && trackInfo.lastfmurl != "none") {
			trackDataHtml += buttonHtml(trackInfo.lastfmurl, chrome.extension.getURL("lastfm_button.png"), "See this track on Last.fm.");
		}
		if(settings.showscrobblestatus && trackInfo.lastfmstatus) {
			var imagePath = "";
			var titleText = "";
			if(trackInfo.lastfmstatus == lastfmStatus.UNSENT || trackInfo.lastfmstatus == lastfmStatus.PLAYING_SENT || trackInfo.lastfmstatus == lastfmStatus.WAITING_FOR_SCROBBLING) {
				imagePath = "notscrobbled.png";
				titleText = "This track has not been scrobbled yet. This will usually happen when the track finishes playing."
			} else if(trackInfo.lastfmstatus == lastfmStatus.SCROBBLED) {
				imagePath = "scrobbled.png";
				titleText = "This track has been scrobbled."
			}
			if(imagePath != "") {
				trackDataHtml += ''
			}
		}
		if(settings.showlastfmlovebutton && !trackInfo.lastfmloved && track.metadata.title) {
			trackDataHtml += ''
		}

	} else {
		fetchTrackInfo(trackId);
	}

	el.html(trackDataHtml);
	if(settings.showlastfmlovebutton) {
		el.find("a.addons_lastfm_lovebutton").click(function() {
			setTrackLoved(trackId, track.metadata.title, track.metadata.artist);
			$(this).hide();
		});
	}
}

function applyChatHidden() {
	var styleNode = $("style#addons_css_hidechat");
	if(settings.hidechat && !styleNode.length) {
		styleNode = document.createElement("style");
		$(styleNode).attr("type", "text/css")
			.attr("id", "addons_css_hidechat")
			.append("div.annotation {display: none !important;}");
		$("head").append(styleNode);
	} else if(!settings.hidechat && styleNode.length) {
		styleNode.remove();
	}
}

function removeRecordImagesIfNecessary() {
	var styleNode = $("style#addons_css_records");
	if(!settings.albumart && styleNode.length) {
		styleNode.remove();
		recordsWithArtInCss = {};
	}
}

function setRecordImage(trackId, url) {
	if(settings.albumart && !recordsWithArtInCss[trackId]) {
		var styleNode = $("style#addons_css_records");
		if(!styleNode.length) {
			styleNode = document.createElement("style");
			styleNode = $(styleNode);
			styleNode.attr("type", "text/css")
				.attr("id", "addons_css_records");
			$("head").append(styleNode);
		}
		styleNode.append("div#record-"+ trackId +" div.record {background-image: url("+ url + ");} ");
		recordsWithArtInCss[trackId] = true;
	}
}

function setTrackLoved(trackId, title, artist) {
	chrome.extension.sendRequest({type: "settrackloved", id:trackId, title: title, artist: artist}, function(response) {});
}

function addTrackDataDiv(html, track, opt_userP) {
	var dataDiv = "

";

	var jHtml = $(html);
	jHtml.find("div.description").append(dataDiv);
	html = $('
').append(jHtml.clone()).remove().html();

	return html;
}

function linkifyTwitterNames() {
	if(settings.twitterusernamelinks) {
		$(".username:not(.addons_username), li.user span.name:not(.addons_username)").each(function(index){
			$(this).addClass("addons_username");
			var username = this.innerHTML;
			this.dataset.username = username;
			var twitterUrl = "http://www.twitter.com/"+ username;
			this.innerHTML = "" + username + "";
		});
	}
}

function removeTwitterLinksIfNecessary() {
	if(!settings.twitterusernamelinks) {
		$(".username.addons_username, span.name.addons_username").each(function(index){
			$(this).removeClass("addons_username");
			this.innerHTML = this.dataset.username;
		});
	}
}

function pulse() {
	checkForNewTrack();
	linkifyTwitterNames();
}

function slowPulse() {
	updateAllTrackData();
}

function init() {
	$("body").append("

");
	chrome.extension.sendRequest({type: "gethtml", url:"popups.html"}, function(response) {
		$("#addons").html(response);

		$("#addons_settings_save").click(saveSettings);
		$("#addons_settings_cancel").click(hideSettings);
		$("#addons_changelog_close").click(hideChangelog);

		loadSettings();

		$("#addons_lastfm_button").click(sendLastFmLogin);
		$("#addons_lastfm_cancel").click(dontDoLastFmLogin);
	});

	$("#sponsor").before("

");
	chrome.extension.sendRequest({type: "gethtml", url:"links.html"}, function(response) {
		$("#addons_links").html(response);
		$("#addons_settings_link").click(showSettings);
		$("#addons_changelog_link").click(showChangelog);
	});

	if(!p.viz.recordHtmlOriginal) {
		p.viz.recordHtmlOriginal = p.viz.recordHtml;
		p.viz.recordHtmlMods = [];

		p.viz.recordHtml = function(track, opt_userP) {
			var html = p.viz.recordHtmlOriginal(track, opt_userP);
			html = addTrackDataDiv(html, track, opt_userP);
			return html;
		};
	}

	setInterval(pulse, 1000);
	setInterval(slowPulse, 3000);
	chrome.extension.onRequest.addListener(processMessage);
}

init();<|endoftext|>


<commit_before>
/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

let instance = null;
let log = require("../../net2/logger.js")(__filename);

const firewalla = require('../../net2/Firewalla.js');

const fHome = firewalla.getFirewallaHome()
const frpDirectory = __dirname
const configTemplateFile = `${frpDirectory}/frpc.ini.template`  // default template
const serviceTemplateFile = `${frpDirectory}/frpc.service.template`;

const Promise = require('bluebird');

const async = require('asyncawait/async');
const await = require('asyncawait/await');

const rclient = require('../../util/redis_manager.js').getRedisClient()

//const spawn = require('child-process-promise').spawn;
const spawn = require('child_process').spawn
const spawnSync = require('child_process').spawnSync

const fs = require('fs')
const readFile = Promise.promisify(fs.readFile)
const writeFile = Promise.promisify(fs.writeFile)
const unlink = Promise.promisify(fs.unlink)

function delay(t) {
  return new Promise(function(resolve) {
    setTimeout(resolve, t)
  });
}

module.exports = class {
  constructor(name) {
    this.name = name || "support";
    this.started = false
    this.serviceTag = "SSH"
    this.configComplete = false;

    (async () => {
      if (await this._isUp()) {
        // need to refresh config
        await this._loadConfigFile();
        this.started = true;
        this.configComplete = true;
      }
    })();
    return this
  }

  async _loadConfigFile() {
    const configPath = this._getConfigPath();
    const configData = await readFile(configPath, 'utf8');
    let lines = configData.split('\n');
    lines = lines.filter(l => l.includes("remote_port"));
    const remotePort = lines[0].substring(14);  // length of "remote_port = "
    this.port = remotePort;
  }

  async createConfigFile(config) {
    if (this.name === "support") {
      return this._prepareConfiguration(config);
    }
    const genericTemplate = `${frpDirectory}/frpc.generic.ini.template`
    const port = config.port || this._getRandomPort(config.portBase, config.portLength)
    this.port = port;

    let templateData = await readFile(genericTemplate, 'utf8');

    if(config.name) {
      templateData = templateData.replace(/FRP_SERVICE_NAME/g, config.name)
    }

    if(port) {
      templateData = templateData.replace(/FRP_SERVICE_PORT/g, port)
    }

    if(config.token) {
      templateData = templateData.replace(/FRP_SERVICE_TOKEN/g, config.token)
    }

    if(config.server) {
      templateData = templateData.replace(/FRP_SERVER_ADDR/g, config.server)
    }

    if(config.serverPort) {
      templateData = templateData.replace(/FRP_SERVER_PORT/g, config.serverPort)
    }

    if(config.internalPort) {
      templateData = templateData.replace(/FRP_SERVICE_INTERNAL_PORT/g, config.internalPort)
    }

    if(config.protocol) {
      templateData = templateData.replace(/FRP_SERVICE_PROTOCOL/g, config.protocol)
    }

    const filePath = this._getConfigPath();
    await writeFile(filePath, templateData, 'utf8');

    this.configComplete = true;
    return {
      filePath: filePath,
      port: port
    };
  }

  _getConfigPath() {
    return `${frpDirectory}/frpc.${this.name}.ini`;
  }

  _getPidPath() {
    if (this.name !== "support") {
      return `${frpDirectory}/frpc.customized.${this.name}.pid`;
    } else {
      // use default pid file
      return pidFile;
    }
  }

  _getServiceName() {
    return `frpc.${this.name}`;
  }

  _getServiceFilePath() {
    return `${frpDirectory}/frpc.${this.name}.service`;
  }

  async _isUp() {
    const serviceName = this._getServiceName();
    const o = spawnSync('systemctl', ['is-active', '--quiet', serviceName]);
    const exitCode = o.status;
    if (exitCode === 0) {
      log.info(`Service ${serviceName} is already up`);
      return true;
    }
    return false;
  }

  async _prepareConfiguration(config) {
    let templateFile = configTemplateFile // default is the support config template file
    const userToken = null;
    if (config) {
      userToken = config.userToken;
    }

    if(this.templateFilename) {
      templateFile = `${frpDirectory}/${this.templateFilename}`
    }

    this.port = this._getRandomPort();

    let templateData = await readFile(templateFile, 'utf8')
    templateData = templateData.replace(/FRP_SERVICE_NAME/g, `${this.serviceTag}${this.port}`)
    templateData = templateData.replace(/FRP_SERVICE_PORT/g, this.port)

    let token = await rclient.hgetAsync("sys:config", "frpToken")
    if(userToken) {
      token = userToken
    }
    if(this.token) {
      token = this.token
    }
    if(token) {
      templateData = templateData.replace(/FRP_SERVICE_TOKEN/g, token)
    }

    if(this.server) {
      templateData = templateData.replace(/FRP_SERVER/g, this.server)
    }

    const configFilePath = this._getConfigPath();
    await writeFile(configFilePath, templateData, 'utf8')

    this.configComplete = true;
    return {
      filePath: configFilePath,
      port: 22
    };
  }

  configFile() {
    return this._getConfigPath();
  }

  server() {
    return "support.firewalla.com"
  }

  user() {
    return "pi"
  }

  getConfig() {

    return {
      started: this.started,
      port: this.port,
      server: this.server(),
      user: this.user()
    }
  }

  _getRandomPort(base, length) {
    base = base || 9000
    length = length || 1000
    return  Math.floor(Math.random() * length) + base
  }

  start() {
    return async(() => {
      const isUp = await(this._isUp());
      if (!isUp) {
        await(this.createConfigFile());
        return this._start();
      } else {
        await(this._loadConfigFile());
        this.started = true;
        this.configComplete = true;
      }
    })()
  }

  stop() {
    (async () => {
      if (await this._isUp()) {
        this._stop();
      }
    })();
    return delay(500)
  }

  _start() {
    const serviceName = this._getServiceName();
    const serviceFilePath = this._getServiceFilePath();
    const configFilePath = this._getConfigPath();
    const frpCmd = `${frpDirectory}/frpc.${firewalla.getPlatform()}`;
    /*
    // TODO: ini file needs to be customized before being used
    const args = ["-c", configFilePath];

    this.cp = spawn(cmd, args, {cwd: frpDirectory, encoding: 'utf8', detached: true});
    this.cp.unref();
    const childPid = this.cp.pid;
    log.info("frp process id: " + childPid);
    */

    return new Promise((resolve, reject) => {
      // generate service spec file
      let templateData = await(readFile(serviceTemplateFile, 'utf8'));
      templateData = templateData.replace(/FRPC_COMMAND/g, frpCmd);
      templateData = templateData.replace(/FRPC_CONF/g, configFilePath);
      await(writeFile(serviceFilePath, templateData, 'utf8'));

      spawnSync('sudo', ['cp', serviceFilePath, '/etc/systemd/system/']);
      const cp = spawn('sudo', ['systemctl', 'start', serviceName]);
      let hasTimeout = true;

      cp.stderr.on('data', (data) => {
        log.error(data.toString())
      })

      cp.on('exit', (code, signal) => {
        if (code === 0) {
          log.info("Service " + serviceName + " started successfully");
          this.started = true;
          hasTimeout = false;
          resolve();
        } else {
          log.error("Failed to start " + serviceName, code, signal, {});
        }
      })

      /*
      process.on('exit', () => {
        this._stop();
      });
      */

      // wait for 15 seconds
      delay(15000).then(() => {
        if(hasTimeout) {
          log.error("Timeout, failed to start frp")
          reject(new Error("Failed to start frp"))
        }
      })
    })
  }

  _stop() {
    const serviceName = this._getServiceName();
    log.info("Try to stop FRP service:" + serviceName);
    spawnSync('sudo', ['systemctl', 'stop', serviceName]);
    this.started = false;
  }
}

<commit_msg>add comment in frp.js<commit_after>
/*    Copyright 2016 Firewalla LLC
 *
 *    This program is free software: you can redistribute it and/or  modify
 *    it under the terms of the GNU Affero General Public License, version 3,
 *    as published by the Free Software Foundation.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Affero General Public License for more details.
 *
 *    You should have received a copy of the GNU Affero General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
'use strict';

let instance = null;
let log = require("../../net2/logger.js")(__filename);

const firewalla = require('../../net2/Firewalla.js');

const fHome = firewalla.getFirewallaHome()
const frpDirectory = __dirname
const configTemplateFile = `${frpDirectory}/frpc.ini.template`  // default template
const serviceTemplateFile = `${frpDirectory}/frpc.service.template`;

const Promise = require('bluebird');

const async = require('asyncawait/async');
const await = require('asyncawait/await');

const rclient = require('../../util/redis_manager.js').getRedisClient()

//const spawn = require('child-process-promise').spawn;
const spawn = require('child_process').spawn
const spawnSync = require('child_process').spawnSync

const fs = require('fs')
const readFile = Promise.promisify(fs.readFile)
const writeFile = Promise.promisify(fs.writeFile)
const unlink = Promise.promisify(fs.unlink)

function delay(t) {
  return new Promise(function(resolve) {
    setTimeout(resolve, t)
  });
}

module.exports = class {
  constructor(name) {
    this.name = name || "support";
    this.started = false
    this.serviceTag = "SSH"
    this.configComplete = false;

    // if frp service is started during execution of async block, inconsistency may occur?
    (async () => {
      if (await this._isUp()) {
        // need to refresh config
        await this._loadConfigFile();
        this.started = true;
        this.configComplete = true;
      }
    })();
    return this
  }

  async _loadConfigFile() {
    const configPath = this._getConfigPath();
    const configData = await readFile(configPath, 'utf8');
    let lines = configData.split('\n');
    lines = lines.filter(l => l.includes("remote_port"));
    const remotePort = lines[0].substring(14);  // length of "remote_port = "
    this.port = remotePort;
  }

  async createConfigFile(config) {
    if (this.name === "support") {
      return this._prepareConfiguration(config);
    }
    const genericTemplate = `${frpDirectory}/frpc.generic.ini.template`
    const port = config.port || this._getRandomPort(config.portBase, config.portLength)
    this.port = port;

    let templateData = await readFile(genericTemplate, 'utf8');

    if(config.name) {
      templateData = templateData.replace(/FRP_SERVICE_NAME/g, config.name)
    }

    if(port) {
      templateData = templateData.replace(/FRP_SERVICE_PORT/g, port)
    }

    if(config.token) {
      templateData = templateData.replace(/FRP_SERVICE_TOKEN/g, config.token)
    }

    if(config.server) {
      templateData = templateData.replace(/FRP_SERVER_ADDR/g, config.server)
    }

    if(config.serverPort) {
      templateData = templateData.replace(/FRP_SERVER_PORT/g, config.serverPort)
    }

    if(config.internalPort) {
      templateData = templateData.replace(/FRP_SERVICE_INTERNAL_PORT/g, config.internalPort)
    }

    if(config.protocol) {
      templateData = templateData.replace(/FRP_SERVICE_PROTOCOL/g, config.protocol)
    }

    const filePath = this._getConfigPath();
    await writeFile(filePath, templateData, 'utf8');

    this.configComplete = true;
    return {
      filePath: filePath,
      port: port
    };
  }

  _getConfigPath() {
    return `${frpDirectory}/frpc.${this.name}.ini`;
  }

  _getPidPath() {
    if (this.name !== "support") {
      return `${frpDirectory}/frpc.customized.${this.name}.pid`;
    } else {
      // use default pid file
      return pidFile;
    }
  }

  _getServiceName() {
    return `frpc.${this.name}`;
  }

  _getServiceFilePath() {
    return `${frpDirectory}/frpc.${this.name}.service`;
  }

  async _isUp() {
    const serviceName = this._getServiceName();
    const o = spawnSync('systemctl', ['is-active', '--quiet', serviceName]);
    const exitCode = o.status;
    if (exitCode === 0) {
      log.info(`Service ${serviceName} is already up`);
      return true;
    }
    return false;
  }

  async _prepareConfiguration(config) {
    let templateFile = configTemplateFile // default is the support config template file
    const userToken = null;
    if (config) {
      userToken = config.userToken;
    }

    if(this.templateFilename) {
      templateFile = `${frpDirectory}/${this.templateFilename}`
    }

    this.port = this._getRandomPort();

    let templateData = await readFile(templateFile, 'utf8')
    templateData = templateData.replace(/FRP_SERVICE_NAME/g, `${this.serviceTag}${this.port}`)
    templateData = templateData.replace(/FRP_SERVICE_PORT/g, this.port)

    let token = await rclient.hgetAsync("sys:config", "frpToken")
    if(userToken) {
      token = userToken
    }
    if(this.token) {
      token = this.token
    }
    if(token) {
      templateData = templateData.replace(/FRP_SERVICE_TOKEN/g, token)
    }

    if(this.server) {
      templateData = templateData.replace(/FRP_SERVER/g, this.server)
    }

    const configFilePath = this._getConfigPath();
    await writeFile(configFilePath, templateData, 'utf8')

    this.configComplete = true;
    return {
      filePath: configFilePath,
      port: 22
    };
  }

  configFile() {
    return this._getConfigPath();
  }

  server() {
    return "support.firewalla.com"
  }

  user() {
    return "pi"
  }

  getConfig() {

    return {
      started: this.started,
      port: this.port,
      server: this.server(),
      user: this.user()
    }
  }

  _getRandomPort(base, length) {
    base = base || 9000
    length = length || 1000
    return  Math.floor(Math.random() * length) + base
  }

  start() {
    return async(() => {
      const isUp = await(this._isUp());
      if (!isUp) {
        await(this.createConfigFile());
        return this._start();
      } else {
        await(this._loadConfigFile());
        this.started = true;
        this.configComplete = true;
      }
    })()
  }

  stop() {
    (async () => {
      if (await this._isUp()) {
        this._stop();
      }
    })();
    return delay(500)
  }

  _start() {
    const serviceName = this._getServiceName();
    const serviceFilePath = this._getServiceFilePath();
    const configFilePath = this._getConfigPath();
    const frpCmd = `${frpDirectory}/frpc.${firewalla.getPlatform()}`;
    /*
    // TODO: ini file needs to be customized before being used
    const args = ["-c", configFilePath];

    this.cp = spawn(cmd, args, {cwd: frpDirectory, encoding: 'utf8', detached: true});
    this.cp.unref();
    const childPid = this.cp.pid;
    log.info("frp process id: " + childPid);
    */

    return new Promise((resolve, reject) => {
      // generate service spec file
      let templateData = await(readFile(serviceTemplateFile, 'utf8'));
      templateData = templateData.replace(/FRPC_COMMAND/g, frpCmd);
      templateData = templateData.replace(/FRPC_CONF/g, configFilePath);
      await(writeFile(serviceFilePath, templateData, 'utf8'));

      spawnSync('sudo', ['cp', serviceFilePath, '/etc/systemd/system/']);
      const cp = spawn('sudo', ['systemctl', 'start', serviceName]);
      let hasTimeout = true;

      cp.stderr.on('data', (data) => {
        log.error(data.toString())
      })

      cp.on('exit', (code, signal) => {
        if (code === 0) {
          log.info("Service " + serviceName + " started successfully");
          this.started = true;
          hasTimeout = false;
          resolve();
        } else {
          log.error("Failed to start " + serviceName, code, signal, {});
        }
      })

      /*
      process.on('exit', () => {
        this._stop();
      });
      */

      // wait for 15 seconds
      delay(15000).then(() => {
        if(hasTimeout) {
          log.error("Timeout, failed to start frp")
          reject(new Error("Failed to start frp"))
        }
      })
    })
  }

  _stop() {
    const serviceName = this._getServiceName();
    log.info("Try to stop FRP service:" + serviceName);
    spawnSync('sudo', ['systemctl', 'stop', serviceName]);
    this.started = false;
  }
}

<|endoftext|>