<commit_before>Grocy.Components.ProductAmountPicker = {};
Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled = false;

Grocy.Components.ProductAmountPicker.Reload = function(productId, destinationQuId, forceInitialDisplayQu = false)
{
	var conversionsForProduct = FindAllObjectsInArrayByPropertyValue(Grocy.QuantityUnitConversionsResolved, 'product_id', productId);

	if (!Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled)
	{
		$("#qu_id").find("option").remove().end();
		$("#qu_id").attr("data-destination-qu-name", FindObjectInArrayByPropertyValue(Grocy.QuantityUnits, 'id', destinationQuId).name);
		conversionsForProduct.forEach(conversion =>
		{
			var factor = conversion.factor;
			if (conversion.to_qu_id == destinationQuId)
			{
				factor = 1;
			}

			$("#qu_id").append('<option value="' + conversion.to_qu_id + '" data-qu-factor="' + factor + '">' + conversion.to_qu_name + '</option>');
		});
	}

	if (!Grocy.Components.ProductAmountPicker.InitialValueSet || forceInitialDisplayQu)
	{
		$("#qu_id").val($("#qu_id").attr("data-initial-qu-id"));
	}

	if (!Grocy.Components.ProductAmountPicker.InitialValueSet)
	{
		var convertedAmount = $("#display_amount").val() * $("#qu_id option:selected").attr("data-qu-factor");
		$("#display_amount").val(convertedAmount);

		Grocy.Components.ProductAmountPicker.InitialValueSet = true;
	}

	if (conversionsForProduct.length === 1 && !forceInitialDisplayQu)
	{
		$("#qu_id").val($("#qu_id option:first").val());
	}

	$(".input-group-productamountpicker").trigger("change");
}

Grocy.Components.ProductAmountPicker.SetQuantityUnit = function(quId)
{
	$("#qu_id").val(quId);
}

Grocy.Components.ProductAmountPicker.AllowAnyQu = function(keepInitialQu = false)
{
	Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled = true;

	$("#qu_id").find("option").remove().end();
	Grocy.QuantityUnits.forEach(qu =>
	{
		$("#qu_id").append('<option value="' + qu.id + '" data-qu-factor="1">' + qu.name + '</option>');
	});

	if (keepInitialQu)
	{
		Grocy.Components.ProductAmountPicker.SetQuantityUnit($("#qu_id").attr("data-initial-qu-id"));
	}

	$(".input-group-productamountpicker").trigger("change");
}

Grocy.Components.ProductAmountPicker.Reset = function()
{
	$("#qu_id").find("option").remove();
	$("#qu-conversion-info").addClass("d-none");
	$("#qu-display_amount-info").val("");
}

$(".input-group-productamountpicker").on("change", function()
{
	var destinationQuName = $("#qu_id").attr("data-destination-qu-name");
	var selectedQuName = $("#qu_id option:selected").text();
	var quFactor = $("#qu_id option:selected").attr("data-qu-factor");
	var amount = $("#display_amount").val();
	var destinationAmount = amount / quFactor;

	if (destinationQuName == selectedQuName || Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled || amount.toString().isEmpty() || selectedQuName.toString().isEmpty())
	{
		$("#qu-conversion-info").addClass("d-none");
	}
	else
	{
		$("#qu-conversion-info").removeClass("d-none");
		$("#qu-conversion-info").text(__t("This equals %1$s %2$s in stock", destinationAmount.toLocaleString(), destinationQuName));
	}

	$("#amount").val(destinationAmount.toFixed(4).replace(/0*$/g, ''));
});

$("#display_amount").on("keyup", function()
{
	$(".input-group-productamountpicker").trigger("change");
});
<commit_msg>Improved productamountpicker stock amount display<commit_after>Grocy.Components.ProductAmountPicker = {};
Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled = false;

Grocy.Components.ProductAmountPicker.Reload = function(productId, destinationQuId, forceInitialDisplayQu = false)
{
	var conversionsForProduct = FindAllObjectsInArrayByPropertyValue(Grocy.QuantityUnitConversionsResolved, 'product_id', productId);

	if (!Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled)
	{
		$("#qu_id").find("option").remove().end();
		$("#qu_id").attr("data-destination-qu-name", FindObjectInArrayByPropertyValue(Grocy.QuantityUnits, 'id', destinationQuId).name);
		conversionsForProduct.forEach(conversion =>
		{
			var factor = conversion.factor;
			if (conversion.to_qu_id == destinationQuId)
			{
				factor = 1;
			}

			$("#qu_id").append('<option value="' + conversion.to_qu_id + '" data-qu-factor="' + factor + '">' + conversion.to_qu_name + '</option>');
		});
	}

	if (!Grocy.Components.ProductAmountPicker.InitialValueSet || forceInitialDisplayQu)
	{
		$("#qu_id").val($("#qu_id").attr("data-initial-qu-id"));
	}

	if (!Grocy.Components.ProductAmountPicker.InitialValueSet)
	{
		var convertedAmount = $("#display_amount").val() * $("#qu_id option:selected").attr("data-qu-factor");
		$("#display_amount").val(convertedAmount);

		Grocy.Components.ProductAmountPicker.InitialValueSet = true;
	}

	if (conversionsForProduct.length === 1 && !forceInitialDisplayQu)
	{
		$("#qu_id").val($("#qu_id option:first").val());
	}

	$(".input-group-productamountpicker").trigger("change");
}

Grocy.Components.ProductAmountPicker.SetQuantityUnit = function(quId)
{
	$("#qu_id").val(quId);
}

Grocy.Components.ProductAmountPicker.AllowAnyQu = function(keepInitialQu = false)
{
	Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled = true;

	$("#qu_id").find("option").remove().end();
	Grocy.QuantityUnits.forEach(qu =>
	{
		$("#qu_id").append('<option value="' + qu.id + '" data-qu-factor="1">' + qu.name + '</option>');
	});

	if (keepInitialQu)
	{
		Grocy.Components.ProductAmountPicker.SetQuantityUnit($("#qu_id").attr("data-initial-qu-id"));
	}

	$(".input-group-productamountpicker").trigger("change");
}

Grocy.Components.ProductAmountPicker.Reset = function()
{
	$("#qu_id").find("option").remove();
	$("#qu-conversion-info").addClass("d-none");
	$("#qu-display_amount-info").val("");
}

$(".input-group-productamountpicker").on("change", function()
{
	var destinationQuName = $("#qu_id").attr("data-destination-qu-name");
	var selectedQuName = $("#qu_id option:selected").text();
	var quFactor = $("#qu_id option:selected").attr("data-qu-factor");
	var amount = $("#display_amount").val();
	var destinationAmount = amount / quFactor;

	if (destinationQuName == selectedQuName || Grocy.Components.ProductAmountPicker.AllowAnyQuEnabled || amount.toString().isEmpty() || selectedQuName.toString().isEmpty())
	{
		$("#qu-conversion-info").addClass("d-none");
	}
	else
	{
		$("#qu-conversion-info").removeClass("d-none");
		$("#qu-conversion-info").text(__t("This equals %1$s %2$s in stock", destinationAmount.toLocaleString({ minimumFractionDigits: 0, maximumFractionDigits: Grocy.UserSettings.stock_decimal_places_amounts }), destinationQuName));
	}

	$("#amount").val(destinationAmount.toFixed(4).replace(/0*$/g, ''));
});

$("#display_amount").on("keyup", function()
{
	$(".input-group-productamountpicker").trigger("change");
});
<|endoftext|>


<commit_before>import * as validation from 'utils/validation';
import memoize from 'lru-memoize';

const nameInput = [
  validation.valueRequired,
];

const feedbackInput = [
  validation.valueRequired,
];

const formValidation = validation.createValidator({
  nameInput,
  feedbackInput,
});

const validator = memoize(10)(formValidation);
export default validator;
<commit_msg>Fix: Validate url input for feedback<commit_after>import * as validation from 'utils/validation';
import memoize from 'lru-memoize';

const nameInput = [
  validation.valueRequired,
];

const urlInput = [
  validation.valueRequired,
];

const formValidation = validation.createValidator({
  nameInput,
  urlInput,
});

const validator = memoize(10)(formValidation);
export default validator;
<|endoftext|>


<commit_before>// Depends on
//	Knockout
// 	toastr
//	my.datacontext
//
// Description
//  vm.favorites is the ViewModel for a view displaying just the sessions
//  that the current user has marked as favorites.
//  The user can further filter this subset of Sessions by additional criteria,
//  the same filter criteria that can be applied to all sessions.
//
// ----------------------------------------------
app.vm = app.vm || {}

app.vm.favorites = (function (ko, toastr, datacontext) {
    var
        sessionFilter = new app.filter.SessionFilter(),
        timeslots = ko.observableArray(),
        sessions = ko.observableArray(), //.trackReevaluations(),
        searchText = ko.observable(),
        days = ko.computed(function() {
            var result = _.reduce(timeslots(), function(memo, slot) {
                var date = moment(slot.start()).format('MM-DD-YYYY'), //.toDate(),
                    day = moment(date).format('ddd MMM DD')

                if (!memo.index[day.toString()]) {
                    // This is created so i dont have to loop through the array each time again
                    memo.index[day.toString()] = true
                    memo.slots.push({ date: date, day: day })
                }
                return memo
            }, { index: { }, slots: [] })

            sortedDays = result.slots.sort(function(a, b) { return a.date > b.date })
            return sortedDays
        }),
        activate = function() { //routeData) { //TODO: routeData is not used. Remove it later.
            datacontext.timeslots.getData({ results: timeslots });
        },
        setFilter = function () {
            var day = new Date(data.date);
            sessionFilter.favoriteOnly(true) //TODO: implement this
            sessionFilter.minTimeSlot(day)
            var maxDate = moment(new Date(day)).add('days', 1).add('seconds', -1).toDate()
            sessionFilter.maxTimeSlot(maxDate)
            sessionFilter.searchText(searchText())
        },
        loadByDate = function (data) {
            // sessionFilter always limits to favorite sessions of the current user
            setFilter()

            sessionFilter.execute(datacontext, sessions); // populate with favorite sessions

            //datacontext.sessions.getData({ results: sessions });

            //TODO: implement activity indicator (if needed)
            //$('#busy1').activity();
            //$.when(sessionFilter.execute(datacontext, sessions))
            //    .always(function() {
            //        toastr.success('done loading')
            //        $('#busy1').activity(false);
            //    })

        },
        debugInfo = app.debugInfo(sessions);
    return {
        sessions: sessions,
        timeslots: timeslots,
        searchText: searchText,
        days: days,
        activate: activate,
        loadByDate: loadByDate,
        debugInfo: debugInfo,
    }
})(ko, toastr, app.datacontext);<commit_msg>fixed bug with filter<commit_after>// Depends on
//	Knockout
// 	toastr
//	my.datacontext
//
// Description
//  vm.favorites is the ViewModel for a view displaying just the sessions
//  that the current user has marked as favorites.
//  The user can further filter this subset of Sessions by additional criteria,
//  the same filter criteria that can be applied to all sessions.
//
// ----------------------------------------------
app.vm = app.vm || {}

app.vm.favorites = (function (ko, toastr, datacontext) {
    var
        sessionFilter = new app.filter.SessionFilter(),
        timeslots = ko.observableArray(),
        sessions = ko.observableArray(), //.trackReevaluations(),
        searchText = ko.observable(),
        days = ko.computed(function() {
            var result = _.reduce(timeslots(), function(memo, slot) {
                var date = moment(slot.start()).format('MM-DD-YYYY'), //.toDate(),
                    day = moment(date).format('ddd MMM DD')

                if (!memo.index[day.toString()]) {
                    // This is created so i dont have to loop through the array each time again
                    memo.index[day.toString()] = true
                    memo.slots.push({ date: date, day: day })
                }
                return memo
            }, { index: { }, slots: [] })

            sortedDays = result.slots.sort(function(a, b) { return a.date > b.date })
            return sortedDays
        }),
        activate = function() { //routeData) { //TODO: routeData is not used. Remove it later.
            datacontext.timeslots.getData({ results: timeslots });
        },
        setFilter = function (data) {
            if(data && data.date) {
                var day = new Date(data.date)
                sessionFilter.minTimeSlot(day)
                var maxDate = moment(new Date(day)).add('days', 1).add('seconds', -1).toDate()
                sessionFilter.maxTimeSlot(maxDate)
            }
            sessionFilter.favoriteOnly(true) //TODO: implement this
            sessionFilter.searchText(searchText())
        },
        loadByDate = function (data) {
            // sessionFilter always limits to favorite sessions of the current user
            setFilter(data)

            sessionFilter.execute(datacontext, sessions); // populate with favorite sessions

            //datacontext.sessions.getData({ results: sessions });

            //TODO: implement activity indicator (if needed)
            //$('#busy1').activity();
            //$.when(sessionFilter.execute(datacontext, sessions))
            //    .always(function() {
            //        toastr.success('done loading')
            //        $('#busy1').activity(false);
            //    })

        },
        debugInfo = app.debugInfo(sessions);
    return {
        sessions: sessions,
        timeslots: timeslots,
        searchText: searchText,
        days: days,
        activate: activate,
        loadByDate: loadByDate,
        debugInfo: debugInfo,
    }
})(ko, toastr, app.datacontext);<|endoftext|>


<commit_before>/* بسم الله الرحمن الرحیم
 *
 * Mickey v0.1
 * LICENSE: MIT
 *
 *
 */

Mickey = function( el ) {

	if( typeof el == 'string' ) return new Mickey.fn( document.querySelectorAll( el ) );

	el = el || document.body;

	return new Mickey.fn( [el] )

}

Mickey.forEach = function( target, fn ) {

  for( var i = 0, len = target.length; i < len; i++ ) {

    fn( target[i] );

  }

}

/* OPTIONS AVAILABLE:
 * blink :: cursor blinks with a delay
 * chase :: scrolls follow the mouse
 * timeout :: changing cursor after a delay
 * interval :: changing cursor after a delay ( repeated )
 * shadow :: adds shadow to your mouse
 * text :: adds a text following your mouse
 */

Mickey.fn = function( el ) {

	this.el = el;

}

Mickey.fn.prototype = {

	chase : function() {

	 Mickey.forEach( this.el, function( target ) {

     target.addEventListener('mousemove', function( e ) {

  			var
  			  top = Mickey.top,
  				left = Mickey.left,
  				topScrl = window.scrollY,
  				leftScrl = window.scrollX,
  				offsetWidth = target.offsetWidth,
  				offsetHeight = target.offsetHeight;

  			window.scroll( ( left - leftScrl ) * ( offsetWidth / 700 ), ( top -  topScrl ) * ( offsetHeight / 700 ) ); // Works on almost every size, tested up to 40000px height & width

  		});

		});

		return new Mickey.fn( this.el )
	},

	blink : function( delay, cursor ) {

		Mickey.forEach( this.el, function(target) {

			var turn = 0;

  		setInterval(function() {

  			if( turn == 0 ) {

  				target.style.cursor = 'none',
  				turn = 1;

  			}
  			else {

  				target.style.cursor = cursor || 'default',
  				turn = 0;

  			}
  		}, delay || 300);

		});

		return new Mickey.fn( this.el )
	},

	timeout : function( cursor, delay, ret ) {

    Mickey.forEach( this.el, function( target ) {

      var shift  = target.style.cursor;

      setTimeout(function() {

        target.style.cursor = cursor || 'pointer';

        if( ret ) setTimeout(function(){

            if( typeof ret == 'string' ) target.style.cursor = ret;

            else target.style.cursor = shift;

            }, delay)

      }, delay || 300);

    });

    return new Mickey.fn( this.el )
  },

	interval : function( from, to, delay ) { // Has same structure as blink

    Mickey.forEach( this.el, function( target ) {

      turn = 0;

      setInterval(function() {

        if( turn == 0 ) {

          target.style.cursor = from,
          turn = 1;

        }
        else {

          target.style.cursor = to,
          turn = 0;

        }

      }, delay || 300);

    });

    return new Mickey.fn( this.el );
  },

//FIXME: If `x` and / or `y` are less than 0, clickable parts cannot be clicked ( canvas overlays them )
//TODO: We need a way to detect user's mouse model, user's mouse might be ANYTHING, so we need a way to draw the cursor's shadow depending on user's cursor
//TODO: Shadow's blur, because of canvas' limited height and width we can't do that correctly

	shadow : function( x, y, color, delay, className ) {

	  Mickey.forEach( this.el, function( target ) {

  	  var shadow = document.createElement('canvas'),
  	      canvas = shadow.getContext('2d'),
  	      mouse  = target.style.cursor.style;

  	  shadow.setAttribute('width','14'),
  	  shadow.setAttribute('height','21');
  	  shadow.style.position = 'absolute';
  	  shadow.style.display = 'none';
  	  if( className ) txt.className = className;

  	  canvas.fillStyle = color || 'black';

  	  switch (mouse) {

  	    default: // Ubuntu's default cursor, similar to Win7's cursor
  	      canvas.moveTo( 0, 0);
          canvas.lineTo( 13.5, 14);
          canvas.lineTo( 8, 14.5);
          canvas.lineTo( 10, 20);
          canvas.lineTo( 8, 20.5);
          canvas.lineTo( 5, 15.5);
          canvas.lineTo( 0, 18.5);
          canvas.lineTo( 0, 0);
          canvas.fill();
          break;

  	  }

      target.appendChild( shadow );

  	  target.addEventListener('mousemove', function( e ) {

  	    shadow.style.display='block';

  	    setTimeout( function() {

    	    x = x || 0,
    	    y = y || 0;

    	    shadow.style.top      = Mickey.top + x + 1 + 'px';
    	    shadow.style.left     = Mickey.left + x + 1 + 'px';

  	    }, delay || 0)

  	  });

  	  target.addEventListener('mouseleave', function() {

        shadow.style.display='none';

      });

    });

	  return new Mickey.fn( this.el )
	},

	hover : function( fn ) {

	  Mickey.forEach( this.el, function( target ) {

	    target.addEventListener('mouseover', fn );

    });

	  return new Mickey.fn( this.el )
	},

	click : function( fn ) {

	  Mickey.forEach( this.el, function( target ) {

	    target.addEventListener('click', fn );

	  });

	  return new Mickey.fn( this.el )
	},

	text : function( text, styles, x, y, effect, className ) {

	  var txt = document.createElement('span');

	  txt.innerHTML = text;
	  txt.style.position = 'absolute';
	  txt.style.display = 'none';
	  txt.className = 'mickey-text';
	  if( className ) txt.className = className;

	  if( styles ) {
  	  for( var i in styles ) {

  	    txt.style[i] = styles[i];

  	  }
	  }

	  var x = x || 0,
        y = y || 0;

	  switch( effect ) {

        case 'heartbeat':

        i = 14 || styles.fontSize;
        turn = 0;
        setInterval( function() {

          if( turn == 0 && i < 25 ) {
            txt.innerHTML = '' + text + '';
            i++;
          }
          if( i == 25 ) turn = 1;

          if( turn == 1 && i > 14 ){
            i--;
            txt.innerHTML = '' + text + '';
          }

          if( i == 14 ) turn = 0;

        }, 30 );

     }

	  Mickey.forEach( this.el, function( target ) {

	    target.appendChild( txt );

	    target.addEventListener('mousemove', function( e ) {

        txt.style.display = 'block';
	      txt.style.top = Mickey.top + 21 + y + 'px';
	      txt.style.left = Mickey.left + 14 + x + 'px';

	    });

	    target.addEventListener('mouseleave', function( e ) {

	      txt.style.display = 'none';

	    });

	  });

	  return new Mickey.fn( this.el );
	},

	image : function( src, styles, x, y, effect, className) {

	  var
	  img = document.createElement('img');
    img.setAttribute('src', src);
    img.style.position = 'absolute';
    img.style.display = 'none';
    img.className = 'mickey-image';
    if( className ) img.className = className;

    if( styles ) {
      for( var i in styles ) {

        img.style[i] = styles[i];

      }
    }
    var x = x || 0,
        y = y || 0;

    Mickey.forEach( this.el, function( target ) {

      target.appendChild( img )

      target.addEventListener('mousemove', function( e ) {

        img.style.display='block';
        img.style.top = Mickey.top + 21 + y + 'px';
        img.style.left = Mickey.left + 14 + x + 'px';

      });

       target.addEventListener('mouseleave', function( e ) {

        img.style.display='none';

      });

    });

    return new Mickey.fn( this.el );
  },

  absolute : function() {

    return { top : Mickey.top, left : Mickey.left };

  },

  relative : function() {

    var eTop = this.el[0].offsetTop,
        eLeft = this.el[0].offsetLeft;

    return { top : Mickey.top - eTop, left : Mickey.left - eLeft}

  }

}

document.body.addEventListener('mousemove', function( e ) {

  Mickey.top = e.pageY,
  Mickey.left = e.pageX;

})
<commit_msg>Simplified Heartbeat<commit_after>/* بسم الله الرحمن الرحیم
 *
 * Mickey v0.1
 * LICENSE: MIT
 *
 *
 */

Mickey = function( el ) {

	if( typeof el == 'string' ) return new Mickey.fn( document.querySelectorAll( el ) );

	el = el || document.body;

	return new Mickey.fn( [el] )

}

Mickey.forEach = function( target, fn ) {

  for( var i = 0, len = target.length; i < len; i++ ) {

    fn( target[i] );

  }

}

/* OPTIONS AVAILABLE:
 * blink :: cursor blinks with a delay
 * chase :: scrolls follow the mouse
 * timeout :: changing cursor after a delay
 * interval :: changing cursor after a delay ( repeated )
 * shadow :: adds shadow to your mouse
 * text :: adds a text following your mouse
 */

Mickey.fn = function( el ) {

	this.el = el;

}

Mickey.fn.prototype = {

	chase : function() {

	 Mickey.forEach( this.el, function( target ) {

     target.addEventListener('mousemove', function( e ) {

  			var
  			  top = Mickey.top,
  				left = Mickey.left,
  				topScrl = window.scrollY,
  				leftScrl = window.scrollX,
  				offsetWidth = target.offsetWidth,
  				offsetHeight = target.offsetHeight;

  			window.scroll( ( left - leftScrl ) * ( offsetWidth / 700 ), ( top -  topScrl ) * ( offsetHeight / 700 ) ); // Works on almost every size, tested up to 40000px height & width

  		});

		});

		return new Mickey.fn( this.el )
	},

	blink : function( delay, cursor ) {

		Mickey.forEach( this.el, function(target) {

			var turn = 0;

  		setInterval(function() {

  			if( turn == 0 ) {

  				target.style.cursor = 'none',
  				turn = 1;

  			}
  			else {

  				target.style.cursor = cursor || 'default',
  				turn = 0;

  			}
  		}, delay || 300);

		});

		return new Mickey.fn( this.el )
	},

	timeout : function( cursor, delay, ret ) {

    Mickey.forEach( this.el, function( target ) {

      var shift  = target.style.cursor;

      setTimeout(function() {

        target.style.cursor = cursor || 'pointer';

        if( ret ) setTimeout(function(){

            if( typeof ret == 'string' ) target.style.cursor = ret;

            else target.style.cursor = shift;

            }, delay)

      }, delay || 300);

    });

    return new Mickey.fn( this.el )
  },

	interval : function( from, to, delay ) { // Has same structure as blink

    Mickey.forEach( this.el, function( target ) {

      turn = 0;

      setInterval(function() {

        if( turn == 0 ) {

          target.style.cursor = from,
          turn = 1;

        }
        else {

          target.style.cursor = to,
          turn = 0;

        }

      }, delay || 300);

    });

    return new Mickey.fn( this.el );
  },

//FIXME: If `x` and / or `y` are less than 0, clickable parts cannot be clicked ( canvas overlays them )
//TODO: We need a way to detect user's mouse model, user's mouse might be ANYTHING, so we need a way to draw the cursor's shadow depending on user's cursor
//TODO: Shadow's blur, because of canvas' limited height and width we can't do that correctly

	shadow : function( x, y, color, delay, className ) {

	  Mickey.forEach( this.el, function( target ) {

  	  var shadow = document.createElement('canvas'),
  	      canvas = shadow.getContext('2d'),
  	      mouse  = target.style.cursor.style;

  	  shadow.setAttribute('width','14'),
  	  shadow.setAttribute('height','21');
  	  shadow.style.position = 'absolute';
  	  shadow.style.display = 'none';
  	  if( className ) txt.className = className;

  	  canvas.fillStyle = color || 'black';

  	  switch (mouse) {

  	    default: // Ubuntu's default cursor, similar to Win7's cursor
  	      canvas.moveTo( 0, 0);
          canvas.lineTo( 13.5, 14);
          canvas.lineTo( 8, 14.5);
          canvas.lineTo( 10, 20);
          canvas.lineTo( 8, 20.5);
          canvas.lineTo( 5, 15.5);
          canvas.lineTo( 0, 18.5);
          canvas.lineTo( 0, 0);
          canvas.fill();
          break;

  	  }

      target.appendChild( shadow );

  	  target.addEventListener('mousemove', function( e ) {

  	    shadow.style.display='block';

  	    setTimeout( function() {

    	    x = x || 0,
    	    y = y || 0;

    	    shadow.style.top      = Mickey.top + x + 1 + 'px';
    	    shadow.style.left     = Mickey.left + x + 1 + 'px';

  	    }, delay || 0)

  	  });

  	  target.addEventListener('mouseleave', function() {

        shadow.style.display='none';

      });

    });

	  return new Mickey.fn( this.el )
	},

	hover : function( fn ) {

	  Mickey.forEach( this.el, function( target ) {

	    target.addEventListener('mouseover', fn );

    });

	  return new Mickey.fn( this.el )
	},

	click : function( fn ) {

	  Mickey.forEach( this.el, function( target ) {

	    target.addEventListener('click', fn );

	  });

	  return new Mickey.fn( this.el )
	},

	text : function( text, styles, x, y, effect, className ) {

	  var txt = document.createElement('span');

	  txt.innerHTML = text;
	  txt.style.position = 'absolute';
	  txt.style.display = 'none';
	  txt.className = 'mickey-text';
	  if( className ) txt.className = className;

	  if( styles ) {
  	  for( var i in styles ) {

  	    txt.style[i] = styles[i];

  	  }
	  }

	  var x = x || 0,
        y = y || 0;

	  switch( effect ) {

        case 'heartbeat':

        i = 14 || styles.fontSize;
        turn = 0;
        setInterval( function() {

          if( turn == 0 && i < 25 ) {
            txt.style.fontSize = i + 'px';
            i++;
          }
          if( i == 25 ) turn = 1;

          if( turn == 1 && i > 14 ){
            i--;
            txt.style.fontSize = i + 'px';
          }

          if( i == 14 ) turn = 0;

        }, 30 );

     }

	  Mickey.forEach( this.el, function( target ) {

	    target.appendChild( txt );

	    target.addEventListener('mousemove', function( e ) {

        txt.style.display = 'block';
	      txt.style.top = Mickey.top + 21 + y + 'px';
	      txt.style.left = Mickey.left + 14 + x + 'px';

	    });

	    target.addEventListener('mouseleave', function( e ) {

	      txt.style.display = 'none';

	    });

	  });

	  return new Mickey.fn( this.el );
	},

	image : function( src, styles, x, y, effect, className) {

	  var
	  img = document.createElement('img');
    img.setAttribute('src', src);
    img.style.position = 'absolute';
    img.style.display = 'none';
    img.className = 'mickey-image';
    if( className ) img.className = className;

    if( styles ) {
      for( var i in styles ) {

        img.style[i] = styles[i];

      }
    }
    var x = x || 0,
        y = y || 0;

    Mickey.forEach( this.el, function( target ) {

      target.appendChild( img )

      target.addEventListener('mousemove', function( e ) {

        img.style.display='block';
        img.style.top = Mickey.top + 21 + y + 'px';
        img.style.left = Mickey.left + 14 + x + 'px';

      });

       target.addEventListener('mouseleave', function( e ) {

        img.style.display='none';

      });

    });

    return new Mickey.fn( this.el );
  },

  absolute : function() {

    return { top : Mickey.top, left : Mickey.left };

  },

  relative : function() {

    var eTop = this.el[0].offsetTop,
        eLeft = this.el[0].offsetLeft;

    return { top : Mickey.top - eTop, left : Mickey.left - eLeft}

  }

}

document.body.addEventListener('mousemove', function( e ) {

  Mickey.top = e.pageY,
  Mickey.left = e.pageX;

})
<|endoftext|>


<commit_before>function(args) {
/*
is_app(true)
control_type("VB")
display_name("Radio button control")
description("This will return the radio button control")
base_component_id("radio_button_control")
load_once_from_file(true)
visibility("PRIVATE")
read_only(true)
properties(
    [
        {
            id:     "text",
            name:   "Text",
            type:   "String"
        }
        ,
        {
            id:     "checked",
            name:   "Checked",
            type:   "String"
        }
        ,
        {
            id:     "background_color",
            name:   "Background color",
            type:   "String"
        }
    ]
)//properties
logo_url("/driver_icons/radio.png")
*/

    Vue.component("radio_button_control",{
      props: ["args","design_mode"]
      ,
      template: `<input v-bind:id='design_mode?"":args.name'
                        type="checkbox"
                        v-model="args.checked"
                        v-bind:value='args.text'>{{args.text}}

                 </input>`
      ,
      data: function() {
       return {
         msg: "...",
         checked: true
     }
      },
    })
}
<commit_msg>Added radio button<commit_after>function(args) {
/*
is_app(true)
control_type("VB")
display_name("Radio button control")
description("This will return the radio button control")
base_component_id("radio_button_control")
load_once_from_file(true)
visibility("PRIVATE")
read_only(true)
properties(
    [
        {
            id:     "text",
            name:   "Text",
            type:   "String"
        }
        ,
        {
            id:     "checked",
            name:   "Checked",
            type:   "String"
        }
        ,
        {
            id:     "background_color",
            name:   "Background color",
            type:   "String"
        }
    ]
)//properties
logo_url("/driver_icons/radio.png")
*/

    Vue.component("radio_button_control",{
      props: ["args","design_mode"]
      ,
      template: `<input v-bind:id='design_mode?"":args.name'
                        type="radio"
                        v-model="args.checked"
                        v-bind:value='args.text'>{{args.text}}

                 </input>`
      ,
      data: function() {
       return {
         msg: "...",
         checked: true
     }
      },
    })
}
<|endoftext|>


<commit_before>/* global assert, process, setup, suite, test */

const helpers = require('../helpers')
const entityFactory = helpers.entityFactory

suite('physics-collider', function () {
  setup(function (done) {
    var el = this.el = entityFactory()
    window.CANNON = {Body: {KINEMATIC: 4}}
    el.body = {el: el, id: 2}
    this.scene = el.sceneEl
    this.el.setAttribute('physics-collider', '')
    this.target1 = document.createElement('a-entity')
    this.scene.appendChild(this.target1)
    this.target1.body = {el: this.target1, id: 1}
    this.target2 = document.createElement('a-entity')
    this.scene.appendChild(this.target2)
    this.target2.body = {el: this.target2, id: 3}
    this.scene.addEventListener('loaded', () => {
      this.comp = this.el.components['physics-collider']
      done()
    })
  })
  suite('lifecyle', function () {
    test('component attaches and removes without errors', function (done) {
      this.el.removeAttribute('physics-collider')
      process.nextTick(done)
    })
  })
  suite('collisions', function () {
    test('finds collided entities in contacts array', function () {
      const hitSpy = this.sinon.spy()
      this.el.addEventListener('collisions', hitSpy)
      this.el.body.world = {
        bodyOverlapKeeper: {current: [
          (this.target1.body.id << 16) + this.el.body.id,
          (this.el.body.id << 16) + this.target2.body.id
        ]},
        idToBodyMap: [undefined, this.target1.body, this.el.body, this.target2.body]
      }
      this.comp.tick()
      assert.isTrue(
        hitSpy.calledWithMatch({detail: {els: [this.target1, this.target2]}}),
        'finds new collisions'
      )
      this.comp.tick()
      assert.strictEqual(this.comp.collisions.size, 2, 'ignores duplicates')
      this.el.body.world.bodyOverlapKeeper.current.pop()
      this.comp.tick()
      assert.isTrue(
        hitSpy.calledWithMatch({detail: {els: [], clearedEls: [this.target2]}}),
        'clears old collisions and ignores duplicates'
      )
      assert.strictEqual(this.comp.collisions.size, 1, 'keeps ongoing collisions')
      assert.isTrue(this.comp.collisions.has(this.target1), 'keeps ongoing collisions')
    })
    test('Handles bodies removed while collided', function () {
      this.el.body.world = {
        bodyOverlapKeeper: {current: [
          (this.target1.body.id << 16) + this.el.body.id,
          (this.el.body.id << 16) + this.target2.body.id
        ]},
        idToBodyMap: [undefined, this.target1.body, this.el.body, this.target2.body]
      }
      this.comp.tick()
      this.el.body.world.idToBodyMap[3] = undefined
      this.comp.tick()
      assert.isFalse(this.comp.collisions.has(this.target2), 'lower loop')
    })
  })
})
<commit_msg>Also test removal of collided entities in the upper loop<commit_after>/* global assert, process, setup, suite, test */

const helpers = require('../helpers')
const entityFactory = helpers.entityFactory

suite('physics-collider', function () {
  setup(function (done) {
    var el = this.el = entityFactory()
    window.CANNON = {Body: {KINEMATIC: 4}}
    el.body = {el: el, id: 2}
    this.scene = el.sceneEl
    this.el.setAttribute('physics-collider', '')
    this.target1 = document.createElement('a-entity')
    this.scene.appendChild(this.target1)
    this.target1.body = {el: this.target1, id: 1}
    this.target2 = document.createElement('a-entity')
    this.scene.appendChild(this.target2)
    this.target2.body = {el: this.target2, id: 3}
    this.scene.addEventListener('loaded', () => {
      this.comp = this.el.components['physics-collider']
      done()
    })
  })
  suite('lifecyle', function () {
    test('component attaches and removes without errors', function (done) {
      this.el.removeAttribute('physics-collider')
      process.nextTick(done)
    })
  })
  suite('collisions', function () {
    test('finds collided entities in contacts array', function () {
      const hitSpy = this.sinon.spy()
      this.el.addEventListener('collisions', hitSpy)
      this.el.body.world = {
        bodyOverlapKeeper: {current: [
          (this.target1.body.id << 16) + this.el.body.id,
          (this.el.body.id << 16) + this.target2.body.id
        ]},
        idToBodyMap: [undefined, this.target1.body, this.el.body, this.target2.body]
      }
      this.comp.tick()
      assert.isTrue(
        hitSpy.calledWithMatch({detail: {els: [this.target1, this.target2]}}),
        'finds new collisions'
      )
      this.comp.tick()
      assert.strictEqual(this.comp.collisions.size, 2, 'ignores duplicates')
      this.el.body.world.bodyOverlapKeeper.current.pop()
      this.comp.tick()
      assert.isTrue(
        hitSpy.calledWithMatch({detail: {els: [], clearedEls: [this.target2]}}),
        'clears old collisions and ignores duplicates'
      )
      assert.strictEqual(this.comp.collisions.size, 1, 'keeps ongoing collisions')
      assert.isTrue(this.comp.collisions.has(this.target1), 'keeps ongoing collisions')
    })
    test('Handles bodies removed while collided', function () {
      this.el.body.world = {
        bodyOverlapKeeper: {current: [
          (this.target1.body.id << 16) + this.el.body.id,
          (this.el.body.id << 16) + this.target2.body.id
        ]},
        idToBodyMap: [undefined, this.target1.body, this.el.body, this.target2.body]
      }
      this.comp.tick()
      this.el.body.world.idToBodyMap[3] = undefined
      this.comp.tick()
      assert.isFalse(this.comp.collisions.has(this.target2), 'lower loop')
      this.el.body.world.idToBodyMap[1] = undefined
      this.comp.tick()
      assert.isFalse(this.comp.collisions.has(this.target1), 'upper loop')
    })
  })
})
<|endoftext|>


<commit_before>(function() {
    'use strict';

    var module = angular.module('billett.admin');

    //module.controller('AdminEventgroupEditNewController', function (Page, $stateParams){
    module.controller('AdminEventgroupEditNewController', function (Page, AdminEventgroup, $stateParams, $rootScope, $scope, $location, $window, $timeout) {
        var is_new = $scope.is_new = !('id' in $stateParams);

	console.log('is_new: ' + is_new);

        var loader = Page.setLoading();

        if (is_new) {
            Page.setTitle('Ny arrangementgruppe');
            loader();
        }
        else {
            Page.setTitle('Rediger arrangementgruppe');
	    //loader();

            AdminEventgroup.get({id: $stateParams['id']}, function (ret) {
                loader();

		console.log($scope);

                $scope.eventgroup = ret;

		console.log($scope);

            }, function () {
                loader();
                Page.set404();
            });

        }

        $scope.storeEventgroup = function () {

            if (is_new) {

                if (!($scope.eventgroup.title)) return;

                var eg = new AdminEventgroup($scope.eventgroup);

                console.log(eg);

                eg.$save(function (res) {
                    $location.path('/a/eventgroup/' + res.id);
                }, function (err) {
                    alert(err.data);
                });
            } else {
                $scope.eventgroup.$update(function (res) {
                    // go to previous page or redirect to eventgroup admin page
                    var timer = $timeout(function () {
                        $location.path('/a/eventgroup/' + res.id);
                    }, 100);
                    var ev = $rootScope.$on('$routeChangeStart', function (event, next, current) {
                        ev();
                        $timeout.cancel(timer);
                    });
                    $window.history.back();
                }, function (err) {
                    alert(err.data);
                });
            }
        };
    });
})();

<commit_msg>remove debug<commit_after>(function() {
    'use strict';

    var module = angular.module('billett.admin');

    //module.controller('AdminEventgroupEditNewController', function (Page, $stateParams){
    module.controller('AdminEventgroupEditNewController', function (Page, AdminEventgroup, $stateParams, $rootScope, $scope, $location, $window, $timeout) {
        var is_new = $scope.is_new = !('id' in $stateParams);

        var loader = Page.setLoading();

        if (is_new) {
            Page.setTitle('Ny arrangementgruppe');
            loader();
        }
        else {
            Page.setTitle('Rediger arrangementgruppe');
	    //loader();

            AdminEventgroup.get({id: $stateParams['id']}, function (ret) {
                loader();

                $scope.eventgroup = ret;

            }, function () {
                loader();
                Page.set404();
            });

        }

        $scope.storeEventgroup = function () {

            if (is_new) {

                if (!($scope.eventgroup.title)) return;

                var eg = new AdminEventgroup($scope.eventgroup);

                eg.$save(function (res) {
                    $location.path('/a/eventgroup/' + res.id);
                }, function (err) {
                    alert(err.data);
                });
            } else {
                $scope.eventgroup.$update(function (res) {
                    // go to previous page or redirect to eventgroup admin page
                    var timer = $timeout(function () {
                        $location.path('/a/eventgroup/' + res.id);
                    }, 100);
                    var ev = $rootScope.$on('$routeChangeStart', function (event, next, current) {
                        ev();
                        $timeout.cancel(timer);
                    });
                    $window.history.back();
                }, function (err) {
                    alert(err.data);
                });
            }
        };
    });
})();

<|endoftext|>


<commit_before>var yeoman = require('yeoman-generator');
var steps = require('./steps');

module.exports = yeoman.generators.Base.extend({
  constructor: function () {
    yeoman.generators.Base.apply(this, arguments);

    var args = require('./arguments'),
      options = require('./options');

    Object.keys(args).forEach(function (argName) {
      this.argument(argName, args[argName]);
    }.bind(this));

    Object.keys(options).forEach(function (optionName) {
      this.option(optionName, options[optionName]);
    }.bind(this));

    this.description = "Yeoman generator that provides already configured and optimized Sails REST API with bundle of predefined features";
    this.config.save();
  },

  initializing: steps.initializing,
  prompting: steps.prompting,
  configuring: steps.configuring,
  writing: steps.writing,
  conflicts: steps.conflicts,
  install: steps.install,
  end: steps.end
});
<commit_msg>Style fix<commit_after>var yeoman = require('yeoman-generator');
var steps = require('./steps');

module.exports = yeoman.generators.Base.extend({
  constructor: function () {
    yeoman.generators.Base.apply(this, arguments);

    var args = require('./arguments');
    var options = require('./options');

    Object.keys(args).forEach(function (argName) {
      this.argument(argName, args[argName]);
    }.bind(this));

    Object.keys(options).forEach(function (optionName) {
      this.option(optionName, options[optionName]);
    }.bind(this));

    this.description = "Yeoman generator that provides already configured and optimized Sails REST API with bundle of predefined features";
    this.config.save();
  },

  initializing: steps.initializing,
  prompting: steps.prompting,
  configuring: steps.configuring,
  writing: steps.writing,
  conflicts: steps.conflicts,
  install: steps.install,
  end: steps.end
});
<|endoftext|>


<commit_before>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you 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';

var fs = require('fs'),
    path = require('path'),
    rimraf = require('rimraf'),
    tmp = require('tmp');

/**
 * @param {!Function} fn .
 * @return {!Promise<T>} .
 * @template T
 */
function checkedCall(fn) {
  return new Promise((resolve, reject) => {
    try {
      fn((err, value) => {
        if (err) {
          reject(err);
        } else {
          resolve(value);
        }
      });
    } catch (e) {
      reject(e);
    }
  });
}

// PUBLIC API

/**
 * Recursively removes a directory and all of its contents. This is equivalent
 * to {@code rm -rf} on a POSIX system.
 * @param {string} dirPath Path to the directory to remove.
 * @return {!Promise} A promise to be resolved when the operation has
 *     completed.
 */
exports.rmDir = function(dirPath) {
  return new Promise(function(fulfill, reject) {
    var numAttempts = 0;
    attemptRm();
    function attemptRm() {
      numAttempts += 1;
      rimraf(dirPath, function(err) {
        if (err) {
          if (err.code && err.code === 'ENOTEMPTY' && numAttempts < 2) {
            attemptRm();
            return;
          }
          reject(err);
        } else {
          fulfill();
        }
      });
    }
  });
};

/**
 * Copies one file to another.
 * @param {string} src The source file.
 * @param {string} dst The destination file.
 * @return {!Promise<string>} A promise for the copied file's path.
 */
exports.copy = function(src, dst) {
  return new Promise(function(fulfill, reject) {
    var rs = fs.createReadStream(src);
    rs.on('error', reject);

    var ws = fs.createWriteStream(dst);
    ws.on('error', reject);
    ws.on('close', () => fulfill(dst));

    rs.pipe(ws);
  });
};

/**
 * Recursively copies the contents of one directory to another.
 * @param {string} src The source directory to copy.
 * @param {string} dst The directory to copy into.
 * @param {(RegExp|function(string): boolean)=} opt_exclude An exclusion filter
 *     as either a regex or predicate function. All files matching this filter
 *     will not be copied.
 * @return {!Promise<string>} A promise for the destination
 *     directory's path once all files have been copied.
 */
exports.copyDir = function(src, dst, opt_exclude) {
  var predicate = opt_exclude;
  if (opt_exclude && typeof opt_exclude !== 'function') {
    predicate = function(p) {
      return !opt_exclude.test(p);
    };
  }

  // TODO(jleyba): Make this function completely async.
  if (!fs.existsSync(dst)) {
    fs.mkdirSync(dst);
  }

  var files = fs.readdirSync(src);
  files = files.map(function(file) {
    return path.join(src, file);
  });

  if (predicate) {
    files = files.filter(/** @type {function(string): boolean} */(predicate));
  }

  var results = [];
  files.forEach(function(file) {
    var stats = fs.statSync(file);
    var target = path.join(dst, path.basename(file));

    if (stats.isDirectory()) {
      if (!fs.existsSync(target)) {
        fs.mkdirSync(target, stats.mode);
      }
      results.push(exports.copyDir(file, target, predicate));
    } else {
      results.push(exports.copy(file, target));
    }
  });

  return Promise.all(results).then(() => dst);
};

/**
 * Tests if a file path exists.
 * @param {string} aPath The path to test.
 * @return {!Promise<boolean>} A promise for whether the file exists.
 */
exports.exists = function(aPath) {
  return new Promise(function(fulfill, reject) {
    let type = typeof aPath;
    if (type !== 'string') {
      reject(TypeError(`expected string path, but got ${type}`));
    } else {
      fs.exists(aPath, fulfill);
    }
  });
};

/**
 * Calls `stat(2)`.
 * @param {string} aPath The path to stat.
 * @return {!Promise<!fs.Stats>} A promise for the file stats.
 */
exports.stat = function stat(aPath) {
  return checkedCall(callback => fs.stat(aPath, callback));
};

/**
 * Deletes a name from the filesystem and possibly the file it refers to. Has
 * no effect if the file does not exist.
 * @param {string} aPath The path to remove.
 * @return {!Promise} A promise for when the file has been removed.
 */
exports.unlink = function(aPath) {
  return new Promise(function(fulfill, reject) {
    fs.exists(aPath, function(exists) {
      if (exists) {
        fs.unlink(aPath, function(err) {
          err && reject(err) || fulfill();
        });
      } else {
        fulfill();
      }
    });
  });
};

/**
 * @return {!Promise<string>} A promise for the path to a temporary directory.
 * @see https://www.npmjs.org/package/tmp
 */
exports.tmpDir = function() {
  return checkedCall(tmp.dir);
};

/**
 * @param {{postfix: string}=} opt_options Temporary file options.
 * @return {!Promise<string>} A promise for the path to a temporary file.
 * @see https://www.npmjs.org/package/tmp
 */
exports.tmpFile = function(opt_options) {
  return checkedCall(callback => {
    // |tmp.file| checks arguments length to detect options rather than doing a
    // truthy check, so we must only pass options if there are some to pass.
    if (opt_options) {
      tmp.file(opt_options, callback);
    } else {
      tmp.file(callback);
    }
  });
};

/**
 * Searches the {@code PATH} environment variable for the given file.
 * @param {string} file The file to locate on the PATH.
 * @param {boolean=} opt_checkCwd Whether to always start with the search with
 *     the current working directory, regardless of whether it is explicitly
 *     listed on the PATH.
 * @return {?string} Path to the located file, or {@code null} if it could
 *     not be found.
 */
exports.findInPath = function(file, opt_checkCwd) {
  let dirs = [];
  if (opt_checkCwd) {
    dirs.push(process.cwd());
  }
  dirs.push.apply(dirs, process.env['PATH'].split(path.delimiter));

  let foundInDir = dirs.find(dir => {
    let tmp = path.join(dir, file);
    try {
      let stats = fs.statSync(tmp);
      return stats.isFile() && !stats.isDirectory();
    } catch (ex) {
      return false;
    }
  });

  return foundInDir ? path.join(foundInDir, file) : null;
};

/**
 * Reads the contents of the given file.
 *
 * @param {string} aPath Path to the file to read.
 * @return {!Promise<!Buffer>} A promise that will resolve with a buffer of the
 *     file contents.
 */
exports.read = function(aPath) {
  return checkedCall(callback => fs.readFile(aPath, callback));
};

/**
 * Writes to a file.
 *
 * @param {string} aPath Path to the file to write to.
 * @param {(string|!Buffer)} data The data to write.
 * @return {!Promise} A promise that will resolve when the operation has
 *     completed.
 */
exports.write = function(aPath, data) {
  return checkedCall(callback => fs.writeFile(aPath, data, callback));
};

/**
 * Creates a directory.
 *
 * @param {string} aPath The directory path.
 * @return {!Promise<string>} A promise that will resolve with the path of the
 *     created directory.
 */
exports.mkdir = function(aPath) {
  return checkedCall(callback => {
    fs.mkdir(aPath, undefined, err => {
      if (err && err.code !== 'EEXIST') {
        callback(err);
      } else {
        callback(null, aPath);
      }
    });
  });
};

/**
 * Recursively creates a directory and any ancestors that do not yet exist.
 *
 * @param {string} dir The directory path to create.
 * @return {!Promise<string>} A promise that will resolve with the path of the
 *     created directory.
 */
exports.mkdirp = function mkdirp(dir) {
  return checkedCall(callback => {
    fs.mkdir(dir, undefined, err => {
      if (!err) {
        callback(null, dir);
        return;
      }

      switch (err.code) {
        case 'EEXIST':
          callback(null, dir);
          return;
        case 'ENOENT':
          return mkdirp(path.dirname(dir))
              .then(() => mkdirp(dir))
              .then(() => callback(null, dir), err => callback(err));
        default:
          callback(err);
          return;
      }
    });
  });
};

/**
 * Recursively walks a directory, returning a promise that will resolve with
 * a list of all files/directories seen.
 *
 * @param {string} rootPath the directory to walk.
 * @return {!Promise<!Array<{path: string, dir: boolean}>>} a promise that will
 *     resolve with a list of entries seen. For each entry, the recorded path
 *     will be relative to `rootPath`.
 */
exports.walkDir = function(rootPath) {
  let seen = [];
  return (function walk(dir) {
    return checkedCall(callback => fs.readdir(dir, callback))
        .then(files => Promise.all(files.map(file => {
          file = path.join(dir, file);
          return checkedCall(cb => fs.stat(file, cb)).then(stats => {
            seen.push({
              path: path.relative(rootPath, file),
              dir: stats.isDirectory()
            });
            return stats.isDirectory() && walk(file);
          });
        })));
  })(rootPath).then(() => seen);
};
<commit_msg>Cleanup temporary directories even if non-empty (#8066)<commit_after>// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you 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';

var fs = require('fs'),
    path = require('path'),
    rimraf = require('rimraf'),
    tmp = require('tmp');

/**
 * @param {!Function} fn .
 * @return {!Promise<T>} .
 * @template T
 */
function checkedCall(fn) {
  return new Promise((resolve, reject) => {
    try {
      fn((err, value) => {
        if (err) {
          reject(err);
        } else {
          resolve(value);
        }
      });
    } catch (e) {
      reject(e);
    }
  });
}

// PUBLIC API

/**
 * Recursively removes a directory and all of its contents. This is equivalent
 * to {@code rm -rf} on a POSIX system.
 * @param {string} dirPath Path to the directory to remove.
 * @return {!Promise} A promise to be resolved when the operation has
 *     completed.
 */
exports.rmDir = function(dirPath) {
  return new Promise(function(fulfill, reject) {
    var numAttempts = 0;
    attemptRm();
    function attemptRm() {
      numAttempts += 1;
      rimraf(dirPath, function(err) {
        if (err) {
          if (err.code && err.code === 'ENOTEMPTY' && numAttempts < 2) {
            attemptRm();
            return;
          }
          reject(err);
        } else {
          fulfill();
        }
      });
    }
  });
};

/**
 * Copies one file to another.
 * @param {string} src The source file.
 * @param {string} dst The destination file.
 * @return {!Promise<string>} A promise for the copied file's path.
 */
exports.copy = function(src, dst) {
  return new Promise(function(fulfill, reject) {
    var rs = fs.createReadStream(src);
    rs.on('error', reject);

    var ws = fs.createWriteStream(dst);
    ws.on('error', reject);
    ws.on('close', () => fulfill(dst));

    rs.pipe(ws);
  });
};

/**
 * Recursively copies the contents of one directory to another.
 * @param {string} src The source directory to copy.
 * @param {string} dst The directory to copy into.
 * @param {(RegExp|function(string): boolean)=} opt_exclude An exclusion filter
 *     as either a regex or predicate function. All files matching this filter
 *     will not be copied.
 * @return {!Promise<string>} A promise for the destination
 *     directory's path once all files have been copied.
 */
exports.copyDir = function(src, dst, opt_exclude) {
  var predicate = opt_exclude;
  if (opt_exclude && typeof opt_exclude !== 'function') {
    predicate = function(p) {
      return !opt_exclude.test(p);
    };
  }

  // TODO(jleyba): Make this function completely async.
  if (!fs.existsSync(dst)) {
    fs.mkdirSync(dst);
  }

  var files = fs.readdirSync(src);
  files = files.map(function(file) {
    return path.join(src, file);
  });

  if (predicate) {
    files = files.filter(/** @type {function(string): boolean} */(predicate));
  }

  var results = [];
  files.forEach(function(file) {
    var stats = fs.statSync(file);
    var target = path.join(dst, path.basename(file));

    if (stats.isDirectory()) {
      if (!fs.existsSync(target)) {
        fs.mkdirSync(target, stats.mode);
      }
      results.push(exports.copyDir(file, target, predicate));
    } else {
      results.push(exports.copy(file, target));
    }
  });

  return Promise.all(results).then(() => dst);
};

/**
 * Tests if a file path exists.
 * @param {string} aPath The path to test.
 * @return {!Promise<boolean>} A promise for whether the file exists.
 */
exports.exists = function(aPath) {
  return new Promise(function(fulfill, reject) {
    let type = typeof aPath;
    if (type !== 'string') {
      reject(TypeError(`expected string path, but got ${type}`));
    } else {
      fs.exists(aPath, fulfill);
    }
  });
};

/**
 * Calls `stat(2)`.
 * @param {string} aPath The path to stat.
 * @return {!Promise<!fs.Stats>} A promise for the file stats.
 */
exports.stat = function stat(aPath) {
  return checkedCall(callback => fs.stat(aPath, callback));
};

/**
 * Deletes a name from the filesystem and possibly the file it refers to. Has
 * no effect if the file does not exist.
 * @param {string} aPath The path to remove.
 * @return {!Promise} A promise for when the file has been removed.
 */
exports.unlink = function(aPath) {
  return new Promise(function(fulfill, reject) {
    fs.exists(aPath, function(exists) {
      if (exists) {
        fs.unlink(aPath, function(err) {
          err && reject(err) || fulfill();
        });
      } else {
        fulfill();
      }
    });
  });
};

/**
 * @return {!Promise<string>} A promise for the path to a temporary directory.
 * @see https://www.npmjs.org/package/tmp
 */
exports.tmpDir = function() {
  return checkedCall(callback => tmp.dir({ unsafeCleanup : true }, callback));
};

/**
 * @param {{postfix: string}=} opt_options Temporary file options.
 * @return {!Promise<string>} A promise for the path to a temporary file.
 * @see https://www.npmjs.org/package/tmp
 */
exports.tmpFile = function(opt_options) {
  return checkedCall(callback => {
    // |tmp.file| checks arguments length to detect options rather than doing a
    // truthy check, so we must only pass options if there are some to pass.
    if (opt_options) {
      tmp.file(opt_options, callback);
    } else {
      tmp.file(callback);
    }
  });
};

/**
 * Searches the {@code PATH} environment variable for the given file.
 * @param {string} file The file to locate on the PATH.
 * @param {boolean=} opt_checkCwd Whether to always start with the search with
 *     the current working directory, regardless of whether it is explicitly
 *     listed on the PATH.
 * @return {?string} Path to the located file, or {@code null} if it could
 *     not be found.
 */
exports.findInPath = function(file, opt_checkCwd) {
  let dirs = [];
  if (opt_checkCwd) {
    dirs.push(process.cwd());
  }
  dirs.push.apply(dirs, process.env['PATH'].split(path.delimiter));

  let foundInDir = dirs.find(dir => {
    let tmp = path.join(dir, file);
    try {
      let stats = fs.statSync(tmp);
      return stats.isFile() && !stats.isDirectory();
    } catch (ex) {
      return false;
    }
  });

  return foundInDir ? path.join(foundInDir, file) : null;
};

/**
 * Reads the contents of the given file.
 *
 * @param {string} aPath Path to the file to read.
 * @return {!Promise<!Buffer>} A promise that will resolve with a buffer of the
 *     file contents.
 */
exports.read = function(aPath) {
  return checkedCall(callback => fs.readFile(aPath, callback));
};

/**
 * Writes to a file.
 *
 * @param {string} aPath Path to the file to write to.
 * @param {(string|!Buffer)} data The data to write.
 * @return {!Promise} A promise that will resolve when the operation has
 *     completed.
 */
exports.write = function(aPath, data) {
  return checkedCall(callback => fs.writeFile(aPath, data, callback));
};

/**
 * Creates a directory.
 *
 * @param {string} aPath The directory path.
 * @return {!Promise<string>} A promise that will resolve with the path of the
 *     created directory.
 */
exports.mkdir = function(aPath) {
  return checkedCall(callback => {
    fs.mkdir(aPath, undefined, err => {
      if (err && err.code !== 'EEXIST') {
        callback(err);
      } else {
        callback(null, aPath);
      }
    });
  });
};

/**
 * Recursively creates a directory and any ancestors that do not yet exist.
 *
 * @param {string} dir The directory path to create.
 * @return {!Promise<string>} A promise that will resolve with the path of the
 *     created directory.
 */
exports.mkdirp = function mkdirp(dir) {
  return checkedCall(callback => {
    fs.mkdir(dir, undefined, err => {
      if (!err) {
        callback(null, dir);
        return;
      }

      switch (err.code) {
        case 'EEXIST':
          callback(null, dir);
          return;
        case 'ENOENT':
          return mkdirp(path.dirname(dir))
              .then(() => mkdirp(dir))
              .then(() => callback(null, dir), err => callback(err));
        default:
          callback(err);
          return;
      }
    });
  });
};

/**
 * Recursively walks a directory, returning a promise that will resolve with
 * a list of all files/directories seen.
 *
 * @param {string} rootPath the directory to walk.
 * @return {!Promise<!Array<{path: string, dir: boolean}>>} a promise that will
 *     resolve with a list of entries seen. For each entry, the recorded path
 *     will be relative to `rootPath`.
 */
exports.walkDir = function(rootPath) {
  let seen = [];
  return (function walk(dir) {
    return checkedCall(callback => fs.readdir(dir, callback))
        .then(files => Promise.all(files.map(file => {
          file = path.join(dir, file);
          return checkedCall(cb => fs.stat(file, cb)).then(stats => {
            seen.push({
              path: path.relative(rootPath, file),
              dir: stats.isDirectory()
            });
            return stats.isDirectory() && walk(file);
          });
        })));
  })(rootPath).then(() => seen);
};
<|endoftext|>


<commit_before>/*
 * * Module dependencies
 * */

var request = require('request');
var cheerio = require('cheerio');

var express = require('express')
  , stylus = require('stylus')
    , nib = require('nib')

    var app = express()

  function compile(str, path) {
    return stylus(str)
      .set('filename', path)
      .use(nib());
  }

var metadataArray = [ ];

function callbackForJSON(callback){
  request('https://news.ycombinator.com', function(error, response, html){
  		if(!error && response.statusCode == 200){
  			var $ = cheerio.load(html);
  			$('span.comhead').each(function(i, element){
  			var a=$(this).prev(); //selects previous data
  			var rank=a.parent().parent().text(); //gets ranks by parsing text two elements higher
  			var title=a.text(); // parses link title
  			var url=a.attr('href'); // parses href attribute from "a" element
  			var subtext = a.parent().parent().next().children('.subtext').children(); // gets the subtext from the children
  			var points = $(subtext).eq(0).text();
  			var username = $(subtext).eq(1).text();
  			var comments = $(subtext).eq(2).text();

  			var metadata = { // creates a new object
  				rank: parseInt(rank),
  				title:title,
  				url:url,
  				points: parseInt(points),
  				username: username,
  				comments: parseInt(comments)
  			};
  			metadataArray.push(metadata);
  			});
        callback(metadataArray);
  		}

  });
}

// in helper.js $.getjson(url)
app.get('/scrape', function(req,res) {
  //pass in a callback that takes in a parameter
  callbackForJSON(function(data){
    res.send(data)
  });
})

app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(express.logger('dev'))
app.use(stylus.middleware(
			  { src: __dirname + '/public'
				  , compile: compile
				  }
			))
app.use(express.static(__dirname + '/public'))

app.get('/', function (req, res) {
  res.render('index',
		  { title : 'Home' }
			  )
})

app.listen(3000)
<commit_msg>fixes an error where the array wasn't printing new info when the page was refreshed.<commit_after>/*
 * * Module dependencies
 * */

var request = require('request');
var cheerio = require('cheerio');
var express = require('express')
  , stylus = require('stylus')
    , nib = require('nib')

var app = express() // sets up the server

  function compile(str, path) {
    return stylus(str)
      .set('filename', path)
      .use(nib());
}

function callbackForJSON(callback){
  request('https://news.ycombinator.com', function(error, response, html){
  		if(!error && response.statusCode == 200){
        var metadataArray = [ ];
  			var $ = cheerio.load(html);
  			$('span.comhead').each(function(i, element){
  			var a=$(this).prev(); //selects previous data
  			var rank=a.parent().parent().text(); //gets ranks by parsing text two elements higher
  			var title=a.text(); // parses link title
  			var url=a.attr('href'); // parses href attribute from "a" element
  			var subtext = a.parent().parent().next().children('.subtext').children(); // gets the subtext from the children
  			var points = $(subtext).eq(0).text();
  			var username = $(subtext).eq(1).text();
  			var comments = $(subtext).eq(2).text();

  			var metadata = { // creates a new object
  				rank: parseInt(rank),
  				title:title,
  				url:url,
  				points: parseInt(points),
  				username: username,
  				comments: parseInt(comments)
  			};
  			metadataArray.push(metadata);
  			});
        callback(metadataArray);
  		}
  });
}

app.get('/scrape', function(req,res) { // pushes the info to a sub url
  callbackForJSON(function(data){
    res.send(data)
  });
})

metadataArray = [ ]; // clears the array

app.set('views', __dirname + '/views')
app.set('view engine', 'jade')
app.use(express.logger('dev'))
app.use(stylus.middleware(
			  { src: __dirname + '/public'
				  , compile: compile
				  }
			))
app.use(express.static(__dirname + '/public'))

app.get('/', function (req, res) {
  res.render('index',
		  { title : 'Home' }
			  )
})

app.listen(3000)
<|endoftext|>


<commit_before>Ext.namespace('Gemma');

/**
 * Config options;
 *
 * @param taskId
 *            (required)
 * @param callback
 *            fired when finished, with the task payload as argument
 * @param showAllMessages
 *            when finished, show all the messages. Useful for complex jobs.
 * @class Gemma.ProgressWindow
 * @extends Ext.Window
 */
Gemma.ProgressWindow = Ext.extend(Ext.Window, {

			modal : true,
			closable : false,
			resizable : false,
			stateful : false,
			showAllMessages : false,

			resizable : false,
			collapsible : false,
			// width : 600,
			autoHeight : true,
			autoWidth : true,

			initComponent : function() {

				this.pBar = new Gemma.ProgressWidget({
							taskId : this.taskId
						});

				Ext.apply(this, {
							items : [this.pBar]
						});

				Gemma.ProgressWindow.superclass.initComponent.call(this);

				this.addEvents('success', 'failed');

				this.on('show', this.pBar.startProgress.createDelegate(this.pBar));
			},

			afterRender : function(a, b) {
				Gemma.ProgressWindow.superclass.afterRender.call(this, a, b);

				this.pBar.on('done', function(payload) {
							this.getEl().switchOff({
										callback : function() {
											if (this.showAllMessages && this.pBar.allMessages.length > 0) {

												var msgs = new Ext.Window({
															title : "Job finished. The following messages were generated",
															layout : 'fit',
															closeAction : 'close',
															items : [{
																		xtype : 'panel',
																		height : 400,
																		autoScroll : true,
																		width : 400,
																		html : this.pBar.allMessages
																	}]
														});
												msgs.show();

											}
											this.destroy();
										},
										scope : this
									});
							if (this.callback) {
								this.callback(payload);
							}
						}.createDelegate(this));

				this.pBar.on('fail', function(message) {
							var msgs = new Ext.Window({
										title : "Error",
										layout : 'fit',
										closeAction : 'close',
										items : [{
											xtype : 'panel',
											height : 400,
											autoScroll : true,
											width : 400,
											html : message + "
Additional log messages during run:
 "
													+ this.pBar.allMessages
										}]
									});
							msgs.show();

							this.destroy();
						}.createDelegate(this));
			}

		});

/**
 * Config options:
 *
 * @param taskId
 *            (required)
 * @class Gemma.ProgressWidget
 * @extends Ext.Panel
 */
Gemma.ProgressWidget = Ext.extend(Ext.Panel, {
			BAR_UPDATE_INTERVAL : 2000,
			allMessages : "",
			previousMessage : '',
			timeoutid : null,
			resizable : false,
			waiting : false,
			layout : 'fit',
			bodyBorder : false,
			stateful : false,
			// width : 600,

			initComponent : function() {

				this.progressBar = new Ext.ProgressBar({
							style : 'font-weight:normal;font-size:smaller;',
							width : 400,
							text : "Initializing ..."
						});

				Ext.apply(this, {
							items : [this.progressBar]
						});

				Gemma.ProgressWidget.superclass.initComponent.call(this);

				Ext.apply(this);

				this.addEvents('done', 'fail', 'cancel');
			},

			handleFailure : function(data, e) {
				this.stopProgress();
				var messageText = "";
				if (data.description) {
					messageText = data.description;
				} else if (!e) {
					messageText = data;
				} else if (e.message) {
					messageText = e.message;
				} else {
					messageText = e;
				}
				this.fireEvent("fail", messageText);
			},

			/**
			 * Start the progressbar in motion.
			 */
			startProgress : function() {
				/*
				 * Don't start twice.
				 */
				if (this.waiting) {
					return;
				}
				this.progressBar.wait({
							text : "Starting ..."
						});

				if (!this.taskId) {

					var taskId = this.findTaskId();

					if (!taskId) {
						alert("no task id");
						return;
					}

					this.taskId = taskId;

				}

				var callParams = [];
				var callback = this.updateProgress.createDelegate(this);
				var errorHandler = this.handleFailure.createDelegate(this);
				callParams.push(callback);
				callParams.push(errorHandler);

				/*
				 * Start it running on a delay.
				 */

				var f = this.refreshProgress.createDelegate(this, callParams, false);
				this.timeoutid = window.setInterval(f, this.BAR_UPDATE_INTERVAL);
			},

			stopProgress : function() {
				window.clearInterval(this.timeoutid);
				this.previousMessage = null;
				this.waiting = false;
				this.progressBar.updateText("Finished ...");
				this.progressBar.reset();
			},

			handleFinalResult : function(result) {
				this.stopProgress();
				this.fireEvent('done', result);
			},

			done : false,

			updateProgress : function(data) {
				this.waiting = false;
				var messages = "";
				var messagesToSave = '';

				for (var i = 0, len = data.length; i < len; i++) {
					var d = data[i];
					if (messages.length > 0) {
						messages = messages + "; " + d.description;
					} else {
						messages = d.description;
					}
					messagesToSave = messagesToSave + "
" + d.description;

					if (d.failed) {
						return this.handleFailure(d);
					} else if (d.done && !this.done) {
						// try to ensure we only call this once.
						TaskCompletionController.checkResult(this.taskId, {
									callback : this.handleFinalResult.createDelegate(this),
									errorHandler : this.handleFailure.createDelegate(this)
								});
						this.done = true;

					}
				}

				if (this.previousMessage != messages && messages.length > 0) {
					this.previousMessage = messages;
					this.progressBar.updateText(messages);
					this.allMessages = this.allMessages + messagesToSave;
					// document.getElementById("progressTextArea").innerHTML += messages;
				} else {
					this.progressBar.updateText(this.progressBar.text + '.');
				}
			},

			/*
			 * Private Send a cancel notification to the server.
			 */
			cancelJob : function() {
				this.stopProgress();
				// document.getElementById("progressTextArea").innerHTML = "Cancelling...";
				var f = this.cancelCallback.createDelegate(this, [], true);
				ProgressStatusService.cancelJob(this.taskId, f);
			},

			/*
			 * Private Check for status from server.
			 */
			refreshProgress : function(callback, errorHandler) {
				// only check for status if we aren't already waiting for a reply.
				if (!this.waiting) {
					ProgressStatusService.getProgressStatus(this.taskId, {
								callback : callback,
								errorHandler : errorHandler
							});
					this.waiting = true;
				}
			},

			/*
			 * Private callback to handle cancellation @param {Object} data
			 */
			cancelCallback : function(data) {
				this.stopProgress(); // should already be stopped.
				var messageArea = Ext.get("messages");
				if (messageArea) {
					Ext.DomHelper.overwrite("messages", {
								tag : 'img',
								src : '/Gemma/images/icons/ok.png'
							});
					Ext.DomHelper.append("messages", " Job was cancelled.");
				}
				this.fireEvent('cancel');

			},

			findTaskId : function() {

				// try to get from query string

				var queryStart = document.URL.indexOf("?");
				if (queryStart > -1) {
					var param = Ext.urlDecode(document.URL.substr(queryStart + 1));
					if (param.taskId)
						return param.taskId;
				}

				// try to get from hidden input field.
				return dwr.util.getValue("taskId");
			}

		});<commit_msg>add ids for components, and stateful=false for the error message window<commit_after>Ext.namespace('Gemma');

/**
 * Config options;
 *
 * @param taskId
 *            (required)
 * @param callback
 *            fired when finished, with the task payload as argument
 * @param showAllMessages
 *            when finished, show all the messages. Useful for complex jobs.
 * @class Gemma.ProgressWindow
 * @extends Ext.Window
 */
Gemma.ProgressWindow = Ext.extend(Ext.Window, {

			modal : true,
			closable : false,
			resizable : false,
			stateful : false,
			showAllMessages : false,

			resizable : false,
			collapsible : false,
			// width : 600,
			autoHeight : true,
			autoWidth : true,
			id : "progressWidget-window",

			initComponent : function() {

				this.pBar = new Gemma.ProgressWidget({
							taskId : this.taskId
						});

				Ext.apply(this, {
							items : [this.pBar]
						});

				Gemma.ProgressWindow.superclass.initComponent.call(this);

				this.addEvents('success', 'failed');

				this.on('show', this.pBar.startProgress.createDelegate(this.pBar));
			},

			afterRender : function(a, b) {
				Gemma.ProgressWindow.superclass.afterRender.call(this, a, b);

				this.pBar.on('done', function(payload) {
							this.getEl().switchOff({
										callback : function() {
											if (this.showAllMessages && this.pBar.allMessages.length > 0) {

												var msgs = new Ext.Window({
															title : "Job finished. The following messages were generated",
															layout : 'fit',
															closeAction : 'close',
															items : [{
																		xtype : 'panel',
																		id : 'progress-messages-panel',
																		stateful : false,
																		height : 400,
																		autoScroll : true,
																		width : 400,
																		html : this.pBar.allMessages
																	}]
														});
												msgs.show();

											}
											this.destroy();
										},
										scope : this
									});
							if (this.callback) {
								this.callback(payload);
							}
						}.createDelegate(this));

				this.pBar.on('fail', function(message) {
							var msgs = new Ext.Window({
										title : "Error",
										layout : 'fit',
										closeAction : 'close',
										items : [{
											xtype : 'panel',
											height : 400,
											autoScroll : true,
											width : 400,
											html : message + "
Additional log messages during run:
 "
													+ this.pBar.allMessages
										}]
									});
							msgs.show();

							this.destroy();
						}.createDelegate(this));
			}

		});

/**
 * Config options:
 *
 * @param taskId
 *            (required)
 * @class Gemma.ProgressWidget
 * @extends Ext.Panel
 */
Gemma.ProgressWidget = Ext.extend(Ext.Panel, {
			BAR_UPDATE_INTERVAL : 2000,
			allMessages : "",
			previousMessage : '',
			timeoutid : null,
			resizable : false,
			waiting : false,
			layout : 'fit',
			bodyBorder : false,
			stateful : false,
			id : "progressWidget-panel",
			// width : 600,

			initComponent : function() {

				this.progressBar = new Ext.ProgressBar({
							style : 'font-weight:normal;font-size:smaller;',
							width : 400,
							text : "Initializing ..."
						});

				Ext.apply(this, {
							items : [this.progressBar]
						});

				Gemma.ProgressWidget.superclass.initComponent.call(this);

				Ext.apply(this);

				this.addEvents('done', 'fail', 'cancel');
			},

			handleFailure : function(data, e) {
				this.stopProgress();
				var messageText = "";
				if (data.description) {
					messageText = data.description;
				} else if (!e) {
					messageText = data;
				} else if (e.message) {
					messageText = e.message;
				} else {
					messageText = e;
				}
				this.fireEvent("fail", messageText);
			},

			/**
			 * Start the progressbar in motion.
			 */
			startProgress : function() {
				/*
				 * Don't start twice.
				 */
				if (this.waiting) {
					return;
				}
				this.progressBar.wait({
							text : "Starting ..."
						});

				if (!this.taskId) {

					var taskId = this.findTaskId();

					if (!taskId) {
						alert("no task id");
						return;
					}

					this.taskId = taskId;

				}

				var callParams = [];
				var callback = this.updateProgress.createDelegate(this);
				var errorHandler = this.handleFailure.createDelegate(this);
				callParams.push(callback);
				callParams.push(errorHandler);

				/*
				 * Start it running on a delay.
				 */

				var f = this.refreshProgress.createDelegate(this, callParams, false);
				this.timeoutid = window.setInterval(f, this.BAR_UPDATE_INTERVAL);
			},

			stopProgress : function() {
				window.clearInterval(this.timeoutid);
				this.previousMessage = null;
				this.waiting = false;
				this.progressBar.updateText("Finished ...");
				this.progressBar.reset();
			},

			handleFinalResult : function(result) {
				this.stopProgress();
				this.fireEvent('done', result);
			},

			done : false,

			updateProgress : function(data) {
				this.waiting = false;
				var messages = "";
				var messagesToSave = '';

				for (var i = 0, len = data.length; i < len; i++) {
					var d = data[i];
					if (messages.length > 0) {
						messages = messages + "; " + d.description;
					} else {
						messages = d.description;
					}
					messagesToSave = messagesToSave + "
" + d.description;

					if (d.failed) {
						return this.handleFailure(d);
					} else if (d.done && !this.done) {
						// try to ensure we only call this once.
						TaskCompletionController.checkResult(this.taskId, {
									callback : this.handleFinalResult.createDelegate(this),
									errorHandler : this.handleFailure.createDelegate(this)
								});
						this.done = true;

					}
				}

				if (this.previousMessage != messages && messages.length > 0) {
					this.previousMessage = messages;
					this.progressBar.updateText(messages);
					this.allMessages = this.allMessages + messagesToSave;
					// document.getElementById("progressTextArea").innerHTML += messages;
				} else {
					this.progressBar.updateText(this.progressBar.text + '.');
				}
			},

			/*
			 * Private Send a cancel notification to the server.
			 */
			cancelJob : function() {
				this.stopProgress();
				// document.getElementById("progressTextArea").innerHTML = "Cancelling...";
				var f = this.cancelCallback.createDelegate(this, [], true);
				ProgressStatusService.cancelJob(this.taskId, f);
			},

			/*
			 * Private Check for status from server.
			 */
			refreshProgress : function(callback, errorHandler) {
				// only check for status if we aren't already waiting for a reply.
				if (!this.waiting) {
					ProgressStatusService.getProgressStatus(this.taskId, {
								callback : callback,
								errorHandler : errorHandler
							});
					this.waiting = true;
				}
			},

			/*
			 * Private callback to handle cancellation @param {Object} data
			 */
			cancelCallback : function(data) {
				this.stopProgress(); // should already be stopped.
				var messageArea = Ext.get("messages");
				if (messageArea) {
					Ext.DomHelper.overwrite("messages", {
								tag : 'img',
								src : '/Gemma/images/icons/ok.png'
							});
					Ext.DomHelper.append("messages", " Job was cancelled.");
				}
				this.fireEvent('cancel');

			},

			findTaskId : function() {

				// try to get from query string

				var queryStart = document.URL.indexOf("?");
				if (queryStart > -1) {
					var param = Ext.urlDecode(document.URL.substr(queryStart + 1));
					if (param.taskId)
						return param.taskId;
				}

				// try to get from hidden input field.
				return dwr.util.getValue("taskId");
			}

		});<|endoftext|>


<commit_before>'use strict';

var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
var wiredep = require('wiredep');
var mkdirp = require('mkdirp');
var _s = require('underscore.string');

module.exports = yeoman.generators.Base.extend({
    prompting: function() {
        var done = this.async();

        // Have Yeoman greet the user.
        this.log(yosay(
            'Welcome to the awesome ' + chalk.red('GulpExpressWeb') + ' generator!'
        ));

        this.log(chalk.magenta('Out of the box I include HTML5 Boilerplate, sass, an express server, and a gulpfile to build your app.'));

        var prompts = [{
            type: 'checkbox',
            name: 'features',
            message: 'What else would you like?',
            choices: [{
                name: 'Bootstrap',
                value: 'includeBootstrap',
                checked: true
            }, {
                name: 'FontAwesome',
                value: 'includeFontAwesome',
                checked: true
            }],
            default: true
        }, {
            type: 'confirm',
            name: 'includeJQuery',
            message: 'Would you like to include jQuery?',
            default: true,
            when: function(promptAnswers) {
                return promptAnswers.features.indexOf('includeBootstrap') === -1;
            }
        }];

        this.prompt(prompts, function(promptAnswers) {
            var features = promptAnswers.features;
            this.props = promptAnswers;

            function hasFeature(feat) {
                return features && features.indexOf(feat) !== -1;
            }

            this.includeBootstrap = hasFeature('includeBootstrap');
            this.includeFontAwesome = hasFeature('includeFontAwesome');
            this.includeJQuery = promptAnswers.includeJQuery;

            done();
        }.bind(this));

    },

    writing: {
        packageJson: function() {
            this.fs.copy(
                this.templatePath('_package.json'),
                this.destinationPath('package.json')
            );
        },

        settings: function() {
            this.fs.copy(
                this.templatePath('editorconfig'),
                this.destinationPath('.editorconfig')
            );

            this.fs.copy(
                this.templatePath('jshintrc'),
                this.destinationPath('.jshintrc')
            );
        },

        projectfiles: function() {
            this.fs.copy(
                this.templatePath('README.md'),
                this.destinationPath('README.md')
            );

            this.fs.copy(
                this.templatePath('favicon.ico'),
                this.destinationPath('app/favicon.ico')
            );
        },

        git: function() {
            this.fs.copy(
                this.templatePath('gitignore'),
                this.destinationPath('.gitignore')
            );

            this.fs.copy(
                this.templatePath('gitattributes'),
                this.destinationPath('.gitattributes')
            );
        },

        gulp: function() {
            this.fs.copy(
                this.templatePath('gulpfile.js'),
                this.destinationPath('gulpfile.js')
            );

            this.fs.copyTpl(
                this.templatePath('gulp/**/*'),
                this.destinationPath('gulp'), {
                    includeFontAwesome: this.includeFontAwesome
                }
            );
        },

        bower: function() {
            var bowerJson = {
                name: _s.slugify(this.appname),
                private: true,
                dependencies: {}
            };

            if (this.includeBootstrap) {
                bowerJson.dependencies['bootstrap-sass'] = '~3.3.5';
                bowerJson.overrides = {
                    'bootstrap-sass': {
                        'main': [
                            'assets/stylesheets/_bootstrap.scss',
                            'assets/fonts/bootstrap/*',
                            'assets/javascripts/bootstrap.js'
                        ]
                    }
                };
            } else if (this.includeJQuery) {
                bowerJson.dependencies.jquery = '~2.1.1';
            }

            if (this.includeFontAwesome) {
                bowerJson.dependencies['font-awesome'] = '~4.4.0';
            }

            this.fs.writeJSON('bower.json', bowerJson);
            this.fs.copy(
                this.templatePath('bowerrc'),
                this.destinationPath('.bowerrc')
            );
        },

        server: function() {
            this.fs.copy(
                this.templatePath('server/**/*'),
                this.destinationPath('server')
            );
        },

        app: function() {
            this.fs.copy(
                this.templatePath('app.js'),
                this.destinationPath('app.js')
            );
        },

        styles: function() {
            this.fs.copyTpl(
                this.templatePath('styles/**/*'),
                this.destinationPath('app/styles/'), {
                    includeBootstrap: this.includeBootstrap,
                    includeFontAwesome: this.includeFontAwesome
                }
            );
        },

        javascript: function() {
            this.fs.copy(
                this.templatePath('js/main.js'),
                this.destinationPath('app/js/main.js')
            );
        },

        html: function() {
            var bootstrapPath;

            // path prefix for Bootstrap JS files
            if (this.includeBootstrap) {
                bootstrapPath = '/bower_components/bootstrap-sass/assets/javascripts/bootstrap/';
            }

            this.fs.copyTpl(
                this.templatePath('index.html'),
                this.destinationPath('app/index.html'),
                {
                    appname: this.appname,
                    includeBootstrap: this.includeBootstrap,
                    includeFontAwesome: this.includeFontAwesome,
                    bootstrapPath: bootstrapPath,
                    bootstrapPlugins: [
                        'affix',
                        'alert',
                        'dropdown',
                        'tooltip',
                        'modal',
                        'transition',
                        'button',
                        'popover',
                        'carousel',
                        'scrollspy',
                        'collapse',
                        'tab'
                    ]
                }
            );
        },

        misc: function() {
            mkdirp('app/images');
            mkdirp('app/fonts');
        }

    },

    install: function() {
        this.installDependencies({
            skipInstall: this.options.skipInstall
        });
    },

    end: function() {
        var bowerJson = this.fs.readJSON(this.destinationPath('bower.json')),
            howToInstall = '\nAfter running ' +
                chalk.yellow.bold('npm install & bower install') + ', inject your' +
                '\nfront end dependencies by running ' +
                chalk.yellow.bold('gulp wiredep') +'.';

        if (this.options.skipInstall) {
            this.log(howToInstall);
            return;
        }

        // wire Bower packages to .html
        wiredep({
            bowerJson: bowerJson,
            directory: 'bower_components',
            exclude: ['bootstrap-sass', 'bootstrap.js'],
            ignorePath: /^(\.\.\/)*\.\./,
            src: 'app/index.html'
        });

        // wire Bower packages to .scss
        wiredep({
            bowerJson: bowerJson,
            directory: 'bower_components',
            src: 'app/styles/*.scss'
        });
    }
});
<commit_msg>fixing build issue when no bower dependencies are set<commit_after>'use strict';

var yeoman = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
var wiredep = require('wiredep');
var mkdirp = require('mkdirp');
var _s = require('underscore.string');

module.exports = yeoman.generators.Base.extend({
    prompting: function() {
        var done = this.async();

        // Have Yeoman greet the user.
        this.log(yosay(
            'Welcome to the awesome ' + chalk.red('GulpExpressWeb') + ' generator!'
        ));

        this.log(chalk.magenta('Out of the box I include HTML5 Boilerplate, sass, an express server, and a gulpfile to build your app.'));

        var prompts = [{
            type: 'checkbox',
            name: 'features',
            message: 'What else would you like?',
            choices: [{
                name: 'Bootstrap',
                value: 'includeBootstrap',
                checked: true
            }, {
                name: 'FontAwesome',
                value: 'includeFontAwesome',
                checked: true
            }],
            default: true
        }, {
            type: 'confirm',
            name: 'includeJQuery',
            message: 'Would you like to include jQuery?',
            default: true,
            when: function(promptAnswers) {
                return promptAnswers.features.indexOf('includeBootstrap') === -1;
            }
        }];

        this.prompt(prompts, function(promptAnswers) {
            var features = promptAnswers.features;
            this.props = promptAnswers;

            function hasFeature(feat) {
                return features && features.indexOf(feat) !== -1;
            }

            this.includeBootstrap = hasFeature('includeBootstrap');
            this.includeFontAwesome = hasFeature('includeFontAwesome');
            this.includeJQuery = promptAnswers.includeJQuery;

            done();
        }.bind(this));

    },

    writing: {
        packageJson: function() {
            this.fs.copy(
                this.templatePath('_package.json'),
                this.destinationPath('package.json')
            );
        },

        settings: function() {
            this.fs.copy(
                this.templatePath('editorconfig'),
                this.destinationPath('.editorconfig')
            );

            this.fs.copy(
                this.templatePath('jshintrc'),
                this.destinationPath('.jshintrc')
            );
        },

        projectfiles: function() {
            this.fs.copy(
                this.templatePath('README.md'),
                this.destinationPath('README.md')
            );

            this.fs.copy(
                this.templatePath('favicon.ico'),
                this.destinationPath('app/favicon.ico')
            );
        },

        git: function() {
            this.fs.copy(
                this.templatePath('gitignore'),
                this.destinationPath('.gitignore')
            );

            this.fs.copy(
                this.templatePath('gitattributes'),
                this.destinationPath('.gitattributes')
            );
        },

        gulp: function() {
            this.fs.copy(
                this.templatePath('gulpfile.js'),
                this.destinationPath('gulpfile.js')
            );

            this.fs.copyTpl(
                this.templatePath('gulp/**/*'),
                this.destinationPath('gulp'), {
                    includeFontAwesome: this.includeFontAwesome
                }
            );
        },

        bower: function() {
            var bowerJson = {
                name: _s.slugify(this.appname),
                private: true,
                dependencies: {}
            };

            if (this.includeBootstrap) {
                bowerJson.dependencies['bootstrap-sass'] = '~3.3.5';
                bowerJson.overrides = {
                    'bootstrap-sass': {
                        'main': [
                            'assets/stylesheets/_bootstrap.scss',
                            'assets/fonts/bootstrap/*',
                            'assets/javascripts/bootstrap.js'
                        ]
                    }
                };
            } else if (this.includeJQuery) {
                bowerJson.dependencies.jquery = '~2.1.1';
            }

            if (this.includeFontAwesome) {
                bowerJson.dependencies['font-awesome'] = '~4.4.0';
            }

            // If no bower dependecies specified, create an empty bower_components folder
            if (Object.keys(bowerJson.dependencies).length === 0) {
                mkdirp('bower_components');
            }

            this.fs.writeJSON('bower.json', bowerJson);
            this.fs.copy(
                this.templatePath('bowerrc'),
                this.destinationPath('.bowerrc')
            );
        },

        server: function() {
            this.fs.copy(
                this.templatePath('server/**/*'),
                this.destinationPath('server')
            );
        },

        app: function() {
            this.fs.copy(
                this.templatePath('app.js'),
                this.destinationPath('app.js')
            );
        },

        styles: function() {
            this.fs.copyTpl(
                this.templatePath('styles/**/*'),
                this.destinationPath('app/styles/'), {
                    includeBootstrap: this.includeBootstrap,
                    includeFontAwesome: this.includeFontAwesome
                }
            );
        },

        javascript: function() {
            this.fs.copy(
                this.templatePath('js/main.js'),
                this.destinationPath('app/js/main.js')
            );
        },

        html: function() {
            var bootstrapPath;

            // path prefix for Bootstrap JS files
            if (this.includeBootstrap) {
                bootstrapPath = '/bower_components/bootstrap-sass/assets/javascripts/bootstrap/';
            }

            this.fs.copyTpl(
                this.templatePath('index.html'),
                this.destinationPath('app/index.html'),
                {
                    appname: this.appname,
                    includeBootstrap: this.includeBootstrap,
                    includeFontAwesome: this.includeFontAwesome,
                    bootstrapPath: bootstrapPath,
                    bootstrapPlugins: [
                        'affix',
                        'alert',
                        'dropdown',
                        'tooltip',
                        'modal',
                        'transition',
                        'button',
                        'popover',
                        'carousel',
                        'scrollspy',
                        'collapse',
                        'tab'
                    ]
                }
            );
        },

        misc: function() {
            mkdirp('app/images');
            mkdirp('app/fonts');
        }

    },

    install: function() {
        this.installDependencies({
            skipInstall: this.options.skipInstall
        });
    },

    end: function() {
        var bowerJson = this.fs.readJSON(this.destinationPath('bower.json')),
            howToInstall = '\nAfter running ' +
                chalk.yellow.bold('npm install & bower install') + ', inject your' +
                '\nfront end dependencies by running ' +
                chalk.yellow.bold('gulp wiredep') +'.';

        if (this.options.skipInstall) {
            this.log(howToInstall);
            return;
        }

        // wire Bower packages to .html
        wiredep({
            bowerJson: bowerJson,
            directory: 'bower_components',
            exclude: ['bootstrap-sass', 'bootstrap.js'],
            ignorePath: /^(\.\.\/)*\.\./,
            src: 'app/index.html'
        });

        // wire Bower packages to .scss
        wiredep({
            bowerJson: bowerJson,
            directory: 'bower_components',
            src: 'app/styles/*.scss'
        });
    }
});
<|endoftext|>