<commit_before>import { sendGoogleAnalyticsEvent } from './googleAnalytics.js';
import { previewEndTime, previewStartTime } from './mediaPlayer.js';
import { convertHHMMSSToSeconds, convertSecToHHMMSS, isHHMMSS,
         isInt, isUUID } from './utility.js';

export function initClipper () {

  $('#make-clip-start-time i').on('click', function () {
    var startTime = $('#make-clip-start-time input').val() || "0";
    var endTime = $('#make-clip-end-time input').val();
    startTime = convertHHMMSSToSeconds(startTime);
    endTime = convertHHMMSSToSeconds(endTime);
    previewStartTime(startTime, endTime);
  });

  $('#make-clip-end-time i').on('click', function () {
    var endTime = $('#make-clip-end-time input').val() || "3";
    endTime = convertHHMMSSToSeconds(endTime);
    previewEndTime(endTime);
  });

  $('#make-clip-time-set').on('click', function () {
    var currentTimeHHMMSS = convertSecToHHMMSS(Math.floor(audio.currentTime));
    var currentSetMode = $('#make-clip-time-set').html();
    if (currentSetMode === 'Set Start') {
      $('#make-clip-start-time input').val(currentTimeHHMMSS);
      $('#make-clip-end-time input').focus();
      $('#make-clip-time-set').html('Set End');
      sendGoogleAnalyticsEvent('Make Clip', 'Set End button clicked')
    } else if (currentSetMode === 'Set End') {
      $('#make-clip-end-time input').val(currentTimeHHMMSS);
      $('#make-clip-time-set').html('Set Start');
      $('#make-clip-title textarea').focus();
      sendGoogleAnalyticsEvent('Make Clip', 'Set Start button clicked')
    }
  });

  $('#player').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-set').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-back').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-forwards').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-back').on('click', function () {
    audio.currentTime = audio.currentTime - 15;
  });

  $('#make-clip-time-forwards').on('click', function () {
    audio.currentTime = audio.currentTime + 15;
  });

}

export function setStartTime () {
  $('#make-clip-start-time input').val(convertSecToHHMMSS(Math.floor(audio.currentTime)));
  $('#make-clip-end-time input').focus();
}

export function setEndTime () {
  $('#make-clip-end-time input').val(convertSecToHHMMSS(Math.floor(audio.currentTime)));
  $('#make-clip-title textarea').focus();
}

export function toggleMakeClipWidget (_this) {
  if ($('#add-to-playlist').css('display') !== 'block' && $('#recommend').css('display') !== 'block') {
    $('#player-description-truncated').hide();
    $('#player-description-full').hide();
    $('#playlist').hide();
  }

  if ($(_this).hasClass('active')) {
    $('#player-description-truncated').show();
    $('#playlist').show();
  }

  $('#add-to-playlist').hide();
  $('#toggle-playlist-btn').removeClass('active');

  $('#recommend').hide();
  $('#toggle-recommend-btn').removeClass('active');

  $('#toggle-make-clip-btn').toggleClass('active');
  $('#make-clip').toggle();

  sendGoogleAnalyticsEvent('Make Clip', 'Toggle Make Clip Widget');
}

export function makeClip (event) {
  event.preventDefault();

  if (window.preventResubmit) { return }

  window.preventResubmit = true;
  $('#make-clip-btn').attr('disabled', true);
  $('#make-clip-btn').html('')

  sendGoogleAnalyticsEvent('Make Clip', 'Make Clip');

  $('#make-clip-start-time-error').hide();
  $('#make-clip-end-time-error').hide();
  $('#make-clip-start-time').removeClass('has-danger');
  $('#make-clip-end-time').removeClass('has-danger');
  $('#make-clip-time').removeClass('has-danger');

  var startTime = $('#make-clip-start-time input').val(),
      endTime = $('#make-clip-end-time input').val();

  if (startTime === '' && endTime === '') {
    $('#make-clip-start-time-error').html('Type a start time and/or end time to create a clip.');
    $('#make-clip-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (!isHHMMSS(startTime) && startTime !== '') {
    $('#make-clip-start-time-error').html('Type time in hh:mm:ss format.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (!isHHMMSS(endTime) && endTime !== '') {
    $('#make-clip-end-time-error').html('Type time in hh:mm:ss format.');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-end-time-error').show();
    return;
  }

  startTime = convertHHMMSSToSeconds(startTime);
  endTime = convertHHMMSSToSeconds(endTime);

  if (endTime === 0) {
    endTime = null;
  }

  if (startTime === endTime) {
    $('#make-clip-start-time-error').html('Start time and end time cannot be the same.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (endTime !== null && endTime <= startTime) {
    $('#make-clip-start-time-error').html('End time cannot be earlier than start time.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  // TODO: how can we prevent malicious scripts in the title?
  var clipTitle = $('#make-clip-title textarea').val();

  // TODO: set owner name based on ownerId
  var ownerName = 'random owner name';

  if (endTime === "") {
    endTime = null;
  }

  // TODO: HACK: DANGER WILL ROBINSON: passing window variables into a POST
  // can't be a good idea. Should seriously consider fixing this...

  let dataObj = {
    startTime: startTime,
    endTime: endTime,
    title: clipTitle,
    ownerName: ownerName,
    podcastFeedURL: window.podcastFeedURL,
    podcastTitle: window.podcastTitle,
    episodeMediaURL: window.episodeMediaURL,
    episodeTitle: window.episodeTitle,
    episodePubDate: window.episodePubDate,
    episodeSummary: window.episodeSummary,
    episodeDuration: window.episodeDuration
  }

  if (window.podcastImageURL && window.podcastImageURL.indexOf('http') === 0) {
    dataObj.podcastImageURL = window.podcastImageURL;
  }

  if (window.episodeImageURL && window.episodeImageURL.indexOf('http') === 0) {
    dataObj.episodeImageURL = window.episodeImageURL;
  }

  setTimeout(function () {
    $.ajax({
      type: 'POST',
      url: '/clips',
      headers: {
        Authorization: $.cookie('idToken')
      },
      data: dataObj,
      success: function (response) {
        if (window.isPlayerPage) {
          toggleMakeClipWidget();
          $('#playlist').show();
          $('#make-clip-start-time input').val('');
          $('#make-clip-end-time input').val('');
          $('#make-clip-title textarea').val('');
          $('#player-description-truncated').show();
          $('#clip-created-modal-link').val(location.protocol + '\/\/' + location.hostname + (location.port ? ':'+location.port: '')  + '\/clips\/' + response.id);
          $('#clip-created-modal').modal('show');
        } else {
          location.href = '\/clips\/' + response.id;
        }
      },
      error: function (xhr, status, error) {
        console.log(error);
        alert('Failed to create clip. Please check your internet connection and try again.');
      },
      done: function () {
        window.preventResubmit = false;
        $('#make-clip-btn').removeAttr('disabled');
      }
    });
  }, 3000);

}
<commit_msg>Fix finally block of ajax make clip function<commit_after>import { sendGoogleAnalyticsEvent } from './googleAnalytics.js';
import { previewEndTime, previewStartTime } from './mediaPlayer.js';
import { convertHHMMSSToSeconds, convertSecToHHMMSS, isHHMMSS,
         isInt, isUUID } from './utility.js';

export function initClipper () {

  $('#make-clip-start-time i').on('click', function () {
    var startTime = $('#make-clip-start-time input').val() || "0";
    var endTime = $('#make-clip-end-time input').val();
    startTime = convertHHMMSSToSeconds(startTime);
    endTime = convertHHMMSSToSeconds(endTime);
    previewStartTime(startTime, endTime);
  });

  $('#make-clip-end-time i').on('click', function () {
    var endTime = $('#make-clip-end-time input').val() || "3";
    endTime = convertHHMMSSToSeconds(endTime);
    previewEndTime(endTime);
  });

  $('#make-clip-time-set').on('click', function () {
    var currentTimeHHMMSS = convertSecToHHMMSS(Math.floor(audio.currentTime));
    var currentSetMode = $('#make-clip-time-set').html();
    if (currentSetMode === 'Set Start') {
      $('#make-clip-start-time input').val(currentTimeHHMMSS);
      $('#make-clip-end-time input').focus();
      $('#make-clip-time-set').html('Set End');
      sendGoogleAnalyticsEvent('Make Clip', 'Set End button clicked')
    } else if (currentSetMode === 'Set End') {
      $('#make-clip-end-time input').val(currentTimeHHMMSS);
      $('#make-clip-time-set').html('Set Start');
      $('#make-clip-title textarea').focus();
      sendGoogleAnalyticsEvent('Make Clip', 'Set Start button clicked')
    }
  });

  $('#player').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-set').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-back').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-forwards').on('mousedown', function (e) {
    e.preventDefault(e);
  });

  $('#make-clip-time-back').on('click', function () {
    audio.currentTime = audio.currentTime - 15;
  });

  $('#make-clip-time-forwards').on('click', function () {
    audio.currentTime = audio.currentTime + 15;
  });

}

export function setStartTime () {
  $('#make-clip-start-time input').val(convertSecToHHMMSS(Math.floor(audio.currentTime)));
  $('#make-clip-end-time input').focus();
}

export function setEndTime () {
  $('#make-clip-end-time input').val(convertSecToHHMMSS(Math.floor(audio.currentTime)));
  $('#make-clip-title textarea').focus();
}

export function toggleMakeClipWidget (_this) {
  if ($('#add-to-playlist').css('display') !== 'block' && $('#recommend').css('display') !== 'block') {
    $('#player-description-truncated').hide();
    $('#player-description-full').hide();
    $('#playlist').hide();
  }

  if ($(_this).hasClass('active')) {
    $('#player-description-truncated').show();
    $('#playlist').show();
  }

  $('#add-to-playlist').hide();
  $('#toggle-playlist-btn').removeClass('active');

  $('#recommend').hide();
  $('#toggle-recommend-btn').removeClass('active');

  $('#toggle-make-clip-btn').toggleClass('active');
  $('#make-clip').toggle();

  sendGoogleAnalyticsEvent('Make Clip', 'Toggle Make Clip Widget');
}

export function makeClip (event) {
  event.preventDefault();

  if (window.preventResubmit) { return }

  window.preventResubmit = true;
  $('#make-clip-btn').attr('disabled', true);
  $('#make-clip-btn').html('')

  sendGoogleAnalyticsEvent('Make Clip', 'Make Clip');

  $('#make-clip-start-time-error').hide();
  $('#make-clip-end-time-error').hide();
  $('#make-clip-start-time').removeClass('has-danger');
  $('#make-clip-end-time').removeClass('has-danger');
  $('#make-clip-time').removeClass('has-danger');

  var startTime = $('#make-clip-start-time input').val(),
      endTime = $('#make-clip-end-time input').val();

  if (startTime === '' && endTime === '') {
    $('#make-clip-start-time-error').html('Type a start time and/or end time to create a clip.');
    $('#make-clip-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (!isHHMMSS(startTime) && startTime !== '') {
    $('#make-clip-start-time-error').html('Type time in hh:mm:ss format.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (!isHHMMSS(endTime) && endTime !== '') {
    $('#make-clip-end-time-error').html('Type time in hh:mm:ss format.');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-end-time-error').show();
    return;
  }

  startTime = convertHHMMSSToSeconds(startTime);
  endTime = convertHHMMSSToSeconds(endTime);

  if (endTime === 0) {
    endTime = null;
  }

  if (startTime === endTime) {
    $('#make-clip-start-time-error').html('Start time and end time cannot be the same.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  if (endTime !== null && endTime <= startTime) {
    $('#make-clip-start-time-error').html('End time cannot be earlier than start time.');
    $('#make-clip-start-time').addClass('has-danger');
    $('#make-clip-end-time').addClass('has-danger');
    $('#make-clip-start-time-error').show();
    return;
  }

  // TODO: how can we prevent malicious scripts in the title?
  var clipTitle = $('#make-clip-title textarea').val();

  // TODO: set owner name based on ownerId
  var ownerName = 'random owner name';

  if (endTime === "") {
    endTime = null;
  }

  // TODO: HACK: DANGER WILL ROBINSON: passing window variables into a POST
  // can't be a good idea. Should seriously consider fixing this...

  let dataObj = {
    startTime: startTime,
    endTime: endTime,
    title: clipTitle,
    ownerName: ownerName,
    podcastFeedURL: window.podcastFeedURL,
    podcastTitle: window.podcastTitle,
    episodeMediaURL: window.episodeMediaURL,
    episodeTitle: window.episodeTitle,
    episodePubDate: window.episodePubDate,
    episodeSummary: window.episodeSummary,
    episodeDuration: window.episodeDuration
  }

  if (window.podcastImageURL && window.podcastImageURL.indexOf('http') === 0) {
    dataObj.podcastImageURL = window.podcastImageURL;
  }

  if (window.episodeImageURL && window.episodeImageURL.indexOf('http') === 0) {
    dataObj.episodeImageURL = window.episodeImageURL;
  }

  setTimeout(function () {
    $.ajax({
      type: 'POST',
      url: '/clips',
      headers: {
        Authorization: $.cookie('idToken')
      },
      data: dataObj,
      success: function (response) {
        if (window.isPlayerPage) {
          toggleMakeClipWidget();
          $('#playlist').show();
          $('#make-clip-start-time input').val('');
          $('#make-clip-end-time input').val('');
          $('#make-clip-title textarea').val('');
          $('#player-description-truncated').show();
          $('#clip-created-modal-link').val(location.protocol + '\/\/' + location.hostname + (location.port ? ':'+location.port: '')  + '\/clips\/' + response.id);
          $('#clip-created-modal').modal('show');
        } else {
          location.href = '\/clips\/' + response.id;
        }
      },
      error: function (xhr, status, error) {
        console.log(error);
        alert('Failed to create clip. Please check your internet connection and try again.');
      },
      complete: function () {
        window.preventResubmit = false;
        $('#make-clip-btn').removeAttr('disabled');
        $('#make-clip-btn').html('Save');
      }
    });
  }, 3000);

}
<|endoftext|>


<commit_before>var RPYeti = RPYeti || {};

RPYeti.Gameplay = function (game, player, camera, scene) {
	this.game = game;
	this.player = player;
	this.camera = camera;
	this.scene = scene;
	this.level = 0;

	this.characters = { yetis: { count: 0, objs: {} } };

	this.yetis = new THREE.Group();
	this.scene.add( this.yetis );

	this.settings = jQuery.extend(true, {}, RPYeti.config.gamePlayBaseline);

	(function (self) {
		self.player.on('defeated', function (context) {
			RPYeti.music.publisher.trigger('rpyeti.music.lose');
			self.game.hud.addText(RPYeti.config.dialogs.gameOver, 0);

			if (window) {
				self.game.hud.startCountdown(10, function () {
					location = RPYeti.config.urls.leaderBoard;
					if (window.location.hash) {
						location += '#' + window.location.hash;
					}
					window.location.assign(location);
				});
			}
		});

		self.player.on('hit', function (context) {
			if (!context.lowHealthTrigger && context.health < RPYeti.config.player.lowHealth) {
				context.lowHealthTrigger = true;
				RPYeti.music.publisher.trigger('rpyeti.music.lowhealth');
			}

			self.game.hud.updateReticle();
		});

		self.player.on('yeti.defeat', function (context, yeti) {
			context.points += yeti.points;
			self.currentLevelDefeated++;

			RPYeti.service.publisher.trigger('rpyeti.game.score', context.points);
		});

		self.player.on('yeti.defeated', function (context, yeti) {
			self.nextRound();
		})
	})(this);
};

RPYeti.Gameplay.prototype.constructor = RPYeti.Gameplay;

RPYeti.Gameplay.prototype.start = function (level, reset) {
	this.level = level;

	if (reset) {
		this.player.points = 0;
	}

	this.player.health = RPYeti.config.player.health;
	this.player.lowHealthTrigger = false;

	if (level == 0) {
		RPYeti.music.publisher.trigger('rpyeti.music.selection');
		this.startIntro();
	} else {
		RPYeti.music.publisher.trigger('rpyeti.music.fight');
		this.levelBegin(level);
	}
};

RPYeti.Gameplay.prototype.levelBegin = function (level) {
	this.game.hud.addText('Level ' + level);

	delete this.settings
	this.settings = jQuery.extend(true, {}, RPYeti.config.gameplay.baseline);
	this.currentLevelDefeated = 0;

	this.modSettings(this.settings, RPYeti.config.gameplay.modifiers, (level - 1));
	this.nextRound();

};

RPYeti.Gameplay.prototype.setTimer = function () {
	if (this.popTimer === undefined || this.popTimer.expired) {
		(function (self) {
			self.popTimer = self.player.setTimeout(function () {
				delete self.popTimer;

				self.yetiSpawner();
				self.setTimer();
			}, self.random(self.settings.popTimer));
		})(this);
	}
}

RPYeti.Gameplay.prototype.stopTimer = function () {
	this.player.clearTimer(this.popTimer);
	delete this.popTimer;
}

RPYeti.Gameplay.prototype.nextRound = function () {
	if (this.currentLevelDefeated >= this.settings.yeti.total) {
		this.levelComplete();
	} else {
		this.setTimer();
	}
};

RPYeti.Gameplay.prototype.levelComplete = function () {
	this.game.hud.addText('Level Complete\nScore: ' + this.player.points, 9600);

	RPYeti.music.publisher.trigger('rpyeti.music.win');

	(function (self) {
		self.stopTimer();
		self.player.setTimeout(function () {
			self.start(self.level + 1);
		}, 9600);
	})(this);
};

RPYeti.Gameplay.prototype.startIntro = function () {
	var introPoints = RPYeti.loader.maps.main.intro,
		signs = [ RPYeti.loader.models.sign_cn, RPYeti.loader.models.sign_ja, RPYeti.loader.models.sign_wawf ],
		treeModel = RPYeti.loader.models.decoratedtree,
		treeScale = 5,
		signScale = 4,
		density = RPYeti.loader.maps.main.density,
		cameraPos = this.camera.getWorldPosition(),
		centerPos = null;

		if (this.intro !== undefined) {
			this.scene.remove(this.intro);
			while (this.intro.children.length) { this.intro.children.pop(); }
		}

		cameraPos.y = treeModel.position.y;

		this.intro = new THREE.Group();
		for (var i = 0; i < introPoints.length; i++) {
			var tree = treeModel.clone(),
				x = introPoints[i][0] * density,
				z = introPoints[i][1] * density;

			tree.translateX(x + 8);
			tree.translateZ(z);
			tree.scale.set(treeScale, treeScale, treeScale);

			tree.lookAt(cameraPos);
			this.intro.add(tree);

			centerPos = tree.position.clone();

			(function (self, position) {
				position.x += 10;
				position.z -= 15;
				setTimeout(function () {
					self.spawnYeti(self.intro, position, undefined, 1.85, 9001, 0);
				});
			})(this, tree.position.clone());
		}

		if (centerPos != null && signs.length > 0) {
			var xOffset = 12;

			cameraPos.y = signs[0].position.y;

			centerPos.x -= 15;
			centerPos.z -= xOffset * Math.floor(signs.length / 2);

			for (var i = 0; i < signs.length; i++) {
				signs[i].position.set(centerPos.x, centerPos.y, centerPos.z);
				signs[i].scale.set(signScale, signScale, signScale);

				signs[i].lookAt(cameraPos);

				this.intro.add(signs[i]);

				centerPos.z += xOffset;
			}
		}

		this.scene.add(this.intro);
		this.game.snowballBlockers.push(this.intro);

		(function (self) {
			self.player.setTimeout(function () {
				self.game.hud.addText(RPYeti.config.dialogs.select, 0);
			}, 1500);

			self.player.on('intro.select', function (context, number) {
				var pattern = /decoration_(.*)/i;
				if (number.match(pattern)) {
					context.selected = number.replace(pattern, '$1');

					RPYeti.service.publisher.trigger('rpyeti.game.charity', context.selected);

					self.endIntro(number);
				}
			});
		})(this);
};

RPYeti.Gameplay.prototype.endIntro = function (number) {
	var yeti = null;

	this.player.on('intro.select', function () {});

	for (var i in this.intro.children) {
		if (this.intro.children[i].userData && this.intro.children[i].userData.character instanceof RPYeti.Yeti) {
			yeti = this.intro.children[i].userData.character;
			yeti.appear();
		}
	}

	if (yeti === null) {
		return;
	}

	(function (self) {
		yeti.on('appear', function (context) {
			context.roar = self.game.createSoundEffect( RPYeti.loader.sounds.yeti_roar );
			context.pivot.add( context.roar );

			self.game.hud.addText('', 0);
			self.game.hud.addText('...?');

			RPYeti.music.publisher.trigger('rpyeti.music.theft', function () {
				context.roar.play();
				self.game.hud.addText(RPYeti.config.dialogs.exclamation);

				var bounds = new THREE.Box3().setFromObject(self.intro);
				context.setTimeout(function () {
					var positionTween = new TWEEN.Tween(self.intro.position)
						.easing(RPYeti.config.character.yeti.disappearEasing)
						.onComplete(function () {
							// Cleanup
							if (self.intro !== undefined) {
								self.intro.visible = false;
								self.scene.remove(self.intro);
								for (var i = self.game.snowballBlockers.length + 1; i > 0; i--) {
									if (self.game.snowballBlockers[i] == self.intro) {
										self.game.snowballBlockers.splice(i, 1);
										break;
									}
								}
								while (self.intro.children.length) { self.intro.children.pop(); }
								delete self.intro;
							}

							// TODO: Move this seque to dialog
							context.setTimeout(function () {
								// Start level 1!
								self.start(1);
							}, 9600)
							self.game.hud.addText(RPYeti.config.dialogs.introSeque, 9600);
						});

					positionTween.to({ y: -Math.abs(bounds.max.y) }, RPYeti.config.character.yeti.disappearDuration * 2).start();
				}, 3000);

			});
		});
	})(this);
};

RPYeti.Gameplay.prototype.spawnYeti = function (group, position, lookAt, scale, health, points) {
	var yeti = new RPYeti.Yeti(group, health, points),
		cameraPos = this.camera.getWorldPosition(),
		lookAt = lookAt || cameraPos,
		blockers = [ this.game.trees, this.yetis ],
		tries = 100;

	if (position === undefined) {
		while (tries-- > 0) {
			var x = this.random(RPYeti.config.character.maxX, RPYeti.config.character.minX),
				z = this.random(RPYeti.config.character.maxZ, RPYeti.config.character.minZ);

			yeti.position(x, z, scale, lookAt);
			if (!yeti.isBlocked(cameraPos, blockers) && yeti.pivot.position.distanceTo(cameraPos) > 40) {
				break;
			}
		}
	} else {
		yeti.position(position.x, position.z, scale, lookAt);
	}

	yeti.hide();

	return yeti;
};

RPYeti.Gameplay.prototype.yetiSpawner = function () {
	if (this.characters.yetis.count < this.settings.yeti.maxOnScreen && (this.currentLevelDefeated + this.characters.yetis.count) < this.settings.yeti.total) {
		var yeti = this.spawnYeti(this.yetis, undefined, undefined, undefined, this.settings.yeti.health, this.settings.yeti.points);

		this.characters.yetis.objs[yeti.model.id] = yeti;
		this.characters.yetis.count++;

		(function (self, yeti) {
			yeti.setAction(function (context) {
				var pos = context.pivot.position.clone();
				pos.y = context.handHeight;

				self.game.throwSnowball(pos, context);
			});

			yeti.on('appear', function (context) {
				if (context.roar) {
					context.roar.stop();
					context.roar.isPlaying = false;
				} else {
					context.roar = self.game.createSoundEffect( RPYeti.loader.sounds.yeti_roar );
					context.pivot.add( context.roar );
				}

				context.roar.play();

				context.throwCount = self.random(self.settings.yeti.throwCount);
				context.setTimeout(context.action, self.random(self.settings.yeti.throwDelay));
			});

			yeti.on('disappear', function (context) {
				context.setTimeout(context.appear, self.random(self.settings.yeti.appearDelay));
			});

			yeti.on('action', function (context) {
				context.throwCount--;
				context.setTimeout(function () {
					if (context.throwCount > 0) {
						context.action();
					} else {
						context.disappear();
					}
				}, self.random(self.settings.yeti.throwDelay));
			});

			yeti.on('defeat', function (context, param) {
				if (param !== undefined
					&& param.userData.initiator !== undefined
					&& param.userData.initiator instanceof RPYeti.Yeti) {

					self.game.hud.addText(RPYeti.config.dialogs.yetiOnYeti);
				} else if (param.userData.initiator == self.player) {
					self.player.trigger('yeti.defeat', context);
					self.game.hud.addText(RPYeti.config.dialogs.yetiDowned
						+ ' ' + self.player.points + '\n'
						+ (self.settings.yeti.total - self.currentLevelDefeated) + ' ' + RPYeti.config.dialogs.remaining);
				}
			});

			yeti.on('defeated', function (context) {
				delete self.characters.yetis.objs[context.model.id];
				self.characters.yetis.count--;

				self.player.trigger('yeti.defeated');

				context.setTimeout(context.remove, 1500);
			});

			yeti.appear();
		})(this, yeti);
	}
};

RPYeti.Gameplay.prototype.modSettings = function (settings, modifiers, level) {
	for (var i in settings) {
		if (typeof settings[i] === 'object' && typeof modifiers[i] == 'object') {
			this.modSettings(settings[i], modifiers[i], level);
		} else if (typeof modifiers[i] === 'function') {
			settings[i] += modifiers[i](level);;
			if (settings[i] < 0) {
				settings[i] = 0;
			}
		}
	}
}

RPYeti.Gameplay.prototype.random = function (min, max) {
	if (typeof min == 'object') {
		max = min.max;
		min = min.min;
	}
	return Math.floor(Math.random() * (max - min + 1) + min);
};
<commit_msg>fixed location hash<commit_after>var RPYeti = RPYeti || {};

RPYeti.Gameplay = function (game, player, camera, scene) {
	this.game = game;
	this.player = player;
	this.camera = camera;
	this.scene = scene;
	this.level = 0;

	this.characters = { yetis: { count: 0, objs: {} } };

	this.yetis = new THREE.Group();
	this.scene.add( this.yetis );

	this.settings = jQuery.extend(true, {}, RPYeti.config.gamePlayBaseline);

	(function (self) {
		self.player.on('defeated', function (context) {
			RPYeti.music.publisher.trigger('rpyeti.music.lose');
			self.game.hud.addText(RPYeti.config.dialogs.gameOver, 0);

			if (window) {
				self.game.hud.startCountdown(10, function () {
					var l = RPYeti.config.urls.leaderBoard;
					if (window.location.hash) {
						l += window.location.hash;
					}
					window.location.assign(l);
				});
			}
		});

		self.player.on('hit', function (context) {
			if (!context.lowHealthTrigger && context.health < RPYeti.config.player.lowHealth) {
				context.lowHealthTrigger = true;
				RPYeti.music.publisher.trigger('rpyeti.music.lowhealth');
			}

			self.game.hud.updateReticle();
		});

		self.player.on('yeti.defeat', function (context, yeti) {
			context.points += yeti.points;
			self.currentLevelDefeated++;

			RPYeti.service.publisher.trigger('rpyeti.game.score', context.points);
		});

		self.player.on('yeti.defeated', function (context, yeti) {
			self.nextRound();
		})
	})(this);
};

RPYeti.Gameplay.prototype.constructor = RPYeti.Gameplay;

RPYeti.Gameplay.prototype.start = function (level, reset) {
	this.level = level;

	if (reset) {
		this.player.points = 0;
	}

	this.player.health = RPYeti.config.player.health;
	this.player.lowHealthTrigger = false;

	if (level == 0) {
		RPYeti.music.publisher.trigger('rpyeti.music.selection');
		this.startIntro();
	} else {
		RPYeti.music.publisher.trigger('rpyeti.music.fight');
		this.levelBegin(level);
	}
};

RPYeti.Gameplay.prototype.levelBegin = function (level) {
	this.game.hud.addText('Level ' + level);

	delete this.settings
	this.settings = jQuery.extend(true, {}, RPYeti.config.gameplay.baseline);
	this.currentLevelDefeated = 0;

	this.modSettings(this.settings, RPYeti.config.gameplay.modifiers, (level - 1));
	this.nextRound();

};

RPYeti.Gameplay.prototype.setTimer = function () {
	if (this.popTimer === undefined || this.popTimer.expired) {
		(function (self) {
			self.popTimer = self.player.setTimeout(function () {
				delete self.popTimer;

				self.yetiSpawner();
				self.setTimer();
			}, self.random(self.settings.popTimer));
		})(this);
	}
}

RPYeti.Gameplay.prototype.stopTimer = function () {
	this.player.clearTimer(this.popTimer);
	delete this.popTimer;
}

RPYeti.Gameplay.prototype.nextRound = function () {
	if (this.currentLevelDefeated >= this.settings.yeti.total) {
		this.levelComplete();
	} else {
		this.setTimer();
	}
};

RPYeti.Gameplay.prototype.levelComplete = function () {
	this.game.hud.addText('Level Complete\nScore: ' + this.player.points, 9600);

	RPYeti.music.publisher.trigger('rpyeti.music.win');

	(function (self) {
		self.stopTimer();
		self.player.setTimeout(function () {
			self.start(self.level + 1);
		}, 9600);
	})(this);
};

RPYeti.Gameplay.prototype.startIntro = function () {
	var introPoints = RPYeti.loader.maps.main.intro,
		signs = [ RPYeti.loader.models.sign_cn, RPYeti.loader.models.sign_ja, RPYeti.loader.models.sign_wawf ],
		treeModel = RPYeti.loader.models.decoratedtree,
		treeScale = 5,
		signScale = 4,
		density = RPYeti.loader.maps.main.density,
		cameraPos = this.camera.getWorldPosition(),
		centerPos = null;

		if (this.intro !== undefined) {
			this.scene.remove(this.intro);
			while (this.intro.children.length) { this.intro.children.pop(); }
		}

		cameraPos.y = treeModel.position.y;

		this.intro = new THREE.Group();
		for (var i = 0; i < introPoints.length; i++) {
			var tree = treeModel.clone(),
				x = introPoints[i][0] * density,
				z = introPoints[i][1] * density;

			tree.translateX(x + 8);
			tree.translateZ(z);
			tree.scale.set(treeScale, treeScale, treeScale);

			tree.lookAt(cameraPos);
			this.intro.add(tree);

			centerPos = tree.position.clone();

			(function (self, position) {
				position.x += 10;
				position.z -= 15;
				setTimeout(function () {
					self.spawnYeti(self.intro, position, undefined, 1.85, 9001, 0);
				});
			})(this, tree.position.clone());
		}

		if (centerPos != null && signs.length > 0) {
			var xOffset = 12;

			cameraPos.y = signs[0].position.y;

			centerPos.x -= 15;
			centerPos.z -= xOffset * Math.floor(signs.length / 2);

			for (var i = 0; i < signs.length; i++) {
				signs[i].position.set(centerPos.x, centerPos.y, centerPos.z);
				signs[i].scale.set(signScale, signScale, signScale);

				signs[i].lookAt(cameraPos);

				this.intro.add(signs[i]);

				centerPos.z += xOffset;
			}
		}

		this.scene.add(this.intro);
		this.game.snowballBlockers.push(this.intro);

		(function (self) {
			self.player.setTimeout(function () {
				self.game.hud.addText(RPYeti.config.dialogs.select, 0);
			}, 1500);

			self.player.on('intro.select', function (context, number) {
				var pattern = /decoration_(.*)/i;
				if (number.match(pattern)) {
					context.selected = number.replace(pattern, '$1');

					RPYeti.service.publisher.trigger('rpyeti.game.charity', context.selected);

					self.endIntro(number);
				}
			});
		})(this);
};

RPYeti.Gameplay.prototype.endIntro = function (number) {
	var yeti = null;

	this.player.on('intro.select', function () {});

	for (var i in this.intro.children) {
		if (this.intro.children[i].userData && this.intro.children[i].userData.character instanceof RPYeti.Yeti) {
			yeti = this.intro.children[i].userData.character;
			yeti.appear();
		}
	}

	if (yeti === null) {
		return;
	}

	(function (self) {
		yeti.on('appear', function (context) {
			context.roar = self.game.createSoundEffect( RPYeti.loader.sounds.yeti_roar );
			context.pivot.add( context.roar );

			self.game.hud.addText('', 0);
			self.game.hud.addText('...?');

			RPYeti.music.publisher.trigger('rpyeti.music.theft', function () {
				context.roar.play();
				self.game.hud.addText(RPYeti.config.dialogs.exclamation);

				var bounds = new THREE.Box3().setFromObject(self.intro);
				context.setTimeout(function () {
					var positionTween = new TWEEN.Tween(self.intro.position)
						.easing(RPYeti.config.character.yeti.disappearEasing)
						.onComplete(function () {
							// Cleanup
							if (self.intro !== undefined) {
								self.intro.visible = false;
								self.scene.remove(self.intro);
								for (var i = self.game.snowballBlockers.length + 1; i > 0; i--) {
									if (self.game.snowballBlockers[i] == self.intro) {
										self.game.snowballBlockers.splice(i, 1);
										break;
									}
								}
								while (self.intro.children.length) { self.intro.children.pop(); }
								delete self.intro;
							}

							// TODO: Move this seque to dialog
							context.setTimeout(function () {
								// Start level 1!
								self.start(1);
							}, 9600)
							self.game.hud.addText(RPYeti.config.dialogs.introSeque, 9600);
						});

					positionTween.to({ y: -Math.abs(bounds.max.y) }, RPYeti.config.character.yeti.disappearDuration * 2).start();
				}, 3000);

			});
		});
	})(this);
};

RPYeti.Gameplay.prototype.spawnYeti = function (group, position, lookAt, scale, health, points) {
	var yeti = new RPYeti.Yeti(group, health, points),
		cameraPos = this.camera.getWorldPosition(),
		lookAt = lookAt || cameraPos,
		blockers = [ this.game.trees, this.yetis ],
		tries = 100;

	if (position === undefined) {
		while (tries-- > 0) {
			var x = this.random(RPYeti.config.character.maxX, RPYeti.config.character.minX),
				z = this.random(RPYeti.config.character.maxZ, RPYeti.config.character.minZ);

			yeti.position(x, z, scale, lookAt);
			if (!yeti.isBlocked(cameraPos, blockers) && yeti.pivot.position.distanceTo(cameraPos) > 40) {
				break;
			}
		}
	} else {
		yeti.position(position.x, position.z, scale, lookAt);
	}

	yeti.hide();

	return yeti;
};

RPYeti.Gameplay.prototype.yetiSpawner = function () {
	if (this.characters.yetis.count < this.settings.yeti.maxOnScreen && (this.currentLevelDefeated + this.characters.yetis.count) < this.settings.yeti.total) {
		var yeti = this.spawnYeti(this.yetis, undefined, undefined, undefined, this.settings.yeti.health, this.settings.yeti.points);

		this.characters.yetis.objs[yeti.model.id] = yeti;
		this.characters.yetis.count++;

		(function (self, yeti) {
			yeti.setAction(function (context) {
				var pos = context.pivot.position.clone();
				pos.y = context.handHeight;

				self.game.throwSnowball(pos, context);
			});

			yeti.on('appear', function (context) {
				if (context.roar) {
					context.roar.stop();
					context.roar.isPlaying = false;
				} else {
					context.roar = self.game.createSoundEffect( RPYeti.loader.sounds.yeti_roar );
					context.pivot.add( context.roar );
				}

				context.roar.play();

				context.throwCount = self.random(self.settings.yeti.throwCount);
				context.setTimeout(context.action, self.random(self.settings.yeti.throwDelay));
			});

			yeti.on('disappear', function (context) {
				context.setTimeout(context.appear, self.random(self.settings.yeti.appearDelay));
			});

			yeti.on('action', function (context) {
				context.throwCount--;
				context.setTimeout(function () {
					if (context.throwCount > 0) {
						context.action();
					} else {
						context.disappear();
					}
				}, self.random(self.settings.yeti.throwDelay));
			});

			yeti.on('defeat', function (context, param) {
				if (param !== undefined
					&& param.userData.initiator !== undefined
					&& param.userData.initiator instanceof RPYeti.Yeti) {

					self.game.hud.addText(RPYeti.config.dialogs.yetiOnYeti);
				} else if (param.userData.initiator == self.player) {
					self.player.trigger('yeti.defeat', context);
					self.game.hud.addText(RPYeti.config.dialogs.yetiDowned
						+ ' ' + self.player.points + '\n'
						+ (self.settings.yeti.total - self.currentLevelDefeated) + ' ' + RPYeti.config.dialogs.remaining);
				}
			});

			yeti.on('defeated', function (context) {
				delete self.characters.yetis.objs[context.model.id];
				self.characters.yetis.count--;

				self.player.trigger('yeti.defeated');

				context.setTimeout(context.remove, 1500);
			});

			yeti.appear();
		})(this, yeti);
	}
};

RPYeti.Gameplay.prototype.modSettings = function (settings, modifiers, level) {
	for (var i in settings) {
		if (typeof settings[i] === 'object' && typeof modifiers[i] == 'object') {
			this.modSettings(settings[i], modifiers[i], level);
		} else if (typeof modifiers[i] === 'function') {
			settings[i] += modifiers[i](level);;
			if (settings[i] < 0) {
				settings[i] = 0;
			}
		}
	}
}

RPYeti.Gameplay.prototype.random = function (min, max) {
	if (typeof min == 'object') {
		max = min.max;
		min = min.min;
	}
	return Math.floor(Math.random() * (max - min + 1) + min);
};
<|endoftext|>


<commit_before>const { exec: nodeExec } = require('child_process')
const clipboardy = require('clipboardy')
const { split, head, tail, dissoc, trim, identity } = require('ramda')
const execa = require('execa')
const nodeWhich = require('which')
const crossSpawn = require('cross-spawn')

/**
 * Extensions to launch processes, open files, and talk to the clipboard.
 *
 * @return {Function} A function to attach to the context.
 */
module.exports = function (plugin, command, context) {
  /**
   * Executes a commandline program asynchronously.
   *
   * @param {string} commandLine The command line to execute.
   * @param {options} options Additional child_process options for node.
   * @returns {Promise}
   */
  async function run (commandLine, options = {}) {
    const trimmer = options && options.trim ? trim : identity
    const nodeOptions = dissoc('trim', options)

    return new Promise((resolve, reject) => {
      nodeExec(commandLine, nodeOptions, (error, stdout, stderr) => {
        if (error) {
          error.stderr = stderr
          reject(error)
        }
        resolve(trimmer(stdout || ''))
      })
    })
  }

  /**
   * Executes a commandline via execa.
   *
   * @param {string} commandLine The command line to execute.
   * @param {options} options Additional child_process options for node.
   * @returns {Promise}
   */
  async function exec (commandLine, options) {
    return new Promise((resolve, reject) => {
      const args = split(' ', commandLine)
      execa(head(args), tail(args), options)
        .then(result => resolve(result.stdout))
        .catch(error => reject(error))
    })
  }

  /**
   * Uses cross-spawn to run a process.
   *
   * @param {any} commandLine The command line to execute.
   * @param {options} options Additional child_process options for node.
   * @returns {Promise} The response code.
   */
  async function spawn (commandLine, options) {
    return new Promise((resolve, reject) => {
      const args = split(' ', commandLine)
      const spawned = crossSpawn(head(args), tail(args), options)
      let result = {
        stdout: null,
        status: null,
        error: null
      }
      spawned.stdout.on('data', data => {
        if (result.stdout == null) {
          result.stdout = data
        } else {
          result.stdout += data
        }
      })
      spawned.on('close', code => {
        result.status = code
        resolve(result)
      })
      spawned.on('error', err => {
        result.error = err
        resolve(result)
      })
    })
  }

  /**
   * Returns text that is on the clipboard.
   *
   * @return {string}
   */
  function readFromClipboard () {
    return clipboardy.readSync()
  }

  /**
   * Writes text to the clipboard.
   *
   * @param {string} text The text to send
   */
  function writeToClipboard (text) {
    clipboardy.writeSync(text)
  }

  /**
   * Finds the location of the path.
   *
   * @param {string} command The name of program you're looking for.
   * @return {string} The full path or null.
   */
  function which (command) {
    return nodeWhich.sync(command)
  }

  return { exec, run, spawn, readFromClipboard, writeToClipboard, which }
}
<commit_msg>Makes stdout optional with spawn. (#183)<commit_after>const { exec: nodeExec } = require('child_process')
const clipboardy = require('clipboardy')
const { isNil, split, head, tail, dissoc, trim, identity } = require('ramda')
const execa = require('execa')
const nodeWhich = require('which')
const crossSpawn = require('cross-spawn')

/**
 * Extensions to launch processes, open files, and talk to the clipboard.
 *
 * @return {Function} A function to attach to the context.
 */
module.exports = function (plugin, command, context) {
  /**
   * Executes a commandline program asynchronously.
   *
   * @param {string} commandLine The command line to execute.
   * @param {options} options Additional child_process options for node.
   * @returns {Promise}
   */
  async function run (commandLine, options = {}) {
    const trimmer = options && options.trim ? trim : identity
    const nodeOptions = dissoc('trim', options)

    return new Promise((resolve, reject) => {
      nodeExec(commandLine, nodeOptions, (error, stdout, stderr) => {
        if (error) {
          error.stderr = stderr
          reject(error)
        }
        resolve(trimmer(stdout || ''))
      })
    })
  }

  /**
   * Executes a commandline via execa.
   *
   * @param {string} commandLine The command line to execute.
   * @param {options} options Additional child_process options for node.
   * @returns {Promise}
   */
  async function exec (commandLine, options) {
    return new Promise((resolve, reject) => {
      const args = split(' ', commandLine)
      execa(head(args), tail(args), options)
        .then(result => resolve(result.stdout))
        .catch(error => reject(error))
    })
  }

  /**
   * Uses cross-spawn to run a process.
   *
   * @param {any} commandLine The command line to execute.
   * @param {options} options Additional child_process options for node.
   * @returns {Promise} The response code.
   */
  async function spawn (commandLine, options) {
    return new Promise((resolve, reject) => {
      const args = split(' ', commandLine)
      const spawned = crossSpawn(head(args), tail(args), options)
      let result = {
        stdout: null,
        status: null,
        error: null
      }
      if (spawned.stdout) {
        spawned.stdout.on('data', data => {
          if (isNil(result.stdout)) {
            result.stdout = data
          } else {
            result.stdout += data
          }
        })
      }
      spawned.on('close', code => {
        result.status = code
        resolve(result)
      })
      spawned.on('error', err => {
        result.error = err
        resolve(result)
      })
    })
  }

  /**
   * Returns text that is on the clipboard.
   *
   * @return {string}
   */
  function readFromClipboard () {
    return clipboardy.readSync()
  }

  /**
   * Writes text to the clipboard.
   *
   * @param {string} text The text to send
   */
  function writeToClipboard (text) {
    clipboardy.writeSync(text)
  }

  /**
   * Finds the location of the path.
   *
   * @param {string} command The name of program you're looking for.
   * @return {string} The full path or null.
   */
  function which (command) {
    return nodeWhich.sync(command)
  }

  return { exec, run, spawn, readFromClipboard, writeToClipboard, which }
}
<|endoftext|>


<commit_before>//Import dependencies
var assert = require('assert');
var fs = require('fs');
var path = require('path');
var utily = require('../index.js');

//Test the fs methods
describe('utily -> fs', function()
{
  //Test checksum method
  describe('-> checksum method', function()
  {
    var file = path.join(__dirname, './fs-checksum-test.txt');
    fs.writeFileSync(file, 'Hello\nThis is the content\n', 'utf8');
    it('should generate the correct checksum of the file', function(done)
    {
      return utily.fs.checksum(file, 'md5', function(error, sum)
      {
        assert.equal(null, error);
        assert.equal('2c1b03ff58b808e5bd56196131cc8505', sum);
        done();
      });
    });
  });

  //Test copy method
  describe('-> copy method', function()
  {
    //Copy files
    it('shgould copy a file that exists', function(done)
    {
      var file_source = path.join(__dirname, 'fs-copy-source.txt');
      var file_destination = path.join(__dirname, 'fs-copy-destination.txt');
      fs.writeFileSync(file_source, 'This is the content of the file 1', 'utf8');
      return utily.fs.copy(file_source, file_destination, function(error)
      {
        assert.equal(null, error);
        var content1 = fs.readFileSync(file_source, 'utf8');
        var content2 = fs.readFileSync(file_destination, 'utf8');
        assert.equal(content1, content2);
        done();
      });
    });

    //Display an error
    it('should return an error if source file does not exists', function(done)
    {
      var file_source = path.join(__dirname, 'fs-copy-source-unexistent.txt');
      var file_destination = path.join(__dirname, 'fs-copy-destination.txt');
      return utily.fs.copy(file_source, file_destination, function(error)
      {
        assert.notEqual(null, error);
        done();
      });
    });
  });

  //Test exists method
  describe('-> exists method', function()
  {
    //Folder that does not exists
    it('should return false if path does not exists', function(done)
    {
      return utily.fs.exists(path.join(__dirname, './inexistent'), function(error, exists)
      {
        assert.equal(null, error);
        assert.equal(false, exists);
        done();
      });
    });
    //Folder that exists
    it('should return true if path exists', function(done)
    {
      return utily.fs.exists(__dirname, function(error, exists)
      {
        assert.equal(null, error);
        assert.equal(true, exists);
        done();
      });
    });
  });

  //Test mkdir method
  describe('-> mkdir method', function()
  {
    //Create a folder
    it('should create the folders', function(done)
    {
      var folders = path.join(__dirname, './new/folders/yeah');
      return utily.fs.mkdir(folders, function(error)
      {
        assert.equal(null, error);
        return utily.fs.exists(folders, function(error, exists)
        {
          assert.equal(null, error);
          assert.equal(true, exists);
          done();
        });
      });
    });
  });

  //Test size method
  describe('-> size method', function()
  {
    //Check the file size
    it('should get the real file size', function(done)
    {
      var file = path.join(__dirname, './fs-size-test.txt');
      fs.writeFileSync(file, 'This is the content of the \nfile\n', 'utf8');
      return utily.fs.size(file, function(error, size)
      {
        assert.equal(null, error);
        assert.equal(33, size);
        done();
      });
    });
  });

  //Test unlink method
  describe('-> unlink method', function()
  {
    //Delete a list of file
    it('should delete a list of files', function(done)
    {
      var file1 = path.join(__dirname, './fs-unlink-test1.txt');
      var file2 = path.join(__dirname, './fs-unlink-test2.txt');
      fs.writeFileSync(file1, 'Test 1', 'utf8');
      fs.writeFileSync(file2, 'Test 2', 'utf8');
      return utily.fs.unlink([ file1, file2 ], function(error)
      {
        assert.equal(null, error);
        return utily.fs.exists(file1, function(error, exists)
        {
          assert.equal(null, error);
          assert.equal(false, exists);
          return utily.fs.exists(file2, function(error, exists)
          {
            assert.equal(null, error);
            assert.equal(false, exists);
            done();
          });
        });
      });
    });
  });
});

<commit_msg>test/test.js: fixed fs.mkdir test<commit_after>//Import dependencies
var assert = require('assert');
var fs = require('fs');
var path = require('path');
var utily = require('../index.js');

//Test the fs methods
describe('utily -> fs', function()
{
  //Test checksum method
  describe('-> checksum method', function()
  {
    var file = path.join(__dirname, './fs-checksum-test.txt');
    fs.writeFileSync(file, 'Hello\nThis is the content\n', 'utf8');
    it('should generate the correct checksum of the file', function(done)
    {
      return utily.fs.checksum(file, 'md5', function(error, sum)
      {
        assert.equal(null, error);
        assert.equal('2c1b03ff58b808e5bd56196131cc8505', sum);
        done();
      });
    });
  });

  //Test copy method
  describe('-> copy method', function()
  {
    //Copy files
    it('shgould copy a file that exists', function(done)
    {
      var file_source = path.join(__dirname, 'fs-copy-source.txt');
      var file_destination = path.join(__dirname, 'fs-copy-destination.txt');
      fs.writeFileSync(file_source, 'This is the content of the file 1', 'utf8');
      return utily.fs.copy(file_source, file_destination, function(error)
      {
        assert.equal(null, error);
        var content1 = fs.readFileSync(file_source, 'utf8');
        var content2 = fs.readFileSync(file_destination, 'utf8');
        assert.equal(content1, content2);
        done();
      });
    });

    //Display an error
    it('should return an error if source file does not exists', function(done)
    {
      var file_source = path.join(__dirname, 'fs-copy-source-unexistent.txt');
      var file_destination = path.join(__dirname, 'fs-copy-destination.txt');
      return utily.fs.copy(file_source, file_destination, function(error)
      {
        assert.notEqual(null, error);
        done();
      });
    });
  });

  //Test exists method
  describe('-> exists method', function()
  {
    //Folder that does not exists
    it('should return false if path does not exists', function(done)
    {
      return utily.fs.exists(path.join(__dirname, './inexistent'), function(error, exists)
      {
        assert.equal(null, error);
        assert.equal(false, exists);
        done();
      });
    });
    //Folder that exists
    it('should return true if path exists', function(done)
    {
      return utily.fs.exists(__dirname, function(error, exists)
      {
        assert.equal(null, error);
        assert.equal(true, exists);
        done();
      });
    });
  });

  //Test mkdir method
  describe('-> mkdir method', function()
  {
    //Create a folder
    it('should create the folders', function(done)
    {
      var folders = path.join(__dirname, './new/folders/yeah');
      return utily.fs.mkdir(folders, function(error)
      {
        assert.equal(null, error);
        assert.equal(true, fs.existsSync(folders));
        done();
      });
    });
  });

  //Test size method
  describe('-> size method', function()
  {
    //Check the file size
    it('should get the real file size', function(done)
    {
      var file = path.join(__dirname, './fs-size-test.txt');
      fs.writeFileSync(file, 'This is the content of the \nfile\n', 'utf8');
      return utily.fs.size(file, function(error, size)
      {
        assert.equal(null, error);
        assert.equal(33, size);
        done();
      });
    });
  });

  //Test unlink method
  describe('-> unlink method', function()
  {
    //Delete a list of file
    it('should delete a list of files', function(done)
    {
      var file1 = path.join(__dirname, './fs-unlink-test1.txt');
      var file2 = path.join(__dirname, './fs-unlink-test2.txt');
      fs.writeFileSync(file1, 'Test 1', 'utf8');
      fs.writeFileSync(file2, 'Test 2', 'utf8');
      return utily.fs.unlink([ file1, file2 ], function(error)
      {
        assert.equal(null, error);
        return utily.fs.exists(file1, function(error, exists)
        {
          assert.equal(null, error);
          assert.equal(false, exists);
          return utily.fs.exists(file2, function(error, exists)
          {
            assert.equal(null, error);
            assert.equal(false, exists);
            done();
          });
        });
      });
    });
  });
});

<|endoftext|>


<commit_before>'use strict';
var debugLevel = process.env['NODE_DEBUG_AMQP'] ? 1 : 0;

var DEBUG = debugLevel > 0;

module.exports = function debug () {
  if (DEBUG) console.error.apply(null, arguments);
};

<commit_msg>Simplify debug file<commit_after>'use strict';

var DEBUG = process.env['NODE_DEBUG_AMQP'];

module.exports = function debug () {
  if (DEBUG) console.error.apply(null, arguments);
};

<|endoftext|>


<commit_before>import * as dom from '../utils/dom/index.js'
import Swal from '../sweetalert2.js'
import { swalClasses } from '../utils/classes.js'

/**
 * Show spinner instead of Confirm button
 */
const showLoading = () => {
  let popup = dom.getPopup()
  if (!popup) {
    Swal.fire('')
  }
  popup = dom.getPopup()
  const actions = dom.getActions()
  const confirmButton = dom.getConfirmButton()

  dom.show(actions)
  dom.show(confirmButton)
  dom.addClass([popup, actions], swalClasses.loading)
  confirmButton.disabled = true

  popup.setAttribute('data-loading', true)
  popup.setAttribute('aria-busy', true)
  popup.focus()
}

export {
  showLoading,
  showLoading as enableLoading
}
<commit_msg>fix: use inline-block for confirm button in showLoading() (#1810)<commit_after>import * as dom from '../utils/dom/index.js'
import Swal from '../sweetalert2.js'
import { swalClasses } from '../utils/classes.js'

/**
 * Show spinner instead of Confirm button
 */
const showLoading = () => {
  let popup = dom.getPopup()
  if (!popup) {
    Swal.fire()
  }
  popup = dom.getPopup()
  const actions = dom.getActions()
  const confirmButton = dom.getConfirmButton()

  dom.show(actions)
  dom.show(confirmButton, 'inline-block')
  dom.addClass([popup, actions], swalClasses.loading)
  confirmButton.disabled = true

  popup.setAttribute('data-loading', true)
  popup.setAttribute('aria-busy', true)
  popup.focus()
}

export {
  showLoading,
  showLoading as enableLoading
}
<|endoftext|>


<commit_before>import babelLoader from 'next/dist/compiled/babel-loader'
import hash from 'next/dist/compiled/string-hash'
import { basename, join } from 'path'

// increment 'm' to invalidate cache
// eslint-disable-next-line no-useless-concat
const cacheKey = 'babel-cache-' + 'm' + '-'
const nextBabelPreset = require('../../babel/preset')

const getModernOptions = (babelOptions = {}) => {
  const presetEnvOptions = Object.assign({}, babelOptions['preset-env'])
  const transformRuntimeOptions = Object.assign(
    {},
    babelOptions['transform-runtime'],
    { regenerator: false }
  )

  presetEnvOptions.targets = {
    esmodules: true,
  }
  presetEnvOptions.exclude = [
    ...(presetEnvOptions.exclude || []),
    // Blacklist accidental inclusions
    'transform-regenerator',
    'transform-async-to-generator',
  ]

  return {
    ...babelOptions,
    'preset-env': presetEnvOptions,
    'transform-runtime': transformRuntimeOptions,
  }
}

const nextBabelPresetModern = (presetOptions) => (context) =>
  nextBabelPreset(context, getModernOptions(presetOptions))

module.exports = babelLoader.custom((babel) => {
  const presetItem = babel.createConfigItem(nextBabelPreset, {
    type: 'preset',
  })
  const applyCommonJs = babel.createConfigItem(
    require('../../babel/plugins/commonjs'),
    { type: 'plugin' }
  )
  const commonJsItem = babel.createConfigItem(
    require('@babel/plugin-transform-modules-commonjs'),
    { type: 'plugin' }
  )

  const configs = new Set()

  return {
    customOptions(opts) {
      const custom = {
        isServer: opts.isServer,
        isModern: opts.isModern,
        pagesDir: opts.pagesDir,
        hasModern: opts.hasModern,
        babelPresetPlugins: opts.babelPresetPlugins,
        development: opts.development,
        hasReactRefresh: opts.hasReactRefresh,
      }
      const filename = join(opts.cwd, 'noop.js')
      const loader = Object.assign(
        opts.cache
          ? {
              cacheCompression: false,
              cacheDirectory: join(opts.distDir, 'cache', 'next-babel-loader'),
              cacheIdentifier:
                cacheKey +
                (opts.isServer ? '-server' : '') +
                (opts.isModern ? '-modern' : '') +
                (opts.hasModern ? '-has-modern' : '') +
                '-new-polyfills' +
                (opts.development ? '-development' : '-production') +
                (opts.hasReactRefresh ? '-react-refresh' : '') +
                JSON.stringify(
                  babel.loadPartialConfig({
                    filename,
                    cwd: opts.cwd,
                    sourceFileName: filename,
                  }).options
                ),
            }
          : {
              cacheDirectory: false,
            },
        opts
      )

      delete loader.isServer
      delete loader.cache
      delete loader.distDir
      delete loader.isModern
      delete loader.hasModern
      delete loader.pagesDir
      delete loader.babelPresetPlugins
      delete loader.development
      delete loader.hasReactRefresh
      return { loader, custom }
    },
    config(
      cfg,
      {
        source,
        customOptions: {
          isServer,
          isModern,
          hasModern,
          pagesDir,
          babelPresetPlugins,
          development,
          hasReactRefresh,
        },
      }
    ) {
      const filename = this.resourcePath
      const options = Object.assign({}, cfg.options)
      const isPageFile = filename.startsWith(pagesDir)

      if (cfg.hasFilesystemConfig()) {
        for (const file of [cfg.babelrc, cfg.config]) {
          // We only log for client compilation otherwise there will be double output
          if (file && !isServer && !configs.has(file)) {
            configs.add(file)
            console.log(`> Using external babel configuration`)
            console.log(`> Location: "${file}"`)
          }
        }
      } else {
        // Add our default preset if the no "babelrc" found.
        options.presets = [...options.presets, presetItem]
      }

      options.caller.isServer = isServer
      options.caller.isModern = isModern
      options.caller.isDev = development

      options.plugins = options.plugins || []

      if (hasReactRefresh) {
        const reactRefreshPlugin = babel.createConfigItem(
          [require('react-refresh/babel'), { skipEnvCheck: true }],
          { type: 'plugin' }
        )
        options.plugins.unshift(reactRefreshPlugin)
      }

      if (!isServer && isPageFile) {
        const pageConfigPlugin = babel.createConfigItem(
          [require('../../babel/plugins/next-page-config')],
          { type: 'plugin' }
        )
        options.plugins.push(pageConfigPlugin)
      }

      if (isServer && source.indexOf('next/data') !== -1) {
        const nextDataPlugin = babel.createConfigItem(
          [
            require('../../babel/plugins/next-data'),
            { key: basename(filename) + '-' + hash(filename) },
          ],
          { type: 'plugin' }
        )
        options.plugins.push(nextDataPlugin)
      }

      if (isModern) {
        const nextPreset = options.presets.find(
          (preset) => preset && preset.value === nextBabelPreset
        ) || { options: {} }

        const additionalPresets = options.presets.filter(
          (preset) => preset !== nextPreset
        )

        const presetItemModern = babel.createConfigItem(
          nextBabelPresetModern(nextPreset.options),
          {
            type: 'preset',
          }
        )

        options.presets = [...additionalPresets, presetItemModern]
      }

      // If the file has `module.exports` we have to transpile commonjs because Babel adds `import` statements
      // That break webpack, since webpack doesn't support combining commonjs and esmodules
      if (!hasModern && source.indexOf('module.exports') !== -1) {
        options.plugins.push(applyCommonJs)
      }

      options.plugins.push([
        require.resolve('babel-plugin-transform-define'),
        {
          'process.env.NODE_ENV': development ? 'development' : 'production',
          'typeof window': isServer ? 'undefined' : 'object',
          'process.browser': isServer ? false : true,
        },
        'next-js-transform-define-instance',
      ])

      if (isPageFile) {
        if (!isServer) {
          options.plugins.push([
            require.resolve('../../babel/plugins/next-ssg-transform'),
            {},
          ])
        }
      }

      // As next-server/lib has stateful modules we have to transpile commonjs
      options.overrides = [
        ...(options.overrides || []),
        {
          test: [
            /next[\\/]dist[\\/]next-server[\\/]lib/,
            /next[\\/]dist[\\/]client/,
            /next[\\/]dist[\\/]pages/,
          ],
          plugins: [commonJsItem],
        },
      ]

      for (const plugin of babelPresetPlugins) {
        require(join(plugin.dir, 'src', 'babel-preset-build.js'))(
          options,
          plugin.config || {}
        )
      }

      return options
    },
  }
})
<commit_msg>Update babel config found log to new logging output (#13550)<commit_after>import babelLoader from 'next/dist/compiled/babel-loader'
import hash from 'next/dist/compiled/string-hash'
import { basename, join } from 'path'
import * as Log from '../../output/log'

// increment 'm' to invalidate cache
// eslint-disable-next-line no-useless-concat
const cacheKey = 'babel-cache-' + 'm' + '-'
const nextBabelPreset = require('../../babel/preset')

const getModernOptions = (babelOptions = {}) => {
  const presetEnvOptions = Object.assign({}, babelOptions['preset-env'])
  const transformRuntimeOptions = Object.assign(
    {},
    babelOptions['transform-runtime'],
    { regenerator: false }
  )

  presetEnvOptions.targets = {
    esmodules: true,
  }
  presetEnvOptions.exclude = [
    ...(presetEnvOptions.exclude || []),
    // Blacklist accidental inclusions
    'transform-regenerator',
    'transform-async-to-generator',
  ]

  return {
    ...babelOptions,
    'preset-env': presetEnvOptions,
    'transform-runtime': transformRuntimeOptions,
  }
}

const nextBabelPresetModern = (presetOptions) => (context) =>
  nextBabelPreset(context, getModernOptions(presetOptions))

module.exports = babelLoader.custom((babel) => {
  const presetItem = babel.createConfigItem(nextBabelPreset, {
    type: 'preset',
  })
  const applyCommonJs = babel.createConfigItem(
    require('../../babel/plugins/commonjs'),
    { type: 'plugin' }
  )
  const commonJsItem = babel.createConfigItem(
    require('@babel/plugin-transform-modules-commonjs'),
    { type: 'plugin' }
  )

  const configs = new Set()

  return {
    customOptions(opts) {
      const custom = {
        isServer: opts.isServer,
        isModern: opts.isModern,
        pagesDir: opts.pagesDir,
        hasModern: opts.hasModern,
        babelPresetPlugins: opts.babelPresetPlugins,
        development: opts.development,
        hasReactRefresh: opts.hasReactRefresh,
      }
      const filename = join(opts.cwd, 'noop.js')
      const loader = Object.assign(
        opts.cache
          ? {
              cacheCompression: false,
              cacheDirectory: join(opts.distDir, 'cache', 'next-babel-loader'),
              cacheIdentifier:
                cacheKey +
                (opts.isServer ? '-server' : '') +
                (opts.isModern ? '-modern' : '') +
                (opts.hasModern ? '-has-modern' : '') +
                '-new-polyfills' +
                (opts.development ? '-development' : '-production') +
                (opts.hasReactRefresh ? '-react-refresh' : '') +
                JSON.stringify(
                  babel.loadPartialConfig({
                    filename,
                    cwd: opts.cwd,
                    sourceFileName: filename,
                  }).options
                ),
            }
          : {
              cacheDirectory: false,
            },
        opts
      )

      delete loader.isServer
      delete loader.cache
      delete loader.distDir
      delete loader.isModern
      delete loader.hasModern
      delete loader.pagesDir
      delete loader.babelPresetPlugins
      delete loader.development
      delete loader.hasReactRefresh
      return { loader, custom }
    },
    config(
      cfg,
      {
        source,
        customOptions: {
          isServer,
          isModern,
          hasModern,
          pagesDir,
          babelPresetPlugins,
          development,
          hasReactRefresh,
        },
      }
    ) {
      const filename = this.resourcePath
      const options = Object.assign({}, cfg.options)
      const isPageFile = filename.startsWith(pagesDir)

      if (cfg.hasFilesystemConfig()) {
        for (const file of [cfg.babelrc, cfg.config]) {
          // We only log for client compilation otherwise there will be double output
          if (file && !isServer && !configs.has(file)) {
            configs.add(file)
            Log.info(`Using external babel configuration from ${file}`)
          }
        }
      } else {
        // Add our default preset if the no "babelrc" found.
        options.presets = [...options.presets, presetItem]
      }

      options.caller.isServer = isServer
      options.caller.isModern = isModern
      options.caller.isDev = development

      options.plugins = options.plugins || []

      if (hasReactRefresh) {
        const reactRefreshPlugin = babel.createConfigItem(
          [require('react-refresh/babel'), { skipEnvCheck: true }],
          { type: 'plugin' }
        )
        options.plugins.unshift(reactRefreshPlugin)
      }

      if (!isServer && isPageFile) {
        const pageConfigPlugin = babel.createConfigItem(
          [require('../../babel/plugins/next-page-config')],
          { type: 'plugin' }
        )
        options.plugins.push(pageConfigPlugin)
      }

      if (isServer && source.indexOf('next/data') !== -1) {
        const nextDataPlugin = babel.createConfigItem(
          [
            require('../../babel/plugins/next-data'),
            { key: basename(filename) + '-' + hash(filename) },
          ],
          { type: 'plugin' }
        )
        options.plugins.push(nextDataPlugin)
      }

      if (isModern) {
        const nextPreset = options.presets.find(
          (preset) => preset && preset.value === nextBabelPreset
        ) || { options: {} }

        const additionalPresets = options.presets.filter(
          (preset) => preset !== nextPreset
        )

        const presetItemModern = babel.createConfigItem(
          nextBabelPresetModern(nextPreset.options),
          {
            type: 'preset',
          }
        )

        options.presets = [...additionalPresets, presetItemModern]
      }

      // If the file has `module.exports` we have to transpile commonjs because Babel adds `import` statements
      // That break webpack, since webpack doesn't support combining commonjs and esmodules
      if (!hasModern && source.indexOf('module.exports') !== -1) {
        options.plugins.push(applyCommonJs)
      }

      options.plugins.push([
        require.resolve('babel-plugin-transform-define'),
        {
          'process.env.NODE_ENV': development ? 'development' : 'production',
          'typeof window': isServer ? 'undefined' : 'object',
          'process.browser': isServer ? false : true,
        },
        'next-js-transform-define-instance',
      ])

      if (isPageFile) {
        if (!isServer) {
          options.plugins.push([
            require.resolve('../../babel/plugins/next-ssg-transform'),
            {},
          ])
        }
      }

      // As next-server/lib has stateful modules we have to transpile commonjs
      options.overrides = [
        ...(options.overrides || []),
        {
          test: [
            /next[\\/]dist[\\/]next-server[\\/]lib/,
            /next[\\/]dist[\\/]client/,
            /next[\\/]dist[\\/]pages/,
          ],
          plugins: [commonJsItem],
        },
      ]

      for (const plugin of babelPresetPlugins) {
        require(join(plugin.dir, 'src', 'babel-preset-build.js'))(
          options,
          plugin.config || {}
        )
      }

      return options
    },
  }
})
<|endoftext|>


<commit_before>require('source-map-support').install();

const fs = require('fs');
const path = require('path');
const glob = require('glob');
const rimraf = require('rimraf').sync;
const assert = require('assert');
const child_process = require('child_process');

const degit = require('../index.js');
const degitPath = path.resolve('bin.js');

function exec(cmd) {
	return new Promise((fulfil, reject) => {
		child_process.exec(cmd, (err, stdout, stderr) => {
			if (err) return reject(err);
			console.log(stdout);
			console.error(stderr);
			fulfil();
		});
	});
}

describe('degit', () => {
	function compare(dir, files) {
		const expected = glob.sync('**', { cwd: dir });
		assert.deepEqual(Object.keys(files).sort(), expected.sort());

		expected.forEach(file => {
			assert.equal(files[file].trim(), read(`${dir}/${file}`).trim());
		});
	}

	describe('github', () => {
		beforeEach(() => rimraf('.tmp'));

		[
			'Rich-Harris/degit-test-repo',
			'github:Rich-Harris/degit-test-repo',
			'git@github.com:Rich-Harris/degit-test-repo',
			'https://github.com/Rich-Harris/degit-test-repo.git'
		].forEach(src => {
			it(src, async () => {
				await exec(`node ${degitPath} ${src} .tmp/test-repo -v`);
				compare(`.tmp/test-repo`, {
					'file.txt': 'hello from github!'
				});
			});
		});
	});

	describe('gitlab', () => {
		beforeEach(() => rimraf('.tmp'));

		[
			'gitlab:Rich-Harris/degit-test-repo',
			'git@gitlab.com:Rich-Harris/degit-test-repo',
			'https://gitlab.com/Rich-Harris/degit-test-repo.git'
		].forEach(src => {
			it(src, async () => {
				await exec(`node ${degitPath} ${src} .tmp/test-repo -v`);
				compare(`.tmp/test-repo`, {
					'file.txt': 'hello from gitlab!'
				});
			});
		});
	});

	describe('bitbucket', () => {
		beforeEach(() => rimraf('.tmp'));

		[
			'bitbucket:Rich_Harris/degit-test-repo',
			'git@bitbucket.org:Rich_Harris/degit-test-repo',
			'https://bitbucket.org/Rich_Harris/degit-test-repo.git'
		].forEach(src => {
			it(src, async () => {
				await exec(`node ${degitPath} ${src} .tmp/test-repo -v`);
				compare(`.tmp/test-repo`, {
					'file.txt': 'hello from bitbucket'
				});
			});
		});
	});

	describe('non-empty directories', () => {
		it('fails without --force', async () => {
			let succeeded;

			try {
				await exec(`echo "not empty" > .tmp/test-repo/file.txt`);
				await exec(`node ${degitPath} Rich-Harris/degit-test-repo .tmp/test-repo -v`);
				succeeded = true;
			} catch (err) {
				assert.ok(/destination directory is not empty/.test(err.message));
			}

			assert.ok(!succeeded);
		});

		it('succeeds with --force', async () => {
			await exec(`node ${degitPath} Rich-Harris/degit-test-repo .tmp/test-repo -fv`);
		});
	});

	describe('command line arguments', () => {
		it('allows flags wherever', async () => {
			await rimraf('.tmp');

			await exec(`node ${degitPath} -v Rich-Harris/degit-test-repo .tmp/test-repo`);
			compare(`.tmp/test-repo`, {
				'file.txt': 'hello from github!'
			});
		});
	});

	describe('api', () => {
		it('is usable from node scripts', async () => {
			await degit('Rich-Harris/degit-test-repo', { force: true }).clone('.tmp/test-repo');

			compare(`.tmp/test-repo`, {
				'file.txt': 'hello from github!'
			});
		});
	});

	describe('git mode', () => {
		it('is able to clone correctly using git mode', async () => {
			await rimraf('.tmp');

			await exec(`node ${degitPath} --mode=git https://github.com/Rich-Harris/degit-test-repo.git .tmp/test-repo`);
			compare('.tmp/test-repo', {
				'file.txt': 'hello from github!'
			});
		});
	});
});

function read(file) {
	return fs.readFileSync(file, 'utf-8');
}<commit_msg>Making tests a little more forgiving of git being slow.<commit_after>require('source-map-support').install();

const fs = require('fs');
const path = require('path');
const glob = require('glob');
const rimraf = require('rimraf').sync;
const assert = require('assert');
const child_process = require('child_process');

const degit = require('../index.js');
const degitPath = path.resolve('bin.js');

function exec(cmd) {
	return new Promise((fulfil, reject) => {
		child_process.exec(cmd, (err, stdout, stderr) => {
			if (err) return reject(err);
			console.log(stdout);
			console.error(stderr);
			fulfil();
		});
	});
}

describe('degit', () => {
	function compare(dir, files) {
		const expected = glob.sync('**', { cwd: dir });
		assert.deepEqual(Object.keys(files).sort(), expected.sort());

		expected.forEach(file => {
			assert.equal(files[file].trim(), read(`${dir}/${file}`).trim());
		});
	}

	describe('github', () => {
		beforeEach(() => rimraf('.tmp'));

		[
			'Rich-Harris/degit-test-repo',
			'github:Rich-Harris/degit-test-repo',
			'git@github.com:Rich-Harris/degit-test-repo',
			'https://github.com/Rich-Harris/degit-test-repo.git'
		].forEach(src => {
			it(src, async () => {
				await exec(`node ${degitPath} ${src} .tmp/test-repo -v`);
				compare(`.tmp/test-repo`, {
					'file.txt': 'hello from github!'
				});
			});
		});
	});

	describe('gitlab', () => {
		beforeEach(() => rimraf('.tmp'));

		[
			'gitlab:Rich-Harris/degit-test-repo',
			'git@gitlab.com:Rich-Harris/degit-test-repo',
			'https://gitlab.com/Rich-Harris/degit-test-repo.git'
		].forEach(src => {
			it(src, async () => {
				await exec(`node ${degitPath} ${src} .tmp/test-repo -v`);
				compare(`.tmp/test-repo`, {
					'file.txt': 'hello from gitlab!'
				});
			});
		});
	});

	describe('bitbucket', () => {
		beforeEach(() => rimraf('.tmp'));

		[
			'bitbucket:Rich_Harris/degit-test-repo',
			'git@bitbucket.org:Rich_Harris/degit-test-repo',
			'https://bitbucket.org/Rich_Harris/degit-test-repo.git'
		].forEach(src => {
			it(src, async () => {
				await exec(`node ${degitPath} ${src} .tmp/test-repo -v`);
				compare(`.tmp/test-repo`, {
					'file.txt': 'hello from bitbucket'
				});
			});
		});
	});

	describe('non-empty directories', () => {
		it('fails without --force', async () => {
			let succeeded;

			try {
				await exec(`echo "not empty" > .tmp/test-repo/file.txt`);
				await exec(`node ${degitPath} Rich-Harris/degit-test-repo .tmp/test-repo -v`);
				succeeded = true;
			} catch (err) {
				assert.ok(/destination directory is not empty/.test(err.message));
			}

			assert.ok(!succeeded);
		});

		it('succeeds with --force', async () => {
			await exec(`node ${degitPath} Rich-Harris/degit-test-repo .tmp/test-repo -fv`);
		});
	});

	describe('command line arguments', () => {
		it('allows flags wherever', async () => {
			await rimraf('.tmp');

			await exec(`node ${degitPath} -v Rich-Harris/degit-test-repo .tmp/test-repo`);
			compare(`.tmp/test-repo`, {
				'file.txt': 'hello from github!'
			});
		});
	});

	describe('api', () => {
		it('is usable from node scripts', async () => {
			await degit('Rich-Harris/degit-test-repo', { force: true }).clone('.tmp/test-repo');

			compare(`.tmp/test-repo`, {
				'file.txt': 'hello from github!'
			});
		});
	});

	describe('git mode', () => {
		beforeEach(function() {
			// this method is notably slower
			this.timeout(750);
		});

		it('is able to clone correctly using git mode', async () => {
			await rimraf('.tmp');

			await exec(`node ${degitPath} --mode=git https://github.com/Rich-Harris/degit-test-repo.git .tmp/test-repo`);
			compare('.tmp/test-repo', {
				'file.txt': 'hello from github!'
			});
		});
	});
});

function read(file) {
	return fs.readFileSync(file, 'utf-8');
}<|endoftext|>


<commit_before>var _    = require('lodash');

var fs    = require('fs');
var spawn = require('child_process').spawn;
var join  = require('path').join;
var shell = require('shelljs');

module.exports = function ($){
  return new App($);
};

function App($) {
  this.$ = $;
  this.log = require('./log')($, 'electrify:app');
}

App.prototype.terminate = function(){
  this.$.electron.terminate();
};

App.prototype.run = function(done){
  this.log.info('running app');
  this.$.scaffold.prepare();
  this.$.waterfal([
    [this.$.electron.ensure_deps            , this.$.electron ] ,
    [this.ensure_deps                       , this            ] ,
    [this.$.plugins.auto_load               , this.$.plugins  ] ,
    [this.$.plugins.acquire                 , this.$.plugins  ] ,
    [this.$.plugins.start                   , this.$.plugins  ] ,
    [this.start_meteor                      , this            ] ,
    [this.$.electron.launch                 , this.$.electron ] ,
    [function(){ if(done) done(); }         , null            ]
  ]);
};

App.prototype.start_meteor = function(done){
  this.log.info('starting meteor');
  spawn('meteor' + (this.$.env.sys.is_windows ? '.bat' : ''), [], {
    cwd: this.$.env.app,
    env: _.extend(this.$.plugins.env(), process.env),
    stdio: 'inherit'
  });

  this.$.plugins.get('nodejs').meteor_ready('http://localhost:3000', done);
};

App.prototype.bundle = function(done){
  this.log.info('bundling app');
  this.$.scaffold.prepare();
  this.$.waterfal([
    [this.$.electron.ensure_deps            , this.$.electron ] ,
    [this.ensure_deps                       , this.$.plugins  ] ,
    [this.$.plugins.auto_load               , this.$.plugins  ] ,
    [this.$.plugins.acquire                 , this.$.plugins  ] ,
    [this.bundle_meteor                     , this            ] ,
    [function(){ if(done) done(); }         , null            ]
  ]);
};

App.prototype.package = function(done){
  var self = this;
  this.bundle(function(){
    self.$.electron.package(function(){
      if(done) done();
    });
  });
};

App.prototype.bundle_meteor = function( /* server_url, */ done) {
  this.log.info('bundling meteor');

  var tmp_dir             = join(this.$.env.core.tmp, 'bundling');
  var bundled_dir         = join(tmp_dir, 'bundle');
  var electrify_app_dir   = join(this.$.env.app.electrify, 'app');
  var programs_server_dir = join(electrify_app_dir, 'programs', 'server');

  // resetting folders
  shell.rm('-rf', tmp_dir);
  shell.mkdir('-p', tmp_dir);

  // bundle meteor
  var self = this;
  spawn('meteor' + (this.$.env.sys.is_windows ? '.bat' : ''), [
      'build', tmp_dir,
      '--server', null,
      // '--server', (server_url !== undefined ? server_url : null),
      '--directory'
    ], {
      cwd: this.$.env.app.electrify,
      stdio: this.$.env.stdio
    }
  ).on('exit', function(){

    // inject meteor's settings file within the bundled app
    fs.writeFileSync(
      join(bundled_dir, 'settings.json'),
      JSON.stringify(self.$.env.app.settings, null, 2)
    );

    // move bundled meteor into .electrify
    shell.rm('-rf', electrify_app_dir);
    shell.mv(bundled_dir, electrify_app_dir);
    shell.rm('-rf', tmp_dir);

    self.log.info('ensuring meteor dependencies');

    // instead of entering the folder and doing an usual `npm install`, which
    // would imply in another bugs around node-fibers native re-build with
    // node-gyp, we just copy the whole `node_modules` folder that is officially
    // distributed with meteor, its 'ready to go and doesn't need to be rebuilt
    shell.cp('-r', self.$.env.meteor.server_modules, programs_server_dir);

    if(done) done();
  });
};

App.prototype.ensure_deps = function(done) {

  // skips installing local dependencies in dev mode so node will walk up the
  // dirs until an ypper `node_modules` folder is found, in which case the
  // folder will be a synlink to the electrify source. In case you're wondering
  // why its really necessary, take a look at the `CONTRIBUTING.md` file in
  // the repo root
  if(this.$.env.is_development_mode) return done();

  // fetch version infos
  var pkg_path    = join(this.$.env.app.electrify, 'package.json');
  var pkg_version = require(pkg_path).dependencies.electrify;
  var version     = this.$.env.version;

  // check and warn users about electrify versions mismatch
  if(pkg_version != version) {
    this.log.error([
      "{{IMPORTANT}} Your local electrify npm package must match version",
      version,
      " -- please update it to avoid errors"
    ].join(' '));
  }

  this.log.info('ensuring electrify dependencies');
  spawn(this.$.env.meteor.node, [this.$.env.meteor.npm, 'i', '--production'], {
    cwd: this.$.env.app.electrify,
    stdio: this.$.env.stdio
  }).on('exit', done);
};<commit_msg>changing log type<commit_after>var _    = require('lodash');

var fs    = require('fs');
var spawn = require('child_process').spawn;
var join  = require('path').join;
var shell = require('shelljs');

module.exports = function ($){
  return new App($);
};

function App($) {
  this.$ = $;
  this.log = require('./log')($, 'electrify:app');
}

App.prototype.terminate = function(){
  this.$.electron.terminate();
};

App.prototype.run = function(done){
  this.log.info('running app');
  this.$.scaffold.prepare();
  this.$.waterfal([
    [this.$.electron.ensure_deps            , this.$.electron ] ,
    [this.ensure_deps                       , this            ] ,
    [this.$.plugins.auto_load               , this.$.plugins  ] ,
    [this.$.plugins.acquire                 , this.$.plugins  ] ,
    [this.$.plugins.start                   , this.$.plugins  ] ,
    [this.start_meteor                      , this            ] ,
    [this.$.electron.launch                 , this.$.electron ] ,
    [function(){ if(done) done(); }         , null            ]
  ]);
};

App.prototype.start_meteor = function(done){
  this.log.info('starting meteor');
  spawn('meteor' + (this.$.env.sys.is_windows ? '.bat' : ''), [], {
    cwd: this.$.env.app,
    env: _.extend(this.$.plugins.env(), process.env),
    stdio: 'inherit'
  });

  this.$.plugins.get('nodejs').meteor_ready('http://localhost:3000', done);
};

App.prototype.bundle = function(done){
  this.log.info('bundling app');
  this.$.scaffold.prepare();
  this.$.waterfal([
    [this.$.electron.ensure_deps            , this.$.electron ] ,
    [this.ensure_deps                       , this.$.plugins  ] ,
    [this.$.plugins.auto_load               , this.$.plugins  ] ,
    [this.$.plugins.acquire                 , this.$.plugins  ] ,
    [this.bundle_meteor                     , this            ] ,
    [function(){ if(done) done(); }         , null            ]
  ]);
};

App.prototype.package = function(done){
  var self = this;
  this.bundle(function(){
    self.$.electron.package(function(){
      if(done) done();
    });
  });
};

App.prototype.bundle_meteor = function( /* server_url, */ done) {
  this.log.info('bundling meteor');

  var tmp_dir             = join(this.$.env.core.tmp, 'bundling');
  var bundled_dir         = join(tmp_dir, 'bundle');
  var electrify_app_dir   = join(this.$.env.app.electrify, 'app');
  var programs_server_dir = join(electrify_app_dir, 'programs', 'server');

  // resetting folders
  shell.rm('-rf', tmp_dir);
  shell.mkdir('-p', tmp_dir);

  // bundle meteor
  var self = this;
  spawn('meteor' + (this.$.env.sys.is_windows ? '.bat' : ''), [
      'build', tmp_dir,
      '--server', null,
      // '--server', (server_url !== undefined ? server_url : null),
      '--directory'
    ], {
      cwd: this.$.env.app.electrify,
      stdio: this.$.env.stdio
    }
  ).on('exit', function(){

    // inject meteor's settings file within the bundled app
    fs.writeFileSync(
      join(bundled_dir, 'settings.json'),
      JSON.stringify(self.$.env.app.settings, null, 2)
    );

    // move bundled meteor into .electrify
    shell.rm('-rf', electrify_app_dir);
    shell.mv(bundled_dir, electrify_app_dir);
    shell.rm('-rf', tmp_dir);

    self.log.info('ensuring meteor dependencies');

    // instead of entering the folder and doing an usual `npm install`, which
    // would imply in another bugs around node-fibers native re-build with
    // node-gyp, we just copy the whole `node_modules` folder that is officially
    // distributed with meteor, its 'ready to go and doesn't need to be rebuilt
    shell.cp('-r', self.$.env.meteor.server_modules, programs_server_dir);

    if(done) done();
  });
};

App.prototype.ensure_deps = function(done) {

  // skips installing local dependencies in dev mode so node will walk up the
  // dirs until an ypper `node_modules` folder is found, in which case the
  // folder will be a synlink to the electrify source. In case you're wondering
  // why its really necessary, take a look at the `CONTRIBUTING.md` file in
  // the repo root
  if(this.$.env.is_development_mode) return done();

  // fetch version infos
  var pkg_path    = join(this.$.env.app.electrify, 'package.json');
  var pkg_version = require(pkg_path).dependencies.electrify;
  var version     = this.$.env.version;

  // check and warn users about electrify versions mismatch
  if(pkg_version != version) {
    this.log.warn([
      "{{IMPORTANT}} Your local electrify npm package must match version",
      version,
      " -- please update it to avoid errors"
    ].join(' '));
  }

  this.log.info('ensuring electrify dependencies');
  spawn(this.$.env.meteor.node, [this.$.env.meteor.npm, 'i', '--production'], {
    cwd: this.$.env.app.electrify,
    stdio: this.$.env.stdio
  }).on('exit', done);
};<|endoftext|>