<commit_before>/**
 * @license
 * Copyright (C) 2013 Steven Berry (http://www.sberry.me/minimodal)
 * Licensed: MIT (http://opensource.org/licenses/mit-license.php)
 *
 * Steven Berry
 * www.sberry.me
 * steven@sberry.me
 */
(function(root, factory) {
	if (typeof module === 'object' && module && typeof module.exports === 'object') {
		factory.call(root, require('jquery'));
	}
	else if (typeof define === 'function' && define.amd) {
		define(['jquery'], function() {
			return factory.apply(root, arguments);
		});
	}
	else if (typeof root === 'object' && root && typeof root.document === 'object') {
		factory.call(root, root.jQuery);
	}
})(this, function($, undefined) {
	var window = this;
	var document = window.document;

	var $shade;

	// Prepare the DOM with necessary elements for minimodal operation.
	$(document).ready(function() {
		// Create the minimodal shade element and insert it (hidden) into the document body.
		$(document.body).append('

');
		// Retain an internal reference to the shade element.
		$shade = $('#minimodal-shade').hide();

		// Handle click events on any .modal-close classed element to close the active modal.
		$(document).delegate('.modal-close', 'click', function(e) {
			$.modal.close();
		});
	});

	/**
	 * Helper function that constructs an object to be passed
	 * into jQuery's .trigger() on `modalopen` and `modalclose`.
	 * The eventData function parameter on the modal is used to
	 * set the object values.
	 *
	 * @private
	 * @param {string} [type] The type of event that will be triggered.
	 * @returns {Object} An object with event key/value pairs to be passed to $.trigger().
	 */
	function getEvent(type, obj) {
		var add, event = {};

		if ($.isFunction(this.eventData)) {
			$.extend(event, this.eventData.call(this.obj));
		}

		$.extend(event, obj || {});
		event.type = type;

		return event;
	}

	/**
	 * An internally referenced object that keeps track of key variables
	 * and associates a $.fn.modal() call with some prototype functions.
	 *
	 * @private
	 * @class
	 * @param {jQuery} obj A jQuery object to use as the active modal.
	 * @param {Object} [options] An object containing setting variables for the modal.
	 * @config {Function} [preOpen] A callback that runs before the modal window opens.
	 * @config {Function} [postOpen] A callback that runs after the modal window opens.
	 * @config {Function} [preClose] A callback that runs before the modal window closes.
	 * @config {Function} [postClose] A callback that runs after the modal window closes.
	 * @config {Function} [eventData] A callback returns a plain object containing data properties to pass to the `modalclose` event.
	 * @property {jQuery} obj A jQuery object to use as the active modal. This is a copy of the `obj` parameter.
	 * @property {jQuery} parent The parent jQuery object of `obj`. This is used to reset the placement of the DOM node after the modal closes.
	 * @property {HTMLElement} focused The DOM element that was focused before the modal opened. This element is refocused when the modal is closed.
	 */
	function Modal(obj, options) {
		options.obj = obj;
		options.parent = obj.parent();
		options.focused = document.activeElement;
		// TODO: Just use an `options` own-property.
		// This will prevent option parameters from overwriting
		// the prototype `open` and `close`
		$.extend(this, options);

		return this;
	}
	Modal.prototype = {
		/**
		 * Performs modal pre-processing, opens the specified modal DOM element,
		 * and finally performs modal post-processing.
		 *
		 * @returns {Modal} Chainable return object.
		 */
		open: function() {
			// Apply the preOpen function if it's specified.
			if ($.isFunction(this.preOpen)) {
				this.preOpen.apply(this.obj, arguments);
			}

			// Move the modal object to the document body (instead of wherever it was).
			// This helps with the stacking order to make sure that absolute/fixed position
			// elements don't pop up over the modal.
			$(document.body).append(this.obj);
			this.obj.after($shade);

			// Display the shade DOM object.
			$shade.show();
			// Display and center the specified modal.
			// Fire the `modalopen` event after everything is loaded.
			this.obj.show()
				.css({
					marginTop: -this.obj.outerHeight() / 2,
					marginLeft: -this.obj.outerWidth() / 2
				})
				.trigger(getEvent.call(this, 'modalopen'));

			// Focus the first available input in the opened modal.
			this.obj.find('input, select, textarea, button').first().focus();

			// Apply the postOpen function if it's specified.
			if ($.isFunction(this.postOpen)) {
				this.postOpen.apply(this.obj, arguments);
			}

			// Create a keydown listener for the ESC key to close the active modal.
			$(document).on('keydown.modal', function(e) {
				// Do I really want this? It's necessary in one of my applications...
				// But I don't know if it's just because I didn't design the events/DOM properly.
				e.stopPropagation();

				if (e.which == 27) { // ESC key closes the modal window.
					$.modal.close();
				}
			});

			return this;
		},

		/**
		 * Performs modal pre-processing, closes the active modal DOM element,
		 * and finally performs modal post-processing.
		 *
		 * @returns {Modal} Chainable return object.
		 */
		close: function(obj) {
			// Apply the preClose function if it's specified.
			if ($.isFunction(this.preClose)) {
				this.preClose.apply(this.obj, arguments);
			}

			// Hide the shade DOM object.
			$shade.hide();
			// Hide the active modal and fire the `modalclose` event with
			// parameters obtained from the `eventData` option.
			this.obj.hide().trigger(getEvent.call(this, 'modalclose', obj));

			// Reposition the DOM element back under its original parent.
			this.parent.append(this.obj);
			// Focus the pre-modal focused element.
			// TODO: Do we care about preventing autoscroll here?
			$(this.focused).focus();
			// Clear the modal reference from the jQuery object.
			$.modal = null;

			// Apply the postClose function if it's specified.
			if ($.isFunction(this.postClose)) {
				this.postClose.apply(this.obj, arguments);
			}

			// Clear out the keydown listener for the ESC key.
			$(document).off('keydown.modal');

			return this;
		}
	};

	$.fn.extend({
		/**
		 * jQuery fn extension function to expose the internal `Modal` class and functionality.
		 *
		 * @param {Object} [options] An object containing setting variables for the modal.
		 * @config {Function} [preOpen] A callback that runs before the modal window opens.
		 * @config {Function} [postOpen] A callback that runs after the modal window opens.
		 * @config {Function} [preClose] A callback that runs before the modal window closes.
		 * @config {Function} [postClose] A callback that runs after the modal window closes.
		 * @config {Function} [eventData] A callback returns a plain object containing data properties to pass to the `modalclose` event.
		 * @returns {Modal} The `Modal` instance created for the jQuery object DOM element. Returns `undefined` if using an empty or non HTMLElement selector.
		 */
		modal: function(options) {
			options = options || {};

			// Check to see if there's actually an object.
			if (this.length >= 1 && this[0].nodeType) {
				// Close all existing modals that were created with the minimodal plugin.
				if ($.modal instanceof Modal) {
					$.modal.close();
				}

				// Set the active modal and return it.
				return $.modal = new Modal(this.first(), options).open();
			}
		}
	});
});<commit_msg>Lint fixes.<commit_after>/**
 * @license
 * Copyright (C) 2013 Steven Berry (http://www.sberry.me/minimodal)
 * Licensed: MIT (http://opensource.org/licenses/mit-license.php)
 *
 * Steven Berry
 * www.sberry.me
 * steven@sberry.me
 */
(function(root, factory) {
	if (typeof module === 'object' && module && typeof module.exports === 'object') {
		factory.call(root, require('jquery'));
	}
	else if (typeof define === 'function' && define.amd) {
		define(['jquery'], function() {
			return factory.apply(root, arguments);
		});
	}
	else if (typeof root === 'object' && root && typeof root.document === 'object') {
		factory.call(root, root.jQuery);
	}
})(this, function($) {
	var window = this;
	var document = window.document;

	var $shade;

	// Prepare the DOM with necessary elements for minimodal operation.
	$(document).ready(function() {
		// Create the minimodal shade element and insert it (hidden) into the document body.
		$(document.body).append('

');
		// Retain an internal reference to the shade element.
		$shade = $('#minimodal-shade').hide();

		// Handle click events on any .modal-close classed element to close the active modal.
		$(document).delegate('.modal-close', 'click', function(e) {
			$.modal.close();
		});
	});

	/**
	 * Helper function that constructs an object to be passed
	 * into jQuery's .trigger() on `modalopen` and `modalclose`.
	 * The eventData function parameter on the modal is used to
	 * set the object values.
	 *
	 * @private
	 * @param {string} [type] The type of event that will be triggered.
	 * @returns {Object} An object with event key/value pairs to be passed to $.trigger().
	 */
	function getEvent(type, obj) {
		var add, event = {};

		if ($.isFunction(this.eventData)) {
			$.extend(event, this.eventData.call(this.obj));
		}

		$.extend(event, obj || {});
		event.type = type;

		return event;
	}

	/**
	 * An internally referenced object that keeps track of key variables
	 * and associates a $.fn.modal() call with some prototype functions.
	 *
	 * @private
	 * @class
	 * @param {jQuery} obj A jQuery object to use as the active modal.
	 * @param {Object} [options] An object containing setting variables for the modal.
	 * @config {Function} [preOpen] A callback that runs before the modal window opens.
	 * @config {Function} [postOpen] A callback that runs after the modal window opens.
	 * @config {Function} [preClose] A callback that runs before the modal window closes.
	 * @config {Function} [postClose] A callback that runs after the modal window closes.
	 * @config {Function} [eventData] A callback returns a plain object containing data properties to pass to the `modalclose` event.
	 * @property {jQuery} obj A jQuery object to use as the active modal. This is a copy of the `obj` parameter.
	 * @property {jQuery} parent The parent jQuery object of `obj`. This is used to reset the placement of the DOM node after the modal closes.
	 * @property {HTMLElement} focused The DOM element that was focused before the modal opened. This element is refocused when the modal is closed.
	 */
	function Modal(obj, options) {
		options.obj = obj;
		options.parent = obj.parent();
		options.focused = document.activeElement;
		// TODO: Just use an `options` own-property.
		// This will prevent option parameters from overwriting
		// the prototype `open` and `close`
		$.extend(this, options);

		return this;
	}
	Modal.prototype = {
		/**
		 * Performs modal pre-processing, opens the specified modal DOM element,
		 * and finally performs modal post-processing.
		 *
		 * @returns {Modal} Chainable return object.
		 */
		open: function() {
			// Apply the preOpen function if it's specified.
			if ($.isFunction(this.preOpen)) {
				this.preOpen.apply(this.obj, arguments);
			}

			// Move the modal object to the document body (instead of wherever it was).
			// This helps with the stacking order to make sure that absolute/fixed position
			// elements don't pop up over the modal.
			$(document.body).append(this.obj);
			this.obj.after($shade);

			// Display the shade DOM object.
			$shade.show();
			// Display and center the specified modal.
			// Fire the `modalopen` event after everything is loaded.
			this.obj.show()
				.css({
					marginTop: -this.obj.outerHeight() / 2,
					marginLeft: -this.obj.outerWidth() / 2
				})
				.trigger(getEvent.call(this, 'modalopen'));

			// Focus the first available input in the opened modal.
			this.obj.find('input, select, textarea, button').first().focus();

			// Apply the postOpen function if it's specified.
			if ($.isFunction(this.postOpen)) {
				this.postOpen.apply(this.obj, arguments);
			}

			// Create a keydown listener for the ESC key to close the active modal.
			$(document).on('keydown.modal', function(e) {
				// Do I really want this? It's necessary in one of my applications...
				// But I don't know if it's just because I didn't design the events/DOM properly.
				e.stopPropagation();

				if (e.which == 27) { // ESC key closes the modal window.
					$.modal.close();
				}
			});

			return this;
		},

		/**
		 * Performs modal pre-processing, closes the active modal DOM element,
		 * and finally performs modal post-processing.
		 *
		 * @returns {Modal} Chainable return object.
		 */
		close: function(obj) {
			// Apply the preClose function if it's specified.
			if ($.isFunction(this.preClose)) {
				this.preClose.apply(this.obj, arguments);
			}

			// Hide the shade DOM object.
			$shade.hide();
			// Hide the active modal and fire the `modalclose` event with
			// parameters obtained from the `eventData` option.
			this.obj.hide().trigger(getEvent.call(this, 'modalclose', obj));

			// Reposition the DOM element back under its original parent.
			this.parent.append(this.obj);
			// Focus the pre-modal focused element.
			// TODO: Do we care about preventing autoscroll here?
			$(this.focused).focus();
			// Clear the modal reference from the jQuery object.
			$.modal = null;

			// Apply the postClose function if it's specified.
			if ($.isFunction(this.postClose)) {
				this.postClose.apply(this.obj, arguments);
			}

			// Clear out the keydown listener for the ESC key.
			$(document).off('keydown.modal');

			return this;
		}
	};

	$.fn.extend({
		/**
		 * jQuery fn extension function to expose the internal `Modal` class and functionality.
		 *
		 * @param {Object} [options] An object containing setting variables for the modal.
		 * @config {Function} [preOpen] A callback that runs before the modal window opens.
		 * @config {Function} [postOpen] A callback that runs after the modal window opens.
		 * @config {Function} [preClose] A callback that runs before the modal window closes.
		 * @config {Function} [postClose] A callback that runs after the modal window closes.
		 * @config {Function} [eventData] A callback returns a plain object containing data properties to pass to the `modalclose` event.
		 * @returns {Modal} The `Modal` instance created for the jQuery object DOM element. Returns `undefined` if using an empty or non HTMLElement selector.
		 */
		modal: function(options) {
			options = options || {};

			// Check to see if there's actually an object.
			if (this.length >= 1 && this[0].nodeType) {
				// Close all existing modals that were created with the minimodal plugin.
				if ($.modal instanceof Modal) {
					$.modal.close();
				}

				// Set the active modal and return it.
				return $.modal = new Modal(this.first(), options).open();
			}
		}
	});
});
<|endoftext|>


<commit_before>import _ from 'lodash'
import { EmptyMJMLError } from './Error'
import { html as beautify } from 'js-beautify'
import { parseInstance } from './helpers/mjml'
import defaultStyle from './defaultStyle'
import documentParser from './documentParser'
import dom from './helpers/dom'
import MJMLElementsCollection from './MJMLElementsCollection'
import React from 'react'
import ReactDOMServer from 'react-dom/server'

const debug = require('debug')('mjml-engine/mjml2html')

const mjml2html = (content, options = {}) => {
  let parsedContent = content

  if (typeof content == 'string') {
    debug('Start parsing content')
    parsedContent = documentParser(content)
    debug('Content parsed.')
  }

  debug('Start rendering')
  const html = render({ mjml: parsedContent, options })
  debug('Done rendering')

  return html
}

const removeCDATA = str => str.replace(//g, '$1')

const insertColumnMediaQuery = $ => {
  const mediaQueries = []

  _.each({'mj-column-per': '%', 'mj-column-px': 'px'}, (unit, className) => {
    const columnWidths = []

    $(`[class*="${className}"]`).each(function () {
      columnWidths.push($(this).data('column-width'))
      $(this).removeAttr('data-column-width')
    })

    _.uniq(columnWidths).forEach((width) => {
      const mediaQueryClass = `${className}-${width}`

      mediaQueries.push(`.${mediaQueryClass}, * [aria-labelledby="${mediaQueryClass}"] { width:${width}${unit}!important; }`)
    })
  })

  const mediaQuery = ``

  $('head').append(mediaQuery)

  return $
}

const fixOutlookLayout = $ => {
  const bodyWidth = $('.mj-body').data('width')

  $('.mj-body').removeAttr('data-width')

  $('.mj-section-outlook-background').each(function () {
    const url = $(this).data('url')
    const width = $(this).data('width')

    $(this).removeAttr('class')
           .removeAttr('data-url')
           .removeAttr('data-width')

    if (!url) {
      return
    }

    $(this).before(``)

    $(this).after(``)
  })

  $('.mj-body-outlook-open').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-body-outlook-line').each(function () {
    $(this).replaceWith(`
      `)
  })

  $('.mj-body-outlook-close').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-section-outlook-open').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-section-outlook-line').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-section-outlook-close').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-social-outlook-open').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-social-outlook-line').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-social-outlook-close').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-divider-outlook').each(function () {
    const $insertNode = dom.createElement('

').attr('style', $(this).attr('style'))

    $(this).removeClass('mj-divider-outlook')
           .after(`<!--[if mso]>${$insertNode}<![endif]-->`)
  })

  return $
}

const fixLegacyAttrs = $ => {
  const legacyAttrs = ['align', 'valign', 'bgcolor', 'border', 'background']

  $('#YIELD_MJML').css({ background: $('.mj-body').data('background-color') })
  $('.mj-body').removeAttr('data-background-color')

  // https://github.com/facebook/react/issues/140 ...
  // server side workaround to allow custom tags.
  legacyAttrs.forEach(attr => {
    const dataAttr = `data-legacy-${attr}`

    $(`[${dataAttr}]`).each(function () {
      $(this).attr(attr, $(this).attr(dataAttr))
      $(this).removeAttr(dataAttr)
    })
  })

  return $
}

const container = (title = '', content = '') => (
`<!doctype html>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>${title}</title>

<link href="https://fonts.googleapis.com/css?family=Ubuntu:400,500,700,300" rel="stylesheet" type="text/css">

  ${content}

`
)

const render = ({ mjml, options }) => {
  let content = ''

  if (mjml) {
    debug('Create root React element')
    const rootElemComponent = React.createElement(MJMLElementsCollection[mjml.tagName.substr(3)], { mjml: parseInstance(mjml) })

    debug('Render to static markup')
    content = ReactDOMServer.renderToStaticMarkup(rootElemComponent)
  } else {
    throw (new EmptyMJMLError(`.render: No MJML to render in options ${options.toString()}`))
  }

  debug('React rendering done. Continue with special overrides.')
  let $ = dom.parseHTML(container(options.title, content))

  $('.mj-raw').each(function () {
    $(this).replaceWith($(this).html())
  })

  $ = insertColumnMediaQuery($)
  $ = fixLegacyAttrs($)
  $ = fixOutlookLayout($)

  let html = removeCDATA(dom.getHTML($))

  if (options.beautify) {
    html = beautify(html, {
      indent_size: 2,
      wrap_attributes_indent_size: 2
    })
  }

  return html
}

export default mjml2html
<commit_msg>Remove unsuned attrs on render<commit_after>import _ from 'lodash'
import { EmptyMJMLError } from './Error'
import { html as beautify } from 'js-beautify'
import { parseInstance } from './helpers/mjml'
import defaultStyle from './defaultStyle'
import documentParser from './documentParser'
import dom from './helpers/dom'
import MJMLElementsCollection from './MJMLElementsCollection'
import React from 'react'
import ReactDOMServer from 'react-dom/server'

const debug = require('debug')('mjml-engine/mjml2html')

const mjml2html = (content, options = {}) => {
  let parsedContent = content

  if (typeof content == 'string') {
    debug('Start parsing content')
    parsedContent = documentParser(content)
    debug('Content parsed.')
  }

  debug('Start rendering')
  const html = render({ mjml: parsedContent, options })
  debug('Done rendering')

  return html
}

const removeCDATA = str => str.replace(//g, '$1')

const insertColumnMediaQuery = $ => {
  const mediaQueries = []

  _.each({'mj-column-per': '%', 'mj-column-px': 'px'}, (unit, className) => {
    const columnWidths = []

    $(`[class*="${className}"]`).each(function () {
      columnWidths.push($(this).data('column-width'))
      $(this).removeAttr('data-column-width')
    })

    _.uniq(columnWidths).forEach((width) => {
      const mediaQueryClass = `${className}-${width}`

      mediaQueries.push(`.${mediaQueryClass}, * [aria-labelledby="${mediaQueryClass}"] { width:${width}${unit}!important; }`)
    })
  })

  const mediaQuery = ``

  $('head').append(mediaQuery)

  return $
}

const fixOutlookLayout = $ => {
  const bodyWidth = $('.mj-body').data('width')

  $('.mj-body').removeAttr('data-width')

  $('.mj-section-outlook-background').each(function () {
    const url = $(this).data('url')
    const width = $(this).data('width')

    $(this)
      .removeAttr('class')
      .removeAttr('data-url')
      .removeAttr('data-width')

    if (!url) {
      return
    }

    $(this).before(``)

    $(this).after(``)
  })

  $('.mj-body-outlook-open').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-body-outlook-line').each(function () {
    $(this).replaceWith(`
      `)
  })

  $('.mj-body-outlook-close').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-section-outlook-open').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-section-outlook-line').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-section-outlook-close').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-social-outlook-open').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-social-outlook-line').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-social-outlook-close').each(function () {
    $(this).replaceWith(``)
  })

  $('.mj-divider-outlook').each(function () {
    const $insertNode = dom.createElement('

').attr('style', $(this).attr('style'))

    $(this)
      .removeClass('mj-divider-outlook')
      .after(`<!--[if mso]>${$insertNode}<![endif]-->`)
  })

  return $
}

const fixLegacyAttrs = $ => {
  const legacyAttrs = ['align', 'valign', 'bgcolor', 'border', 'background']

  $('#YIELD_MJML').css({ background: $('.mj-body').data('background-color') })
  $('.mj-body').removeAttr('data-background-color')

  // https://github.com/facebook/react/issues/140 ...
  // server side workaround to allow custom tags.
  legacyAttrs.forEach(attr => {
    const dataAttr = `data-legacy-${attr}`

    $(`[${dataAttr}]`).each(function () {
      $(this).attr(attr, $(this).attr(dataAttr))
      $(this).removeAttr(dataAttr)
    })
  })

  return $
}

const clean = $ => {
  $('#YIELD_MJML').each(function () {
    $(this).removeAttr('id')

    if ($(this).attr('style') === '') {
      $(this).removeAttr('style')
    }
  })

  $('.mj-body')
    .removeAttr('class')
    .removeAttr('style')

  $('.mj-content').removeAttr('class')

  return $
}

const container = (title = '', content = '') => (
`<!doctype html>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<title>${title}</title>

<link href="https://fonts.googleapis.com/css?family=Ubuntu:400,500,700,300" rel="stylesheet" type="text/css">

  ${content}

`
)

const render = ({ mjml, options }) => {
  let content = ''

  if (mjml) {
    debug('Create root React element')
    const rootElemComponent = React.createElement(MJMLElementsCollection[mjml.tagName.substr(3)], { mjml: parseInstance(mjml) })

    debug('Render to static markup')
    content = ReactDOMServer.renderToStaticMarkup(rootElemComponent)
  } else {
    throw (new EmptyMJMLError(`.render: No MJML to render in options ${options.toString()}`))
  }

  debug('React rendering done. Continue with special overrides.')
  let $ = dom.parseHTML(container(options.title, content))

  $('.mj-raw').each(function () {
    $(this).replaceWith($(this).html())
  })

  $ = insertColumnMediaQuery($)
  $ = fixLegacyAttrs($)
  $ = fixOutlookLayout($)
  $ = clean($)

  let html = removeCDATA(dom.getHTML($))

  if (options.beautify) {
    html = beautify(html, {
      indent_size: 2,
      wrap_attributes_indent_size: 2
    })
  }

  return html
}

export default mjml2html
<|endoftext|>


<commit_before>var mongoose = require('mongoose');

var connectionString = process.env.DB_HOST;
mongoose.connect(connectionString);

mongoose.connection.on('connected', function() {
  console.log('mongoose connected to ' + connectionString);
})

mongoose.connection.on('error', function(err) {
  console.log('mongoose connection error ' + err);
})

mongoose.connection.on('disconnected', function() {
  console.log('mongoose disconnected');
})
<commit_msg>minus commas<commit_after>var mongoose = require('mongoose');

var connectionString = process.env.DB_HOST
mongoose.connect(connectionString)

mongoose.connection.on('connected', function() {
  console.log('mongoose connected to ' + connectionString)
})

mongoose.connection.on('error', function(err) {
  console.log('mongoose connection error ' + err)
})

mongoose.connection.on('disconnected', function() {
  console.log('mongoose disconnected')
})
<|endoftext|>


<commit_before>idrinth.core = {
    /**
     *
     * @param {string} str
     * @returns {string}
     */
    escapeRegExp: function ( str ) {
        return str.replace ( /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&" );
    },
    /**
     *
     * @param {object} parent
     * @param {string} field
     * @param {Boolean} allowObjects
     * @returns {Boolean}
     */
    fieldIsSetting: function ( parent, field, allowObjects ) {
        return parent && typeof parent === 'object' && field && parent.hasOwnProperty ( field ) && ( parent[field] === null || typeof parent[field] !== 'object' || allowObjects ) && typeof parent[field] !== 'function';
    },
    /**
     *
     * @type {object}
     */
    ajax: {
        /**
         *
         * @type {object}
         */
        active: { },
        /**
         *
         * @param {string} url
         * @param {function} success
         * @param {function} failure
         * @param {function} timeout
         * @param {string} additionalHeader
         * @param {Boolean} [false] isStatic
         * @returns {undefined}
         */
        runHome: function ( url, success, failure, timeout, additionalHeader, isStatic ) {
            var server = isStatic ? 'static' : ( idrinth.settings.get ( "isWorldServer" ) ? 'world-' : '' ) + idrinth.platform;
            var homeUrl = 'https://dotd.idrinth.de/' + server + ( '/' + url ).replace ( /\/\//, '/' );
            idrinth.core.ajax.run ( homeUrl, success, failure, timeout, additionalHeader );
        },
        /**
         *
         * @param {string} url
         * @param {function} success
         * @param {function} failure
         * @param {function} timeout
         * @param {string} additionalHeader
         * @param {Boolean} [false] isStatic
         * @returns {undefined}
         */
        run: function ( url, success, failure, timeout, additionalHeader ) {
            'use strict';
            var requestHandler = new XMLHttpRequest ( );
            requestHandler.onreadystatechange = function ( event ) {
                var request = ( event || window.event ).target;
                var call = function ( func, value ) {
                    if ( typeof func !== 'function' ) {
                        return;
                    }
                    try {
                        return func ( value );
                    } catch ( e ) {
                        idrinth.core.log ( typeof e.getMessage === 'function' ? e.getMessage () : ( e.message ? e.message : e ) );
                        return null;
                    }
                };
                if ( request.readyState === 4 ) {
                    var status = ( request.status > 199 && request.status < 300 ) || request.status === 0;
                    call ( status ? success : failure, status ? request.responseText : request );
                    delete idrinth.core.ajax.active[request._url];
                }
            };
            requestHandler.timeout = 30000;
            requestHandler.ontimeout = function ( event ) {
                var request = ( event || window.event ).target;
                if ( typeof timeout === 'function' ) {
                    timeout.bind ( request );
                }
                delete idrinth.core.ajax.active[request._url];
                idrinth.core.log ( 'Request to ' + request._url + ' failed.' );
            };
            var error = function ( event ) {
                delete idrinth.core.ajax.active[( event || window.event ).target._url];
                idrinth.core.log ( 'Request to ' + ( event || window.event ).target._url + ' failed.' );
            };
            requestHandler.onerror = error;
            requestHandler.onabort = error;
            requestHandler._url = url;
            requestHandler.open ( "GET", url, true );
            if ( url.match ( '/dotd\.idrinth\.de/' ) ) {
                if ( additionalHeader ) {
                    requestHandler.setRequestHeader ( "Idrinth-Addition", additionalHeader );
                }
                requestHandler.withCredentials = true;
            }
            idrinth.core.ajax.active[url] = requestHandler;
            idrinth.core.ajax.active[url].send ( );
        }
    },
    /**
     *
     * @type {object}
     */
    copyToClipboard: {
        /**
         *
         * @param {string} text
         * @returns {Boolean}
         */
        text: function ( text ) {
            var success;
            try {
                var textAreaElement = idrinth.ui.buildElement ( {
                    type: 'textarea',
                    id: "idrinth-copy-helper"
                } );
                textAreaElement.value = text;
                idrinth.ui.base.appendChild ( textAreaElement );
                textAreaElement.select ( );
                success = document.execCommand ( 'copy' );
            } catch ( exception ) {
                idrinth.core.log ( exception.getMessage ( ) );
                success = false;
            }
            idrinth.ui.removeElement ( "idrinth-copy-helper" );
            return success;
        },
        /**
         *
         * @param {HTMLElement} element
         * @returns {string}
         */
        element: function ( element ) {
            if ( element.hasAttribute ( 'data-clipboard-text' ) ) {
                return idrinth.core.copyToClipboard.text ( element.getAttribute ( 'data-clipboard-text' ) );
            }
            if ( element.value ) {
                return idrinth.core.copyToClipboard.text ( element.value );
            }
            return idrinth.core.copyToClipboard.text ( element.innerHTML );
        }
    },
    /**
     *
     * @param {string} title
     * @param {string|HTMLElement} content
     * @returns {Boolean|window.Notification}
     */
    sendNotification: function ( title, content ) {
        if ( !( "Notification" in window ) ) {
            return false;
        }
        if ( window.Notification.permission === "default" ) {
            window.Notification.requestPermission ( );
        }
        if ( window.Notification.permission === "denied" ) {
            return false;
        }
        return new window.Notification ( title, {
            icon: "https://dotd.idrinth.de/Resources/Images/logo.png",
            body: content
        } );
    },
    /**
     *
     * @type {object}
     */
    timeouts: {
        /**
         *
         * @type {object}
         */
        next: null,
        /**
         *
         * @type {object}
         */
        list: { },
        /**
         * makes sure the timeout is removed when called next
         * @param {string} identifier
         * @returns {undefined}
         */
        remove: function ( identifier ) {
            'use strict';
            if ( idrinth.core.timeouts.list[identifier] !== undefined ) {
                idrinth.core.timeouts.list[identifier].repeats = 1;
                idrinth.core.timeouts.list[identifier].func = function () {
                };
            }
        },
        /**
         *
         * @param {string} identifier
         * @param {function} func
         * @param {int} time in milliseconds
         * @param {Number} [1] maxRepeats -1 will repeat until the end of time
         * @returns {undefined}
         */
        add: function ( identifier, func, time, maxRepeats ) {
            'use strict';
            var date = new Date ();
            idrinth.core.timeouts.list[identifier] = {
                func: func,
                next: date.getTime () + date.getMilliseconds () / 1000 + time / 1000,
                duration: time,
                repeats: maxRepeats ? maxRepeats : 1
            };
            if ( !idrinth.core.timeouts.next ) {
                idrinth.core.timeouts.next = window.setTimeout ( idrinth.core.timeouts.process, 1000 );
            }
        },
        /**
         * activates all relevant timeouts and intervals
         * @returns {undefined}
         */
        process: function () {
            'use strict';
            var date = ( new Date () ).getTime () + ( new Date () ).getMilliseconds () / 1000;
            var min = 10;
            /**
             *
             * @param {Number} durationLeft
             * @param {Number} minDuration
             * @returns {Number}
             */
            var getVal = function ( durationLeft, minDuration ) {
                if ( durationLeft < 0.1 ) {
                    return 0.1;
                }
                return durationLeft < minDuration ? durationLeft : minDuration;
            };
            for (var property in idrinth.core.timeouts.list) {
                if ( idrinth.core.timeouts.list.hasOwnProperty ( property ) ) {
                    if ( date >= idrinth.core.timeouts.list[property].next ) {
                        try {
                            idrinth.core.timeouts.list[property].func ();
                            idrinth.core.timeouts.list[property].repeats = Math.max ( -1, idrinth.core.timeouts.list[property].repeats - 1 );
                            if ( idrinth.core.timeouts.list[property].repeats ) {
                                min = getVal ( idrinth.core.timeouts.list[property].duration, min );
                                idrinth.core.timeouts.list[property].next = date + idrinth.core.timeouts.list[property].duration / 1000;
                            } else {
                                delete idrinth.core.timeouts.list[property];
                            }
                        } catch ( e ) {
                            idrinth.core.log ( e.message ? e.message : e.getMessage () );
                        }
                    } else {
                        min = getVal ( idrinth.core.timeouts.list[property].next - date, min );
                    }
                }
            }
            if ( Object.keys ( idrinth.core.timeouts.list ).length ) {
                idrinth.core.timeouts.next = window.setTimeout ( idrinth.core.timeouts.process, Math.ceil ( min * 1000 ) );
            }
        }
    },
    /**
     *
     * @param {string} string
     * @returns {undefined}
     */
    log: function ( string ) {
        'use strict';
        console.log ( '[IDotDS] ' + string );
    },
    /**
     *
     * @param {string} text
     * @returns {undefined}
     */
    alert: function ( text ) {
        idrinth.ui.buildModal ( 'Info', text );
    },
    /**
     *
     * @param {string} text
     * @param {function} callback
     * @returns {undefined}
     */
    confirm: function ( text, callback ) {
        idrinth.ui.buildModal ( 'Do you?', text, callback );
    },
    /**
     *
     * @type {object}
     */
    multibind: {
        /**
         *
         * @type {object}
         */
        events: { },
        /**
         *
         * @param {string} event
         * @param {string} selector
         * @param {function} method
         * @returns {undefined}
         */
        add: function ( event, selector, method ) {
            var bind = function ( event, selector, method ) {
                idrinth.core.multibind.events[event] = idrinth.core.multibind.events[event] ? idrinth.core.multibind.events[event] : { };
                idrinth.core.multibind.events[event][selector] = idrinth.core.multibind.events[event][selector] ? idrinth.core.multibind.events[event][selector] : [ ];
                idrinth.core.multibind.events[event][selector].push ( method );
            };
            if ( !idrinth.core.multibind.events[event] ) {
                idrinth.ui.base.addEventListener ( event, idrinth.core.multibind.triggered );
            }
            bind ( event, selector, method );
        },
        /**
         *
         * @param {Event} [window.event] event
         * @returns {undefined}
         */
        triggered: function ( event ) {
            /**
             *
             * @param {HTMLElement} el
             * @param {string} event
             * @param {string} selector
             * @returns {undefined}
             */
            var handleElement = function ( el, event, selector ) {
                if ( !el ) {
                    return;
                }
                for (var pos = 0; pos < idrinth.core.multibind.events[event][selector].length; pos++) {
                    try {
                        idrinth.core.multibind.events[event][selector][pos] ( el, event );
                    } catch ( exception ) {
                        idrinth.core.log ( exception.message ? exception.message : exception.getMessage () );
                    }
                }
            };
            event = event || window.event;
            if ( idrinth.core.multibind.events[event.type] ) {
                for (var selector in idrinth.core.multibind.events[event.type]) {
                    if ( idrinth.core.multibind.events[event.type].hasOwnProperty ( selector ) ) {
                        handleElement ( idrinth.ui.matchesCss ( event.target, selector ), event.type, selector );
                    }
                }
            }
        }
    }
};
<commit_msg>extracting functionality from loop into own function<commit_after>idrinth.core = {
    /**
     *
     * @param {string} str
     * @returns {string}
     */
    escapeRegExp: function ( str ) {
        return str.replace ( /[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&" );
    },
    /**
     *
     * @param {object} parent
     * @param {string} field
     * @param {Boolean} allowObjects
     * @returns {Boolean}
     */
    fieldIsSetting: function ( parent, field, allowObjects ) {
        return parent && typeof parent === 'object' && field && parent.hasOwnProperty ( field ) && ( parent[field] === null || typeof parent[field] !== 'object' || allowObjects ) && typeof parent[field] !== 'function';
    },
    /**
     *
     * @type {object}
     */
    ajax: {
        /**
         *
         * @type {object}
         */
        active: { },
        /**
         *
         * @param {string} url
         * @param {function} success
         * @param {function} failure
         * @param {function} timeout
         * @param {string} additionalHeader
         * @param {Boolean} [false] isStatic
         * @returns {undefined}
         */
        runHome: function ( url, success, failure, timeout, additionalHeader, isStatic ) {
            var server = isStatic ? 'static' : ( idrinth.settings.get ( "isWorldServer" ) ? 'world-' : '' ) + idrinth.platform;
            var homeUrl = 'https://dotd.idrinth.de/' + server + ( '/' + url ).replace ( /\/\//, '/' );
            idrinth.core.ajax.run ( homeUrl, success, failure, timeout, additionalHeader );
        },
        /**
         *
         * @param {string} url
         * @param {function} success
         * @param {function} failure
         * @param {function} timeout
         * @param {string} additionalHeader
         * @param {Boolean} [false] isStatic
         * @returns {undefined}
         */
        run: function ( url, success, failure, timeout, additionalHeader ) {
            'use strict';
            var requestHandler = new XMLHttpRequest ( );
            requestHandler.onreadystatechange = function ( event ) {
                var request = ( event || window.event ).target;
                var call = function ( func, value ) {
                    if ( typeof func !== 'function' ) {
                        return;
                    }
                    try {
                        return func ( value );
                    } catch ( e ) {
                        idrinth.core.log ( typeof e.getMessage === 'function' ? e.getMessage () : ( e.message ? e.message : e ) );
                        return null;
                    }
                };
                if ( request.readyState === 4 ) {
                    var status = ( request.status > 199 && request.status < 300 ) || request.status === 0;
                    call ( status ? success : failure, status ? request.responseText : request );
                    delete idrinth.core.ajax.active[request._url];
                }
            };
            requestHandler.timeout = 30000;
            requestHandler.ontimeout = function ( event ) {
                var request = ( event || window.event ).target;
                if ( typeof timeout === 'function' ) {
                    timeout.bind ( request );
                }
                delete idrinth.core.ajax.active[request._url];
                idrinth.core.log ( 'Request to ' + request._url + ' failed.' );
            };
            var error = function ( event ) {
                delete idrinth.core.ajax.active[( event || window.event ).target._url];
                idrinth.core.log ( 'Request to ' + ( event || window.event ).target._url + ' failed.' );
            };
            requestHandler.onerror = error;
            requestHandler.onabort = error;
            requestHandler._url = url;
            requestHandler.open ( "GET", url, true );
            if ( url.match ( '/dotd\.idrinth\.de/' ) ) {
                if ( additionalHeader ) {
                    requestHandler.setRequestHeader ( "Idrinth-Addition", additionalHeader );
                }
                requestHandler.withCredentials = true;
            }
            idrinth.core.ajax.active[url] = requestHandler;
            idrinth.core.ajax.active[url].send ( );
        }
    },
    /**
     *
     * @type {object}
     */
    copyToClipboard: {
        /**
         *
         * @param {string} text
         * @returns {Boolean}
         */
        text: function ( text ) {
            var success;
            try {
                var textAreaElement = idrinth.ui.buildElement ( {
                    type: 'textarea',
                    id: "idrinth-copy-helper"
                } );
                textAreaElement.value = text;
                idrinth.ui.base.appendChild ( textAreaElement );
                textAreaElement.select ( );
                success = document.execCommand ( 'copy' );
            } catch ( exception ) {
                idrinth.core.log ( exception.getMessage ( ) );
                success = false;
            }
            idrinth.ui.removeElement ( "idrinth-copy-helper" );
            return success;
        },
        /**
         *
         * @param {HTMLElement} element
         * @returns {string}
         */
        element: function ( element ) {
            if ( element.hasAttribute ( 'data-clipboard-text' ) ) {
                return idrinth.core.copyToClipboard.text ( element.getAttribute ( 'data-clipboard-text' ) );
            }
            if ( element.value ) {
                return idrinth.core.copyToClipboard.text ( element.value );
            }
            return idrinth.core.copyToClipboard.text ( element.innerHTML );
        }
    },
    /**
     *
     * @param {string} title
     * @param {string|HTMLElement} content
     * @returns {Boolean|window.Notification}
     */
    sendNotification: function ( title, content ) {
        if ( !( "Notification" in window ) ) {
            return false;
        }
        if ( window.Notification.permission === "default" ) {
            window.Notification.requestPermission ( );
        }
        if ( window.Notification.permission === "denied" ) {
            return false;
        }
        return new window.Notification ( title, {
            icon: "https://dotd.idrinth.de/Resources/Images/logo.png",
            body: content
        } );
    },
    /**
     *
     * @type {object}
     */
    timeouts: {
        /**
         *
         * @type {object}
         */
        next: null,
        /**
         *
         * @type {object}
         */
        list: { },
        /**
         * makes sure the timeout is removed when called next
         * @param {string} identifier
         * @returns {undefined}
         */
        remove: function ( identifier ) {
            'use strict';
            if ( idrinth.core.timeouts.list[identifier] !== undefined ) {
                idrinth.core.timeouts.list[identifier].repeats = 1;
                idrinth.core.timeouts.list[identifier].func = function () {
                };
            }
        },
        /**
         *
         * @param {string} identifier
         * @param {function} func
         * @param {int} time in milliseconds
         * @param {Number} [1] maxRepeats -1 will repeat until the end of time
         * @returns {undefined}
         */
        add: function ( identifier, func, time, maxRepeats ) {
            'use strict';
            var date = new Date ();
            idrinth.core.timeouts.list[identifier] = {
                func: func,
                next: date.getTime () + date.getMilliseconds () / 1000 + time / 1000,
                duration: time,
                repeats: maxRepeats ? maxRepeats : 1
            };
            if ( !idrinth.core.timeouts.next ) {
                idrinth.core.timeouts.next = window.setTimeout ( idrinth.core.timeouts.process, 1000 );
            }
        },
        /**
         * activates all relevant timeouts and intervals
         * @returns {undefined}
         */
        process: function () {
            'use strict';
            var date = ( new Date () ).getTime () + ( new Date () ).getMilliseconds () / 1000;
            var min = 10;
            /**
             *
             * @param {Number} durationLeft
             * @param {Number} minDuration
             * @returns {Number}
             */
            var getVal = function ( durationLeft, minDuration ) {
                if ( durationLeft < 0.1 ) {
                    return 0.1;
                }
                return durationLeft < minDuration ? durationLeft : minDuration;
            };
            /**
             *
             * @param {string} property
             * @returns {undefined}
             */
            var handle = function ( property, min ) {
                idrinth.core.timeouts.list[property].func ();
                idrinth.core.timeouts.list[property].repeats = Math.max ( -1, idrinth.core.timeouts.list[property].repeats - 1 );
                if ( idrinth.core.timeouts.list[property].repeats ) {
                    min = getVal ( idrinth.core.timeouts.list[property].duration, min );
                    idrinth.core.timeouts.list[property].next = date + idrinth.core.timeouts.list[property].duration / 1000;
                } else {
                    delete idrinth.core.timeouts.list[property];
                }
                return min;
            };
            for (var property in idrinth.core.timeouts.list) {
                if ( idrinth.core.timeouts.list.hasOwnProperty ( property ) ) {
                    if ( date >= idrinth.core.timeouts.list[property].next ) {
                        try {
                            min = handle ( property, min );
                        } catch ( e ) {
                            idrinth.core.log ( e.message ? e.message : e.getMessage () );
                        }
                    } else {
                        min = getVal ( idrinth.core.timeouts.list[property].next - date, min );
                    }
                }
            }
            if ( Object.keys ( idrinth.core.timeouts.list ).length ) {
                idrinth.core.timeouts.next = window.setTimeout ( idrinth.core.timeouts.process, Math.ceil ( min * 1000 ) );
            }
        }
    },
    /**
     *
     * @param {string} string
     * @returns {undefined}
     */
    log: function ( string ) {
        'use strict';
        console.log ( '[IDotDS] ' + string );
    },
    /**
     *
     * @param {string} text
     * @returns {undefined}
     */
    alert: function ( text ) {
        idrinth.ui.buildModal ( 'Info', text );
    },
    /**
     *
     * @param {string} text
     * @param {function} callback
     * @returns {undefined}
     */
    confirm: function ( text, callback ) {
        idrinth.ui.buildModal ( 'Do you?', text, callback );
    },
    /**
     *
     * @type {object}
     */
    multibind: {
        /**
         *
         * @type {object}
         */
        events: { },
        /**
         *
         * @param {string} event
         * @param {string} selector
         * @param {function} method
         * @returns {undefined}
         */
        add: function ( event, selector, method ) {
            var bind = function ( event, selector, method ) {
                idrinth.core.multibind.events[event] = idrinth.core.multibind.events[event] ? idrinth.core.multibind.events[event] : { };
                idrinth.core.multibind.events[event][selector] = idrinth.core.multibind.events[event][selector] ? idrinth.core.multibind.events[event][selector] : [ ];
                idrinth.core.multibind.events[event][selector].push ( method );
            };
            if ( !idrinth.core.multibind.events[event] ) {
                idrinth.ui.base.addEventListener ( event, idrinth.core.multibind.triggered );
            }
            bind ( event, selector, method );
        },
        /**
         *
         * @param {Event} [window.event] event
         * @returns {undefined}
         */
        triggered: function ( event ) {
            /**
             *
             * @param {HTMLElement} el
             * @param {string} event
             * @param {string} selector
             * @returns {undefined}
             */
            var handleElement = function ( el, event, selector ) {
                if ( !el ) {
                    return;
                }
                for (var pos = 0; pos < idrinth.core.multibind.events[event][selector].length; pos++) {
                    try {
                        idrinth.core.multibind.events[event][selector][pos] ( el, event );
                    } catch ( exception ) {
                        idrinth.core.log ( exception.message ? exception.message : exception.getMessage () );
                    }
                }
            };
            event = event || window.event;
            if ( idrinth.core.multibind.events[event.type] ) {
                for (var selector in idrinth.core.multibind.events[event.type]) {
                    if ( idrinth.core.multibind.events[event.type].hasOwnProperty ( selector ) ) {
                        handleElement ( idrinth.ui.matchesCss ( event.target, selector ), event.type, selector );
                    }
                }
            }
        }
    }
};
<|endoftext|>


<commit_before>/*
This module provides a direct interface with the ctpubsub backend. Here's how to use it.

	CT.pubsub.connect(host, port, uname)
	CT.pubsub.publish(channel, message)
	CT.pubsub.subscribe(channel)
	CT.pubsub.unsubscribe(channel)
	CT.pubsub.meta(channel, meta)
	CT.pubsub.pm(user, message)
	CT.pubsub.set_cb(action, cb)
	CT.pubsub.set_reconnect(bool)
	CT.pubsub.isInitialized() (returns bool)
*/

CT.pubsub = {
	"_": {
		"ws": null,
		"args": null,
		"open": false,
		"initialized": false,
		"autohistory": false,
		"autohistory_exemptions": [],
		"reconnect": true,
		"reconnect_interval": 250,
		"protocol": location.protocol == "http:" && "ws" || "wss",
		"log": CT.log.getLogger("CT.pubsub"),
		"queue": [],
		"channels": {},
		"cb": { // default callbacks -- override w/ set_cb()
			"snapshot": CT.log.getLogger("CT.pubsub|snapshot"),
			"pm": CT.log.getLogger("CT.pubsub|pm"),
			"meta": CT.log.getLogger("CT.pubsub|meta"),
			"message": CT.log.getLogger("CT.pubsub|message"),
			"subscribe": CT.log.getLogger("CT.pubsub|subscribe"),
			"join": CT.log.getLogger("CT.pubsub|join"),
			"leave": CT.log.getLogger("CT.pubsub|leave"),
			"presence": CT.log.getLogger("CT.pubsub|presence"),
			"open": CT.log.getLogger("CT.pubsub|open"),
			"close": CT.log.getLogger("CT.pubsub|close"),
			"wserror": CT.log.getLogger("CT.pubsub|wserror"), // websocket -- almost same as close
			"error": CT.log.getLogger("CT.pubsub|error") // non-fatal pubsub error
		},
		"process": { // pubsub events
			"channel": function(data) {
				var _ = CT.pubsub._;
				if (data.meta) {
					data.metamap = {};
					data.presence.forEach(function(u, i) {
						data.metamap[u] = data.meta[i];
					});
				}
				_.channels[data.channel] = data;
				_.cb.subscribe(data);
				if (_.autohistory && (_.autohistory_exemptions.indexOf(data.channel) == -1))
					data.history.forEach(CT.pubsub._.process.publish);
				CT.pubsub._.cb.presence(data.presence.length, data.channel);
			},
			"meta": function(data) {
				CT.pubsub._.channels[data.channel].metamap[data.user] = data.meta;
				CT.pubsub._.cb.meta(data);
			},
			"publish": function(data) {
				CT.pubsub._.cb.message(data);
			},
			"subscribe": function(data) {
				CT.pubsub._.cb.join(data.channel, data.user, data.meta);
				var chan = CT.pubsub._.channels[data.channel];
				if (chan) {
					if (chan.metamap)
						chan.metamap[data.user] = data.meta;
					CT.data.append(chan.presence, data.user);
					CT.pubsub._.cb.presence(chan.presence.length, data.channel);
				}
			},
			"unsubscribe": function(data) {
				CT.pubsub._.cb.leave(data.channel, data.user);
				var chan = CT.pubsub._.channels[data.channel];
				if (chan) {
					if (chan.metamap)
						delete chan.metamap[data.user];
					CT.data.remove(chan.presence, data.user);
					CT.pubsub._.cb.presence(chan.presence.length, data.channel);
				}
			},
			"pm": function(data) {
				CT.pubsub._.cb.pm(data.message, data.user);
			},
			"error": function(data) {
				CT.pubsub._.cb.error(data.message);
			},
			"snapshot": function(data) {
				CT.pubsub._.cb.snapshot(data);
				data.channels.forEach(function(c) {
					var cdata = CT.pubsub._.channels[c.name] = {
						channel: c.name,
						presence: c.users
					};
					CT.pubsub._.cb.subscribe(cdata);
				});
			}
		},
		"on": { // websocket events
			"open": function() {
				CT.pubsub._.open = true;
				CT.pubsub._.reconnect_interval = 250;
				CT.pubsub._.write({
					"action": "register",
					"data": CT.pubsub._.args[2],
					"meta": CT.pubsub._.args[4]
				});
				for (var channel in CT.pubsub._.channels)
					CT.pubsub.subscribe(channel);
				CT.pubsub._.queue.forEach(CT.pubsub._.write);
				CT.pubsub._.queue.length = 0;
				CT.pubsub._.cb.open();
			},
			"close": function() {
				CT.pubsub._.open = false;
				CT.pubsub._.cb.close();
				if (CT.pubsub._.reconnect)
					CT.pubsub._.try_reconnect()
			},
			"error": function() {
				CT.pubsub._.cb.wserror();
			},
			"message": function(msg) {
				var d = JSON.parse(atob(msg.data));
				CT.pubsub._.process[d.action](d.data);
			}
		},
		"write": function(data) {
			if (CT.pubsub._.open) {
				var dstring = JSON.stringify(data),
					b64str = btoa(dstring);
				CT.pubsub._.ws.send(b64str);
			} else
				CT.pubsub._.queue.push(data);
		},
		"try_reconnect": function() {
			var r_int = CT.pubsub._.reconnect_interval;
			CT.pubsub._.log("RECONNECT", r_int);
			setTimeout(function() {
				CT.pubsub.connect.apply(null, CT.pubsub._.args)
			}, r_int);
			CT.pubsub._.reconnect_interval = Math.min(2 * r_int, 30000);
		}
	},
	"isInitialized": function() {
		return CT.pubsub._.initialized;
	},
	"set_protocol": function(protocol) {
		CT.pubsub._.protocol = protocol;
	},
	"set_reconnect": function(bool) {
		CT.pubsub._.reconnect = bool;
	},
	"set_autohistory": function(bool, exemptions, mergeExemptions) {
		CT.pubsub._.autohistory = bool;
		if (exemptions) {
			if (mergeExemptions) {
				exemptions.forEach(function(e) {
					CT.pubsub._.autohistory_exemptions.push(e);
				});
			} else
				CT.pubsub._.autohistory_exemptions = exemptions;
		}
	},
	"set_cb": function(action, cb) {
		// action: message|subscribe|join|leave|presence|open|close|error|pm|meta
		CT.pubsub._.cb[action] = cb;
	},
	"presence": function(channel) {
		return CT.pubsub._.channels[channel].presence;
	},
	"pm": function(user, message) {
		CT.pubsub._.write({
			"action": "pm",
			"data": {
				"user": user,
				"message": message
			}
		});
	},
	"meta": function(channel, meta) {
		CT.pubsub._.write({
			"action": "meta",
			"data": {
				"channel": channel,
				"meta": meta
			}
		});
	},
	"publish": function(channel, message) {
		CT.pubsub._.write({
			"action": "publish",
			"data": {
				"channel": channel,
				"message": message
			}
		});
	},
	"subscribe": function(channel) {
		CT.pubsub._.write({
			"action": "subscribe",
			"data": channel
		});
	},
	"unsubscribe": function(channel) {
		CT.pubsub._.write({
			"action": "unsubscribe",
			"data": channel
		});
	},
	"connect": function(host, port, uname, onbeforeunload, meta) {
		CT.pubsub._.args = arguments;
		CT.pubsub._.initialized = true;
		CT.pubsub._.ws = new WebSocket(CT.pubsub._.protocol + "://" + host + ":" + port);
		for (var action in CT.pubsub._.on)
			CT.pubsub._.ws["on" + action] = CT.pubsub._.on[action];
		window.addEventListener("beforeunload", function() {
			onbeforeunload && onbeforeunload();
			CT.pubsub._.write({ "action": "close" });
		});
	}
};<commit_msg>CT.pubsub b64 configurization: set_b64(); read/write switches<commit_after>/*
This module provides a direct interface with the ctpubsub backend. Here's how to use it.

	CT.pubsub.connect(host, port, uname)
	CT.pubsub.publish(channel, message)
	CT.pubsub.subscribe(channel)
	CT.pubsub.unsubscribe(channel)
	CT.pubsub.meta(channel, meta)
	CT.pubsub.pm(user, message)
	CT.pubsub.set_cb(action, cb)
	CT.pubsub.set_reconnect(bool)
	CT.pubsub.isInitialized() (returns bool)
*/

CT.pubsub = {
	"_": {
		"ws": null,
		"b64": false,
		"args": null,
		"open": false,
		"initialized": false,
		"autohistory": false,
		"autohistory_exemptions": [],
		"reconnect": true,
		"reconnect_interval": 250,
		"protocol": location.protocol == "http:" && "ws" || "wss",
		"log": CT.log.getLogger("CT.pubsub"),
		"queue": [],
		"channels": {},
		"cb": { // default callbacks -- override w/ set_cb()
			"snapshot": CT.log.getLogger("CT.pubsub|snapshot"),
			"pm": CT.log.getLogger("CT.pubsub|pm"),
			"meta": CT.log.getLogger("CT.pubsub|meta"),
			"message": CT.log.getLogger("CT.pubsub|message"),
			"subscribe": CT.log.getLogger("CT.pubsub|subscribe"),
			"join": CT.log.getLogger("CT.pubsub|join"),
			"leave": CT.log.getLogger("CT.pubsub|leave"),
			"presence": CT.log.getLogger("CT.pubsub|presence"),
			"open": CT.log.getLogger("CT.pubsub|open"),
			"close": CT.log.getLogger("CT.pubsub|close"),
			"wserror": CT.log.getLogger("CT.pubsub|wserror"), // websocket -- almost same as close
			"error": CT.log.getLogger("CT.pubsub|error") // non-fatal pubsub error
		},
		"process": { // pubsub events
			"channel": function(data) {
				var _ = CT.pubsub._;
				if (data.meta) {
					data.metamap = {};
					data.presence.forEach(function(u, i) {
						data.metamap[u] = data.meta[i];
					});
				}
				_.channels[data.channel] = data;
				_.cb.subscribe(data);
				if (_.autohistory && (_.autohistory_exemptions.indexOf(data.channel) == -1))
					data.history.forEach(CT.pubsub._.process.publish);
				CT.pubsub._.cb.presence(data.presence.length, data.channel);
			},
			"meta": function(data) {
				CT.pubsub._.channels[data.channel].metamap[data.user] = data.meta;
				CT.pubsub._.cb.meta(data);
			},
			"publish": function(data) {
				CT.pubsub._.cb.message(data);
			},
			"subscribe": function(data) {
				CT.pubsub._.cb.join(data.channel, data.user, data.meta);
				var chan = CT.pubsub._.channels[data.channel];
				if (chan) {
					if (chan.metamap)
						chan.metamap[data.user] = data.meta;
					CT.data.append(chan.presence, data.user);
					CT.pubsub._.cb.presence(chan.presence.length, data.channel);
				}
			},
			"unsubscribe": function(data) {
				CT.pubsub._.cb.leave(data.channel, data.user);
				var chan = CT.pubsub._.channels[data.channel];
				if (chan) {
					if (chan.metamap)
						delete chan.metamap[data.user];
					CT.data.remove(chan.presence, data.user);
					CT.pubsub._.cb.presence(chan.presence.length, data.channel);
				}
			},
			"pm": function(data) {
				CT.pubsub._.cb.pm(data.message, data.user);
			},
			"error": function(data) {
				CT.pubsub._.cb.error(data.message);
			},
			"snapshot": function(data) {
				CT.pubsub._.cb.snapshot(data);
				data.channels.forEach(function(c) {
					var cdata = CT.pubsub._.channels[c.name] = {
						channel: c.name,
						presence: c.users
					};
					CT.pubsub._.cb.subscribe(cdata);
				});
			}
		},
		"on": { // websocket events
			"open": function() {
				CT.pubsub._.open = true;
				CT.pubsub._.reconnect_interval = 250;
				CT.pubsub._.write({
					"action": "register",
					"data": CT.pubsub._.args[2],
					"meta": CT.pubsub._.args[4]
				});
				for (var channel in CT.pubsub._.channels)
					CT.pubsub.subscribe(channel);
				CT.pubsub._.queue.forEach(CT.pubsub._.write);
				CT.pubsub._.queue.length = 0;
				CT.pubsub._.cb.open();
			},
			"close": function() {
				CT.pubsub._.open = false;
				CT.pubsub._.cb.close();
				if (CT.pubsub._.reconnect)
					CT.pubsub._.try_reconnect()
			},
			"error": function() {
				CT.pubsub._.cb.wserror();
			},
			"message": function(msg) {
				var _ = CT.pubsub._,
					d = JSON.parse(_.b64 ? atob(msg.data) : msg.data);
				_.process[d.action](d.data);
			}
		},
		"write": function(data) {
			var _ = CT.pubsub._;
			if (_.open) {
				var dstring = JSON.stringify(data);
				_.ws.send(_.b64 ? btoa(dstring) : dstring);
			} else
				_.queue.push(data);
		},
		"try_reconnect": function() {
			var r_int = CT.pubsub._.reconnect_interval;
			CT.pubsub._.log("RECONNECT", r_int);
			setTimeout(function() {
				CT.pubsub.connect.apply(null, CT.pubsub._.args)
			}, r_int);
			CT.pubsub._.reconnect_interval = Math.min(2 * r_int, 30000);
		}
	},
	"isInitialized": function() {
		return CT.pubsub._.initialized;
	},
	"set_b64": function(bool) {
		CT.pubsub._.b64 = bool;
	},
	"set_protocol": function(protocol) {
		CT.pubsub._.protocol = protocol;
	},
	"set_reconnect": function(bool) {
		CT.pubsub._.reconnect = bool;
	},
	"set_autohistory": function(bool, exemptions, mergeExemptions) {
		CT.pubsub._.autohistory = bool;
		if (exemptions) {
			if (mergeExemptions) {
				exemptions.forEach(function(e) {
					CT.pubsub._.autohistory_exemptions.push(e);
				});
			} else
				CT.pubsub._.autohistory_exemptions = exemptions;
		}
	},
	"set_cb": function(action, cb) {
		// action: message|subscribe|join|leave|presence|open|close|error|pm|meta
		CT.pubsub._.cb[action] = cb;
	},
	"presence": function(channel) {
		return CT.pubsub._.channels[channel].presence;
	},
	"pm": function(user, message) {
		CT.pubsub._.write({
			"action": "pm",
			"data": {
				"user": user,
				"message": message
			}
		});
	},
	"meta": function(channel, meta) {
		CT.pubsub._.write({
			"action": "meta",
			"data": {
				"channel": channel,
				"meta": meta
			}
		});
	},
	"publish": function(channel, message) {
		CT.pubsub._.write({
			"action": "publish",
			"data": {
				"channel": channel,
				"message": message
			}
		});
	},
	"subscribe": function(channel) {
		CT.pubsub._.write({
			"action": "subscribe",
			"data": channel
		});
	},
	"unsubscribe": function(channel) {
		CT.pubsub._.write({
			"action": "unsubscribe",
			"data": channel
		});
	},
	"connect": function(host, port, uname, onbeforeunload, meta) {
		CT.pubsub._.args = arguments;
		CT.pubsub._.initialized = true;
		CT.pubsub._.ws = new WebSocket(CT.pubsub._.protocol + "://" + host + ":" + port);
		for (var action in CT.pubsub._.on)
			CT.pubsub._.ws["on" + action] = CT.pubsub._.on[action];
		window.addEventListener("beforeunload", function() {
			onbeforeunload && onbeforeunload();
			CT.pubsub._.write({ "action": "close" });
		});
	}
};<|endoftext|>


<commit_before>//create the map, set the zoom, add it to the 'map' div element
    var map = L.map('map')
        .setView([36, -93], 3);
        L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            maxZoom: 18,
            minZoom: 3,
            attribution: '© OpenStreetMap',
        }).addTo(map);

//create the geocoder
    new L.Control.GeoSearch({
        provider: new L.GeoSearch.Provider.OpenStreetMap(),
        position: 'topleft',
        showMarker: true,
        retainZoomLevel: false,
    }).addTo(map);

//data location
    var csvrider = "/carpool-map/data/unmatched-rider.csv";
    var csvdriver = "/carpool-map/data/unmatched-driver.csv";

//create a geojson layer from the csv file, .addTo(map) turns these layers on by default
//credits to Mapbox for Omnivore methods
    var omniParseRider = omnivore.csv(csvrider)
    .on('ready', function() {
        // when this is fired, the layer
        // is done being initialized
    })
    .on('error', function() {
        // fired if the layer can't be loaded over AJAX
        // or can't be parsed
    })
    .addTo(map);

    var omniParseDriver = omnivore.csv(csvdriver)
    .on('ready', function() {
    })
    .on('error', function() {
    })
    .addTo(map);

    var overlayGroup = L.layerGroup([omniParseRider, omniParseDriver]);

    var overlaylabels = {
        "Riders": omniParseRider,
        "Drivers": omniParseDriver,
    };

    L.control.layers(null, overlaylabels).addTo(map);<commit_msg>Change in comments<commit_after>//create the map, set the zoom, add it to the 'map' div element
    var map = L.map('map')
        .setView([36, -93], 3);
        L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
            maxZoom: 18,
            minZoom: 3,
            attribution: '© OpenStreetMap',
        }).addTo(map);

//create the geocoder
    new L.Control.GeoSearch({
        provider: new L.GeoSearch.Provider.OpenStreetMap(),
        position: 'topleft',
        showMarker: true,
        retainZoomLevel: false,
    }).addTo(map);

//data location
    var csvrider = "/carpool-map/data/unmatched-rider.csv";
    var csvdriver = "/carpool-map/data/unmatched-driver.csv";

//create a geojson layer from the csv file, .addTo(map) turns these layers on by default
//credits to Mapbox for Omnivore methods
    var omniParseRider = omnivore.csv(csvrider)
    .on('ready', function() {
        // when this is fired, the layer
        // is done being initialized
    })
    .on('error', function() {
        // fired if the layer can't be loaded over AJAX
        // or can't be parsed
    })
    .addTo(map);

    var omniParseDriver = omnivore.csv(csvdriver)
    .on('ready', function() {
    })
    .on('error', function() {
    })
    .addTo(map);

// load these layers into a group for the layer control
    var overlayGroup = L.layerGroup([omniParseRider, omniParseDriver]);

//create "label": key for layers
    var overlaylabels = {
        "Riders": omniParseRider,
        "Drivers": omniParseDriver,
    };

//load the label, then the layer from the layer group
//loads the map controller, using the .addTo(map) method when creating the layer initially determines if on/off at start
    L.control.layers(null, overlaylabels).addTo(map);<|endoftext|>


<commit_before>define(function(require, exports, module) {
    "use strict";

    main.consumes = [
        "connect.render",
        "connect.render.ejs",
        "connect.redirect",
        "connect.static"
    ];
    main.provides = ["preview.handler"];
    return main;

    function main(options, imports, register) {
        var error = require("http-error");
        var https = require("https");
        var http = require("http");
        var mime = require("mime");
        var parseUrl = require("url").parse;
        var debug = require("debug")("preview");

        var staticPrefix = imports["connect.static"].getStaticPrefix();

        function getProjectSession() {
            return function(req, res, next) {
                var session = req.session;

                req.user = req.user || { id: -1 };

                var username = req.params.username;
                var projectname = req.params.projectname;

                var ws = req.ws = username + "/" + projectname;

                if (!session.ws)
                    session.ws = {};

                req.projectSession = session.ws[ws];
                if (!req.projectSession || !req.projectSession.expires || req.projectSession.expires <= Date.now()) {
                    req.projectSession = session.ws[ws] = {
                        expires: Date.now() + 10000
                    };
                }

                next();
            };
        }

        function getRole(db) {
            return function(req, res, next) {
                if (req.projectSession.role) {
                    return next();
                }

                db.Project.findOne({
                    username: req.params.username,
                    name: req.params.projectname
                }, function(err, project) {
                    if (err && err.code == 404)
                        return next(new error.NotFound("Project '" + req.ws + "' doest not exist."));

                    if (err) return next(err);

                    project.getRole(req.user, function(err, role) {
                        if (err) return next(err);

                        if (role == db.Project.ROLE_NONE) {
                            if (project.isPublicPreview())
                                role = db.Project.ROLE_VISITOR;
                            else if (req.user.id == -1)
                                return next(new error.Unauthorized());
                            else
                                return next(new error.Forbidden("You don't have access rights to preview this workspace"));
                        }
                        req.projectSession.role = role;
                        req.projectSession.pid = project.id;

                        var type = project.scm;
                        req.projectSession.type = type;

                        if (type != "docker" || project.state != db.Project.STATE_READY)
                            return next();

                        project.populate("remote", function(err) {
                            if (err) return next(err);

                            var meta = project.remote.metadata;
                            if (meta && meta.host && meta.cid) {
                                db.Container.load(meta.cid, function(err, container) {
                                    if (err) return next(err);

                                    if (container.state == db.Container.STATE_RUNNING)
                                        req.projectSession.proxyUrl = "http://" + meta.host + ":9000/" + meta.cid + "/home/ubuntu/workspace";
                                    else
                                        req.projectSession.expires = Date.now() + 1000;

                                    next();
                                });
                            } else {
                                next();
                            }
                        });
                    });
                });
            };
        }

        function getProxyUrl(getServer) {
            return function(req, res, next) {

                if (req.projectSession.proxyUrl) {
                    req.proxyUrl = req.projectSession.proxyUrl;
                    return next();
                }

                var server = req.projectSession.vfsServer;
                if (!server) {
                    server = getServer();
                    if (!server || !server.url)
                        return next(new error.ServiceUnavailable("No VFS server found"));

                    server = req.projectSession.vfsServer = server.internalUrl || server.url;
                }

                var url = server + "/" + req.projectSession.pid + "/preview";
                if (req.session.token)
                    url += "?access_token=" + encodeURIComponent(req.session.token);

                req.proxyUrl = url;
                next();
            };
        }

        function proxyCall() {
            return function(req, res, next) {

                var path = req.params.path;
                var url = req.proxyUrl + path;

                var parsedUrl = parseUrl(url);
                var httpModule = parsedUrl.protocol == "https:" ? https : http;

                req.headers.accept = "application/json";
                delete req.headers.host;

                var isDir = path[path.length-1] == "/";
                if (isDir || parsedUrl.pathname.match(/\.html?$/i)) {
                    req.headers["accept-encoding"] = "identity";
                    delete req.headers["if-none-match"];
                    delete req.headers["if-range"];
                } else {
                    req.headers["accept-encoding"] = "gzip";
                }

                debug("proxy call %s", url);
                httpModule.get({
                    path: parsedUrl.path,
                    hostname: parsedUrl.hostname,
                    port: parsedUrl.port,
                    headers: req.headers
                }, function(request) {
                    if (request.statusCode >= 400)
                        handleError(request);
                    else if (isDir)
                        serveListing(request);
                    else if (request.headers["content-type"] == "text/html")
                        serveHtml(request, parsedUrl.hostname, req);
                    else
                        serveFile(request);
                }).on("error", function(err) {
                    next(err);
                });

                function handleError(request) {
                    var body = "";

                    debug("handle error %s", request.statusCode);

                    if (request.statusCode == 401)
                        return next(new error.Unauthorized());

                    var stream;
                    if (request.headers["content-encoding"] == "gzip") {
                        stream = require("zlib").createGunzip();
                        request.pipe(stream);
                    } else {
                        stream = request;
                    }

                    stream.on("data", function(data) {
                        body += data;
                    });
                    stream.on("end", function(data) {
                        if (data)
                            body += data;

                        req.headers.accept= "text/html";
                        var statusCode = request.statusCode;

                        if (body.indexOf("EISDIR") !== -1) {
                            res.redirect(req.url + "/");
                        } else if (body.indexOf("ENOENT") !== -1 || statusCode == 404) {
                            next(new error.NotFound("File '" + path + "' could not be found!"));
                        } else {
                            delete req.session.ws[req.ws];

                            var json;
                            try {
                                json = JSON.parse(body);
                            } catch(e) {}

                            if (statusCode == 503) {
                                res.setHeader('Content-Type', 'text/html; charset=utf-8');
                                res.render(__dirname + "/views/progress.html.ejs", {
                                    title: "Connecting to your Workspace",
                                    message: "Please wait a moment while we are connecting to the preview server",
                                    retryIn: 2000,
                                    statusCode: statusCode
                                }, next);
                            }
                            else if (statusCode == 428 && json && json.error) {
                                res.setHeader('Content-Type', 'text/html; charset=utf-8');
                                res.render(__dirname + "/views/progress.html.ejs", {
                                    title: json.error.message,
                                    message: "",
                                    retryIn: 2000,
                                    statusCode: statusCode
                                }, next);
                            }
                            else {
                                next(new error.HttpError(body.split("\n")[0], statusCode));
                            }

                        }
                    });
                }

                function serveListing(request) {
                    debug("serve directory listing %s", request.url);

                    var body = "";
                    request.on("data", function(data) {
                        body += data;
                    });
                    request.on("end", function(data) {
                        if (data)
                            body += data;

                        try {
                            body = JSON.parse(body);
                        } catch (e) {
                            return next(e);
                        }

                        // convert nginx listing
                        if (body[0] && body[0].type) {
                            body = body.map(function(stat) {
                                return {
                                    name: stat.name,
                                    mime: stat.type == "directory" ? "inode/directory" : mime.lookup(stat.name),
                                    size: stat.size || 0,
                                    mtime: stat.mtime
                                };
                            });
                        }
                        var entries = body
                            .filter(function(entry) {
                                return entry.name[0] !== ".";
                            })
                            .sort(function(a, b) {
                                if (a.mime === "inode/directory" && b.mime !== "inode/directory")
                                    return -1;
                                else if (a.mime !== "inode/directory" && b.mime === "inode/directory")
                                    return 1;
                                else if (a.name.toLowerCase() == b.name.toLowerCase())
                                    return 0;
                                else if (a.name.toLowerCase() < b.name.toLowerCase())
                                    return -1;
                                else
                                    return 1;
                            });

                        res.render(__dirname + "/views/listing.html.ejs", {
                            isRoot: path == "/",
                            entries: entries
                        }, next);
                    });
                }

                function serveHtml(request, ideHost, req) {
                    debug("serve HTML %s", request.url);

                    var shouldInject = req.parsedUrl.query["_c9_id"] ? true : false;

                    var inject = shouldInject
                        ? '<script src="' + staticPrefix + '/preview/livecss.js"></script>'
                        : '';
                    var generateInstrumentedHTML = require("../c9.ide.language.html.diff/HTMLSimpleDOM").generateInstrumentedHTML;

                    var buffer = "";
                    request.on("data", function(data) {
                        buffer += data;
                    });
                    request.on("end", function(data) {
                        if (data)
                            buffer += data;

                        if (shouldInject)
                            buffer = generateInstrumentedHTML(buffer) || "";
                        data = new Buffer(buffer);
                        res.writeHead(200, {
                            "content-length": data.length + inject.length,
                            "content-type": request.headers["content-type"],
                            "etag": request.headers.etag,
                            "date": request.headers.data,
                            "access-control-allow-origin": "https://ide." + ideHost
                        });
                        res.write(data);

                        res.end(inject);
                    });
                }

                function serveFile(request) {
                    debug("forward file %s", request.url);
                    res.writeHead(request.statusCode, request.headers);
                    request.pipe(res);
                }

            };
        }

        register(null, {
            "preview.handler": {
                getProjectSession: getProjectSession,
                getRole: getRole,
                getProxyUrl: getProxyUrl,
                proxyCall: proxyCall
            }
        });
    }
});<commit_msg>fix broken ssh preview<commit_after>define(function(require, exports, module) {
    "use strict";

    main.consumes = [
        "connect.render",
        "connect.render.ejs",
        "connect.redirect",
        "connect.static"
    ];
    main.provides = ["preview.handler"];
    return main;

    function main(options, imports, register) {
        var error = require("http-error");
        var https = require("https");
        var http = require("http");
        var mime = require("mime");
        var parseUrl = require("url").parse;
        var debug = require("debug")("preview");

        var staticPrefix = imports["connect.static"].getStaticPrefix();

        function getProjectSession() {
            return function(req, res, next) {
                var session = req.session;

                req.user = req.user || { id: -1 };

                var username = req.params.username;
                var projectname = req.params.projectname;

                var ws = req.ws = username + "/" + projectname;

                if (!session.ws)
                    session.ws = {};

                req.projectSession = session.ws[ws];
                if (!req.projectSession || !req.projectSession.expires || req.projectSession.expires <= Date.now()) {
                    req.projectSession = session.ws[ws] = {
                        expires: Date.now() + 10000
                    };
                }

                next();
            };
        }

        function getRole(db) {
            return function(req, res, next) {
                if (req.projectSession.role) {
                    return next();
                }

                db.Project.findOne({
                    username: req.params.username,
                    name: req.params.projectname
                }, function(err, project) {
                    if (err && err.code == 404)
                        return next(new error.NotFound("Project '" + req.ws + "' doest not exist."));

                    if (err) return next(err);

                    project.getRole(req.user, function(err, role) {
                        if (err) return next(err);

                        if (role == db.Project.ROLE_NONE) {
                            if (project.isPublicPreview())
                                role = db.Project.ROLE_VISITOR;
                            else if (req.user.id == -1)
                                return next(new error.Unauthorized());
                            else
                                return next(new error.Forbidden("You don't have access rights to preview this workspace"));
                        }
                        req.projectSession.role = role;
                        req.projectSession.pid = project.id;

                        var type = project.scm;
                        req.projectSession.type = type;

                        if (type != "docker" || project.state != db.Project.STATE_READY)
                            return next();

                        project.populate("remote", function(err) {
                            if (err) return next(err);

                            var meta = project.remote.metadata;
                            if (meta && meta.host && meta.cid) {
                                db.Container.load(meta.cid, function(err, container) {
                                    if (err) return next(err);

                                    if (container.state == db.Container.STATE_RUNNING)
                                        req.projectSession.proxyUrl = "http://" + meta.host + ":9000/" + meta.cid + "/home/ubuntu/workspace";
                                    else
                                        req.projectSession.expires = Date.now() + 1000;

                                    next();
                                });
                            } else {
                                next();
                            }
                        });
                    });
                });
            };
        }

        function getProxyUrl(getServer) {
            return function(req, res, next) {

                if (req.projectSession.proxyUrl) {
                    req.proxyUrl = req.projectSession.proxyUrl;
                    return next();
                }

                var server = req.projectSession.vfsServer;
                if (!server) {
                    server = getServer();
                    if (!server || !server.url)
                        return next(new error.ServiceUnavailable("No VFS server found"));

                    server = req.projectSession.vfsServer = server.internalUrl || server.url;
                }

                var url = server + "/" + req.projectSession.pid + "/preview";

                req.proxyUrl = url;
                next();
            };
        }

        function proxyCall() {
            return function(req, res, next) {

                var path = req.params.path;
                var url = req.proxyUrl + path;
                if (req.session.token)
                    url += "?access_token=" + encodeURIComponent(req.session.token);

                var parsedUrl = parseUrl(url);
                var httpModule = parsedUrl.protocol == "https:" ? https : http;

                req.headers.accept = "application/json";
                delete req.headers.host;

                var isDir = path[path.length-1] == "/";
                if (isDir || parsedUrl.pathname.match(/\.html?$/i)) {
                    req.headers["accept-encoding"] = "identity";
                    delete req.headers["if-none-match"];
                    delete req.headers["if-range"];
                } else {
                    req.headers["accept-encoding"] = "gzip";
                }

                debug("proxy call %s", url);
                httpModule.get({
                    path: parsedUrl.path,
                    hostname: parsedUrl.hostname,
                    port: parsedUrl.port,
                    headers: req.headers
                }, function(request) {
                    if (request.statusCode >= 400)
                        handleError(request);
                    else if (isDir)
                        serveListing(request);
                    else if (request.headers["content-type"] == "text/html")
                        serveHtml(request, parsedUrl.hostname, req);
                    else
                        serveFile(request);
                }).on("error", function(err) {
                    next(err);
                });

                function handleError(request) {
                    var body = "";

                    debug("handle error %s", request.statusCode);

                    if (request.statusCode == 401)
                        return next(new error.Unauthorized());

                    var stream;
                    if (request.headers["content-encoding"] == "gzip") {
                        stream = require("zlib").createGunzip();
                        request.pipe(stream);
                    } else {
                        stream = request;
                    }

                    stream.on("data", function(data) {
                        body += data;
                    });
                    stream.on("end", function(data) {
                        if (data)
                            body += data;

                        req.headers.accept= "text/html";
                        var statusCode = request.statusCode;

                        if (body.indexOf("EISDIR") !== -1) {
                            res.redirect(req.url + "/");
                        } else if (body.indexOf("ENOENT") !== -1 || statusCode == 404) {
                            next(new error.NotFound("File '" + path + "' could not be found!"));
                        } else {
                            delete req.session.ws[req.ws];

                            var json;
                            try {
                                json = JSON.parse(body);
                            } catch(e) {}

                            if (statusCode == 503) {
                                res.setHeader('Content-Type', 'text/html; charset=utf-8');
                                res.render(__dirname + "/views/progress.html.ejs", {
                                    title: "Connecting to your Workspace",
                                    message: "Please wait a moment while we are connecting to the preview server",
                                    retryIn: 2000,
                                    statusCode: statusCode
                                }, next);
                            }
                            else if (statusCode == 428 && json && json.error) {
                                res.setHeader('Content-Type', 'text/html; charset=utf-8');
                                res.render(__dirname + "/views/progress.html.ejs", {
                                    title: json.error.message,
                                    message: "",
                                    retryIn: 2000,
                                    statusCode: statusCode
                                }, next);
                            }
                            else {
                                next(new error.HttpError(body.split("\n")[0], statusCode));
                            }

                        }
                    });
                }

                function serveListing(request) {
                    debug("serve directory listing %s", request.url);

                    var body = "";
                    request.on("data", function(data) {
                        body += data;
                    });
                    request.on("end", function(data) {
                        if (data)
                            body += data;

                        try {
                            body = JSON.parse(body);
                        } catch (e) {
                            return next(e);
                        }

                        // convert nginx listing
                        if (body[0] && body[0].type) {
                            body = body.map(function(stat) {
                                return {
                                    name: stat.name,
                                    mime: stat.type == "directory" ? "inode/directory" : mime.lookup(stat.name),
                                    size: stat.size || 0,
                                    mtime: stat.mtime
                                };
                            });
                        }
                        var entries = body
                            .filter(function(entry) {
                                return entry.name[0] !== ".";
                            })
                            .sort(function(a, b) {
                                if (a.mime === "inode/directory" && b.mime !== "inode/directory")
                                    return -1;
                                else if (a.mime !== "inode/directory" && b.mime === "inode/directory")
                                    return 1;
                                else if (a.name.toLowerCase() == b.name.toLowerCase())
                                    return 0;
                                else if (a.name.toLowerCase() < b.name.toLowerCase())
                                    return -1;
                                else
                                    return 1;
                            });

                        res.render(__dirname + "/views/listing.html.ejs", {
                            isRoot: path == "/",
                            entries: entries
                        }, next);
                    });
                }

                function serveHtml(request, ideHost, req) {
                    debug("serve HTML %s", request.url);

                    var shouldInject = req.parsedUrl.query["_c9_id"] ? true : false;

                    var inject = shouldInject
                        ? '<script src="' + staticPrefix + '/preview/livecss.js"></script>'
                        : '';
                    var generateInstrumentedHTML = require("../c9.ide.language.html.diff/HTMLSimpleDOM").generateInstrumentedHTML;

                    var buffer = "";
                    request.on("data", function(data) {
                        buffer += data;
                    });
                    request.on("end", function(data) {
                        if (data)
                            buffer += data;

                        if (shouldInject)
                            buffer = generateInstrumentedHTML(buffer) || "";
                        data = new Buffer(buffer);
                        res.writeHead(200, {
                            "content-length": data.length + inject.length,
                            "content-type": request.headers["content-type"],
                            "etag": request.headers.etag,
                            "date": request.headers.data,
                            "access-control-allow-origin": "https://ide." + ideHost
                        });
                        res.write(data);

                        res.end(inject);
                    });
                }

                function serveFile(request) {
                    debug("forward file %s", request.url);
                    res.writeHead(request.statusCode, request.headers);
                    request.pipe(res);
                }

            };
        }

        register(null, {
            "preview.handler": {
                getProjectSession: getProjectSession,
                getRole: getRole,
                getProxyUrl: getProxyUrl,
                proxyCall: proxyCall
            }
        });
    }
});<|endoftext|>