<commit_before>/**
 * Copyright 2013 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');

/**
 * @const
 * @private
 * Path to the temporary directory.
 * @type {String}
 */
Cache.TMP_DIR_ = __dirname + '/../.cache';

/**
 * @const
 * @private
 * Default encoding for cached files.
 * @type {String}
 */
Cache.ENCODING_ = 'utf-8';

/**
 * @const
 * @private
 * Default expires time in micro seconds.
 * @type {Number}
 */
Cache.EXPIRES_IN_ = 5 * 60 * 1000;

/**
 * @constructor
 * Cache constructor.
 * @param  {String} opt_opts  Optional options.
 */
function Cache(opt_opts) {
  this.opts = opt_opts || {};
  this.opts.path = this.opts.path || Cache.TMP_DIR_;
  if (!fs.existsSync(this.opts.path)) {
    fs.mkdirSync(this.opts.path, '700');
  }
}

/**
 * Loads discovery data from cache
 * @param  {object} api
 * @return {object?} Returns the cached discovery data if exists
 *                   or not expired.
 */
Cache.prototype.load = function(api) {
  var path = this.getPath(api);
  // check if file exists and not expired
  if (!fs.existsSync(path)) {
    return null;
  }

  if (this.isExpired(path)) {
    // delete the expired cache file
    fs.unlinkSync(path);
    return null;
  }

  var data = fs.readFileSync(this.getPath(api), Cache.ENCODING_);
  return data && JSON.parse(data);
};

/**
 * Writes api discovery data to the cache.
 * @param  {object} api
 * @param  {object} data
 */
Cache.prototype.write = function(api, data) {
  data && fs.writeFileSync(
      this.getPath(api), JSON.stringify(data), Cache.ENCODING_);
};

/**
 * Checks whether the file at path is expired or not
 * @param  {[type]}  path The path of the file to check.
 * @return {Boolean}      Returns true or false depending on the expiration.
 */
Cache.prototype.isExpired = function(path) {
  var expiresIn = this.opts.expiresIn || Cache.EXPIRES_IN_;
  return new Date(fs.statSync(path).mtime).getTime() - expiresIn < 0;
};

/**
 * Gets the path where the api data is stored at.
 * @param  {[type]} api
 * @return {string} Path to the data file.
 */
Cache.prototype.getPath = function(api) {
  return this.opts.path + '/' + api.name + api.version + '-rest';
};

/**
 * Exports Cache.
 * @type {Cache}
 */
module.exports = Cache;
<commit_msg>Fix cache expiry logic.<commit_after>/**
 * Copyright 2013 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

var fs = require('fs');

/**
 * @const
 * @private
 * Path to the temporary directory.
 * @type {String}
 */
Cache.TMP_DIR_ = __dirname + '/../.cache';

/**
 * @const
 * @private
 * Default encoding for cached files.
 * @type {String}
 */
Cache.ENCODING_ = 'utf-8';

/**
 * @const
 * @private
 * Default expires time in micro seconds.
 * @type {Number}
 */
Cache.EXPIRES_IN_ = 5 * 60 * 1000;

/**
 * @constructor
 * Cache constructor.
 * @param  {String} opt_opts  Optional options.
 */
function Cache(opt_opts) {
  this.opts = opt_opts || {};
  this.opts.path = this.opts.path || Cache.TMP_DIR_;
  if (!fs.existsSync(this.opts.path)) {
    fs.mkdirSync(this.opts.path, '700');
  }
}

/**
 * Loads discovery data from cache
 * @param  {object} api
 * @return {object?} Returns the cached discovery data if exists
 *                   or not expired.
 */
Cache.prototype.load = function(api) {
  var path = this.getPath(api);
  // check if file exists and not expired
  if (!fs.existsSync(path)) {
    return null;
  }

  if (this.isExpired(path)) {
    // delete the expired cache file
    fs.unlinkSync(path);
    return null;
  }

  var data = fs.readFileSync(this.getPath(api), Cache.ENCODING_);
  return data && JSON.parse(data);
};

/**
 * Writes api discovery data to the cache.
 * @param  {object} api
 * @param  {object} data
 */
Cache.prototype.write = function(api, data) {
  data && fs.writeFileSync(
      this.getPath(api), JSON.stringify(data), Cache.ENCODING_);
};

/**
 * Checks whether the file at path is expired or not
 * @param  {[type]}  path The path of the file to check.
 * @return {Boolean}      Returns true or false depending on the expiration.
 */
Cache.prototype.isExpired = function(path) {
  var expiresIn = this.opts.expiresIn || Cache.EXPIRES_IN_;
  return Date.now() - new Date(fs.statSync(path).mtime).getTime() > expiresIn;
};

/**
 * Gets the path where the api data is stored at.
 * @param  {[type]} api
 * @return {string} Path to the data file.
 */
Cache.prototype.getPath = function(api) {
  return this.opts.path + '/' + api.name + api.version + '-rest';
};

/**
 * Exports Cache.
 * @type {Cache}
 */
module.exports = Cache;
<|endoftext|>


<commit_before>/**
 * WP Present - admin.js
 *
 */

var WPPAdmin;
(function($) {

	WPPAdmin = function() {
		this.init();
		return this;
	}

	WPPAdmin.prototype = {
		init: function() {
			var self = this;

			self.widgetButtonExpand();
			self.widgetButtonEdit();
			self.widgetButtonDelete();
			self.widgetButtonAdd();
			self.widgetButtonTidy();
			self.uiSetup();
			self.columnHandle();

			// Select the first column on load
			self.activateColumn( $('#col-1').children('.widget-top').children('.widget-title') );

			return self;
		},

		// Sortables and such
		uiSetup: function () {
			var self = this;

			// Make the outer container resizeable
			$( "#outer-container" ).resizable();

			self.backfillSlides();

			$( ".column-inner" ).sortable({
				connectWith: ".column-inner",
				stop: function( event, ui ) {
					self.updateColumns();
				}
			});

			$( "#container" ).sortable({
				stop: function( event, ui ) {
					self.updateColumns();
				}
			});

			self.updateColumns();
			$( ".column-inner" ).disableSelection();

			// Append an inner column to each column that doesn't contain any slides.
			jQuery('.column' ).not(":has(div.column-inner)").append('

');

			$( ".column-inner" ).sortable({
				connectWith: ".column-inner",
				stop: function( event, ui ) {
					self.updateColumns();
				}
			});
		},

		/**
		 * Close Modal
		 */
		closeModal: function() {
			tinymce.execCommand('mceRemoveControl',true,'editor_slide');
			$( '#dialog' ).dialog( "close" );
		},

		/**
		 * Backfill Slides
		 */
		backfillSlides: function () {
			var numSlides = WPPNumSlides;
			var numExisting = $('#container > .column').size();

			for (var col=numExisting+1;col<=numSlides;col++){
				$('#container').append( '

'+col+'

' );
			}
			$('#container').append( '

' );
		},

		/**
		 * Make the column the target for adding new columns
		 */
		activateColumn: function ( $col ) {
			// Remove the active class from all columns
			$('.widget-title').css('background', '');
			$('.widget-title').css('color', '');
			$('.widget-title').removeClass('active');

			// Select the given column
			$col.css('background-color', '#e14d43').css('color','#ffffff');
			$col.addClass('active');
		},

		/**
		 * update columns
		 */
		updateColumns: function () {
			var self = this;
			var columns = { }; // Creates a new object
			var i = 1;
			$( '.column-inner' ).each(function( index ) {
				var $order = $(this).sortable( "toArray" );
				columns['col-'+i] = $order;
				i++;
			});
			var encoded = JSON.stringify( columns );
			$('#description').val(encoded);

			// Send this change off to ajax land
			self.updatePresentation();
		},

//Dude this is not okay. Fix the post data ajax call

		/**
		 * AJAX request to update the current presentation taxonomy
		 */
		updatePresentation: function () {
			var params = { content: $('#description').val() };
			$.ajax({
				url: ajaxurl + '?action=update_presentation&id=' + presentation,
				type: 'POST',
				data: jQuery.param(params),
				beforeSend: function( xhr ) {
					$('.spinner').show();
				},
				complete: function( xhr ) {
					$('.spinner').hide();
				},
				success: function(result) {
					// Return the excerpt from the editor
					//console.log('presentation updated');
				}
			});
		},

		/**
		 * Bind Tidy button
		 */
		widgetButtonTidy: function () {
			var self = this;
			$('.action-buttons').on('click', '#tidy-button', function(e) {
				e.preventDefault();
				this.consolidateColumns();
				// Why does this break?
				//updatePresentation();
			});
		},

		/**
		 * Expand slide details
		 */
		widgetButtonExpand: function () {
			$('.column').on('click', '.widget-title-action', function(e) {
				$( this ).parents('.widget').children('.widget-inside').toggle();
			});
		},

		/**
		 * The action taken by the Tidy button
		 */
		consolidateColumns: function () {
			var self = this;
			var numCols = $('.column').length;
			// console.log(numCols);

			$('.column').each(function(outerIndex){

				// Don't have a col 0
				var outerIndex = outerIndex + 1;

				// Fixes the condition where we are looking at the last item
				if( outerIndex >= numCols )
					return;

				var $outerCol = $(this);
				var $innerCol = $outerCol.children('.column-inner');

				var innerHTML = $innerCol.html().trim();
				var outerHTML = $outerCol.html().trim();

				if( typeof(innerHTML) !== 'string' || '' == innerHTML ) {
					var $nextOuterCol = $('#col-'+(outerIndex+1));
					var $nextInnerCol = $nextOuterCol.children('.column-inner');

					var nextInnerHTML = $nextInnerCol.html().trim();
					var nextOuterHTML = $nextOuterCol.html().trim();

					$outerCol.html(nextOuterHTML);
					$nextOuterCol.html(outerHTML);
				}
			} );

			//Finally refresh description array
			$( ".column-inner" ).sortable({
				connectWith: ".column-inner",
				stop: (function( event, ui ) {
					self.updateColumns();
				}),
				create: (function( event, ui ) {
					self.updateColumns();
				})
			});
			self.updateColumns();
		},

		columnHandle: function () {
			var self = this;
			$('.column').children('.widget-top').on('click', '.widget-title', function(e) {
				$col = $(this);
				self.activateColumn($col);
			});
		},

		// Bind Edit button
		widgetButtonEdit: function () {
			var self = this;
			$('.column').on('click', '.widget-control-edit', function(e) {
				e.preventDefault();
				var $button = $(this);
				var $parentWidget = $button.parents('.widget');
				var $widgetPreview = $parentWidget.find('.widget-preview');

				// Send the contents from the widget to the editor
				var contentEditor  = $widgetPreview.html();
				var widgetID = $parentWidget.find('.slide-id').val();

				$('#editor_slide-tmce').click(); //Necessary on subsequent loads of the editor
				$( "#dialog" ).dialog({
				  autoOpen: true,
				  width: 640,
				  height: 640,
				  modal: false,
				  buttons: {
					"Update": function() {
						var editorContents = tinymce.get('editor_slide').getContent();
						var params = { content:editorContents };
						// Send the contents of the existing post
						$.ajax({
							url: ajaxurl + '?action=update_slide&id=' + widgetID,
							type: 'POST',
							data: jQuery.param(params),
							beforeSend: function( xhr ) {
								$('.spinner').show();
							},
							complete: function( xhr ) {
								$('.spinner').hide();
							},
							success: function(result) {
								// Return the excerpt from the editor
								$widgetPreview.html( result );
						  }
						});
						self.closeModal();
					},
					Cancel: function() {
						self.closeModal();
					}
				  },
				  create: function() {
						tinymce.execCommand('mceRemoveControl',true,'editor_slide');
						tinymce.execCommand('mceAddControl',true,'editor_slide');
				  },
				  open: function() {
						// Load the contents of the existing post
						$.ajax({
							url: ajaxurl + '?action=get_slide&id=' + widgetID,
							beforeSend: function( xhr ) {
								$('.spinner').show();
							},
							complete: function( xhr ) {
								$('.spinner').hide();
							},
							success: function(contentEditor) {
								tinymce.get('editor_slide').setContent(contentEditor);
							}
						});

						// Hack for getting the reveal class added to tinymce editor body
						// @todo: look at wp_editor in wp/inc/class-wp-editor.php
						var $editorIframe = $('#editor_slide_ifr').contents();
						$editorIframe.find('body').addClass('reveal');
						$editorIframe.css('height','500px');

				  },
				  close: function() {
						self.closeModal();
				  }
				});
			});
		},

		// Bind Delete button
		widgetButtonDelete: function () {
			var self = this;
			$('.column').on('click', '.widget-control-remove', function(e) {
				e.preventDefault();

				var confirmDelete = confirm("You are about to permanently delete the selected items. 'Cancel' to stop, 'OK' to delete.");
				if( false == confirmDelete )
					return;

				var $button = $(this);
				var $parentWidget = $button.parents('.widget');
				var widgetID = $parentWidget.find('.slide-id').val();
				var params = null;

				$.ajax({
					url: ajaxurl + '?action=delete_slide&id=' + widgetID,
					type: 'POST',
					//data: jQuery.param(params),
					beforeSend: function( xhr ) {
						$('.spinner').show();
					},
					complete: function( xhr ) {
						$('.spinner').hide();
					},
					success: function(result) {
						$parentWidget.remove();
						self.updateColumns();
					}
				});
			});
		},

		// Bind Add button
		widgetButtonAdd: function () {
			var self = this;
			$('.action-buttons').on('click', '#add-button', function(e) {
				e.preventDefault();
				var $button = $(this);
				var $activeColumn = $('.widget-title.active').parent('.widget-top').parent('.column').children('.column-inner');

				$('#editor_slide-tmce').click(); //Necessary on subsequent loads of the editor
				$( "#dialog" ).dialog({
				  autoOpen: true,
				  width: 600,
				  height: 600,
				  modal: false,
				  buttons: {
					"Publish": function() {
						var editorContents = tinymce.get('editor_slide').getContent();
						var params = { content:editorContents };
						// Send the contents of the existing post
						$.ajax({
							url: ajaxurl + '?action=new_slide&presentation=' + presentation,
							type: 'POST',
							data: jQuery.param(params),
							success: function(result) {
								$activeColumn.append(result);
								self.updateColumns();
						  }
						});
						self.updateColumns();
						self.closeModal();
					},
					Cancel: function() {
						self.closeModal();
					}
				  },
				  create: function() {
						tinymce.execCommand('mceRemoveControl',true,'editor_slide');
						tinymce.execCommand('mceAddControl',true,'editor_slide');
				  },
				  open: function() {
						// Clear the editor
						tinymce.get('editor_slide').setContent('');
						// Hack for getting the reveal class added to tinymce editor body
						var $editorIframe = $('#editor_slide_ifr').contents();
						$editorIframe.find('body').addClass('reveal');
				  },
				  close: function() {
						self.closeModal();
				  }
				});
			});
		}

	};

})(jQuery);
var slideManager = new WPPAdmin();<commit_msg>Renames WPPAdmin object to WPPresentAdmin<commit_after>/**
 * WP Present - admin.js
 *
 */

var WPPresentAdmin;
(function($) {

	WPPresentAdmin = function() {
		this.init();
		return this;
	}

	WPPresentAdmin.prototype = {
		init: function() {
			var self = this;

			self.widgetButtonExpand();
			self.widgetButtonEdit();
			self.widgetButtonDelete();
			self.widgetButtonAdd();
			self.widgetButtonTidy();
			self.uiSetup();
			self.columnHandle();

			// Select the first column on load
			self.activateColumn( $('#col-1').children('.widget-top').children('.widget-title') );

			return self;
		},

		// Sortables and such
		uiSetup: function () {
			var self = this;

			// Make the outer container resizeable
			$( "#outer-container" ).resizable();

			self.backfillSlides();

			$( ".column-inner" ).sortable({
				connectWith: ".column-inner",
				stop: function( event, ui ) {
					self.updateColumns();
				}
			});

			$( "#container" ).sortable({
				stop: function( event, ui ) {
					self.updateColumns();
				}
			});

			self.updateColumns();
			$( ".column-inner" ).disableSelection();

			// Append an inner column to each column that doesn't contain any slides.
			jQuery('.column' ).not(":has(div.column-inner)").append('

');

			$( ".column-inner" ).sortable({
				connectWith: ".column-inner",
				stop: function( event, ui ) {
					self.updateColumns();
				}
			});
		},

		/**
		 * Close Modal
		 */
		closeModal: function() {
			tinymce.execCommand('mceRemoveControl',true,'editor_slide');
			$( '#dialog' ).dialog( "close" );
		},

		/**
		 * Backfill Slides
		 */
		backfillSlides: function () {
			var numSlides = WPPNumSlides;
			var numExisting = $('#container > .column').size();

			for (var col=numExisting+1;col<=numSlides;col++){
				$('#container').append( '

'+col+'

' );
			}
			$('#container').append( '

' );
		},

		/**
		 * Make the column the target for adding new columns
		 */
		activateColumn: function ( $col ) {
			// Remove the active class from all columns
			$('.widget-title').css('background', '');
			$('.widget-title').css('color', '');
			$('.widget-title').removeClass('active');

			// Select the given column
			$col.css('background-color', '#e14d43').css('color','#ffffff');
			$col.addClass('active');
		},

		/**
		 * update columns
		 */
		updateColumns: function () {
			var self = this;
			var columns = { }; // Creates a new object
			var i = 1;
			$( '.column-inner' ).each(function( index ) {
				var $order = $(this).sortable( "toArray" );
				columns['col-'+i] = $order;
				i++;
			});
			var encoded = JSON.stringify( columns );
			$('#description').val(encoded);

			// Send this change off to ajax land
			self.updatePresentation();
		},

//Dude this is not okay. Fix the post data ajax call

		/**
		 * AJAX request to update the current presentation taxonomy
		 */
		updatePresentation: function () {
			var params = { content: $('#description').val() };
			$.ajax({
				url: ajaxurl + '?action=update_presentation&id=' + presentation,
				type: 'POST',
				data: jQuery.param(params),
				beforeSend: function( xhr ) {
					$('.spinner').show();
				},
				complete: function( xhr ) {
					$('.spinner').hide();
				},
				success: function(result) {
					// Return the excerpt from the editor
					//console.log('presentation updated');
				}
			});
		},

		/**
		 * Bind Tidy button
		 */
		widgetButtonTidy: function () {
			var self = this;
			$('.action-buttons').on('click', '#tidy-button', function(e) {
				e.preventDefault();
				this.consolidateColumns();
				// Why does this break?
				//updatePresentation();
			});
		},

		/**
		 * Expand slide details
		 */
		widgetButtonExpand: function () {
			$('.column').on('click', '.widget-title-action', function(e) {
				$( this ).parents('.widget').children('.widget-inside').toggle();
			});
		},

		/**
		 * The action taken by the Tidy button
		 */
		consolidateColumns: function () {
			var self = this;
			var numCols = $('.column').length;
			// console.log(numCols);

			$('.column').each(function(outerIndex){

				// Don't have a col 0
				var outerIndex = outerIndex + 1;

				// Fixes the condition where we are looking at the last item
				if( outerIndex >= numCols )
					return;

				var $outerCol = $(this);
				var $innerCol = $outerCol.children('.column-inner');

				var innerHTML = $innerCol.html().trim();
				var outerHTML = $outerCol.html().trim();

				if( typeof(innerHTML) !== 'string' || '' == innerHTML ) {
					var $nextOuterCol = $('#col-'+(outerIndex+1));
					var $nextInnerCol = $nextOuterCol.children('.column-inner');

					var nextInnerHTML = $nextInnerCol.html().trim();
					var nextOuterHTML = $nextOuterCol.html().trim();

					$outerCol.html(nextOuterHTML);
					$nextOuterCol.html(outerHTML);
				}
			} );

			//Finally refresh description array
			$( ".column-inner" ).sortable({
				connectWith: ".column-inner",
				stop: (function( event, ui ) {
					self.updateColumns();
				}),
				create: (function( event, ui ) {
					self.updateColumns();
				})
			});
			self.updateColumns();
		},

		columnHandle: function () {
			var self = this;
			$('.column').children('.widget-top').on('click', '.widget-title', function(e) {
				$col = $(this);
				self.activateColumn($col);
			});
		},

		// Bind Edit button
		widgetButtonEdit: function () {
			var self = this;
			$('.column').on('click', '.widget-control-edit', function(e) {
				e.preventDefault();
				var $button = $(this);
				var $parentWidget = $button.parents('.widget');
				var $widgetPreview = $parentWidget.find('.widget-preview');

				// Send the contents from the widget to the editor
				var contentEditor  = $widgetPreview.html();
				var widgetID = $parentWidget.find('.slide-id').val();

				$('#editor_slide-tmce').click(); //Necessary on subsequent loads of the editor
				$( "#dialog" ).dialog({
				  autoOpen: true,
				  width: 640,
				  height: 640,
				  modal: false,
				  buttons: {
					"Update": function() {
						var editorContents = tinymce.get('editor_slide').getContent();
						var params = { content:editorContents };
						// Send the contents of the existing post
						$.ajax({
							url: ajaxurl + '?action=update_slide&id=' + widgetID,
							type: 'POST',
							data: jQuery.param(params),
							beforeSend: function( xhr ) {
								$('.spinner').show();
							},
							complete: function( xhr ) {
								$('.spinner').hide();
							},
							success: function(result) {
								// Return the excerpt from the editor
								$widgetPreview.html( result );
						  }
						});
						self.closeModal();
					},
					Cancel: function() {
						self.closeModal();
					}
				  },
				  create: function() {
						tinymce.execCommand('mceRemoveControl',true,'editor_slide');
						tinymce.execCommand('mceAddControl',true,'editor_slide');
				  },
				  open: function() {
						// Load the contents of the existing post
						$.ajax({
							url: ajaxurl + '?action=get_slide&id=' + widgetID,
							beforeSend: function( xhr ) {
								$('.spinner').show();
							},
							complete: function( xhr ) {
								$('.spinner').hide();
							},
							success: function(contentEditor) {
								tinymce.get('editor_slide').setContent(contentEditor);
							}
						});

						// Hack for getting the reveal class added to tinymce editor body
						// @todo: look at wp_editor in wp/inc/class-wp-editor.php
						var $editorIframe = $('#editor_slide_ifr').contents();
						$editorIframe.find('body').addClass('reveal');
						$editorIframe.css('height','500px');

				  },
				  close: function() {
						self.closeModal();
				  }
				});
			});
		},

		// Bind Delete button
		widgetButtonDelete: function () {
			var self = this;
			$('.column').on('click', '.widget-control-remove', function(e) {
				e.preventDefault();

				var confirmDelete = confirm("You are about to permanently delete the selected items. 'Cancel' to stop, 'OK' to delete.");
				if( false == confirmDelete )
					return;

				var $button = $(this);
				var $parentWidget = $button.parents('.widget');
				var widgetID = $parentWidget.find('.slide-id').val();
				var params = null;

				$.ajax({
					url: ajaxurl + '?action=delete_slide&id=' + widgetID,
					type: 'POST',
					//data: jQuery.param(params),
					beforeSend: function( xhr ) {
						$('.spinner').show();
					},
					complete: function( xhr ) {
						$('.spinner').hide();
					},
					success: function(result) {
						$parentWidget.remove();
						self.updateColumns();
					}
				});
			});
		},

		// Bind Add button
		widgetButtonAdd: function () {
			var self = this;
			$('.action-buttons').on('click', '#add-button', function(e) {
				e.preventDefault();
				var $button = $(this);
				var $activeColumn = $('.widget-title.active').parent('.widget-top').parent('.column').children('.column-inner');

				$('#editor_slide-tmce').click(); //Necessary on subsequent loads of the editor
				$( "#dialog" ).dialog({
				  autoOpen: true,
				  width: 600,
				  height: 600,
				  modal: false,
				  buttons: {
					"Publish": function() {
						var editorContents = tinymce.get('editor_slide').getContent();
						var params = { content:editorContents };
						// Send the contents of the existing post
						$.ajax({
							url: ajaxurl + '?action=new_slide&presentation=' + presentation,
							type: 'POST',
							data: jQuery.param(params),
							success: function(result) {
								$activeColumn.append(result);
								self.updateColumns();
						  }
						});
						self.updateColumns();
						self.closeModal();
					},
					Cancel: function() {
						self.closeModal();
					}
				  },
				  create: function() {
						tinymce.execCommand('mceRemoveControl',true,'editor_slide');
						tinymce.execCommand('mceAddControl',true,'editor_slide');
				  },
				  open: function() {
						// Clear the editor
						tinymce.get('editor_slide').setContent('');
						// Hack for getting the reveal class added to tinymce editor body
						var $editorIframe = $('#editor_slide_ifr').contents();
						$editorIframe.find('body').addClass('reveal');
				  },
				  close: function() {
						self.closeModal();
				  }
				});
			});
		}

	};

})(jQuery);
var slideManager = new WPPresentAdmin();<|endoftext|>


<commit_before>// Credit goes to https://github.com/kurisubrooks/midori

const { Command } = require('discord.js-commando');
const moment = require('moment');
const request = require('request-promise');
const winston = require('winston');

const config = require('../../settings');
const version = require('../../package').version;

module.exports = class WeatherCommand extends Command {
	constructor(client) {
		super(client, {
			name: 'weather-alt',
			aliases: ['w-alt'],
			group: 'weather',
			memberName: 'weather-alt',
			description: 'Get the weather.',
			format: '<location>',
			guildOnly: true,

			args: [
				{
					key: 'location',
					prompt: 'What location would you like to have information on?\n',
					type: 'string'
				}
			]
		});
	}

	async run(msg, args) {
		const location = args.location;

		if (!config.GoogleAPIKey) return msg.reply('my Commander has not set the Google API Key. Go yell at him.');
		if (!config.WeatherAPIKey) return msg.reply('my Commander has not set the Weather API Key. Go yell at him.');

		let locationURI = encodeURIComponent(location.replace(/ /g, '+'));

		return request({
			uri: `https://maps.googleapis.com/maps/api/geocode/json?address=${locationURI}&key=${config.GoogleAPIKey}`,
			headers: { 'User-Agent': `Hamakaze ${version} (https://github.com/iCrawl/Hamakaze/)` },
			json: true
		}).then(response => {
			if (response.status !== 'OK') return this.handleNotOK(msg, response.body.status);
			if (response.results.length === 0) return msg.reply('I couldn\'t find a place with the location you provded me');

			return request({
				uri: `https://api.darksky.net/forecast/${config.WeatherAPIKey}/${response.results[0].geometry.location.lat},${response.results[0].geometry.location.lng}?exclude=minutely,hourly,flags&units=auto`,
				headers: { 'User-Agent': `Hamakaze ${version} (https://github.com/iCrawl/Hamakaze/)` },
				json: true
			}).then(res => {
				let datetime = moment().utcOffset(res.timezone).format('D MMMM, h:mma');
				let condition = res.currently.summary;
				let icon = res.currently.icon;
				let chanceofrain = Math.round((res.currently.precipProbability * 100) / 5) * 5;
				let temperature = Math.round(res.currently.temperature * 10) / 10;
				let temperatureMin = Math.round(res.daily.data[0].temperatureMin * 10) / 10;
				let temperatureMax = Math.round(res.daily.data[0].temperatureMax * 10) / 10;
				let feelslike = Math.round(res.currently.apparentTemperature * 10) / 10;
				let humidity = Math.round(res.currently.humidity * 100);
				let windspeed = res.currently.windSpeed;

				let embed = {
					color: 3447003,
					fields: [
						{
							name: 'Los Angeles',
							value: `${this.getBase(icon)}`,
							inline: true
						},
						{
							name: 'Condition',
							value: `${condition}`,
							inline: true
						},
						{
							name: 'Temperature',
							value: `${temperature}`,
							inline: true
						},
						{
							name: 'High / Low',
							value: `${temperatureMax}\n${temperatureMin}`,
							inline: true
						},
						{
							name: 'Feels like',
							value: `${feelslike}`,
							inline: true
						},
						{
							name: 'Humidity',
							value: `${humidity}`,
							inline: true
						},
						{
							name: 'Chance of rain',
							value: `${chanceofrain}`,
							inline: true
						},
						{
							name: 'Windspeed',
							value: `${windspeed}`,
							inline: true
						}
					],
					footer: {
						icon_url: msg.client.user.avatarURL, // eslint-disable-line camelcase
						text: `${datetime}`
					}
				};

				return msg.channel.sendMessage('', { embed })
					.catch(error => { winston.error(error); });
			}).catch(error => {
				return winston.error(error);
			});
		}).catch(error => {
			winston.error(error);
			return msg.say(`Error: Status code ${error.status || error.response} from Google.`);
		});
	}

	handleNotOK(msg, status) {
		if (status === 'ZERO_RESULTS') {
			return { plain: `${msg.author}, your request returned no results.` };
		} else if (status === 'REQUEST_DENIED') {
			return { plain: `Error: Geocode API Request was denied.` };
		} else if (status === 'INVALID_REQUEST') {
			return { plain: `Error: Invalid Request,` };
		} else if (status === 'OVER_QUERY_LIMIT') {
			return { plain: `${msg.author}, Query Limit Exceeded. Try again tomorrow.` };
		} else {
			return { plain: `Error: Unknown.` };
		}
	}

	getBase(icon) {
		if (icon === 'clear-night' || icon === 'partly-cloudly-night') return `☁`;
		if (icon === 'rain') return `🌧`;
		if (icon === 'snow' || icon === 'sleet' || icon === 'fog' || icon === 'wind') return `🌫`;
		if (icon === 'cloudy') return `☁`;
		return `☀`;
	}

	getUnit(units) {
		let unit = units.find(un => un.types.includes('country'));

		if (unit === undefined) return 'm/s';
		if (unit.short_name === 'US' || unit.short_name === 'GB') return 'mph';
		if (unit.short_name === 'CA') return 'kph';
		return 'm/s';
	}
};
<commit_msg>Improve some more stuff<commit_after>// Credit goes to https://github.com/kurisubrooks/midori

const { Command } = require('discord.js-commando');
const moment = require('moment');
const request = require('request-promise');
const winston = require('winston');

const config = require('../../settings');
const version = require('../../package').version;

module.exports = class WeatherCommand extends Command {
	constructor(client) {
		super(client, {
			name: 'weather-alt',
			aliases: ['w-alt'],
			group: 'weather',
			memberName: 'weather-alt',
			description: 'Get the weather.',
			format: '<location>',
			guildOnly: true,

			args: [
				{
					key: 'location',
					prompt: 'What location would you like to have information on?\n',
					type: 'string'
				}
			]
		});
	}

	async run(msg, args) {
		const location = args.location;

		if (!config.GoogleAPIKey) return msg.reply('my Commander has not set the Google API Key. Go yell at him.');
		if (!config.WeatherAPIKey) return msg.reply('my Commander has not set the Weather API Key. Go yell at him.');

		let locationURI = encodeURIComponent(location.replace(/ /g, '+'));

		return request({
			uri: `https://maps.googleapis.com/maps/api/geocode/json?address=${locationURI}&key=${config.GoogleAPIKey}`,
			headers: { 'User-Agent': `Hamakaze ${version} (https://github.com/iCrawl/Hamakaze/)` },
			json: true
		}).then(response => {
			if (response.status !== 'OK') return this.handleNotOK(msg, response.body.status);
			if (response.results.length === 0) return msg.reply('I couldn\'t find a place with the location you provded me');

			return request({
				uri: `https://api.darksky.net/forecast/${config.WeatherAPIKey}/${response.results[0].geometry.location.lat},${response.results[0].geometry.location.lng}?exclude=minutely,hourly,flags&units=auto`,
				headers: { 'User-Agent': `Hamakaze ${version} (https://github.com/iCrawl/Hamakaze/)` },
				json: true
			}).then(res => {
				let datetime = moment().utcOffset(res.timezone).format('D MMMM, h:mma');
				let condition = res.currently.summary;
				let icon = res.currently.icon;
				let chanceofrain = Math.round((res.currently.precipProbability * 100) / 5) * 5;
				let temperature = Math.round(res.currently.temperature * 10) / 10;
				let temperatureMin = Math.round(res.daily.data[0].temperatureMin * 10) / 10;
				let temperatureMax = Math.round(res.daily.data[0].temperatureMax * 10) / 10;
				let feelslike = Math.round(res.currently.apparentTemperature * 10) / 10;
				let humidity = Math.round(res.currently.humidity * 100);
				let windspeed = res.currently.windSpeed;

				let embed = {
					color: 3447003,
					fields: [
						{
							name: 'Los Angeles',
							value: `${this.getBase(icon)}`,
							inline: true
						},
						{
							name: 'Condition',
							value: `${condition}`,
							inline: true
						},
						{
							name: 'Temperature',
							value: `${temperature}°`,
							inline: true
						},
						{
							name: 'High / Low',
							value: `${temperatureMax}°\n${temperatureMin}°`,
							inline: true
						},
						{
							name: 'Feels like',
							value: `${feelslike}°`,
							inline: true
						},
						{
							name: 'Humidity',
							value: `${humidity}%`,
							inline: true
						},
						{
							name: 'Chance of rain',
							value: `${chanceofrain}%`,
							inline: true
						},
						{
							name: 'Windspeed',
							value: `${windspeed.toFixed(2)} ${this.getUnit(response.results[0].address_components)} `,
							inline: true
						}
					],
					footer: {
						icon_url: msg.client.user.avatarURL, // eslint-disable-line camelcase
						text: `${datetime}`
					}
				};

				return msg.channel.sendMessage('', { embed })
					.catch(error => { winston.error(error); });
			}).catch(error => {
				return winston.error(error);
			});
		}).catch(error => {
			winston.error(error);
			return msg.say(`Error: Status code ${error.status || error.response} from Google.`);
		});
	}

	handleNotOK(msg, status) {
		if (status === 'ZERO_RESULTS') {
			return { plain: `${msg.author}, your request returned no results.` };
		} else if (status === 'REQUEST_DENIED') {
			return { plain: `Error: Geocode API Request was denied.` };
		} else if (status === 'INVALID_REQUEST') {
			return { plain: `Error: Invalid Request,` };
		} else if (status === 'OVER_QUERY_LIMIT') {
			return { plain: `${msg.author}, Query Limit Exceeded. Try again tomorrow.` };
		} else {
			return { plain: `Error: Unknown.` };
		}
	}

	getBase(icon) {
		if (icon === 'clear-night' || icon === 'partly-cloudly-night') return `☁`;
		if (icon === 'rain') return `🌧`;
		if (icon === 'snow' || icon === 'sleet' || icon === 'fog' || icon === 'wind') return `🌫`;
		if (icon === 'cloudy') return `☁`;
		return `☀`;
	}

	getUnit(units) {
		let unit = units.find(un => un.types.includes('country'));

		if (unit === undefined) return 'm/s';
		if (unit.short_name === 'US' || unit.short_name === 'GB') return 'mph';
		if (unit.short_name === 'CA') return 'kph';
		return 'm/s';
	}
};
<|endoftext|>


<commit_before>import FormObject from '../object/FormObject'
import compact from 'lodash/compact'
import flatten from 'lodash/flatten'
import React from 'react'

export default function defaultFormObject(model, children) {
  const properties = collectPropertiesFromAllChildren(children)

  let formObject = class DefaultFormObject extends FormObject {
    static get properties() {
      return properties
    }

    static get model() {
      return model
    }
  }
  // formObject.__defineGetter__('properties', function() { return ['query'] })
  // formObject.__defineGetter__('model', function() { return 'search' })
  return formObject
}

function collectPropertiesFromAllChildren(children) {
  let properties = []

  React.Children.map(children, child => {
    if (child.props.attribute) properties.push(child.props.attribute)
    if (child.props.children) {
      const recursiveProperties =
        collectPropertiesFromAllChildren(child.props.children)
      properties.push(recursiveProperties)
    }
  })

  return compact(flatten(properties))
}
<commit_msg>improve default form object initialization forforms with prop-less children<commit_after>import FormObject from '../object/FormObject'
import compact from 'lodash/compact'
import flatten from 'lodash/flatten'
import React from 'react'

export default function defaultFormObject(model, children) {
  const properties = collectPropertiesFromAllChildren(children)

  let formObject = class DefaultFormObject extends FormObject {
    static get properties() {
      return properties
    }

    static get model() {
      return model
    }
  }
  // formObject.__defineGetter__('properties', function() { return ['query'] })
  // formObject.__defineGetter__('model', function() { return 'search' })
  return formObject
}

function collectPropertiesFromAllChildren(children) {
  let properties = []

  React.Children.map(children, child => {
    if (!child.props) return
    if (child.props.attribute) properties.push(child.props.attribute)
    if (child.props.children) {
      const recursiveProperties =
        collectPropertiesFromAllChildren(child.props.children)
      properties.push(recursiveProperties)
    }
  })

  return compact(flatten(properties))
}
<|endoftext|>


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

var $ = window.jQuery
  , dnd = window.DragDrop
  , doc = $(document)
  , currentPlayer = 2

function countScore (total, factor) {
  return (total % factor === 0) ? total / factor : 0
}

function getScore () {
  return $('#player' + currentPlayer + 'score').int()
}

function setScore (newScore, player) {
  player = player || currentPlayer
  $('#player' + player + 'score').html(newScore)
}

function countUnique (array) {
  var i = 0
    , keys = {}

  for (i = 0; i < array.length; i += 1) {
    keys[array[i]] = 1
  }
  return Object.keys(keys).length
}

function bonusScore (values) {
  var i = 0
    , score = 0
    , straight = 0
    , unique = 0

  if (values.length <= 1) {
    return 0
  }
  unique = countUnique(values)
  if (values.length <= 2) {
    /* a pair */
    if (unique === 1) {
      return 2
    }
    return 0
  }
  if (values.length <= 3) {
    /* a pair */
    if (unique === 2) {
      return 2
    }
    /* three of a kind */
    if (unique === 1) {
      return 6
    }
    return 0
  }
  score = 0
  straight = 0
  values.sort()
  for (i = 0; i < values.length - 1; i += 1) {
    if (values[i] + 1 === values[i + 1]) {
      straight += 1
    }
  }
  /* a straight */
  if (straight === 3) {
    score += 4
  }
  /* a pair */
  if (unique === 3) {
    score += 2
  }
  /* three of a kind */
  if (unique === 2) {
    score += 6
  }
  /* four of a kind */
  if (unique === 1) {
    score += 12
  }
  return score
}

function guessScore (element, guess) {
  var i = 0
    , j = 0
    , value = 0
    , values = []
    , score = getScore()
    , classes = []
    , matches = []
    , total = 0

  element = $(element)
  classes = element.klass().replace(/\s+/g, ' ').split(' ')
  for (i = 0; i < classes.length; i += 1) {
    total = 0
    values = []
    matches = $('.' + classes[i])
    for (j = 0; j < matches.length; j += 1) {
      value = matches[j].data()
      if (guess && matches[j].klass() === element.klass()) {
        value = guess
      }
      if (!isNaN(value)) {
        values.push(value)
        total += value
      }
    }
    score += countScore(total, 3)
    score += countScore(total, 5)
    score += countScore(total, 7)
    score += bonusScore(values)
  }
  return score
}

function isPlayable (element) {
  element = $(element)
  return element.name() === 'TD' && element.html() === ''
}

function getPieces (player) {
  player = player || currentPlayer
  return $('#player' + player + 'pieces').kids('li')
}

function getMode () {
  var player1 = $('#player1icon')
    , player2 = $('#player2icon')

  if (player1.has('human') && player2.has('human')) {
    return 'hvh'
  }
  if (player1.has('human') && player2.has('computer')) {
    return 'hvc'
  }
  if (player1.has('computer') && player2.has('human')) {
    return 'cvh'
  }
  if (player1.has('computer') && player2.has('computer')) {
    return 'cvc'
  }
  return ''
}

function initPieces (player, values) {
  var i = 0
    , mode = getMode()
    , piece = null
    , pieces = getPieces(player)

  for (i = 0; i < pieces.length; i += 1) {
    piece = $(pieces[i])
    piece.html(values.shift())
    piece.remove('hide')
    piece.remove('moving')
    piece.left(0)
    piece.top(0)
    if (mode === 'cvc' ||
       (mode === 'hvc' && player === 1) ||
       (mode === 'cvh' && player === 2)) {
      piece.add('playing')
    } else {
      piece.remove('playing')
    }
  }
}

function initBoard () {
  var i = 0
    , tiles = $('')

  for (i = 0; i < tiles.length; i += 1) {
    tiles[i].html('').data('')
  }
}

function fakeMove (piece, tile, callback) {
  var startX = 0
    , startY = 0

  if (isPlayable(tile)) {
    piece = $(piece)
    tile = $(tile)
    startX = piece.left()
    startY = piece.top()
    piece.add('playing')
    piece.animate('moving', function () {
      callback(piece, tile)
      piece.remove('playing')
      piece.left(startX)
      piece.top(startY)
    })
    piece.left(piece.left() + (tile.center().x - piece.center().x))
    piece.top(piece.top() + (tile.center().y - piece.center().y))
  }
}

function makeMove (callback) {
  var i = 0
    , j = 0
    , tiles = $('')
    , playables = []
    , piece = null
    , pieces = getPieces()
    , value = 0
    , score = 0
    , best = { piece: null, tile: null, score: 0 }

  for (i = 0; i < tiles.length; i += 1) {
    if (isPlayable(tiles[i])) {
      playables.push(tiles[i])
    }
  }

  for (i = 0; i < pieces.length; i += 1) {
    piece = $(pieces[i])
    if (!piece.has('hide')) {
      value = piece.int()
      for (j = 0; j < playables.length; j += 1) {
        score = guessScore(playables[j], value)
        if (score >= best.score) {
          best = { piece: piece, tile: playables[j], score: score }
        }
      }
    }
  }

  fakeMove(best.piece, best.tile, callback)
}

function toggleTurn (callback) {
  var i = 0
    , mode = getMode()
    , pieces = getPieces()
    , klass = ''

  for (i = 0; i < pieces.length; i += 1) {
    dnd.unbind(pieces[i])
    if (mode === 'hvh') {
      $(pieces[i]).remove('playing')
    }
  }

  currentPlayer = (currentPlayer === 1) ? 2 : 1
  klass = (currentPlayer === 1) ? 'dropping-cyan' : 'dropping-yellow'

  pieces = getPieces()
  for (i = 0; i < pieces.length; i += 1) {
    dnd.bind(pieces[i], isPlayable, callback, klass)
    if ((currentPlayer === 1 && mode === 'hvc') ||
        (currentPlayer === 2 && mode === 'cvh') ||
        (mode === 'hvh' || mode === 'cvc')) {
      $(pieces[i]).add('playing')
    }
  }

  if (mode === 'cvc' ||
     (mode === 'cvh' && currentPlayer === 1) ||
     (mode === 'hvc' && currentPlayer === 2)) {
    makeMove(callback)
  }
}

function endTurn (piece, tile) {
  piece = $(piece)
  tile = $(tile)
  tile.data(piece.html())
  tile.html(''+piece.html()+'')
  piece.add('hide')
  setScore(guessScore(tile))
  toggleTurn(endTurn)
}

function shuffle (array) {
  var i = 0
    , j = 0
    , temp

  for (i = array.length - 1; i > 0; i -= 1) {
    j = Math.floor(Math.random() * (i + 1))
    temp = array[i]
    array[i] = array[j]
    array[j] = temp
  }
}

function restart () {
  var i = 0
    , j = 0
    , pieces = []

  $.stopAnimations()

  for (i = 0; i < 4; i += 1) {
    for (j = 1; j <= 13; j += 1) {
      pieces.push(j)
    }
  }
  shuffle(pieces)

  currentPlayer = 2

  initPieces(1, pieces)
  initPieces(2, pieces)
  initBoard()

  setScore(0, 1)
  setScore(0, 2)

  toggleTurn(endTurn)
}

function onIconPress (e) {
  var element = $(e.currentTarget), wrapper = function () {
    doc.off('mouseup', wrapper)
    element.toggle('human')
    element.toggle('computer')
    restart()
    return false
  }
  doc.on('mouseup', wrapper)
  return false
}

Mentat.play = function () {
  $('#player1icon').on('mousedown', onIconPress)
  $('#player2icon').on('mousedown', onIconPress)
  $('#notes').add('hide')
  $('#info').on('mousedown', function () {
    var wrapper = function () {
      doc.off('mouseup', wrapper)
      $('#notes').toggle('hide')
    }
    doc.on('mouseup', wrapper)
  })
  restart()
}

})(window.Mentat = window.Mentat || {})
<commit_msg>Provides a named function for when an icon is released.<commit_after>;(function (Mentat) {
'use strict';

var $ = window.jQuery
  , dnd = window.DragDrop
  , doc = $(document)
  , currentPlayer = 2

function countScore (total, factor) {
  return (total % factor === 0) ? total / factor : 0
}

function getScore () {
  return $('#player' + currentPlayer + 'score').int()
}

function setScore (newScore, player) {
  player = player || currentPlayer
  $('#player' + player + 'score').html(newScore)
}

function countUnique (array) {
  var i = 0
    , keys = {}

  for (i = 0; i < array.length; i += 1) {
    keys[array[i]] = 1
  }
  return Object.keys(keys).length
}

function bonusScore (values) {
  var i = 0
    , score = 0
    , straight = 0
    , unique = 0

  if (values.length <= 1) {
    return 0
  }
  unique = countUnique(values)
  if (values.length <= 2) {
    /* a pair */
    if (unique === 1) {
      return 2
    }
    return 0
  }
  if (values.length <= 3) {
    /* a pair */
    if (unique === 2) {
      return 2
    }
    /* three of a kind */
    if (unique === 1) {
      return 6
    }
    return 0
  }
  score = 0
  straight = 0
  values.sort()
  for (i = 0; i < values.length - 1; i += 1) {
    if (values[i] + 1 === values[i + 1]) {
      straight += 1
    }
  }
  /* a straight */
  if (straight === 3) {
    score += 4
  }
  /* a pair */
  if (unique === 3) {
    score += 2
  }
  /* three of a kind */
  if (unique === 2) {
    score += 6
  }
  /* four of a kind */
  if (unique === 1) {
    score += 12
  }
  return score
}

function guessScore (element, guess) {
  var i = 0
    , j = 0
    , value = 0
    , values = []
    , score = getScore()
    , classes = []
    , matches = []
    , total = 0

  element = $(element)
  classes = element.klass().replace(/\s+/g, ' ').split(' ')
  for (i = 0; i < classes.length; i += 1) {
    total = 0
    values = []
    matches = $('.' + classes[i])
    for (j = 0; j < matches.length; j += 1) {
      value = matches[j].data()
      if (guess && matches[j].klass() === element.klass()) {
        value = guess
      }
      if (!isNaN(value)) {
        values.push(value)
        total += value
      }
    }
    score += countScore(total, 3)
    score += countScore(total, 5)
    score += countScore(total, 7)
    score += bonusScore(values)
  }
  return score
}

function isPlayable (element) {
  element = $(element)
  return element.name() === 'TD' && element.html() === ''
}

function getPieces (player) {
  player = player || currentPlayer
  return $('#player' + player + 'pieces').kids('li')
}

function getMode () {
  var player1 = $('#player1icon')
    , player2 = $('#player2icon')

  if (player1.has('human') && player2.has('human')) {
    return 'hvh'
  }
  if (player1.has('human') && player2.has('computer')) {
    return 'hvc'
  }
  if (player1.has('computer') && player2.has('human')) {
    return 'cvh'
  }
  if (player1.has('computer') && player2.has('computer')) {
    return 'cvc'
  }
  return ''
}

function initPieces (player, values) {
  var i = 0
    , mode = getMode()
    , piece = null
    , pieces = getPieces(player)

  for (i = 0; i < pieces.length; i += 1) {
    piece = $(pieces[i])
    piece.html(values.shift())
    piece.remove('hide')
    piece.remove('moving')
    piece.left(0)
    piece.top(0)
    if (mode === 'cvc' ||
       (mode === 'hvc' && player === 1) ||
       (mode === 'cvh' && player === 2)) {
      piece.add('playing')
    } else {
      piece.remove('playing')
    }
  }
}

function initBoard () {
  var i = 0
    , tiles = $('')

  for (i = 0; i < tiles.length; i += 1) {
    tiles[i].html('').data('')
  }
}

function fakeMove (piece, tile, callback) {
  var startX = 0
    , startY = 0

  if (isPlayable(tile)) {
    piece = $(piece)
    tile = $(tile)
    startX = piece.left()
    startY = piece.top()
    piece.add('playing')
    piece.animate('moving', function () {
      callback(piece, tile)
      piece.remove('playing')
      piece.left(startX)
      piece.top(startY)
    })
    piece.left(piece.left() + (tile.center().x - piece.center().x))
    piece.top(piece.top() + (tile.center().y - piece.center().y))
  }
}

function makeMove (callback) {
  var i = 0
    , j = 0
    , tiles = $('')
    , playables = []
    , piece = null
    , pieces = getPieces()
    , value = 0
    , score = 0
    , best = { piece: null, tile: null, score: 0 }

  for (i = 0; i < tiles.length; i += 1) {
    if (isPlayable(tiles[i])) {
      playables.push(tiles[i])
    }
  }

  for (i = 0; i < pieces.length; i += 1) {
    piece = $(pieces[i])
    if (!piece.has('hide')) {
      value = piece.int()
      for (j = 0; j < playables.length; j += 1) {
        score = guessScore(playables[j], value)
        if (score >= best.score) {
          best = { piece: piece, tile: playables[j], score: score }
        }
      }
    }
  }

  fakeMove(best.piece, best.tile, callback)
}

function toggleTurn (callback) {
  var i = 0
    , mode = getMode()
    , pieces = getPieces()
    , klass = ''

  for (i = 0; i < pieces.length; i += 1) {
    dnd.unbind(pieces[i])
    if (mode === 'hvh') {
      $(pieces[i]).remove('playing')
    }
  }

  currentPlayer = (currentPlayer === 1) ? 2 : 1
  klass = (currentPlayer === 1) ? 'dropping-cyan' : 'dropping-yellow'

  pieces = getPieces()
  for (i = 0; i < pieces.length; i += 1) {
    dnd.bind(pieces[i], isPlayable, callback, klass)
    if ((currentPlayer === 1 && mode === 'hvc') ||
        (currentPlayer === 2 && mode === 'cvh') ||
        (mode === 'hvh' || mode === 'cvc')) {
      $(pieces[i]).add('playing')
    }
  }

  if (mode === 'cvc' ||
     (mode === 'cvh' && currentPlayer === 1) ||
     (mode === 'hvc' && currentPlayer === 2)) {
    makeMove(callback)
  }
}

function endTurn (piece, tile) {
  piece = $(piece)
  tile = $(tile)
  tile.data(piece.html())
  tile.html(''+piece.html()+'')
  piece.add('hide')
  setScore(guessScore(tile))
  toggleTurn(endTurn)
}

function shuffle (array) {
  var i = 0
    , j = 0
    , temp

  for (i = array.length - 1; i > 0; i -= 1) {
    j = Math.floor(Math.random() * (i + 1))
    temp = array[i]
    array[i] = array[j]
    array[j] = temp
  }
}

function restart () {
  var i = 0
    , j = 0
    , pieces = []

  $.stopAnimations()

  for (i = 0; i < 4; i += 1) {
    for (j = 1; j <= 13; j += 1) {
      pieces.push(j)
    }
  }
  shuffle(pieces)

  currentPlayer = 2

  initPieces(1, pieces)
  initPieces(2, pieces)
  initBoard()

  setScore(0, 1)
  setScore(0, 2)

  toggleTurn(endTurn)
}

function onIconPress (e) {
  var element = $(e.currentTarget)

  function onIconRelease () {
    doc.off('mouseup', onIconRelease)
    element.toggle('human')
    element.toggle('computer')
    restart()
    return false
  }

  doc.on('mouseup', onIconRelease)
  return false
}

Mentat.play = function () {
  $('#player1icon').on('mousedown', onIconPress)
  $('#player2icon').on('mousedown', onIconPress)
  $('#notes').add('hide')
  $('#info').on('mousedown', function () {
    var wrapper = function () {
      doc.off('mouseup', wrapper)
      $('#notes').toggle('hide')
    }
    doc.on('mouseup', wrapper)
  })
  restart()
}

})(window.Mentat = window.Mentat || {})
<|endoftext|>


<commit_before>/**
 * Competence class
 */
function Competence(viewmodel, id, code, name, weight, locked, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        subcompetences: ko.observableArray(subcompetences),

        addSubCompetence: function() {
            this.subcompetences.push(new SubCompetence(this));
            automatedWeightCalculation(this.subcompetences());
            /*var total = 100;
            alert(total);
            console.log(this.subcompetences);
            for(var sub in this.subcompetences){
                alert(sub);
                sub.calculateWeight(100);
                total -= sub.weight;
                alert(total);
            }*/
        },

        removeThis: function() {
            viewmodel.removeCompetence(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeSubCompetence: function(subCompetence) {
            this.subcompetences.remove(subCompetence);
            automatedWeightCalculation(this.subcompetences());
        }
    };

}

/**
 * SubCompetence class
 */
function SubCompetence(parent, id, code, name, weight, locked, indicators) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        indicators: ko.observableArray(indicators),

        addIndicator: function() {
            this.indicators.push(new Indicator(this));
            automatedWeightCalculation(this.indicators());
        },

        /*calculateWeight: function(total){
            this.weight = total;
        },*/

        removeThis: function() {
            parent.removeSubCompetence(this);

        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeIndicator: function(indicator) {
            this.indicators.remove(indicator);
            automatedWeightCalculation(this.indicators());
        }

    };
}

/**
 * Indicator class
 */
function Indicator(parent, id, name, weight, locked, description) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        description : ko.observable(description),

        removeThis: function() {
            parent.removeIndicator(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.competences = 0;
    gvm.subcomp = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addCompetenceBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddCompetence");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.addCompetence = function() {
        gvm.competences.push(new Competence(this));
        automatedWeightCalculation(this.competences());

        // Update automated weight calculation
        ko.utils.arrayForEach(gvm.competences, function(competence){
            console.log(competence.weight);
            competence.weight(percent);
        });
    };

    gvm.removeCompetence = function(competence) {
        gvm.competences.remove(competence);
        automatedWeightCalculation(this.competences());
    }

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    }

    gvm.clearStructure = function() {
        gvm.competences.destroyAll();
    }
}

/**
 * Push the current project state to the database
 * @returns {undefined}
 */
function saveProjectStructure() {
    $.ajax({
       type: "POST",
       url: "/api/projectstructure/" + projectid,
       data: ko.toJSON(viewModel.competences),
       success: function(){
           // TODO make multilangual and with modals
           alert("Saved projectstructure to server");

           fetchProjectStructure();
       }
    });
}

function fetchProjectStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            var competence = viewModel.updateCompetence(item.id, item.code, item.description, item.max, item.weight);

            $.each(item.subcompetences, function(i, subcomp){
               var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description, subcomp.weight);
               competence.subcompetences.push(subcompetence);

               $.each(subcomp.indicators, function(i, indic){
                  subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.description));
               });
            });
        })
    });
}

function initPage() {
    fetchProjectStructure();

    $(".addCompetenceBtn").click(function() {
        viewModel.addCompetence();
    });

    $(".savePageBtn").click(function(){
        if(totalPercentCheck()) {
            saveProjectStructure();
            console.log("Saved");
        }
        else
        {
            console.log("Not saved");
        }
    });
}

function totalPercentCheck()
{
    var totalPercentCompetences = 0;
    var percentTotalSubcompetences = new Array();
    var percentTotalIndicators = new Array();

    for(var indexCompetences =0; indexCompetences < viewModel.competences().length; indexCompetences++)
    {
        totalPercentCompetences = totalPercentCompetences + parseInt(viewModel.competences()[indexCompetences].weight());
        percentTotalSubcompetences.push(0);
        for(var indexSubCompetences = 0; indexSubCompetences < viewModel.competences()[indexCompetences].subcompetences().length; indexSubCompetences++)
        {
            percentTotalSubcompetences[indexCompetences] = percentTotalSubcompetences[indexCompetences] + parseInt(viewModel.competences()[indexCompetences].subcompetences()[indexSubCompetences].weight());
            percentTotalIndicators.push(0);
            for(var indexIndicators = 0; indexIndicators < viewModel.competences()[indexCompetences].subcompetences()[indexSubCompetences].indicators().length; indexIndicators++)
            {
                percentTotalIndicators[indexSubCompetences] = percentTotalIndicators[indexSubCompetences] + parseInt(viewModel.competences()[indexCompetences].subcompetences()[indexSubCompetences].indicators()[indexIndicators].weight());
            }
        }
    }

    console.log(percentTotalSubcompetences[0]);

    if(totalPercentCompetences == 100)
    {
        return true;
    }
    else
    {
        return false;
    }
}

function automatedWeightCalculation(data)
{
    var lockedPercent = 0;
    var nrOfUnlocked = 0;

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == true)
        {
            lockedPercent = lockedPercent + parseInt(data[index].weight());
        }
        else
        {
            nrOfUnlocked++;
        }
    }

    var remainingPercent = 100 - lockedPercent;

    var percentPerCompetence = remainingPercent / nrOfUnlocked;

    percentPerCompetence = percentPerCompetence.toFixed(2);

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == false)
        {
            data[index].weight(percentPerCompetence);
        }
    }
}
<commit_msg>total percent check<commit_after>/**
 * Competence class
 */
function Competence(viewmodel, id, code, name, weight, locked, subcompetences) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        subcompetences: ko.observableArray(subcompetences),

        addSubCompetence: function() {
            this.subcompetences.push(new SubCompetence(this));
            automatedWeightCalculation(this.subcompetences());
            /*var total = 100;
            alert(total);
            console.log(this.subcompetences);
            for(var sub in this.subcompetences){
                alert(sub);
                sub.calculateWeight(100);
                total -= sub.weight;
                alert(total);
            }*/
        },

        removeThis: function() {
            viewmodel.removeCompetence(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeSubCompetence: function(subCompetence) {
            this.subcompetences.remove(subCompetence);
            automatedWeightCalculation(this.subcompetences());
        }
    };

}

/**
 * SubCompetence class
 */
function SubCompetence(parent, id, code, name, weight, locked, indicators) {
    return {
        id: ko.observable(id),
        code: ko.observable(code),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        indicators: ko.observableArray(indicators),

        addIndicator: function() {
            this.indicators.push(new Indicator(this));
            automatedWeightCalculation(this.indicators());
        },

        /*calculateWeight: function(total){
            this.weight = total;
        },*/

        removeThis: function() {
            parent.removeSubCompetence(this);

        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        },

        removeIndicator: function(indicator) {
            this.indicators.remove(indicator);
            automatedWeightCalculation(this.indicators());
        }

    };
}

/**
 * Indicator class
 */
function Indicator(parent, id, name, weight, locked, description) {
    return {
        id: ko.observable(id),
        name: ko.observable(name),
        weight: ko.observable(weight),
        locked: false,
        description : ko.observable(description),

        removeThis: function() {
            parent.removeIndicator(this);
        },

        toggleLock: function(data, event){
            if(this.locked == true)
            {
                $(event.target).addClass("icon-unlock").removeClass("icon-lock");
                this.locked = false;
            }
            else
            {
                $(event.target).addClass("icon-lock").removeClass("icon-unlock");
                this.locked = true;
            }
        }
    };
}

// View model for the courses page
function pageViewModel(gvm) {
    // projecttitle
    gvm.projecttitle = ko.observable("");
    //gvm.competences = 0;
    gvm.subcomp = 0;

    // Page specific i18n bindings
    gvm.title = ko.computed(function (){i18n.setLocale(gvm.lang()); return gvm.app() + ' - ' + i18n.__("ProjectTitle") + ": " + gvm.projecttitle();}, gvm);
    gvm.pageHeader = ko.observable("Project");
    gvm.projectname = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("ProjectName");}, gvm);

    gvm.addCompetenceBtn = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("AddCompetence");}, gvm);
    gvm.savePage = ko.computed(function(){i18n.setLocale(gvm.lang()); return i18n.__("SaveBtn");}, gvm);

    gvm.competences = ko.observableArray([]);

    gvm.addCompetence = function() {
        gvm.competences.push(new Competence(this));
        automatedWeightCalculation(this.competences());

        // Update automated weight calculation
        ko.utils.arrayForEach(gvm.competences, function(competence){
            console.log(competence.weight);
            competence.weight(percent);
        });
    };

    gvm.removeCompetence = function(competence) {
        gvm.competences.remove(competence);
        automatedWeightCalculation(this.competences());
    }

    gvm.updateCompetence = function(id, code, description, max, weight) {
        var comp = new Competence(this, id, code, description, weight);
        gvm.competences.push(comp);
        return comp;
    }

    gvm.clearStructure = function() {
        gvm.competences.destroyAll();
    }
}

/**
 * Push the current project state to the database
 * @returns {undefined}
 */
function saveProjectStructure() {
    $.ajax({
       type: "POST",
       url: "/api/projectstructure/" + projectid,
       data: ko.toJSON(viewModel.competences),
       success: function(){
           // TODO make multilangual and with modals
           alert("Saved projectstructure to server");

           fetchProjectStructure();
       }
    });
}

function fetchProjectStructure() {
    viewModel.clearStructure();

    $.getJSON("/api/projectstructure/" + projectid, function(data){
        $.each(data, function(i, item){
            var competence = viewModel.updateCompetence(item.id, item.code, item.description, item.max, item.weight);

            $.each(item.subcompetences, function(i, subcomp){
               var subcompetence = new SubCompetence(competence, subcomp.id, subcomp.code, subcomp.description, subcomp.weight);
               competence.subcompetences.push(subcompetence);

               $.each(subcomp.indicators, function(i, indic){
                  subcompetence.indicators.push(new Indicator(subcompetence, indic.id, indic.name, indic.description));
               });
            });
        })
    });
}

function initPage() {
    fetchProjectStructure();

    $(".addCompetenceBtn").click(function() {
        viewModel.addCompetence();
    });

    $(".savePageBtn").click(function(){
        if(totalPercentCheck()) {
            saveProjectStructure();
            console.log("Saved");
        }
        else
        {
            console.log("Not saved");
        }
    });
}

function totalPercentCheck()
{
    var totalPercentCompetences = 0;
    var totalPercentSubcompetences = 0;
    var totalPercentIndicators = 0;

    var nrOfSubcompetences = 0;
    var nrOfIndicators = 0;

    for(var indexCompetences =0; indexCompetences < viewModel.competences().length; indexCompetences++)
    {
        totalPercentCompetences = totalPercentCompetences + parseInt(viewModel.competences()[indexCompetences].weight());
        for(var indexSubCompetences = 0; indexSubCompetences < viewModel.competences()[indexCompetences].subcompetences().length; indexSubCompetences++)
        {
            totalPercentSubcompetences = totalPercentSubcompetences[indexCompetences] + parseInt(viewModel.competences()[indexCompetences].subcompetences()[indexSubCompetences].weight());
            nrOfSubcompetences++;
            for(var indexIndicators = 0; indexIndicators < viewModel.competences()[indexCompetences].subcompetences()[indexSubCompetences].indicators().length; indexIndicators++)
            {
                totalPercentIndicators = totalPercentIndicators + parseInt(viewModel.competences()[indexCompetences].subcompetences()[indexSubCompetences].indicators()[indexIndicators].weight());
                nrOfIndicators++;
            }
        }
    }

    totalPercentSubcompetences = totalPercentSubcompetences / nrOfSubcompetences;
    totalPercentIndicators = totalPercentIndicators / nrOfIndicators;

    console.log(totalPercentSubcompetences + " and " + totalPercentIndicators);

    if(totalPercentCompetences == 100 && totalPercentSubcompetences == 100 && totalPercentIndicators == 100 )
    {
        return true;
    }
    else
    {
        return false;
    }
}

function automatedWeightCalculation(data)
{
    var lockedPercent = 0;
    var nrOfUnlocked = 0;

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == true)
        {
            lockedPercent = lockedPercent + parseInt(data[index].weight());
        }
        else
        {
            nrOfUnlocked++;
        }
    }

    var remainingPercent = 100 - lockedPercent;

    var percentPerCompetence = remainingPercent / nrOfUnlocked;

    percentPerCompetence = percentPerCompetence.toFixed(2);

    for(var index = 0; index < data.length; index++)
    {
        if(data[index].locked == false)
        {
            data[index].weight(percentPerCompetence);
        }
    }
}
<|endoftext|>


<commit_before>(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}

/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	module.exports = __webpack_require__(1);

/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";
	// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
	// but simplifies things for the consumer of this module.
	__webpack_require__(2);
	var http = __webpack_require__(3);
	var path = __webpack_require__(4);
	var ArgsUtil_1 = __webpack_require__(5);
	var ExitWhenParentExits_1 = __webpack_require__(6);
	// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
	// reference to Node's runtime 'require' function.
	var dynamicRequire = eval('require');
	var server = http.createServer(function (req, res) {
	    readRequestBodyAsJson(req, function (bodyJson) {
	        var hasSentResult = false;
	        var callback = function (errorValue, successValue) {
	            if (!hasSentResult) {
	                hasSentResult = true;
	                if (errorValue) {
	                    respondWithError(res, errorValue);
	                }
	                else if (typeof successValue !== 'string') {
	                    // Arbitrary object/number/etc - JSON-serialize it
	                    var successValueJson = void 0;
	                    try {
	                        successValueJson = JSON.stringify(successValue);
	                    }
	                    catch (ex) {
	                        // JSON serialization error - pass it back to .NET
	                        respondWithError(res, ex);
	                        return;
	                    }
	                    res.setHeader('Content-Type', 'application/json');
	                    res.end(successValueJson);
	                }
	                else {
	                    // String - can bypass JSON-serialization altogether
	                    res.setHeader('Content-Type', 'text/plain');
	                    res.end(successValue);
	                }
	            }
	        };
	        // Support streamed responses
	        Object.defineProperty(callback, 'stream', {
	            enumerable: true,
	            get: function () {
	                if (!hasSentResult) {
	                    hasSentResult = true;
	                    res.setHeader('Content-Type', 'application/octet-stream');
	                }
	                return res;
	            }
	        });
	        try {
	            var resolvedPath = path.resolve(process.cwd(), bodyJson.moduleName);
	            var invokedModule = dynamicRequire(resolvedPath);
	            var func = bodyJson.exportedFunctionName ? invokedModule[bodyJson.exportedFunctionName] : invokedModule;
	            if (!func) {
	                throw new Error('The module "' + resolvedPath + '" has no export named "' + bodyJson.exportedFunctionName + '"');
	            }
	            func.apply(null, [callback].concat(bodyJson.args));
	        }
	        catch (synchronousException) {
	            callback(synchronousException, null);
	        }
	    });
	});
	var parsedArgs = ArgsUtil_1.parseArgs(process.argv);
	var requestedPortOrZero = parsedArgs.port || 0; // 0 means 'let the OS decide'
	server.listen(requestedPortOrZero, 'localhost', function () {
	    // Signal to HttpNodeHost which port it should make its HTTP connections on
	    console.log('[Microsoft.AspNetCore.NodeServices.HttpNodeHost:Listening on port ' + server.address().port + '\]');
	    // Signal to the NodeServices base class that we're ready to accept invocations
	    console.log('[Microsoft.AspNetCore.NodeServices:Listening]');
	});
	ExitWhenParentExits_1.exitWhenParentExits(parseInt(parsedArgs.parentPid), /* ignoreSigint */ true);
	function readRequestBodyAsJson(request, callback) {
	    var requestBodyAsString = '';
	    request.on('data', function (chunk) { requestBodyAsString += chunk; });
	    request.on('end', function () { callback(JSON.parse(requestBodyAsString)); });
	}
	function respondWithError(res, errorValue) {
	    res.statusCode = 500;
	    res.end(errorValue.stack || errorValue.toString());
	}

/***/ },
/* 2 */
/***/ function(module, exports) {

	// When Node writes to stdout/strerr, we capture that and convert the lines into calls on the
	// active .NET ILogger. But by default, stdout/stderr don't have any way of distinguishing
	// linebreaks inside log messages from the linebreaks that delimit separate log messages,
	// so multiline strings will end up being written to the ILogger as multiple independent
	// log messages. This makes them very hard to make sense of, especially when they represent
	// something like stack traces.
	//
	// To fix this, we intercept stdout/stderr writes, and replace internal linebreaks with a
	// marker token. When .NET receives the lines, it converts the marker tokens back to regular
	// linebreaks within the logged messages.
	//
	// Note that it's better to do the interception at the stdout/stderr level, rather than at
	// the console.log/console.error (etc.) level, because this takes place after any native
	// message formatting has taken place (e.g., inserting values for % placeholders).
	var findInternalNewlinesRegex = /\n(?!$)/g;
	var encodedNewline = '__ns_newline__';
	encodeNewlinesWrittenToStream(process.stdout);
	encodeNewlinesWrittenToStream(process.stderr);
	function encodeNewlinesWrittenToStream(outputStream) {
	    var origWriteFunction = outputStream.write;
	    outputStream.write = function (value) {
	        // Only interfere with the write if it's definitely a string
	        if (typeof value === 'string') {
	            var argsClone = Array.prototype.slice.call(arguments, 0);
	            argsClone[0] = encodeNewlinesInString(value);
	            origWriteFunction.apply(this, argsClone);
	        }
	        else {
	            origWriteFunction.apply(this, arguments);
	        }
	    };
	}
	function encodeNewlinesInString(str) {
	    return str.replace(findInternalNewlinesRegex, encodedNewline);
	}

/***/ },
/* 3 */
/***/ function(module, exports) {

	module.exports = require("http");

/***/ },
/* 4 */
/***/ function(module, exports) {

	module.exports = require("path");

/***/ },
/* 5 */
/***/ function(module, exports) {

	"use strict";
	function parseArgs(args) {
	    // Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external
	    // dependencies (such as an args-parsing library) to this file.
	    var result = {};
	    var currentKey = null;
	    args.forEach(function (arg) {
	        if (arg.indexOf('--') === 0) {
	            var argName = arg.substring(2);
	            result[argName] = undefined;
	            currentKey = argName;
	        }
	        else if (currentKey) {
	            result[currentKey] = arg;
	            currentKey = null;
	        }
	    });
	    return result;
	}
	exports.parseArgs = parseArgs;

/***/ },
/* 6 */
/***/ function(module, exports) {

	/*
	In general, we want the Node child processes to be terminated as soon as the parent .NET processes exit,
	because we have no further use for them. If the .NET process shuts down gracefully, it will run its
	finalizers, one of which (in OutOfProcessNodeInstance.cs) will kill its associated Node process immediately.

	But if the .NET process is terminated forcefully (e.g., on Linux/OSX with 'kill -9'), then it won't have
	any opportunity to shut down its child processes, and by default they will keep running. In this case, it's
	up to the child process to detect this has happened and terminate itself.

	There are many possible approaches to detecting when a parent process has exited, most of which behave
	differently between Windows and Linux/OS X:

	 - On Windows, the parent process can mark its child as being a 'job' that should auto-terminate when
	   the parent does (http://stackoverflow.com/a/4657392). Not cross-platform.
	 - The child Node process can get a callback when the parent disconnects (process.on('disconnect', ...)).
	   But despite http://stackoverflow.com/a/16487966, no callback fires in any case I've tested (Windows / OS X).
	 - The child Node process can get a callback when its stdin/stdout are disconnected, as described at
	   http://stackoverflow.com/a/15693934. This works well on OS X, but calling stdout.resume() on Windows
	   causes the process to terminate prematurely.
	 - I don't know why, but on Windows, it's enough to invoke process.stdin.resume(). For some reason this causes
	   the child Node process to exit as soon as the parent one does, but I don't see this documented anywhere.
	 - You can poll to see if the parent process, or your stdin/stdout connection to it, is gone
	   - You can directly pass a parent process PID to the child, and then have the child poll to see if it's
	     still running (e.g., using process.kill(pid, 0), which doesn't kill it but just tests whether it exists,
	     as per https://nodejs.org/api/process.html#process_process_kill_pid_signal)
	   - Or, on each poll, you can try writing to process.stdout. If the parent has died, then this will throw.
	     However I don't see this documented anywhere. It would be nice if you could just poll for whether or not
	     process.stdout is still connected (without actually writing to it) but I haven't found any property whose
	     value changes until you actually try to write to it.

	Of these, the only cross-platform approach that is actually documented as a valid strategy is simply polling
	to check whether the parent PID is still running. So that's what we do here.
	*/
	"use strict";
	var pollIntervalMs = 1000;
	function exitWhenParentExits(parentPid, ignoreSigint) {
	    setInterval(function () {
	        if (!processExists(parentPid)) {
	            // Can't log anything at this point, because out stdout was connected to the parent,
	            // but the parent is gone.
	            process.exit();
	        }
	    }, pollIntervalMs);
	    if (ignoreSigint) {
	        // Pressing ctrl+c in the terminal sends a SIGINT to all processes in the foreground process tree.
	        // By default, the Node process would then exit before the .NET process, because ASP.NET implements
	        // a delayed shutdown to allow ongoing requests to complete.
	        //
	        // This is problematic, because if Node exits first, the CopyToAsync code in ConditionalProxyMiddleware
	        // will experience a read fault, and logs a huge load of errors. Fortunately, since the Node process is
	        // already set up to shut itself down if it detects the .NET process is terminated, all we have to do is
	        // ignore the SIGINT. The Node process will then terminate automatically after the .NET process does.
	        //
	        // A better solution would be to have WebpackDevMiddleware listen for SIGINT and gracefully close any
	        // ongoing EventSource connections before letting the Node process exit, independently of the .NET
	        // process exiting. However, doing this well in general is very nontrivial (see all the discussion at
	        // https://github.com/nodejs/node/issues/2642).
	        process.on('SIGINT', function () {
	            console.log('Received SIGINT. Waiting for .NET process to exit...');
	        });
	    }
	}
	exports.exitWhenParentExits = exitWhenParentExits;
	function processExists(pid) {
	    try {
	        // Sending signal 0 - on all platforms - tests whether the process exists. As long as it doesn't
	        // throw, that means it does exist.
	        process.kill(pid, 0);
	        return true;
	    }
	    catch (ex) {
	        // If the reason for the error is that we don't have permission to ask about this process,
	        // report that as a separate problem.
	        if (ex.code === 'EPERM') {
	            throw new Error("Attempted to check whether process " + pid + " was running, but got a permissions error.");
	        }
	        return false;
	    }
	}

/***/ }
/******/ ])));<commit_msg>Fix error formatting by rebuilding entrypoint-http.js<commit_after>(function(e, a) { for(var i in a) e[i] = a[i]; }(exports, /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};

/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {

/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId])
/******/ 			return installedModules[moduleId].exports;

/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			exports: {},
/******/ 			id: moduleId,
/******/ 			loaded: false
/******/ 		};

/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/ 		// Flag the module as loaded
/******/ 		module.loaded = true;

/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}

/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;

/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;

/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";

/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {

	module.exports = __webpack_require__(1);

/***/ },
/* 1 */
/***/ function(module, exports, __webpack_require__) {

	"use strict";
	// Limit dependencies to core Node modules. This means the code in this file has to be very low-level and unattractive,
	// but simplifies things for the consumer of this module.
	__webpack_require__(2);
	var http = __webpack_require__(3);
	var path = __webpack_require__(4);
	var ArgsUtil_1 = __webpack_require__(5);
	var ExitWhenParentExits_1 = __webpack_require__(6);
	// Webpack doesn't support dynamic requires for files not present at compile time, so grab a direct
	// reference to Node's runtime 'require' function.
	var dynamicRequire = eval('require');
	var server = http.createServer(function (req, res) {
	    readRequestBodyAsJson(req, function (bodyJson) {
	        var hasSentResult = false;
	        var callback = function (errorValue, successValue) {
	            if (!hasSentResult) {
	                hasSentResult = true;
	                if (errorValue) {
	                    respondWithError(res, errorValue);
	                }
	                else if (typeof successValue !== 'string') {
	                    // Arbitrary object/number/etc - JSON-serialize it
	                    var successValueJson = void 0;
	                    try {
	                        successValueJson = JSON.stringify(successValue);
	                    }
	                    catch (ex) {
	                        // JSON serialization error - pass it back to .NET
	                        respondWithError(res, ex);
	                        return;
	                    }
	                    res.setHeader('Content-Type', 'application/json');
	                    res.end(successValueJson);
	                }
	                else {
	                    // String - can bypass JSON-serialization altogether
	                    res.setHeader('Content-Type', 'text/plain');
	                    res.end(successValue);
	                }
	            }
	        };
	        // Support streamed responses
	        Object.defineProperty(callback, 'stream', {
	            enumerable: true,
	            get: function () {
	                if (!hasSentResult) {
	                    hasSentResult = true;
	                    res.setHeader('Content-Type', 'application/octet-stream');
	                }
	                return res;
	            }
	        });
	        try {
	            var resolvedPath = path.resolve(process.cwd(), bodyJson.moduleName);
	            var invokedModule = dynamicRequire(resolvedPath);
	            var func = bodyJson.exportedFunctionName ? invokedModule[bodyJson.exportedFunctionName] : invokedModule;
	            if (!func) {
	                throw new Error('The module "' + resolvedPath + '" has no export named "' + bodyJson.exportedFunctionName + '"');
	            }
	            func.apply(null, [callback].concat(bodyJson.args));
	        }
	        catch (synchronousException) {
	            callback(synchronousException, null);
	        }
	    });
	});
	var parsedArgs = ArgsUtil_1.parseArgs(process.argv);
	var requestedPortOrZero = parsedArgs.port || 0; // 0 means 'let the OS decide'
	server.listen(requestedPortOrZero, 'localhost', function () {
	    // Signal to HttpNodeHost which port it should make its HTTP connections on
	    console.log('[Microsoft.AspNetCore.NodeServices.HttpNodeHost:Listening on port ' + server.address().port + '\]');
	    // Signal to the NodeServices base class that we're ready to accept invocations
	    console.log('[Microsoft.AspNetCore.NodeServices:Listening]');
	});
	ExitWhenParentExits_1.exitWhenParentExits(parseInt(parsedArgs.parentPid), /* ignoreSigint */ true);
	function readRequestBodyAsJson(request, callback) {
	    var requestBodyAsString = '';
	    request.on('data', function (chunk) { requestBodyAsString += chunk; });
	    request.on('end', function () { callback(JSON.parse(requestBodyAsString)); });
	}
	function respondWithError(res, errorValue) {
	    res.statusCode = 500;
	    res.end(JSON.stringify({
	        errorMessage: errorValue.message || errorValue,
	        errorDetails: errorValue.stack || null
	    }));
	}

/***/ },
/* 2 */
/***/ function(module, exports) {

	// When Node writes to stdout/strerr, we capture that and convert the lines into calls on the
	// active .NET ILogger. But by default, stdout/stderr don't have any way of distinguishing
	// linebreaks inside log messages from the linebreaks that delimit separate log messages,
	// so multiline strings will end up being written to the ILogger as multiple independent
	// log messages. This makes them very hard to make sense of, especially when they represent
	// something like stack traces.
	//
	// To fix this, we intercept stdout/stderr writes, and replace internal linebreaks with a
	// marker token. When .NET receives the lines, it converts the marker tokens back to regular
	// linebreaks within the logged messages.
	//
	// Note that it's better to do the interception at the stdout/stderr level, rather than at
	// the console.log/console.error (etc.) level, because this takes place after any native
	// message formatting has taken place (e.g., inserting values for % placeholders).
	var findInternalNewlinesRegex = /\n(?!$)/g;
	var encodedNewline = '__ns_newline__';
	encodeNewlinesWrittenToStream(process.stdout);
	encodeNewlinesWrittenToStream(process.stderr);
	function encodeNewlinesWrittenToStream(outputStream) {
	    var origWriteFunction = outputStream.write;
	    outputStream.write = function (value) {
	        // Only interfere with the write if it's definitely a string
	        if (typeof value === 'string') {
	            var argsClone = Array.prototype.slice.call(arguments, 0);
	            argsClone[0] = encodeNewlinesInString(value);
	            origWriteFunction.apply(this, argsClone);
	        }
	        else {
	            origWriteFunction.apply(this, arguments);
	        }
	    };
	}
	function encodeNewlinesInString(str) {
	    return str.replace(findInternalNewlinesRegex, encodedNewline);
	}

/***/ },
/* 3 */
/***/ function(module, exports) {

	module.exports = require("http");

/***/ },
/* 4 */
/***/ function(module, exports) {

	module.exports = require("path");

/***/ },
/* 5 */
/***/ function(module, exports) {

	"use strict";
	function parseArgs(args) {
	    // Very simplistic parsing which is sufficient for the cases needed. We don't want to bring in any external
	    // dependencies (such as an args-parsing library) to this file.
	    var result = {};
	    var currentKey = null;
	    args.forEach(function (arg) {
	        if (arg.indexOf('--') === 0) {
	            var argName = arg.substring(2);
	            result[argName] = undefined;
	            currentKey = argName;
	        }
	        else if (currentKey) {
	            result[currentKey] = arg;
	            currentKey = null;
	        }
	    });
	    return result;
	}
	exports.parseArgs = parseArgs;

/***/ },
/* 6 */
/***/ function(module, exports) {

	/*
	In general, we want the Node child processes to be terminated as soon as the parent .NET processes exit,
	because we have no further use for them. If the .NET process shuts down gracefully, it will run its
	finalizers, one of which (in OutOfProcessNodeInstance.cs) will kill its associated Node process immediately.

	But if the .NET process is terminated forcefully (e.g., on Linux/OSX with 'kill -9'), then it won't have
	any opportunity to shut down its child processes, and by default they will keep running. In this case, it's
	up to the child process to detect this has happened and terminate itself.

	There are many possible approaches to detecting when a parent process has exited, most of which behave
	differently between Windows and Linux/OS X:

	 - On Windows, the parent process can mark its child as being a 'job' that should auto-terminate when
	   the parent does (http://stackoverflow.com/a/4657392). Not cross-platform.
	 - The child Node process can get a callback when the parent disconnects (process.on('disconnect', ...)).
	   But despite http://stackoverflow.com/a/16487966, no callback fires in any case I've tested (Windows / OS X).
	 - The child Node process can get a callback when its stdin/stdout are disconnected, as described at
	   http://stackoverflow.com/a/15693934. This works well on OS X, but calling stdout.resume() on Windows
	   causes the process to terminate prematurely.
	 - I don't know why, but on Windows, it's enough to invoke process.stdin.resume(). For some reason this causes
	   the child Node process to exit as soon as the parent one does, but I don't see this documented anywhere.
	 - You can poll to see if the parent process, or your stdin/stdout connection to it, is gone
	   - You can directly pass a parent process PID to the child, and then have the child poll to see if it's
	     still running (e.g., using process.kill(pid, 0), which doesn't kill it but just tests whether it exists,
	     as per https://nodejs.org/api/process.html#process_process_kill_pid_signal)
	   - Or, on each poll, you can try writing to process.stdout. If the parent has died, then this will throw.
	     However I don't see this documented anywhere. It would be nice if you could just poll for whether or not
	     process.stdout is still connected (without actually writing to it) but I haven't found any property whose
	     value changes until you actually try to write to it.

	Of these, the only cross-platform approach that is actually documented as a valid strategy is simply polling
	to check whether the parent PID is still running. So that's what we do here.
	*/
	"use strict";
	var pollIntervalMs = 1000;
	function exitWhenParentExits(parentPid, ignoreSigint) {
	    setInterval(function () {
	        if (!processExists(parentPid)) {
	            // Can't log anything at this point, because out stdout was connected to the parent,
	            // but the parent is gone.
	            process.exit();
	        }
	    }, pollIntervalMs);
	    if (ignoreSigint) {
	        // Pressing ctrl+c in the terminal sends a SIGINT to all processes in the foreground process tree.
	        // By default, the Node process would then exit before the .NET process, because ASP.NET implements
	        // a delayed shutdown to allow ongoing requests to complete.
	        //
	        // This is problematic, because if Node exits first, the CopyToAsync code in ConditionalProxyMiddleware
	        // will experience a read fault, and logs a huge load of errors. Fortunately, since the Node process is
	        // already set up to shut itself down if it detects the .NET process is terminated, all we have to do is
	        // ignore the SIGINT. The Node process will then terminate automatically after the .NET process does.
	        //
	        // A better solution would be to have WebpackDevMiddleware listen for SIGINT and gracefully close any
	        // ongoing EventSource connections before letting the Node process exit, independently of the .NET
	        // process exiting. However, doing this well in general is very nontrivial (see all the discussion at
	        // https://github.com/nodejs/node/issues/2642).
	        process.on('SIGINT', function () {
	            console.log('Received SIGINT. Waiting for .NET process to exit...');
	        });
	    }
	}
	exports.exitWhenParentExits = exitWhenParentExits;
	function processExists(pid) {
	    try {
	        // Sending signal 0 - on all platforms - tests whether the process exists. As long as it doesn't
	        // throw, that means it does exist.
	        process.kill(pid, 0);
	        return true;
	    }
	    catch (ex) {
	        // If the reason for the error is that we don't have permission to ask about this process,
	        // report that as a separate problem.
	        if (ex.code === 'EPERM') {
	            throw new Error("Attempted to check whether process " + pid + " was running, but got a permissions error.");
	        }
	        return false;
	    }
	}

/***/ }
/******/ ])));<|endoftext|>