<commit_before>/**
*
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/

'use strict';

class Menu {
  constructor () {
    this._menu = document.querySelector('.js-menu');
    this._menuContents = this._menu.querySelector('.js-menu-contents');
    this._menuToggleButton = this._menu.querySelector('.js-menu-toggle');
    this._menuTitle = this._menu.querySelector('.js-menu-title');

    this._expanded = true;
    this._animate = false;
    this._duration = 200;
    this._frameTime = 1/60;
    this._collapsed;

    this.expand = this.expand.bind(this);
    this.collapse = this.collapse.bind(this);
    this.toggle = this.toggle.bind(this);

    this._calculateScales();
    this._createEaseAnimations();
    this._addEventListeners();

    this.collapse();
    this.activate();

  }

  activate () {
    this._menu.classList.add('menu--active');
    this._animate = true;
  }

  collapse () {
    if (!this._expanded) {
      return;
    }
    this._expanded = false;

    const {x, y} = this._collapsed;
    const invX = 1 / x;
    const invY = 1 / y;

    this._menu.style.transform = `scale(${x}, ${y})`;
    this._menuContents.style.transform = `scale(${invX}, ${invY})`;

    if (!this._animate) {
      return;
    }

    this._applyAnimation({expand: false});
  }

  expand () {
    if (this._expanded) {
      return;
    }
    this._expanded = true;

    this._menu.style.transform = `scale(1, 1)`;
    this._menuContents.style.transform = `scale(1, 1)`;

    if (!this._animate) {
      return;
    }

    this._applyAnimation({expand: true});
  }

  toggle () {
    if (this._expanded) {
      this.collapse();
      return;
    }

    this.expand();
  }

  _addEventListeners () {
    this._menuToggleButton.addEventListener('click', this.toggle);
  }

  _applyAnimation ({expand}=opts) {
    this._menu.classList.remove('menu--expanded');
    this._menu.classList.remove('menu--collapsed');
    this._menuContents.classList.remove('menu__contents--expanded');
    this._menuContents.classList.remove('menu__contents--collapsed');

    // Force a recalc styles here so the classes take hold.
    window.getComputedStyle(this._menu).transform;

    if (expand) {
      this._menu.classList.add('menu--expanded');
      this._menuContents.classList.add('menu__contents--expanded');
      return;
    }

    this._menu.classList.add('menu--collapsed');
    this._menuContents.classList.add('menu__contents--collapsed');
  }

  _calculateScales () {
    const collapsed = this._menuTitle.getBoundingClientRect();
    const expanded = this._menu.getBoundingClientRect();

    this._collapsed = {
      x: collapsed.width / expanded.width,
      y: collapsed.height / expanded.height
    }
  }

  _createEaseAnimations () {
    let menuEase = document.querySelector('.menu-ease');
    if (menuEase) {
      return menuEase;
    }

    this._nFrames = Math.round(this._duration / this._frameTime);

    menuEase = document.createElement('style');
    menuEase.classList.add('menu-ease');

    const menuExpandAnimation = [];
    const menuExpandContentsAnimation = [];
    const menuCollapseAnimation = [];
    const menuCollapseContentsAnimation = [];

    const percentIncrement = 100 / this._nFrames;

    for (let i = 0; i <= this._nFrames; i++) {
      const step = this._ease(i / this._nFrames).toFixed(5);
      const percentage = (i * percentIncrement).toFixed(5);
      const startX = this._collapsed.x;
      const startY = this._collapsed.y;
      const endX = 1;
      const endY = 1;

      // Expand animation.
      this._append({
        percentage,
        step,
        startX: this._collapsed.x,
        startY: this._collapsed.y,
        endX: 1,
        endY: 1,
        outerAnimation: menuExpandAnimation,
        innerAnimation: menuExpandContentsAnimation
      });

      // Collapse animation.
      this._append({
        percentage,
        step,
        startX: 1,
        startY: 1,
        endX: this._collapsed.x,
        endY: this._collapsed.y,
        outerAnimation: menuCollapseAnimation,
        innerAnimation: menuCollapseContentsAnimation
      });
    }

    menuEase.textContent = `
    @keyframes menuExpandAnimation {
      ${menuExpandAnimation.join('')}
    }

    @keyframes menuExpandContentsAnimation {
      ${menuExpandContentsAnimation.join('')}
    }

    @keyframes menuCollapseAnimation {
      ${menuCollapseAnimation.join('')}
    }

    @keyframes menuCollapseContentsAnimation {
      ${menuCollapseContentsAnimation.join('')}
    }`;

    document.head.appendChild(menuEase);
    return menuEase;
  }

  _append ({
    percentage,
    step,
    startX,
    startY,
    endX,
    endY,
    outerAnimation,
    innerAnimation}=opts) {

      const xScale = (startX + (endX - startX) * step).toFixed(5);
      const yScale = (startY + (endY - startY) * step).toFixed(5);

      const invScaleX = (1 / xScale).toFixed(5);
      const invScaleY = (1 / yScale).toFixed(5);

      outerAnimation.push(`
      ${percentage}% {
        transform: scale(${xScale}, ${yScale});
      }`);

      innerAnimation.push(`
      ${percentage}% {
        transform: scale(${invScaleX}, ${invScaleY});
      }`);
    }

    _clamp (value, min, max) {
      return Math.max(min, Math.min(max, value));
    }

    _ease (v, pow=4) {
      v = this._clamp(v, 0, 1);

      return 1 - Math.pow(1 - v, pow);
    }
  }

  new Menu()
<commit_msg>moved the _nFrames calc to the constructor<commit_after>/**
*
* Copyright 2017 Google Inc. All rights reserved.
*
* 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.
*/

'use strict';

class Menu {
  constructor () {
    this._menu = document.querySelector('.js-menu');
    this._menuContents = this._menu.querySelector('.js-menu-contents');
    this._menuToggleButton = this._menu.querySelector('.js-menu-toggle');
    this._menuTitle = this._menu.querySelector('.js-menu-title');

    this._expanded = true;
    this._animate = false;
    this._duration = 200;
    this._frameTime = 1/60;
    this._nFrames = Math.round(this._duration / this._frameTime);
    this._collapsed;

    this.expand = this.expand.bind(this);
    this.collapse = this.collapse.bind(this);
    this.toggle = this.toggle.bind(this);

    this._calculateScales();
    this._createEaseAnimations();
    this._addEventListeners();

    this.collapse();
    this.activate();

  }

  activate () {
    this._menu.classList.add('menu--active');
    this._animate = true;
  }

  collapse () {
    if (!this._expanded) {
      return;
    }
    this._expanded = false;

    const {x, y} = this._collapsed;
    const invX = 1 / x;
    const invY = 1 / y;

    this._menu.style.transform = `scale(${x}, ${y})`;
    this._menuContents.style.transform = `scale(${invX}, ${invY})`;

    if (!this._animate) {
      return;
    }

    this._applyAnimation({expand: false});
  }

  expand () {
    if (this._expanded) {
      return;
    }
    this._expanded = true;

    this._menu.style.transform = `scale(1, 1)`;
    this._menuContents.style.transform = `scale(1, 1)`;

    if (!this._animate) {
      return;
    }

    this._applyAnimation({expand: true});
  }

  toggle () {
    if (this._expanded) {
      this.collapse();
      return;
    }

    this.expand();
  }

  _addEventListeners () {
    this._menuToggleButton.addEventListener('click', this.toggle);
  }

  _applyAnimation ({expand}=opts) {
    this._menu.classList.remove('menu--expanded');
    this._menu.classList.remove('menu--collapsed');
    this._menuContents.classList.remove('menu__contents--expanded');
    this._menuContents.classList.remove('menu__contents--collapsed');

    // Force a recalc styles here so the classes take hold.
    window.getComputedStyle(this._menu).transform;

    if (expand) {
      this._menu.classList.add('menu--expanded');
      this._menuContents.classList.add('menu__contents--expanded');
      return;
    }

    this._menu.classList.add('menu--collapsed');
    this._menuContents.classList.add('menu__contents--collapsed');
  }

  _calculateScales () {
    const collapsed = this._menuTitle.getBoundingClientRect();
    const expanded = this._menu.getBoundingClientRect();

    this._collapsed = {
      x: collapsed.width / expanded.width,
      y: collapsed.height / expanded.height
    }
  }

  _createEaseAnimations () {
    let menuEase = document.querySelector('.menu-ease');
    if (menuEase) {
      return menuEase;
    }

    menuEase = document.createElement('style');
    menuEase.classList.add('menu-ease');

    const menuExpandAnimation = [];
    const menuExpandContentsAnimation = [];
    const menuCollapseAnimation = [];
    const menuCollapseContentsAnimation = [];

    const percentIncrement = 100 / this._nFrames;

    for (let i = 0; i <= this._nFrames; i++) {
      const step = this._ease(i / this._nFrames).toFixed(5);
      const percentage = (i * percentIncrement).toFixed(5);
      const startX = this._collapsed.x;
      const startY = this._collapsed.y;
      const endX = 1;
      const endY = 1;

      // Expand animation.
      this._append({
        percentage,
        step,
        startX: this._collapsed.x,
        startY: this._collapsed.y,
        endX: 1,
        endY: 1,
        outerAnimation: menuExpandAnimation,
        innerAnimation: menuExpandContentsAnimation
      });

      // Collapse animation.
      this._append({
        percentage,
        step,
        startX: 1,
        startY: 1,
        endX: this._collapsed.x,
        endY: this._collapsed.y,
        outerAnimation: menuCollapseAnimation,
        innerAnimation: menuCollapseContentsAnimation
      });
    }

    menuEase.textContent = `
    @keyframes menuExpandAnimation {
      ${menuExpandAnimation.join('')}
    }

    @keyframes menuExpandContentsAnimation {
      ${menuExpandContentsAnimation.join('')}
    }

    @keyframes menuCollapseAnimation {
      ${menuCollapseAnimation.join('')}
    }

    @keyframes menuCollapseContentsAnimation {
      ${menuCollapseContentsAnimation.join('')}
    }`;

    document.head.appendChild(menuEase);
    return menuEase;
  }

  _append ({
    percentage,
    step,
    startX,
    startY,
    endX,
    endY,
    outerAnimation,
    innerAnimation}=opts) {

      const xScale = (startX + (endX - startX) * step).toFixed(5);
      const yScale = (startY + (endY - startY) * step).toFixed(5);

      const invScaleX = (1 / xScale).toFixed(5);
      const invScaleY = (1 / yScale).toFixed(5);

      outerAnimation.push(`
      ${percentage}% {
        transform: scale(${xScale}, ${yScale});
      }`);

      innerAnimation.push(`
      ${percentage}% {
        transform: scale(${invScaleX}, ${invScaleY});
      }`);
    }

    _clamp (value, min, max) {
      return Math.max(min, Math.min(max, value));
    }

    _ease (v, pow=4) {
      v = this._clamp(v, 0, 1);

      return 1 - Math.pow(1 - v, pow);
    }
  }

  new Menu()
<|endoftext|>


<commit_before>'use strict';

let cli     = require('heroku-cli-util');
let request = require('request');

module.exports = {
  topic: 'builds',
  command: 'output',
  needsAuth: true,
  needsApp: true,
  description: 'show build output',
  help: 'Show build output for a Heroku app',
  args: [
    {
      name: 'id',
      optional: false,
      hidden: false
    }
  ],
  run: cli.command(showOutput)
};

function showOutput(context, heroku) {
  let id = context.args.id;

  return heroku.request({
    path: `/apps/${context.app}/builds/${id}`,
    method: 'GET',
    parseJSON: true
  }).then(function (build) {
    request(build.output_stream_url).pipe(process.stdout);
  });
}
<commit_msg>Fetch context<commit_after>'use strict';

let cli     = require('heroku-cli-util');
let request = require('request');

module.exports = {
  topic: 'builds',
  command: 'output',
  needsAuth: true,
  needsApp: true,
  description: 'show build output',
  help: 'Show build output for a Heroku app',
  args: [
    {
      name: 'id',
      optional: false,
      hidden: false
    }
  ],
  run: cli.command(showOutput)
};

function showOutput(context, heroku) {
  let app = heroku.apps(context.app);

  let id = context.args.id;

  return heroku.request({
    path: `/apps/${context.app}/builds/${id}`,
    method: 'GET',
    parseJSON: true
  }).then(function (build) {
    request(build.output_stream_url).pipe(process.stdout);
  });
}
<|endoftext|>


<commit_before>'use strict';

var request = require('request'), //get body
nodemailer 	= require('nodemailer'), //send mail
conf		= require('./conf').conf, //that's you!
_			= require('lodash'),
transporter = nodemailer.createTransport({
    service: 'Gmail', //you want something else? deal with it.
    auth: conf.gmail
});

exports.send_mail = function(apparts, from){
	var plural = (apparts.length > 1) ? ' appartements' : ' appartement', //funk. or Useless?
	html = "
";
	apparts.forEach(function(one){
		html += '
' + one.price + ' : ' +  one.title + '';
		if(one.upload !== false) html += '  -- (' + one.upload + ')';
		html += '
';
		one.labels.forEach(function(l, i){ html+= '
' + l + one.values[i] + '
'; });
		html += '
';
		html += '
';
		html += '

';
	});
	html += '
';
	transporter.sendMail({
		encoding: 'unicode',
	    from: conf.gmail.user, //from you
	    to: conf.gmail.user, //to you
	    subject: '[' + from + '] ' + apparts.length + plural + ' à regarder!',
	    html: html
	}, function(error, info){
		if(error) console.log(error);
		else console.log('Message sent: ' + info.response + ' à ' + new Date());
	});
};

var scrap = function(){
	_.forEach(conf.urls, function(list, type){
		var scrapper = require('./scrappers/' + type); //get good scrapper.
		list.forEach(function(url){
			request({uri: url, encoding: null}, scrapper.scrap);
		});
	});
};

//	start srcapping.
scrap();
// setInterval(function(){	scrap();}, conf.sec * 1000);
<commit_msg>uncomment stuff<commit_after>'use strict';

var request = require('request'), //get body
nodemailer 	= require('nodemailer'), //send mail
conf		= require('./conf').conf, //that's you!
_			= require('lodash'),
transporter = nodemailer.createTransport({
    service: 'Gmail', //you want something else? deal with it.
    auth: conf.gmail
});

exports.send_mail = function(apparts, from){
	var plural = (apparts.length > 1) ? ' appartements' : ' appartement', //funk. or Useless?
	html = "
";
	apparts.forEach(function(one){
		html += '
' + one.price + ' : ' +  one.title + '';
		if(one.upload !== false) html += '  -- (' + one.upload + ')';
		html += '
';
		one.labels.forEach(function(l, i){ html+= '
' + l + one.values[i] + '
'; });
		html += '
';
		html += '
';
		html += '

';
	});
	html += '
';
	transporter.sendMail({
		encoding: 'unicode',
	    from: conf.gmail.user, //from you
	    to: conf.gmail.user, //to you
	    subject: '[' + from + '] ' + apparts.length + plural + ' à regarder!',
	    html: html
	}, function(error, info){
		if(error) console.log(error);
		else console.log('Message sent: ' + info.response + ' à ' + new Date());
	});
};

var scrap = function(){
	_.forEach(conf.urls, function(list, type){
		var scrapper = require('./scrappers/' + type); //get good scrapper.
		list.forEach(function(url){
			request({uri: url, encoding: null}, scrapper.scrap);
		});
	});
};

//	start srcapping.
scrap();
setInterval(function(){	scrap();}, conf.sec * 1000);
<|endoftext|>


<commit_before>mini.Module(
		"assets/converter/fromjson/jsontobodyconverter"
)
.requires(
		"assets/converter/fromjson/jsontoclosedshapeconverter",
		"assets/converter/fromjson/jsontointernalspringconverter"
)
.defines(function() {
	var JsonToBodyConverter = {};

	JsonToBodyConverter.convertJsonToBody = function(bodyJson, world) {
		// read bluePrint
		var bluePrint = Jello.BodyFactory.createBluePrint(Jello[bodyJson.class] || Jello.Body);

		if(typeof bodyJson.shape !== "undefined")
			bluePrint.shape(Jello.ClosedShape.fromJson(bodyJson.shape));

		Bloob.JsonToBodyConverter.readBodyParameters(bluePrint, bodyJson);

		var body = bluePrint
			.world(world)
			.build();

		return body;
	};

	JsonToBodyConverter.readBodyParameters = function(bluePrint, jsonWithParameters) {
		var parameterNames = [
	       "pointMasses",
	       "translate",
	       "rotate",
	       "scale",
	       "isKinematic",
	       "edgeSpringK",
	       "edgeSpringDamp",
	       "shapeSpringK",
	       "shapeSpringDamp",
	       "gasPressure",
	       "internalSprings"
		];

		// iterate all possible parameter names
		for(var index in parameterNames) {
			var parameterName = parameterNames[index];

			// if parameter is defined in json...
			if(typeof jsonWithParameters[parameterName] !== "undefined") {
				// annotate blueprint
				if(parameterName == "translate" || parameterName == "scale") {
					// need to convert into Jello.Vector2
					var parameterValue = Jello.Vector2.fromJson(jsonWithParameters[parameterName]);
					bluePrint[parameterName](parameterValue);
				}
				else if(parameterName == "internalSprings") {
					// iterate over internalSprings array; attach each spring to bluePrint
					for(var index in jsonWithParameters["internalSprings"]) {
						var springParameters = jsonWithParameters["internalSprings"][index];
						Jello.InternalSpring.fromJson(springParameters, bluePrint);
					};
				}
				else
				{
					var parameterValue = jsonWithParameters[parameterName];
					bluePrint[parameterName](parameterValue);
				}
			};
		};
	};

	Jello.Body.fromJson = function(bodyJson, world) {
		Bloob.JsonToBodyConverter.convertJsonToBody(bodyJson, world);
	};

	Bloob.JsonToBodyConverter = JsonToBodyConverter;

	return JsonToBodyConverter;
});
<commit_msg>clarified dependencies in JsonToBodyConverter<commit_after>mini.Module(
	"assets/converter/fromjson/jsontobodyconverter"
)
.requires(
	"assets/converter/fromjson/jsontoclosedshapeconverter",
	"assets/converter/fromjson/jsontointernalspringconverter"
)
.defines(function(JsonToClosedShapeConverter, JsonToInternalSpringConverter) {
	var JsonToBodyConverter = {};

	JsonToBodyConverter.convertJsonToBody = function(bodyJson, world) {
		// read bluePrint
		var bluePrint = Jello.BodyFactory.createBluePrint(Jello[bodyJson.class] || Jello.Body);

		if(typeof bodyJson.shape !== "undefined")
			bluePrint.shape(Jello.ClosedShape.fromJson(bodyJson.shape));

		JsonToBodyConverter.readBodyParameters(bluePrint, bodyJson);

		var body = bluePrint
			.world(world)
			.build();

		return body;
	};

	JsonToBodyConverter.readBodyParameters = function(bluePrint, jsonWithParameters) {
		var parameterNames = [
	       "pointMasses",
	       "translate",
	       "rotate",
	       "scale",
	       "isKinematic",
	       "edgeSpringK",
	       "edgeSpringDamp",
	       "shapeSpringK",
	       "shapeSpringDamp",
	       "gasPressure",
	       "internalSprings"
		];

		// iterate all possible parameter names
		for(var index in parameterNames) {
			var parameterName = parameterNames[index];

			// if parameter is defined in json...
			if(typeof jsonWithParameters[parameterName] !== "undefined") {
				// annotate blueprint
				if(parameterName == "translate" || parameterName == "scale") {
					// need to convert into Jello.Vector2
					var parameterValue = Jello.Vector2.fromJson(jsonWithParameters[parameterName]);
					bluePrint[parameterName](parameterValue);
				}
				else if(parameterName == "internalSprings") {
					// iterate over internalSprings array; attach each spring to bluePrint
					for(var index in jsonWithParameters["internalSprings"]) {
						var springParameters = jsonWithParameters["internalSprings"][index];
						Jello.InternalSpring.fromJson(springParameters, bluePrint);
					};
				}
				else
				{
					var parameterValue = jsonWithParameters[parameterName];
					bluePrint[parameterName](parameterValue);
				}
			};
		};
	};

	Jello.Body.fromJson = function(bodyJson, world) {
		JsonToBodyConverter.convertJsonToBody(bodyJson, world);
	};

	return JsonToBodyConverter;
});
<|endoftext|>


<commit_before>//= require js-cookie/v2.0.2
//= require mustache

/*
 * Plugin Name: Jquery Shopping Cart
 *
 * Author: Instant Website Team
 *
 * Note: Call Jquery Shopping Cart after jQuery in Application JS loaded
 */

window.addEventListener("load", function() {
  (function($) {

    ShoppingCart = function(element) {
      this.item = null;
      this.$element = null;
      this.cart = [];
      this.locales = null;

      this.init(element);
    }

    ShoppingCart.prototype.init = function(element) {
      this.$element     = $(element);
      this.locales      = this.$element.data('ecommerce-locales')
      this.checkoutUrl  = this.$element.data('checkout-url')
      this.assignCookieToCart();
      this.bindClickAddToCart();
      this.updateItemInList();
      this.updateTotalItems();
      this.bindClickCartIcon();
      this.bindClickDocument();
    }

    ShoppingCart.prototype.assignCookieToCart = function() {
      var getCookieVal = Cookies.getJSON('shopping-cart');

      if(getCookieVal != undefined) {
        this.cart = getCookieVal.items;
      }
    }

    ShoppingCart.prototype.bindClickDocument = function() {
      var $element = this.$element;

      $(document).on('click', function (e) {
        var container = $('.shopping-cart-icon')

        if (!container.is(e.target) && container.has(e.target).length === 0) {
          $element.find('.badge-open').removeClass('badge-show')
        }
      });
    }

    ShoppingCart.prototype.bindClickCartIcon = function() {
      var $element = this.$element;

      $element.find('.shop-badge').on('click', function() {
        $element.find('.badge-open').toggleClass('badge-show');
      })
    }

    ShoppingCart.prototype.bindClickAddToCart = function() {
      var self = this;

      this.$element.find('.js-add-to-cart').each(function() {
        $(this).click(function() {
          var qty = self.$element.find('#js-item-qty').val() || 1;

          if(self.isPositiveNumber(qty)) {
            var  product = $(this).data('product').product;

            product.quantity = parseInt(qty);
            self.item = product;

            self.addToCart();
            self.updateTotalItems();
            self.flyImageToCart();
          }
        });
      });
    }

    ShoppingCart.prototype.addToCart = function() {
      this.assignCookieToCart();

      if(this.itemExists()) {
        this.updateItem();
      }else {
        this.addItem();
      }

      this.updateItemInList();
    }

    ShoppingCart.prototype.flyImageToCart = function() {
      var imgToDrag = this.$element.find(".js-image-to-cart").eq(0),
        top = (imgToDrag.offset().top + imgToDrag.outerHeight()/2) - 75,
        left = (imgToDrag.offset().left + imgToDrag.outerWidth()/2) - 75,
        cartIcon = this.$element.find(".shop-badge"),
        imgclone;

      if (imgToDrag) {
          imgclone = imgToDrag.clone()
          .offset({
            top: top,
            left: left
        })
          .css({
            'opacity':  '0.5',
            'z-index':  '100',
            'width':    '150px',
            'height':   '150px',
            'position': 'absolute'
        })
          .appendTo($('body'))
          .animate({
            'width': 45,
            'height': 45,
            'top': cartIcon.offset().top + 10,
            'left': cartIcon.offset().left + 10
        }, 1200, 'easeInOutExpo');

        setTimeout(function () {
            cartIcon.effect("shake", {
              times: 2
            }, 200);
        }, 1500);

        imgclone.animate({
          'width': 0,
          'height': 0
        }, function () {
          $(this).detach()
        });
      }
    }

    ShoppingCart.prototype.addItem = function() {
      this.cart.push(this.item);
    }

    ShoppingCart.prototype.updateItem = function() {
      var cart = this.cart,
          item = this.item;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item.id) {
          cart[i]["quantity"] += item.quantity;
        }
      }

      this.cart = cart;
    }

    ShoppingCart.prototype.bindClickRemoveFromCart = function() {
      var self = this;

      this.$element.find('.remove-from-cart').each(function() {
        $(this).on("click", function(e) {
          e.stopPropagation();

          self.removeItem($(this).data('id'));
          self.updateTotalItems();
        })
      })
    }

    ShoppingCart.prototype.removeItem = function(item_id) {
      var cart = this.cart;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item_id) {
          cart = $.grep(cart, function(value) {
            return value != cart[i];
          });
        }
      }

      this.cart = cart;
      this.updateItemInList();
      this.$element.find('.badge-open').addClass('badge-show')
    }

    ShoppingCart.prototype.updateTotalItems = function() {
      var cart = this.cart,
          totalItems = 0;

      for(var i=0; i<cart.length; i++) {
        totalItems += cart[i]["quantity"];
      }

      this.$element.find('#total-items').html(totalItems);
    }

    ShoppingCart.prototype.getTotal = function() {
      var cart = this.cart,
          subtotal = 0,
          total = 0,
          currencyCode = $('body').data('currency-code');

      for(var i=0; i<cart.length; i++) {
        subtotal = cart[i]['quantity'] * cart[i]['price'];

        total += subtotal;
      }

      return this.formatCurrency(total, currencyCode);
    }

    ShoppingCart.prototype.itemExists = function() {
      var cart = this.cart,
          item  = this.item;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item.id) return true;
      }
    }

    ShoppingCart.prototype.updateItemInList = function() {
      var cart = this.cart,
          $unOrderList = $('
'),
          $liSubtotal  = $('
');

          $unOrderList.append(this.buildLiHeader());

          for(var i=0; i<cart.length; i++) {
            $unOrderList.append(this.buildItemLi(cart[i]));
          }

      $unOrderList.append(this.buildSubtotalLi());
      $('#shopping-cart-list').html($unOrderList);

      this.bindClickRemoveFromCart();
      this.emptyCart();
      this.toggleBadge();
      Cookies.set('shopping-cart', { items: this.cart });
    }

    ShoppingCart.prototype.buildLiHeader = function() {
      $liHeader = $('
'),
      $h4 = $('
').text(this.locales.shopping_cart);

      return $liHeader.append($h4);
    }

    ShoppingCart.prototype.buildItemLi = function(item) {
      var currencyCode = $('body').data('currency-code'),
          qtyWithPrice = item.quantity + " x " + item.price + " " + currencyCode,
          $li = $('
'),
          $wrapperLeft = $('
'),
          $wrapperRight = $('
'),
          $imgWrapper = $('
'),
          $img = $('').attr({src: item.image_url}),

          $button = $('<button type="button" class="close remove-from-cart"/>'),
          $overflowH = $('
'),
          $link = $('').text(item.name).attr({href: item.url}),
          $small = $('').text(qtyWithPrice);

      $button.attr({'data-id': item.id}).text("×");
      $imgWrapper.append($img);
      $wrapperLeft.append($imgWrapper);
      $overflowH.append($link, $small)
      $wrapperRight.append($button, $overflowH)

      return $li.append($wrapperLeft, $wrapperRight);
    }

    ShoppingCart.prototype.buildSubtotalLi = function() {
      var totalCost = this.getTotal(),
          $li = $('
'),
          $div = $('
'),
          $spanLabel = $('').text(this.locales.subtotal),
          $spanCost = $('').text(totalCost);
          $btnCheckout = $('').text(this.locales.checkout);

      $div.append($spanLabel, $spanCost);

      return $li.append($div, this.checkoutForm());
    }

    ShoppingCart.prototype.checkoutForm = function() {
      var template = $('#tmpl-checkout').html();
      var data = {
        'products': this.cart,
        'checkout_url': this.checkoutUrl
      };

      // TODO: checkout button locale
      Mustache.parse(template);   // optional, speeds up future uses
      return Mustache.render(template, data);
    }

    ShoppingCart.prototype.emptyCart = function() {
      $unOrderList = $('
'),
      $liEmptyMessage = $('
').text(this.locales.empty_cart);

      $unOrderList.append(this.buildLiHeader(), $liEmptyMessage);

      if(this.cart.length == 0 ) {
        $('#shopping-cart-list').html($unOrderList);
      }
    }

    ShoppingCart.prototype.toggleBadge = function() {
      if(this.cart.length == 0 ) {
        this.$element.find('#total-items').hide();
        $('.fa-shopping-cart').addClass('empty-cart');
      }else {
        this.$element.find('#total-items').show();
        $('.fa-shopping-cart').removeClass('empty-cart');
      }
    }

    ShoppingCart.prototype.isPositiveNumber = function(val) {
      var pattern = /^\d+$/;

      return pattern.test(val) && parseInt(val) > 0
    }

    ShoppingCart.prototype.formatCurrency = function(num, currency) {
      return num.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,") + " " + currency;
    }

    function Plugin() {
      return new ShoppingCart(this);
    }

    var old = $.fn.shoppingCart;

    $.fn.shoppingCart = Plugin;
    $.fn.shoppingCart.Constructor = ShoppingCart;

    // SHOPPING CART NO CONFLICT
    // =================================

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

  }(jQuery));

  // init jquery shopping cart
  $('.js-shopping-cart').shoppingCart();
});<commit_msg>improve fly image to cart<commit_after>//= require js-cookie/v2.0.2
//= require mustache

/*
 * Plugin Name: Jquery Shopping Cart
 *
 * Author: Instant Website Team
 *
 * Note: Call Jquery Shopping Cart after jQuery in Application JS loaded
 */

window.addEventListener("load", function() {
  (function($) {

    ShoppingCart = function(element) {
      this.item = null;
      this.$element = null;
      this.cart = [];
      this.locales = null;

      this.init(element);
    }

    ShoppingCart.prototype.init = function(element) {
      this.$element     = $(element);
      this.locales      = this.$element.data('ecommerce-locales')
      this.checkoutUrl  = this.$element.data('checkout-url')
      this.assignCookieToCart();
      this.bindClickAddToCart();
      this.updateItemInList();
      this.updateTotalItems();
      this.bindClickCartIcon();
      this.bindClickDocument();
    }

    ShoppingCart.prototype.assignCookieToCart = function() {
      var getCookieVal = Cookies.getJSON('shopping-cart');

      if(getCookieVal != undefined) {
        this.cart = getCookieVal.items;
      }
    }

    ShoppingCart.prototype.bindClickDocument = function() {
      var $element = this.$element;

      $(document).on('click', function (e) {
        var container = $('.shopping-cart-icon')

        if (!container.is(e.target) && container.has(e.target).length === 0) {
          $element.find('.badge-open').removeClass('badge-show')
        }
      });
    }

    ShoppingCart.prototype.bindClickCartIcon = function() {
      var $element = this.$element;

      $element.find('.shop-badge').on('click', function() {
        $element.find('.badge-open').toggleClass('badge-show');
      })
    }

    ShoppingCart.prototype.bindClickAddToCart = function() {
      var self = this;

      this.$element.find('.js-add-to-cart').each(function() {
        $(this).click(function() {
          var qty = self.$element.find('#js-item-qty').val() || 1;

          if(self.isPositiveNumber(qty)) {
            var  product = $(this).data('product').product;

            product.quantity = parseInt(qty);
            self.item = product;

            self.addToCart();
            self.updateTotalItems();
            self.flyImageToCart();
          }
        });
      });
    }

    ShoppingCart.prototype.addToCart = function() {
      this.assignCookieToCart();

      if(this.itemExists()) {
        this.updateItem();
      }else {
        this.addItem();
      }

      this.updateItemInList();
    }

    ShoppingCart.prototype.flyImageToCart = function() {
      var wrapper = $("#js-fly-image-to-cart-box"),
        imgToDrag = wrapper.find("img").eq(0),
        top       = (wrapper.offset().top + wrapper.outerHeight()/2) - 75,
        left      = (wrapper.offset().left + wrapper.outerWidth()/2) - 75,
        cartIcon  = this.$element.find(".shop-badge"),
        imgclone;

      if (imgToDrag) {
          imgclone = imgToDrag.clone()
          .offset({
            top: top,
            left: left
        })
          .css({
            'opacity':  '0.5',
            'z-index':  '100',
            'width':    '150px',
            'height':   '150px',
            'position': 'absolute'
        })
          .appendTo($('body'))
          .animate({
            'width': 45,
            'height': 45,
            'top': cartIcon.offset().top + 10,
            'left': cartIcon.offset().left + 10
        }, 1200, 'easeInOutExpo');

        setTimeout(function () {
            cartIcon.effect("shake", {
              times: 2
            }, 200);
        }, 1500);

        imgclone.animate({
          'width': 0,
          'height': 0
        }, function () {
          $(this).detach()
        });
      }
    }

    ShoppingCart.prototype.addItem = function() {
      this.cart.push(this.item);
    }

    ShoppingCart.prototype.updateItem = function() {
      var cart = this.cart,
          item = this.item;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item.id) {
          cart[i]["quantity"] += item.quantity;
        }
      }

      this.cart = cart;
    }

    ShoppingCart.prototype.bindClickRemoveFromCart = function() {
      var self = this;

      this.$element.find('.remove-from-cart').each(function() {
        $(this).on("click", function(e) {
          e.stopPropagation();

          self.removeItem($(this).data('id'));
          self.updateTotalItems();
        })
      })
    }

    ShoppingCart.prototype.removeItem = function(item_id) {
      var cart = this.cart;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item_id) {
          cart = $.grep(cart, function(value) {
            return value != cart[i];
          });
        }
      }

      this.cart = cart;
      this.updateItemInList();
      this.$element.find('.badge-open').addClass('badge-show')
    }

    ShoppingCart.prototype.updateTotalItems = function() {
      var cart = this.cart,
          totalItems = 0;

      for(var i=0; i<cart.length; i++) {
        totalItems += cart[i]["quantity"];
      }

      this.$element.find('#total-items').html(totalItems);
    }

    ShoppingCart.prototype.getTotal = function() {
      var cart = this.cart,
          subtotal = 0,
          total = 0,
          currencyCode = $('body').data('currency-code');

      for(var i=0; i<cart.length; i++) {
        subtotal = cart[i]['quantity'] * cart[i]['price'];

        total += subtotal;
      }

      return this.formatCurrency(total, currencyCode);
    }

    ShoppingCart.prototype.itemExists = function() {
      var cart = this.cart,
          item  = this.item;

      for(var i=0; i<cart.length; i++) {
        if (cart[i]["id"] == item.id) return true;
      }
    }

    ShoppingCart.prototype.updateItemInList = function() {
      var cart = this.cart,
          $unOrderList = $('
'),
          $liSubtotal  = $('
');

          $unOrderList.append(this.buildLiHeader());

          for(var i=0; i<cart.length; i++) {
            $unOrderList.append(this.buildItemLi(cart[i]));
          }

      $unOrderList.append(this.buildSubtotalLi());
      $('#shopping-cart-list').html($unOrderList);

      this.bindClickRemoveFromCart();
      this.emptyCart();
      this.toggleBadge();
      Cookies.set('shopping-cart', { items: this.cart });
    }

    ShoppingCart.prototype.buildLiHeader = function() {
      $liHeader = $('
'),
      $h4 = $('
').text(this.locales.shopping_cart);

      return $liHeader.append($h4);
    }

    ShoppingCart.prototype.buildItemLi = function(item) {
      var currencyCode = $('body').data('currency-code'),
          qtyWithPrice = item.quantity + " x " + item.price + " " + currencyCode,
          $li = $('
'),
          $wrapperLeft = $('
'),
          $wrapperRight = $('
'),
          $imgWrapper = $('
'),
          $img = $('').attr({src: item.image_url}),

          $button = $('<button type="button" class="close remove-from-cart"/>'),
          $overflowH = $('
'),
          $link = $('').text(item.name).attr({href: item.url}),
          $small = $('').text(qtyWithPrice);

      $button.attr({'data-id': item.id}).text("×");
      $imgWrapper.append($img);
      $wrapperLeft.append($imgWrapper);
      $overflowH.append($link, $small)
      $wrapperRight.append($button, $overflowH)

      return $li.append($wrapperLeft, $wrapperRight);
    }

    ShoppingCart.prototype.buildSubtotalLi = function() {
      var totalCost = this.getTotal(),
          $li = $('
'),
          $div = $('
'),
          $spanLabel = $('').text(this.locales.subtotal),
          $spanCost = $('').text(totalCost);
          $btnCheckout = $('').text(this.locales.checkout);

      $div.append($spanLabel, $spanCost);

      return $li.append($div, this.checkoutForm());
    }

    ShoppingCart.prototype.checkoutForm = function() {
      var template = $('#tmpl-checkout').html();
      var data = {
        'products': this.cart,
        'checkout_url': this.checkoutUrl
      };

      // TODO: checkout button locale
      Mustache.parse(template);   // optional, speeds up future uses
      return Mustache.render(template, data);
    }

    ShoppingCart.prototype.emptyCart = function() {
      $unOrderList = $('
'),
      $liEmptyMessage = $('
').text(this.locales.empty_cart);

      $unOrderList.append(this.buildLiHeader(), $liEmptyMessage);

      if(this.cart.length == 0 ) {
        $('#shopping-cart-list').html($unOrderList);
      }
    }

    ShoppingCart.prototype.toggleBadge = function() {
      if(this.cart.length == 0 ) {
        this.$element.find('#total-items').hide();
        $('.fa-shopping-cart').addClass('empty-cart');
      }else {
        this.$element.find('#total-items').show();
        $('.fa-shopping-cart').removeClass('empty-cart');
      }
    }

    ShoppingCart.prototype.isPositiveNumber = function(val) {
      var pattern = /^\d+$/;

      return pattern.test(val) && parseInt(val) > 0
    }

    ShoppingCart.prototype.formatCurrency = function(num, currency) {
      return num.toFixed(2).replace(/(\d)(?=(\d{3})+\.)/g, "$1,") + " " + currency;
    }

    function Plugin() {
      return new ShoppingCart(this);
    }

    var old = $.fn.shoppingCart;

    $.fn.shoppingCart = Plugin;
    $.fn.shoppingCart.Constructor = ShoppingCart;

    // SHOPPING CART NO CONFLICT
    // =================================

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

  }(jQuery));

  // init jquery shopping cart
  $('.js-shopping-cart').shoppingCart();
});<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

/**
 * @fileoverview Gulp tasks for kubernetes cluster management.
 */
import childProcess from 'child_process';
import del from 'del';
import gulp from 'gulp';
import chmod from 'gulp-chmod';
import gulpFilter from 'gulp-filter';
import git from 'gulp-git';
import gunzip from 'gulp-gunzip';
import untar from 'gulp-untar';
import gulpUtil from 'gulp-util';
import pathExists from 'path-exists';
import request from 'request';
import source from 'vinyl-source-stream';

import conf from './conf';

const kubernetesArchive = 'kubernetes.tar.gz';
const kubernetesUrl = 'https://github.com/kubernetes/kubernetes.git';
const stableVersion = 'v1.1.1';
const tarballUrl = 'https://storage.googleapis.com/kubernetes-release/release';
const upScript = `${conf.paths.kubernetes}/hack/local-up-cluster.sh`;

/**
 * The healthz URL of the cluster to check that it is running.
 */
const clusterHealthzUrl = `http://${conf.backend.apiServerHost}/healthz`;

/**
 * Currently running cluster process object. Null if the cluster is not running.
 *
 * @type {?child.ChildProcess}
 */
let clusterProcess = null;

/**
 * @type {boolean} The variable is set when there is an error during cluster creation.
 */
let clusterSpawnFailure = null;

/**
 * A Number, representing the ID value of the timer that is set for function which periodically
 * checks if cluster is running. The null means that no timer is running.
 *
 * @type {?number}
 */
let isRunningSetIntervalHandler = null;

/**
 * Checks if there was a failure during cluster creation.
 * Produces an error in case there was one.
 * @param {function(?Error=)} doneFn - callback for the error
 */
function checkForClusterFailure(doneFn) {
  if (clusterSpawnFailure) {
    clearTimeout(isRunningSetIntervalHandler);
    isRunningSetIntervalHandler = null;
    doneFn(new Error('There was an error during cluster creation. Aborting.'));
  }
}

/**
 * Checks if cluster health check return correct status.
 * When custer is up and running then return 'ok'.
 * @param {function(?Error=)} doneFn
 */
function clusterHealthCheck(doneFn) {
  childProcess.exec(`curl ${clusterHealthzUrl}`, function(err, stdout) {
    if (err) {
      return doneFn(new Error(err));
    }
    return doneFn(stdout.trim());
  });
}

/**
 * Executes controls command using kubectl.
 * @param {string} command
 * @param {function(?Error=)} doneFn
 */
function executeKubectlCommand(command, doneFn) {
  childProcess.exec(`${conf.paths.kubernetes}/cluster/kubectl.sh ${command}`, function(err) {
    if (err) return doneFn(new Error(err));
    doneFn();
  });
}

/**
 * Creates cluster from scratch.
 * Downloads latest version of kubernetes from git repository.
 * Checkouts for latest release.
 * Executes script to up cluster.
 * Prerequisites:
 *  * Install Docker for your OS
 *  * Pull golang docker image: docker pull golang:1.4
 *  * Install golang
 *  * Install etcd
 */
gulp.task('local-up-cluster', ['spawn-cluster', 'wait-for-cluster']);

/**
 * Tears down a Kubernetes cluster.
 */
gulp.task('kill-cluster', function(doneFn) {
  if (clusterProcess) {
    clusterProcess.on('exit', function() {
      clusterProcess = null;
      doneFn();
    });
    clusterProcess.kill();
  } else {
    doneFn();
  }
});

/**
 * Clones kubernetes from git repository. Task skip if kubernetes directory exist.
 */
gulp.task('clone-kubernetes', function(doneFn) {
  pathExists(conf.paths.kubernetes).then(function(exists) {
    if (!exists) {
      git.clone(kubernetesUrl, {args: conf.paths.kubernetes}, function(err) {
        if (err) return doneFn(new Error(err));
        doneFn();
      });
    } else {
      doneFn();
    }
  });
});

/**
 * Checkouts kubernetes to latest stable version.
 */
gulp.task('checkout-kubernetes-version', ['clone-kubernetes'], function(doneFn) {
  git.checkout(stableVersion, {cwd: conf.paths.kubernetes, quiet: true}, function(err) {
    if (err) return doneFn(new Error(err));
    doneFn();
  });
});

/**
 * Checks if kubectl is already downloaded.
 * If not downloads kubectl for all platforms from tarball.
 */
gulp.task('download-kubectl', function(doneFn) {
  let filter = gulpFilter('**/platforms/**');
  pathExists(`${conf.paths.kubernetes}/platforms`).then(function(exists) {
    if (!exists) {
      request(`${tarballUrl}/${stableVersion}/${kubernetesArchive}`)
          .pipe(source(`${kubernetesArchive}`))
          .pipe(gunzip())
          .pipe(untar())
          .pipe(filter)
          .pipe(chmod(755))
          .pipe(gulp.dest(conf.paths.base))
          .on('end', function() { doneFn(); });
    } else {
      doneFn();
    }
  });
});

/**
 * Removes kubernetes before git clone command.
 */
gulp.task('clear-kubernetes', function() { return del(conf.paths.kubernetes); });

/**
 * Spawns local-up-cluster.sh script.
 */
gulp.task(
    'spawn-cluster',
    [
      'checkout-kubernetes-version',
      'kubeconfig-set-cluster-local',
      'kubeconfig-set-context-local',
      'kubeconfig-use-context-local',
      'kill-cluster',
    ],
    function() {
      clusterProcess = childProcess.spawn(upScript, {stdio: 'inherit'});

      clusterProcess.on('exit', function(code) {
        if (code !== 0) {
          clusterSpawnFailure = code;
        }
        clusterProcess = null;
      });
    });

/**
 * Checks periodically if cluster is up and running.
 */
gulp.task('wait-for-cluster', function(doneFn) {
  let counter = 0;
  if (!isRunningSetIntervalHandler) {
    isRunningSetIntervalHandler = setInterval(isRunning, 1000);
  }

  function isRunning() {
    if (counter % 10 === 0) {
      gulpUtil.log(
          gulpUtil.colors.magenta(
              `Waiting for a Kubernetes cluster on ${conf.backend.apiServerHost}...`));
    }
    counter += 1;

    checkForClusterFailure(doneFn);

    // constantly query the cluster until it is properly running
    clusterHealthCheck(function(result) {
      if (result === 'ok') {
        gulpUtil.log(gulpUtil.colors.magenta('Kubernetes cluster is up and running.'));
        clearTimeout(isRunningSetIntervalHandler);
        isRunningSetIntervalHandler = null;
        doneFn();
      }
    });
  }
});

/**
 * Sets a cluster entry in kubeconfig.
 * Configures kubernetes server for localhost.
 */
gulp.task(
    'kubeconfig-set-cluster-local', ['download-kubectl', 'checkout-kubernetes-version'],
    function(doneFn) {
      executeKubectlCommand(
          `config set-cluster local --server=http://${conf.backend.apiServerHost}` +
              `--insecure-skip-tls-verify=true`,
          doneFn);
    });

/**
 * Sets a context entry in kubeconfig as local.
 */
gulp.task(
    'kubeconfig-set-context-local', ['download-kubectl', 'checkout-kubernetes-version'],
    function(doneFn) {
      executeKubectlCommand('config set-context local --cluster=local', doneFn);
    });

/**
 * Sets the current-context in a kubeconfig file
 */
gulp.task(
    'kubeconfig-use-context-local', ['download-kubectl', 'checkout-kubernetes-version'],
    function(doneFn) { executeKubectlCommand('config use-context local', doneFn); });
<commit_msg>Fixed a typo that prevented the proper configuration of kubectl<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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.

/**
 * @fileoverview Gulp tasks for kubernetes cluster management.
 */
import childProcess from 'child_process';
import del from 'del';
import gulp from 'gulp';
import chmod from 'gulp-chmod';
import gulpFilter from 'gulp-filter';
import git from 'gulp-git';
import gunzip from 'gulp-gunzip';
import untar from 'gulp-untar';
import gulpUtil from 'gulp-util';
import pathExists from 'path-exists';
import request from 'request';
import source from 'vinyl-source-stream';

import conf from './conf';

const kubernetesArchive = 'kubernetes.tar.gz';
const kubernetesUrl = 'https://github.com/kubernetes/kubernetes.git';
const stableVersion = 'v1.1.1';
const tarballUrl = 'https://storage.googleapis.com/kubernetes-release/release';
const upScript = `${conf.paths.kubernetes}/hack/local-up-cluster.sh`;

/**
 * The healthz URL of the cluster to check that it is running.
 */
const clusterHealthzUrl = `http://${conf.backend.apiServerHost}/healthz`;

/**
 * Currently running cluster process object. Null if the cluster is not running.
 *
 * @type {?child.ChildProcess}
 */
let clusterProcess = null;

/**
 * @type {boolean} The variable is set when there is an error during cluster creation.
 */
let clusterSpawnFailure = null;

/**
 * A Number, representing the ID value of the timer that is set for function which periodically
 * checks if cluster is running. The null means that no timer is running.
 *
 * @type {?number}
 */
let isRunningSetIntervalHandler = null;

/**
 * Checks if there was a failure during cluster creation.
 * Produces an error in case there was one.
 * @param {function(?Error=)} doneFn - callback for the error
 */
function checkForClusterFailure(doneFn) {
  if (clusterSpawnFailure) {
    clearTimeout(isRunningSetIntervalHandler);
    isRunningSetIntervalHandler = null;
    doneFn(new Error('There was an error during cluster creation. Aborting.'));
  }
}

/**
 * Checks if cluster health check return correct status.
 * When custer is up and running then return 'ok'.
 * @param {function(?Error=)} doneFn
 */
function clusterHealthCheck(doneFn) {
  childProcess.exec(`curl ${clusterHealthzUrl}`, function(err, stdout) {
    if (err) {
      return doneFn(new Error(err));
    }
    return doneFn(stdout.trim());
  });
}

/**
 * Executes controls command using kubectl.
 * @param {string} command
 * @param {function(?Error=)} doneFn
 */
function executeKubectlCommand(command, doneFn) {
  childProcess.exec(`${conf.paths.kubernetes}/cluster/kubectl.sh ${command}`, function(err) {
    if (err) return doneFn(new Error(err));
    doneFn();
  });
}

/**
 * Creates cluster from scratch.
 * Downloads latest version of kubernetes from git repository.
 * Checkouts for latest release.
 * Executes script to up cluster.
 * Prerequisites:
 *  * Install Docker for your OS
 *  * Pull golang docker image: docker pull golang:1.4
 *  * Install golang
 *  * Install etcd
 */
gulp.task('local-up-cluster', ['spawn-cluster', 'wait-for-cluster']);

/**
 * Tears down a Kubernetes cluster.
 */
gulp.task('kill-cluster', function(doneFn) {
  if (clusterProcess) {
    clusterProcess.on('exit', function() {
      clusterProcess = null;
      doneFn();
    });
    clusterProcess.kill();
  } else {
    doneFn();
  }
});

/**
 * Clones kubernetes from git repository. Task skip if kubernetes directory exist.
 */
gulp.task('clone-kubernetes', function(doneFn) {
  pathExists(conf.paths.kubernetes).then(function(exists) {
    if (!exists) {
      git.clone(kubernetesUrl, {args: conf.paths.kubernetes}, function(err) {
        if (err) return doneFn(new Error(err));
        doneFn();
      });
    } else {
      doneFn();
    }
  });
});

/**
 * Checkouts kubernetes to latest stable version.
 */
gulp.task('checkout-kubernetes-version', ['clone-kubernetes'], function(doneFn) {
  git.checkout(stableVersion, {cwd: conf.paths.kubernetes, quiet: true}, function(err) {
    if (err) return doneFn(new Error(err));
    doneFn();
  });
});

/**
 * Checks if kubectl is already downloaded.
 * If not downloads kubectl for all platforms from tarball.
 */
gulp.task('download-kubectl', function(doneFn) {
  let filter = gulpFilter('**/platforms/**');
  pathExists(`${conf.paths.kubernetes}/platforms`).then(function(exists) {
    if (!exists) {
      request(`${tarballUrl}/${stableVersion}/${kubernetesArchive}`)
          .pipe(source(`${kubernetesArchive}`))
          .pipe(gunzip())
          .pipe(untar())
          .pipe(filter)
          .pipe(chmod(755))
          .pipe(gulp.dest(conf.paths.base))
          .on('end', function() { doneFn(); });
    } else {
      doneFn();
    }
  });
});

/**
 * Removes kubernetes before git clone command.
 */
gulp.task('clear-kubernetes', function() { return del(conf.paths.kubernetes); });

/**
 * Spawns local-up-cluster.sh script.
 */
gulp.task(
    'spawn-cluster',
    [
      'checkout-kubernetes-version',
      'kubeconfig-set-cluster-local',
      'kubeconfig-set-context-local',
      'kubeconfig-use-context-local',
      'kill-cluster',
    ],
    function() {
      clusterProcess = childProcess.spawn(upScript, {stdio: 'inherit'});

      clusterProcess.on('exit', function(code) {
        if (code !== 0) {
          clusterSpawnFailure = code;
        }
        clusterProcess = null;
      });
    });

/**
 * Checks periodically if cluster is up and running.
 */
gulp.task('wait-for-cluster', function(doneFn) {
  let counter = 0;
  if (!isRunningSetIntervalHandler) {
    isRunningSetIntervalHandler = setInterval(isRunning, 1000);
  }

  function isRunning() {
    if (counter % 10 === 0) {
      gulpUtil.log(
          gulpUtil.colors.magenta(
              `Waiting for a Kubernetes cluster on ${conf.backend.apiServerHost}...`));
    }
    counter += 1;

    checkForClusterFailure(doneFn);

    // constantly query the cluster until it is properly running
    clusterHealthCheck(function(result) {
      if (result === 'ok') {
        gulpUtil.log(gulpUtil.colors.magenta('Kubernetes cluster is up and running.'));
        clearTimeout(isRunningSetIntervalHandler);
        isRunningSetIntervalHandler = null;
        doneFn();
      }
    });
  }
});

/**
 * Sets a cluster entry in kubeconfig.
 * Configures kubernetes server for localhost.
 */
gulp.task(
    'kubeconfig-set-cluster-local', ['download-kubectl', 'checkout-kubernetes-version'],
    function(doneFn) {
      executeKubectlCommand(
          `config set-cluster local --server=http://${conf.backend.apiServerHost}` +
              ' --insecure-skip-tls-verify=true',
          doneFn);
    });

/**
 * Sets a context entry in kubeconfig as local.
 */
gulp.task(
    'kubeconfig-set-context-local', ['download-kubectl', 'checkout-kubernetes-version'],
    function(doneFn) {
      executeKubectlCommand('config set-context local --cluster=local', doneFn);
    });

/**
 * Sets the current-context in a kubeconfig file
 */
gulp.task(
    'kubeconfig-use-context-local', ['download-kubectl', 'checkout-kubernetes-version'],
    function(doneFn) { executeKubectlCommand('config use-context local', doneFn); });
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { View, Platform, FlatList } from 'react-native';
import { withTheme } from 'react-native-paper';
import ViewPager from '@react-native-community/viewpager';
import Loader from './Loader';
import { globalStyles, globalStyleVariables } from '../styles';

const LIST_WINDOW_SIZE = 3;

class PXViewPager extends Component {
  handleOnIOSViewPagerPageSelected = (e) => {
    const { onPageSelected } = this.props;
    const { contentOffset } = e.nativeEvent;
    const viewSize = e.nativeEvent.layoutMeasurement;
    // Divide the horizontal offset by the width of the view to see which page is visible
    const index = Math.round(contentOffset.x / viewSize.width);
    if (index > -1) {
      onPageSelected(index);
    }
  };

  handleOnAndroidViewPagerPageSelected = (e) => {
    const { items, onEndReached } = this.props;
    // const { position } = e.nativeEvent;
    const { onPageSelected } = this.props;
    const index = e.nativeEvent.position;
    onPageSelected(index);
    if (onEndReached && index >= items.length - 2) {
      onEndReached();
    }
  };

  renderContentForAndroid = () => {
    const { items, keyExtractor, renderContent, index, theme } = this.props;
    const size = Math.floor(LIST_WINDOW_SIZE / 2);
    return items.map((item, i) => {
      if (i >= index - size && i <= index + size) {
        return renderContent({ item, index: i });
      }
      const key = keyExtractor(item, i);
      return (
        <View key={key} style={{ backgroundColor: theme.colors.background }}>
          <Loader />
        </View>
      );
    });
  };

  render() {
    const {
      items,
      index,
      keyExtractor,
      renderContent,
      onEndReached,
      viewPagerRef,
      theme,
    } = this.props;
    if (Platform.OS === 'android') {
      return (
        <ViewPager
          ref={viewPagerRef}
          key={`pxViewPager-${items.length}`} // https://github.com/facebook/react-native/issues/4775
          initialPage={index}
          style={[
            globalStyles.container,
            { backgroundColor: theme.colors.background },
          ]}
          onPageSelected={this.handleOnAndroidViewPagerPageSelected}
        >
          {this.renderContentForAndroid()}
        </ViewPager>
      );
    }
    return (
      <FlatList
        ref={viewPagerRef}
        data={items}
        keyExtractor={keyExtractor}
        renderItem={renderContent}
        scrollEventThrottle={16}
        onMomentumScrollEnd={this.handleOnIOSViewPagerPageSelected}
        onEndReached={onEndReached}
        onEndReachedThreshold={0.1}
        horizontal
        initialScrollIndex={index}
        windowSize={LIST_WINDOW_SIZE}
        initialNumToRender={3}
        pagingEnabled
        debug={false}
        maxToRenderPerBatch={LIST_WINDOW_SIZE}
        getItemLayout={(data, i) => ({
          length: globalStyleVariables.WINDOW_WIDTH,
          offset: globalStyleVariables.WINDOW_WIDTH * i,
          index: i,
        })}
      />
    );
  }
}

export default withTheme(PXViewPager);
<commit_msg>Show loader in view pager when not mounted<commit_after>import React, { Component } from 'react';
import { View, Platform, FlatList } from 'react-native';
import { withTheme } from 'react-native-paper';
import ViewPager from '@react-native-community/viewpager';
import Loader from './Loader';
import { globalStyles, globalStyleVariables } from '../styles';

const LIST_WINDOW_SIZE = 3;

class PXViewPager extends Component {
  state = {
    isMounted: false,
  };

  componentDidMount() {
    this.setState({
      isMounted: true,
    });
  }

  handleOnIOSViewPagerPageSelected = (e) => {
    const { onPageSelected } = this.props;
    const { contentOffset } = e.nativeEvent;
    const viewSize = e.nativeEvent.layoutMeasurement;
    // Divide the horizontal offset by the width of the view to see which page is visible
    const index = Math.round(contentOffset.x / viewSize.width);
    if (index > -1) {
      onPageSelected(index);
    }
  };

  handleOnAndroidViewPagerPageSelected = (e) => {
    const { items, onEndReached } = this.props;
    // const { position } = e.nativeEvent;
    const { onPageSelected } = this.props;
    const index = e.nativeEvent.position;
    onPageSelected(index);
    if (onEndReached && index >= items.length - 2) {
      onEndReached();
    }
  };

  renderContentForAndroid = () => {
    const { items, keyExtractor, renderContent, index, theme } = this.props;
    const size = Math.floor(LIST_WINDOW_SIZE / 2);
    return items.map((item, i) => {
      if (i >= index - size && i <= index + size) {
        return renderContent({ item, index: i });
      }
      const key = keyExtractor(item, i);
      return (
        <View key={key} style={{ backgroundColor: theme.colors.background }}>
          <Loader />
        </View>
      );
    });
  };

  render() {
    const {
      items,
      index,
      keyExtractor,
      renderContent,
      onEndReached,
      viewPagerRef,
      theme,
    } = this.props;
    const { isMounted } = this.state;
    if (Platform.OS === 'android') {
      if (!isMounted) {
        return <Loader />;
      }
      return (
        <ViewPager
          ref={viewPagerRef}
          key={`pxViewPager-${items.length}`} // https://github.com/facebook/react-native/issues/4775
          initialPage={index}
          style={[
            globalStyles.container,
            { backgroundColor: theme.colors.background },
          ]}
          onPageSelected={this.handleOnAndroidViewPagerPageSelected}
        >
          {this.renderContentForAndroid()}
        </ViewPager>
      );
    }
    return (
      <FlatList
        ref={viewPagerRef}
        data={items}
        keyExtractor={keyExtractor}
        renderItem={renderContent}
        scrollEventThrottle={16}
        onMomentumScrollEnd={this.handleOnIOSViewPagerPageSelected}
        onEndReached={onEndReached}
        onEndReachedThreshold={0.1}
        horizontal
        initialScrollIndex={index}
        windowSize={LIST_WINDOW_SIZE}
        initialNumToRender={3}
        pagingEnabled
        debug={false}
        maxToRenderPerBatch={LIST_WINDOW_SIZE}
        getItemLayout={(data, i) => ({
          length: globalStyleVariables.WINDOW_WIDTH,
          offset: globalStyleVariables.WINDOW_WIDTH * i,
          index: i,
        })}
      />
    );
  }
}

export default withTheme(PXViewPager);
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import ResizeObserver from 'resize-observer-polyfill';

/**
 * Affix component
 * @description This component provides similar behavior to Facebook sidebar.
 * Affix component wraps content with two elements. relativeContainer and affixContainer.
 * <relativeContainer>
 *  <affixContainer>
 *    {children}
 *  </affixContainer>
 * </relativeContainer>
 * affixContainer uses absolute and fixed positioning, so its height has to be
 * observed and relativeContainer should be updated with that height.
 * affixContainer should make use of absolute and fixed positioning in order to
 * fix content in place when reaching edges, but also allow scrolling when user
 * want to reach content inside of it.
 */
class Affix extends React.Component {
  static propTypes = {
    children: PropTypes.element.isRequired,
    className: PropTypes.string,
    stickPosition: PropTypes.number,
  }

  static defaultProps = {
    className: '',
    stickPosition: 0,
  }

  constructor(props) {
    super(props);
    this.lastScroll = document.body.scrollTop;

    this.top = 0;
    this.bindedBottom = false;
    this.bindedTop = true;

    this.ro = new ResizeObserver((entries) => {
      entries.forEach((entry) => {
        const { height } = entry.contentRect;
        this.relativeContainer.style.height = `${height}px`;
        this.handleScroll();
      });
    });
  }

  componentDidMount() {
    document.addEventListener('scroll', this.handleScroll.bind(this));
    this.ro.observe(this.affixContainer);
  }

  componentWillUnmount() {
    document.removeEventListener('scroll', this.handleScroll.bind(this));
    this.ro.unobserve(this.affixContainer);
  }

  handleScroll() {
    const { stickPosition } = this.props;

    const windowHeight = document.body.clientHeight;
    const sidebarHeight = this.affixContainer.clientHeight;
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    const scrollBottom = scrollTop + windowHeight;
    const scrollDiff = scrollTop - this.lastScroll;
    const scrollingDown = scrollDiff > 0;
    const parent = this.relativeContainer.offsetParent;
    const parentSpace = parent.offsetTop - stickPosition;

    const viewportOffset = this.affixContainer.getBoundingClientRect();

    const fits = (windowHeight >= sidebarHeight);
    const overlaps = (viewportOffset.top < parent.getBoundingClientRect().top);
    const shouldBindTop = (viewportOffset.top >= stickPosition && !scrollingDown
      && !overlaps && scrollTop >= parent.offsetTop);

    if (fits) {
      if (viewportOffset.top <= stickPosition) {
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${stickPosition}px`;
      }

      if (overlaps) {
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = 'auto';
      }
    } else {
      if (!this.bindedBottom && scrollingDown && viewportOffset.bottom <= windowHeight) {
        console.log('bindBottom');
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${windowHeight - sidebarHeight}px`;
        this.bindedBottom = true;
      }
      if (shouldBindTop) {
        console.log('bindTop');
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${stickPosition}px`;
        this.bindedTop = true;
      }
      if (this.bindedBottom && !scrollingDown) {
        console.log('unbindBottom');
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = `${scrollBottom - (sidebarHeight + parentSpace)}px`;
        this.bindedBottom = false;
      }
      if (this.bindedTop && scrollingDown) {
        console.log('unbindTop');
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = `${scrollTop - (parent.offsetTop - stickPosition)}px`;
        this.bindedTop = false;
      }
      if (overlaps) {
      // if (!scrollingDown && overlaps) {
        console.log('fixTopPosition');
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = 'auto';
      }
    }

    this.lastScroll = scrollTop;
  }

  render() {
    const { className } = this.props;
    return (
      <div
        className={className}
        ref={(relativeContainer) => { this.relativeContainer = relativeContainer; }}
      >
        <div
          style={{ position: 'absolute' }}
          ref={(affixContainer) => { this.affixContainer = affixContainer; }}
        >
          {this.props.children}
        </div>
      </div>
    );
  }
}

export default Affix;
<commit_msg>Use arrow function for handleScroll<commit_after>import React, { PropTypes } from 'react';
import ResizeObserver from 'resize-observer-polyfill';

/**
 * Affix component
 * @description This component provides similar behavior to Facebook sidebar.
 * Affix component wraps content with two elements. relativeContainer and affixContainer.
 * <relativeContainer>
 *  <affixContainer>
 *    {children}
 *  </affixContainer>
 * </relativeContainer>
 * affixContainer uses absolute and fixed positioning, so its height has to be
 * observed and relativeContainer should be updated with that height.
 * affixContainer should make use of absolute and fixed positioning in order to
 * fix content in place when reaching edges, but also allow scrolling when user
 * want to reach content inside of it.
 */
class Affix extends React.Component {
  static propTypes = {
    children: PropTypes.element.isRequired,
    className: PropTypes.string,
    stickPosition: PropTypes.number,
  }

  static defaultProps = {
    className: '',
    stickPosition: 0,
  }

  constructor(props) {
    super(props);
    this.lastScroll = document.body.scrollTop;

    this.top = 0;
    this.bindedBottom = false;
    this.bindedTop = true;

    this.ro = new ResizeObserver((entries) => {
      entries.forEach((entry) => {
        const { height } = entry.contentRect;
        this.relativeContainer.style.height = `${height}px`;
        this.handleScroll();
      });
    });
  }

  componentDidMount() {
    document.addEventListener('scroll', this.handleScroll);
    this.ro.observe(this.affixContainer);
  }

  componentWillUnmount() {
    document.removeEventListener('scroll', this.handleScroll);
    this.ro.unobserve(this.affixContainer);
  }

  handleScroll = () => {
    const { stickPosition } = this.props;

    const windowHeight = document.body.clientHeight;
    const sidebarHeight = this.affixContainer.clientHeight;
    const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
    const scrollBottom = scrollTop + windowHeight;
    const scrollDiff = scrollTop - this.lastScroll;
    const scrollingDown = scrollDiff > 0;
    const parent = this.relativeContainer.offsetParent;
    const parentSpace = parent.offsetTop - stickPosition;

    const viewportOffset = this.affixContainer.getBoundingClientRect();

    const fits = (windowHeight >= sidebarHeight);
    const overlaps = (viewportOffset.top < parent.getBoundingClientRect().top);
    const shouldBindTop = (viewportOffset.top >= stickPosition && !scrollingDown
      && !overlaps && scrollTop >= parent.offsetTop);

    if (fits) {
      if (viewportOffset.top <= stickPosition) {
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${stickPosition}px`;
      }

      if (overlaps) {
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = 'auto';
      }
    } else {
      if (!this.bindedBottom && scrollingDown && viewportOffset.bottom <= windowHeight) {
        console.log('bindBottom');
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${windowHeight - sidebarHeight}px`;
        this.bindedBottom = true;
      }
      if (shouldBindTop) {
        console.log('bindTop');
        this.affixContainer.style.position = 'fixed';
        this.affixContainer.style.top = `${stickPosition}px`;
        this.bindedTop = true;
      }
      if (this.bindedBottom && !scrollingDown) {
        console.log('unbindBottom');
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = `${scrollBottom - (sidebarHeight + parentSpace)}px`;
        this.bindedBottom = false;
      }
      if (this.bindedTop && scrollingDown) {
        console.log('unbindTop');
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = `${scrollTop - (parent.offsetTop - stickPosition)}px`;
        this.bindedTop = false;
      }
      if (overlaps) {
      // if (!scrollingDown && overlaps) {
        console.log('fixTopPosition');
        this.affixContainer.style.position = 'absolute';
        this.affixContainer.style.top = 'auto';
      }
    }

    this.lastScroll = scrollTop;
  }

  render() {
    const { className } = this.props;
    return (
      <div
        className={className}
        ref={(relativeContainer) => { this.relativeContainer = relativeContainer; }}
      >
        <div
          style={{ position: 'absolute' }}
          ref={(affixContainer) => { this.affixContainer = affixContainer; }}
        >
          {this.props.children}
        </div>
      </div>
    );
  }
}

export default Affix;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Panel, Button, Checkbox, Modal, Col, Form, FormGroup, InputGroup, FormControl, ControlLabel } from 'react-bootstrap';

import reactor from 'modules/flux';
import { toImmutable } from 'nuclear-js';

import Wave from 'components/Wave';

import { actions as instrumentActions, getters as instrumentGetters } from 'modules/instrument';

export default class WaveControl extends Component {
  constructor() {
    super();

    this.state = {
    };
  }

  _watch(id, type) {
    const getter = instrumentGetters.byId(id, type);

    // Unwatch if possible
    this._unwatch();

    // Add observer
    this._unwatchFn = reactor.observe(getter, (v) => {
      this.setState((state) => {
        state[type] = v;
        return state;
      });
    });
    // Get initial data
    this.setState((state) => {
      state[type] = reactor.evaluate(getter);
      return state;
    });
  }
  _unwatch() {
    // Remove observer if it exists
    if (this._unwatchFn) {
      this._unwatchFn();
    }
  }

  componentWillUnmount() {
    this._unwatch();
  }

  componentWillMount() {
    this._watch(this.props.waveAddress, 'wave');
  }

  componentWillUpdate(nextProps, nextState) {
    // Check if instrument has changed
    if (this.props.waveAddress !== nextProps.waveAddress) {
      this._watch(nextProps.waveAddress, 'wave');
    }
  }

  _handleSave() {
    // Send to SysEx
    this.props.client.setFixWave(this.props.waveAddress, this.state.wave.toJS())
    .then(() => {
      // Refresh data in case the Wersi has made any changes
      return this.props.client.getFixWave(this.props.waveAddress);
    })
    .then((data) => {
      // Update store
      instrumentActions.update(this.props.waveAddress, 'wave', toImmutable(data));

      // Reload instrument
      return this.props.client.reloadInstrument(this.props.firstInstrumentAddress);
    })
    ;
  }

  render() {
    const { waveAddress } = this.props;

    let header = (

Wavetable control ({this.props.waveAddress})

    );

    return (
      <Panel header={header} collapsible defaultExpanded>

          <Button onClick={this._handleSave.bind(this)} className="pull-right" bsStyle="primary">
            Send
          </Button>

        <Wave client={this.props.client} waveSet='bassData' waveAddress={waveAddress} />
        <Wave client={this.props.client} waveSet='tenorData' waveAddress={waveAddress} />
        <Wave client={this.props.client} waveSet='altoData' waveAddress={waveAddress} />
        <Wave client={this.props.client} waveSet='sopranoData' waveAddress={waveAddress} />
      </Panel>
    );
  }
}

<commit_msg>Loading indicator for Wave.<commit_after>import React, { Component } from 'react';
import { Panel, Button, Checkbox, Modal, Col, Form, FormGroup, InputGroup, FormControl, ControlLabel } from 'react-bootstrap';
import Loader from 'react-loader-advanced';

import reactor from 'modules/flux';
import { toImmutable } from 'nuclear-js';

import Wave from 'components/Wave';

import { actions as instrumentActions, getters as instrumentGetters } from 'modules/instrument';

export default class WaveControl extends Component {
  constructor() {
    super();

    this.state = {
      loading: false
    };
  }

  _watch(id, type) {
    const getter = instrumentGetters.byId(id, type);

    // Unwatch if possible
    this._unwatch();

    // Add observer
    this._unwatchFn = reactor.observe(getter, (v) => {
      this.setState((state) => {
        state[type] = v;
        return state;
      });
    });
    // Get initial data
    this.setState((state) => {
      state[type] = reactor.evaluate(getter);
      return state;
    });
  }
  _unwatch() {
    // Remove observer if it exists
    if (this._unwatchFn) {
      this._unwatchFn();
    }
  }

  componentWillUnmount() {
    this._unwatch();
  }

  componentWillMount() {
    this._watch(this.props.waveAddress, 'wave');
  }

  componentWillUpdate(nextProps, nextState) {
    // Check if instrument has changed
    if (this.props.waveAddress !== nextProps.waveAddress) {
      this._watch(nextProps.waveAddress, 'wave');
    }
  }

  _handleSave() {
    // Send to SysEx
    this.setState({ loading: true }, () => {
      this.props.client.setFixWave(this.props.waveAddress, this.state.wave.toJS())
      .then(() => {
        // Refresh data in case the Wersi has made any changes
        return this.props.client.getFixWave(this.props.waveAddress);
      })
      .then((data) => {
        // Update store
        instrumentActions.update(this.props.waveAddress, 'wave', toImmutable(data));
        this.setState({ loading: false });

        // Reload instrument
        return this.props.client.reloadInstrument(this.props.firstInstrumentAddress);
      })
      ;
    });
  }

  render() {
    const { waveAddress } = this.props;

    let header = (

Wavetable control ({this.props.waveAddress})

    );

    return (
      <Loader show={this.state.loading} message={(
« Downloading... »
)} contentBlur={2}>
        <Panel header={header} collapsible defaultExpanded>

            <Button onClick={this._handleSave.bind(this)} className="pull-right" bsStyle="primary">
              Send
            </Button>

          <Wave client={this.props.client} waveSet='bassData' waveAddress={waveAddress} />
          <Wave client={this.props.client} waveSet='tenorData' waveAddress={waveAddress} />
          <Wave client={this.props.client} waveSet='altoData' waveAddress={waveAddress} />
          <Wave client={this.props.client} waveSet='sopranoData' waveAddress={waveAddress} />
        </Panel>
      </Loader>
    );
  }
}

<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { translate } from 'react-i18next';
import style from './style.styl';

class Alert extends Component {
    render () {
        let {props} = this

        return (

                {props.t(props.message)}
                check

        )
    }
}

export default translate(['alert'])(Alert);
<commit_msg>alert: makeit a functional component<commit_after>import React from 'react';
import { translate } from 'react-i18next';
import style from './style.styl';

const Alert = ({t, message}) => (

        {t(message)}
        check

)

export default translate(['alert'])(Alert);
<|endoftext|>


<commit_before>var React = require('react');

module.exports = React.createClass({
  propTypes: {
    type: React.PropTypes.string.isRequired,
    data: React.PropTypes.object
  },

  getDefaultProps: function () {
    return { data: {} }
  },

  _message: function () {
    if (this.props.type === 'new-player') {
      return this.props.data.name + ' har gått med i spelet.';
    }
    else if (this.props.type === 'connected') {
      return 'Du har gått med i spelet.';
    }
    else if (this.props.type === 'disconnected') {
      return 'Du har lämnat spelet.';
    }
  },

  render: function () {
    return
{this._message()}
;
  }
});
<commit_msg>Correct styling on server messages<commit_after>var React = require('react');

module.exports = React.createClass({
  propTypes: {
    type: React.PropTypes.string.isRequired,
    data: React.PropTypes.object
  },

  getDefaultProps: function () {
    return { data: {} }
  },

  _message: function () {
    if (this.props.type === 'new-player') {
      return this.props.data.name + ' har gått med i spelet.';
    }
    else if (this.props.type === 'connected') {
      return 'Du har gått med i spelet.';
    }
    else if (this.props.type === 'disconnected') {
      return 'Du har lämnat spelet.';
    }
  },

  render: function () {
    return
# {this._message()}
;
  }
});
<|endoftext|>


<commit_before>import React from 'react'
import Link from 'gatsby-link'
import {
  Container,
  Flex,
  Box,
  Heading,
  Text,
  LargeButton
} from '@hackclub/design-system'
import Nav from 'components/Nav'
import Animator from 'components/Animator'

const Root = Box.withComponent('header').extend`
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  background: ${props => props.theme.colors.blue[8]} url('/map.svg') no-repeat;
  background-size: cover;
  background-position: center top;
  max-width: 100%;
  overflow: hidden;
  clip-path: polygon(0% 0%, 100% 0, 100% 100%, 0 95%);
  ${props => props.theme.mediaQueries.md} {
    clip-path: polygon(0% 0%, 100% 0, 100% 100%, 0 90%);
  }

  p,
  h1,
  h2 {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.32);
  }
  p:first-child {
    line-height: 1.125;
  }
  h1 {
    line-height: 1;
  }
  h2 {
    line-height: 1.25;
  }

  @media screen and (max-width: 22em) {
    a span {
      display: none;
    }
  }
`

const Action = LargeButton.extend`
  transition: transform 0.125s ease-out;
  will-change: transform;
  transform: scale(1);
  &:hover,
  &:focus {
    transform: scale(1.06);
  }
  @media (prefers-reduced-motion: reduce) {
    transform: none !important;
  }
`

Action.link = Action.withComponent(Link)

export default () => (
  <Animator
    is={Root}
    data={{
      opacity: [1, 0.75],
      transform: [{ translateY: '0px' }, { translateY: '-96px' }]
    }}
    px={[0, 3]}
  >

    <Container maxWidth={48} color="white" my={[5, 6]}>
      <Text f={[3, 4]} px={2} mx="auto" my={0} caps>
        By the students, for the students.
      </Text>
      <Heading.h1 f={[6, 7]} mx="auto" mt={2} mb={3}>
        High school coding clubs.
      </Heading.h1>
      <Box w={0.75} mx="auto">
        <Text f={[3, 4]} mx="auto" m={0}>
          Hack Club is the world's largest nonprofit network of computer science
          clubs where members learn to code through tinkering and building
          projects.
        </Text>
      </Box>
      <Flex
        justify="center"
        align="center"
        mx={[-1, -2]}
        mt={[3, 4]}
        flexDirection={['column-reverse', 'column-reverse', 'row']}
      >
        <Action.link
          to="/donate"
          bg="accent"
          m={[1, 1, 2]}
          f={[3, 3, 4]}
          px={[5, 5, 4]}
        >
          Donate
        </Action.link>
        <Flex flexDirection="row" align="center">
          <Action href="https://finder.hackclub.com" inverted m={[1, 1, 2]}>
            Find Nearby
          </Action>
          <Action.link to="/start" m={[1, 1, 2]} f={[3, 3, 4]}>
            Start a Club »
          </Action.link>
        </Flex>
      </Flex>
    </Container>
  </Animator>
)
<commit_msg>Refactor media queries on home page header<commit_after>import React from 'react'
import Link from 'gatsby-link'
import {
  Container,
  Flex,
  Box,
  Heading,
  Text,
  LargeButton
} from '@hackclub/design-system'
import Nav from 'components/Nav'
import Animator from 'components/Animator'

const Root = Box.withComponent('header').extend`
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
  background: ${props => props.theme.colors.blue[8]} url('/map.svg') no-repeat;
  background-size: cover;
  background-position: center top;
  max-width: 100%;
  overflow: hidden;
  clip-path: polygon(0% 0%, 100% 0, 100% 100%, 0 95%);
  ${props => props.theme.mediaQueries.md} {
    clip-path: polygon(0% 0%, 100% 0, 100% 100%, 0 90%);
  }

  p,
  h1,
  h2 {
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.32);
  }
  p:first-child {
    line-height: 1.125;
  }
  h1 {
    line-height: 1;
  }
  h2 {
    line-height: 1.25;
  }

  @media screen and (max-width: 22em) {
    a span {
      display: none;
    }
  }
`

const Action = LargeButton.extend`
  transition: transform 0.125s ease-out;
  will-change: transform;
  transform: scale(1);
  &:hover,
  &:focus {
    transform: scale(1.06);
  }
  @media (prefers-reduced-motion: reduce) {
    transform: none !important;
  }
`

Action.link = Action.withComponent(Link)

export default () => (
  <Animator
    is={Root}
    data={{
      opacity: [1, 0.75],
      transform: [{ translateY: '0px' }, { translateY: '-96px' }]
    }}
    px={[0, 3]}
  >

    <Container maxWidth={48} color="white" my={[5, 6]}>
      <Text f={[3, 4]} px={2} mx="auto" my={0} caps>
        By the students, for the students.
      </Text>
      <Heading.h1 f={[6, 7]} mx="auto" mt={2} mb={3}>
        High school coding clubs.
      </Heading.h1>
      <Box w={0.75} mx="auto">
        <Text f={[3, 4]} mx="auto" m={0}>
          Hack Club is the world’s largest nonprofit network of computer science
          clubs where members learn to code through tinkering and building
          projects.
        </Text>
      </Box>
      <Flex
        justify="center"
        align="center"
        mx={[-1, -2]}
        mt={[3, 4]}
        flexDirection={['column-reverse', null, 'row']}
      >
        <Action.link
          to="/donate"
          bg="accent"
          m={[1, null, 2]}
          f={[3, null, 4]}
          px={[5, null, 4]}
        >
          Donate
        </Action.link>
        <Flex flexDirection="row" align="center">
          <Action href="https://finder.hackclub.com" inverted m={[1, null, 2]}>
            Find Nearby
          </Action>
          <Action.link to="/start" m={[1, null, 2]} f={[3, null, 4]}>
            Start a Club »
          </Action.link>
        </Flex>
      </Flex>
    </Container>
  </Animator>
)
<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
 * jQuery Core Release Management
 */

// Debugging variables
var	debug = false,
	skipRemote = false;

var fs = require("fs"),
	child = require("child_process"),
	path = require("path");

var releaseVersion,
	nextVersion,
	finalFiles,
	isBeta,
	pkg,
	branch,

	scpURL = "jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/",
	cdnURL = "http://code.origin.jquery.com/",
	repoURL = "git@github.com:jquery/jquery.git",

	// Windows needs the .cmd version but will find the non-.cmd
	// On Windows, ensure the HOME environment variable is set
	gruntCmd = process.platform === "win32" ? "grunt.cmd" : "grunt",

	devFile = "dist/jquery.js",
	minFile = "dist/jquery.min.js",

	releaseFiles = {
		"jquery-VER.js": devFile,
		"jquery-VER.min.js": minFile,
		"jquery.js": devFile,
		"jquery-latest.js": devFile,
		"jquery.min.js": minFile,
		"jquery-latest.min.js": minFile
	};

steps(
	initialize,
	checkGitStatus,
	tagReleaseVersion,
	gruntBuild,
	makeReleaseCopies,
	setNextVersion,
	uploadToCDN,
	pushToGithub,
	exit
);

function initialize( next ) {

	if ( process.argv[2] === "-d" ) {
		process.argv.shift();
		debug = true;
		console.warn("=== DEBUG MODE ===" );
	}

	// First arg should be the version number being released
	var newver, oldver,
		rversion = /^(\d)\.(\d+)\.(\d)((?:a|b|rc)\d|pre)?$/,
		version = ( process.argv[3] || "" ).toLowerCase().match( rversion ) || {},
		major = version[1],
		minor = version[2],
		patch = version[3],
		xbeta = version[4];

	branch = process.argv[2];
	releaseVersion = process.argv[3];
	isBeta = !!xbeta;

	if ( !branch || !major || !minor || !patch ) {
		die( "Usage: " + process.argv[1] + " branch releaseVersion" );
	}
	if ( xbeta === "pre" ) {
		die( "Cannot release a 'pre' version!" );
	}
	if ( !(fs.existsSync || path.existsSync)( "package.json" ) ) {
		die( "No package.json in this directory" );
	}
	pkg = JSON.parse( fs.readFileSync( "package.json" ) );

	console.log( "Current version is " + pkg.version + "; generating release " + releaseVersion );
	version = pkg.version.match( rversion );
	oldver = ( +version[1] ) * 10000 + ( +version[2] * 100 ) + ( +version[3] )
	newver = ( +major ) * 10000 + ( +minor * 100 ) + ( +patch );
	if ( newver < oldver ) {
		die( "Next version is older than current version!" );
	}

	nextVersion = major + "." + minor + "." + ( isBeta ? patch : +patch + 1 ) + "pre";
	next();
}
function checkGitStatus( next ) {
	git( [ "status" ], function( error, stdout, stderr ) {
		var onBranch = ((stdout||"").match( /On branch (\S+)/ ) || [])[1];
		if ( onBranch !== branch ) {
			die( "Branches don't match: Wanted " + branch + ", got " + onBranch );
		}
		if ( /Changes to be committed/i.test( stdout ) ) {
			die( "Please commit changed files before attemping to push a release." );
		}
		if ( /Changes not staged for commit/i.test( stdout ) ) {
			die( "Please stash files before attempting to push a release." );
		}
		next();
	});
}
function tagReleaseVersion( next ) {
	updatePackageVersion( releaseVersion );
	git( [ "commit", "-a", "-m", "Tagging the " + releaseVersion + " release." ], function(){
		git( [ "tag", releaseVersion ], next, debug);
	}, debug);
}
function gruntBuild( next ) {
	exec( gruntCmd, [], function( error, stdout ) {
		if ( error ) {
			die( error + stderr );
		}
		console.log( stdout );
		next();
	}, debug);
}
function makeReleaseCopies( next ) {
	finalFiles = {};
	Object.keys( releaseFiles ).forEach(function( key ) {
		var builtFile = releaseFiles[ key ],
			releaseFile = key.replace( /VER/g, releaseVersion );

		// Beta releases don't update the jquery-latest etc. copies
		if ( !isBeta || key !== releaseFile ) {
			copy( builtFile, releaseFile );
			finalFiles[ releaseFile ] = builtFile;
		}
	});
	next();
}
function setNextVersion( next ) {
	updatePackageVersion( nextVersion );
	git( [ "commit", "-a", "-m", "Updating the source version to " + nextVersion ], next, debug );
}
function uploadToCDN( next ) {
	var cmds = [];

	Object.keys( finalFiles ).forEach(function( name ) {
		cmds.push(function( nxt ){
			exec( "scp", [ name, scpURL ], nxt, debug || skipRemote );
		});
		cmds.push(function( nxt ){
			exec( "curl", [ cdnURL + name + "?reload" ], nxt, debug || skipRemote );
		});
	});
	cmds.push( next );

	steps.apply( this, cmds );
}
function pushToGithub( next ) {
	git( [ "push", "--tags", repoURL, branch ], next, debug || skipRemote );
}

//==============================

function steps() {
	var cur = 0,
		steps = arguments;
	(function next(){
		var step = steps[ cur++ ];
		step( next );
	})();
}
function updatePackageVersion( ver ) {
	console.log( "Updating package.json version to " + ver );
	pkg.version = ver;
	if ( !debug ) {
		fs.writeFileSync( "package.json", JSON.stringify( pkg, null, "\t" ) + "\n" );
	}
}
function copy( oldFile, newFile ) {
	console.log( "Copying " + oldFile + " to " + newFile );
	if ( !debug ) {
		fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) );
	}
}
function git( args, fn, skip ) {
	exec( "git", args, fn, skip );
}
function exec( cmd, args, fn, skip ) {
	if ( skip ) {
		console.log( "# " + cmd + " " + args.join(" ") );
		fn( "", "", "" );
	} else {
		console.log( cmd + " " + args.join(" ") );
		child.execFile( cmd, args, { env: process.env },
			function( err, stdout, stderr ) {
				if ( err ) {
					die( stderr || stdout || err );
				}
				fn.apply( this, arguments );
			}
		);
	}
}
function die( msg ) {
	console.error( "ERROR: " + msg );
	process.exit( 1 );
}
function exit() {
	process.exit( 0 );
}
<commit_msg>Add release support for map files.<commit_after>#!/usr/bin/env node
/*
 * jQuery Core Release Management
 */

// Debugging variables
var	debug = false,
	skipRemote = false;

var fs = require("fs"),
	child = require("child_process"),
	path = require("path");

var releaseVersion,
	nextVersion,
	CDNFiles,
	isBeta,
	pkg,
	branch,

	scpURL = "jqadmin@code.origin.jquery.com:/var/www/html/code.jquery.com/",
	cdnURL = "http://code.origin.jquery.com/",
	repoURL = "git@github.com:jquery/jquery.git",

	// Windows needs the .cmd version but will find the non-.cmd
	// On Windows, ensure the HOME environment variable is set
	gruntCmd = process.platform === "win32" ? "grunt.cmd" : "grunt",

	devFile = "dist/jquery.js",
	minFile = "dist/jquery.min.js",
	mapFile = "dist/jquery.min.map",

	releaseFiles = {
		"jquery-VER.js": devFile,
		"jquery-VER.min.js": minFile,
		"jquery-VER.min.map": mapFile,
		"jquery.js": devFile,
		"jquery.min.js": minFile,
		"jquery.min.map": mapFile,
		"jquery-latest.js": devFile,
		"jquery-latest.min.js": minFile,
		"jquery-latest.min.map": mapFile
	};

steps(
	initialize,
	checkGitStatus,
	tagReleaseVersion,
	gruntBuild,
	makeReleaseCopies,
	setNextVersion,
	uploadToCDN,
	pushToGithub,
	exit
);

function initialize( next ) {

	if ( process.argv[2] === "-d" ) {
		process.argv.shift();
		debug = true;
		console.warn("=== DEBUG MODE ===" );
	}

	// First arg should be the version number being released
	var newver, oldver,
		rversion = /^(\d)\.(\d+)\.(\d)((?:a|b|rc)\d|pre)?$/,
		version = ( process.argv[3] || "" ).toLowerCase().match( rversion ) || {},
		major = version[1],
		minor = version[2],
		patch = version[3],
		xbeta = version[4];

	branch = process.argv[2];
	releaseVersion = process.argv[3];
	isBeta = !!xbeta;

	if ( !branch || !major || !minor || !patch ) {
		die( "Usage: " + process.argv[1] + " branch releaseVersion" );
	}
	if ( xbeta === "pre" ) {
		die( "Cannot release a 'pre' version!" );
	}
	if ( !(fs.existsSync || path.existsSync)( "package.json" ) ) {
		die( "No package.json in this directory" );
	}
	pkg = JSON.parse( fs.readFileSync( "package.json" ) );

	console.log( "Current version is " + pkg.version + "; generating release " + releaseVersion );
	version = pkg.version.match( rversion );
	oldver = ( +version[1] ) * 10000 + ( +version[2] * 100 ) + ( +version[3] )
	newver = ( +major ) * 10000 + ( +minor * 100 ) + ( +patch );
	if ( newver < oldver ) {
		die( "Next version is older than current version!" );
	}

	nextVersion = major + "." + minor + "." + ( isBeta ? patch : +patch + 1 ) + "pre";
	next();
}

function checkGitStatus( next ) {
	git( [ "status" ], function( error, stdout, stderr ) {
		var onBranch = ((stdout||"").match( /On branch (\S+)/ ) || [])[1];
		if ( onBranch !== branch ) {
			die( "Branches don't match: Wanted " + branch + ", got " + onBranch );
		}
		if ( /Changes to be committed/i.test( stdout ) ) {
			die( "Please commit changed files before attemping to push a release." );
		}
		if ( /Changes not staged for commit/i.test( stdout ) ) {
			die( "Please stash files before attempting to push a release." );
		}
		next();
	});
}

function tagReleaseVersion( next ) {
	updatePackageVersion( releaseVersion );
	git( [ "commit", "-a", "-m", "Tagging the " + releaseVersion + " release." ], function(){
		git( [ "tag", releaseVersion ], next, debug);
	}, debug);
}

function gruntBuild( next ) {
	exec( gruntCmd, [], function( error, stdout ) {
		if ( error ) {
			die( error + stderr );
		}
		console.log( stdout );
		next();
	}, debug);
}

function makeReleaseCopies( next ) {
	CDNFiles = {};
	Object.keys( releaseFiles ).forEach(function( key ) {
		var text,
			builtFile = releaseFiles[ key ],
			releaseFile = key.replace( /VER/g, releaseVersion );

		// Beta releases don't update the jquery-latest etc. copies
		if ( !isBeta || key !== releaseFile ) {

			if ( /\.map$/.test( releaseFile ) ) {
				// Map files need to reference the new uncompressed name;
				// assume that all files reside in the same directory.
				// "file":"jquery.min.js","sources":["jquery.js"]
				text = fs.readFileSync( builtFile, "utf8" )
					.replace( /"file":"([^"]+)","sources":\["([^"]+)"\]/,
						"\"file\":\"" + releaseFile.replace( /\.min\.map/, ".min.js" ) +
						"\",\"sources\":[\"" + releaseFile.replace( /\.min\.map/, ".js" ) + "\"]" );
				console.log( "Modifying map " + builtFile + " to " + releaseFile );
				if ( !debug ) {
					fs.writeFileSync( releaseFile, text );
				}
			} else {
				copy( builtFile, releaseFile );
			}

			CDNFiles[ releaseFile ] = builtFile;
		}
	});
	next();
}

function setNextVersion( next ) {
	updatePackageVersion( nextVersion );
	git( [ "commit", "-a", "-m", "Updating the source version to " + nextVersion ], next, debug );
}

function uploadToCDN( next ) {
	var cmds = [];

	Object.keys( CDNFiles ).forEach(function( name ) {
		cmds.push(function( nxt ){
			exec( "scp", [ name, scpURL ], nxt, debug || skipRemote );
		});
		cmds.push(function( nxt ){
			exec( "curl", [ cdnURL + name + "?reload" ], nxt, debug || skipRemote );
		});
	});
	cmds.push( next );

	steps.apply( this, cmds );
}

function pushToGithub( next ) {
	git( [ "push", "--tags", repoURL, branch ], next, debug || skipRemote );
}

//==============================

function steps() {
	var cur = 0,
		steps = arguments;
	(function next(){
		process.nextTick(function(){
			steps[ cur++ ]( next );
		});
	})();
}

function updatePackageVersion( ver ) {
	console.log( "Updating package.json version to " + ver );
	pkg.version = ver;
	if ( !debug ) {
		fs.writeFileSync( "package.json", JSON.stringify( pkg, null, "\t" ) + "\n" );
	}
}

function copy( oldFile, newFile ) {
	console.log( "Copying " + oldFile + " to " + newFile );
	if ( !debug ) {
		fs.writeFileSync( newFile, fs.readFileSync( oldFile, "utf8" ) );
	}
}

function git( args, fn, skip ) {
	exec( "git", args, fn, skip );
}

function exec( cmd, args, fn, skip ) {
	if ( skip ) {
		console.log( "# " + cmd + " " + args.join(" ") );
		fn( "", "", "" );
	} else {
		console.log( cmd + " " + args.join(" ") );
		child.execFile( cmd, args, { env: process.env },
			function( err, stdout, stderr ) {
				if ( err ) {
					die( stderr || stdout || err );
				}
				fn.apply( this, arguments );
			}
		);
	}
}

function die( msg ) {
	console.error( "ERROR: " + msg );
	process.exit( 1 );
}

function exit() {
	process.exit( 0 );
}
<|endoftext|>