<commit_before>(function ($) {

	// default player values
	mejs.MepDefaults = {
		// url to poster (to fix iOS 3.x)
		poster: '',
		// default if the <video width> is not specified
		defaultVideoWidth: 480,
		// default if the <video height> is not specified
		defaultVideoHeight: 270,
		// if set, overrides <video width>
		videoWidth: -1,
		// if set, overrides <video height>
		videoHeight: -1,
		// width of audio player
		audioWidth: 400,
		// height of audio player
		audioHeight: 30,
		// initial volume when the player starts (overrided by user cookie)
		startVolume: 0.8,
		// useful for <audio> player loops
		loop: false,
		// resize to media dimensions
		enableAutosize: true,
		// features to show
		features: ['playpause','current','progress','duration','tracks','volume','fullscreen']
	};

	mejs.mepIndex = 0;

	// wraps a MediaElement object in player controls
	mejs.MediaElementPlayer = function($media, o) {
		// enforce object, even without "new" (via John Resig)
		if ( !(this instanceof mejs.MediaElementPlayer) ) {
			return new mejs.MediaElementPlayer($media, o);
		}

		var
			t = this,
			mf = mejs.MediaFeatures;

		t.$media = $($media);

		// check for existing player
		if (t.$media[0].player) {
			return t.$media[0].player;
		} else {
			t.$media[0].player = t;
		}

		t.options = $.extend({},mejs.MepDefaults,o);
		t.isVideo = (t.$media[0].tagName.toLowerCase() == 'video');

		if (mf.isiPad || mf.isiPhone) {
			// add controls and stop
			t.$media.attr('controls', 'controls');

			// fix Apple bug
			t.$media.removeAttr('poster');

			// override Apple's autoplay override for iPads
			if (mf.isiPad && t.$media[0].getAttribute('autoplay') !== null) {
				t.$media[0].load();
				t.$media[0].play();
			}

			// don't do the rest
			return;
		} else if (mf.isAndroid && t.isVideo) {

			// Android fails when there are multiple types
			// <video>
			// <source src="file.mp4" type="video/mp4" />
			// <source src="file.webm" type="video/webm" />
			// </video>
			if (t.$media.find('source').length > 0) {
				// find an mp4 and make it the root element source
				t.$media[0].src = t.$media.find('source[src$="mp4"]').attr('src');
			}

			// attach a click event to the video and hope Android can play it
			t.$media.click(function() {
				t.$media[0].play();
			});

			return;

		} else {

			// remove native controls and use MEJS
			t.$media.removeAttr('controls');
		}

		t.init();

		return t;
	};

	// actual player
	mejs.MediaElementPlayer.prototype = {
		init: function() {

			var
				t = this,
				meOptions = $.extend(true, {}, t.options, {
					success: function(media, domNode) { t.meReady(media, domNode); },
					error: function(e) { t.handleError(e);}
				});

			// unique ID
			t.id = 'mep_' + mejs.mepIndex++;

			// build container
			t.container =
				$('
'+
					'
'+
						'

'+
						'

'+
						'

'+
						'

'+
					'
' +
				'
')
				.addClass(t.$media[0].className)
				.insertBefore(t.$media);

			// move the <video/video> tag into the right spot
			t.container.find('.mejs-mediaelement').append(t.$media);

			// find parts
			t.controls = t.container.find('.mejs-controls');
			t.layers = t.container.find('.mejs-layers');

			// determine the size
			if (t.isVideo) {
				// priority = videoWidth (forced), width attribute, defaultVideoWidth
				t.width = (t.options.videoWidth > 0) ? t.options.videoWidth : (t.$media[0].getAttribute('width') !== null) ? t.$media.attr('width') : t.options.defaultVideoWidth;
				t.height = (t.options.videoHeight > 0) ? t.options.videoHeight : (t.$media[0].getAttribute('height') !== null) ? t.$media.attr('height') : t.options.defaultVideoHeight;
			} else {
				t.width = t.options.audioWidth;
				t.height = t.options.audioHeight;
			}

			// set the size, while we wait for the plugins to load below
			t.setPlayerSize(t.width, t.height);

			// create MediaElementShim
			meOptions.pluginWidth = t.height;
			meOptions.pluginHeight = t.width;
			mejs.MediaElement(t.$media[0], meOptions);
		},

		// Sets up all controls and events
		meReady: function(media, domNode) {

			var t = this,
				f,
				feature;

			t.media = media;
			t.domNode = domNode;

			// two built in features
			t.buildposter(t, t.controls, t.layers, t.media);
			t.buildoverlay(t, t.controls, t.layers, t.media);

			// grab for use by feautres
			t.findTracks();

			// add user-defined features/controls
			for (f in t.options.features) {
				feature = t.options.features[f];
				if (t['build' + feature]) {
					try {
						t['build' + feature](t, t.controls, t.layers, t.media);
					} catch (e) {
						// TODO: report control error
					}
				}
			}

			// reset all layers and controls
			t.setPlayerSize(t.width, t.height);
			t.setControlsSize();

			// controls fade
			if (t.isVideo) {
				// show/hide controls
				t.container
					.bind('mouseenter', function () {
						t.controls.css('visibility','visible');
						t.controls.stop(true, true).fadeIn(200);
					})
					.bind('mouseleave', function () {
						if (!t.media.paused) {
							t.controls.stop(true, true).fadeOut(200, function() {
								$(this).css('visibility','hidden');
								$(this).css('display','block');
							});
						}
					});

				// resizer
				if (t.options.enableAutosize) {
					t.media.addEventListener('loadedmetadata', function(e) {
						// if the <video height> was not set and the options.videoHeight was not set
						// then resize to the real dimensions
						if (t.options.videoHeight <= 0 && t.$media[0].getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
							t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
							t.setControlsSize();
							t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
						}
					}, false);
				}
			}

			// ended for all
			t.media.addEventListener('ended', function (e) {
				t.media.setCurrentTime(0);
				t.media.pause();

				if (t.options.loop) {
					t.media.play();
				} else {
					t.controls.css('visibility','visible');
				}
			}, true);

			// webkit has trouble doing this without a delay
			setTimeout(function () {
				t.setControlsSize();
				t.setPlayerSize(t.width, t.height);
			}, 50);

			if (t.options.success) {
				t.options.success(t.media, t.domNode);
			}
		},

		handleError: function(e) {
			// Tell user that the file cannot be played

			this.options.error(e);
		},

		setPlayerSize: function(width,height) {
			var t = this;

			// ie9 appears to need this (jQuery bug?)
			t.width = parseInt(width, 10);
			t.height = parseInt(height, 10);

			t.container
				.width(t.width)
				.height(t.height);

			t.layers.children('div.mejs-layer')
				.width(t.width)
				.height(t.height);
		},

		setControlsSize: function() {
			var t = this,
				usedWidth = 0,
				railWidth = 0,
				rail = t.controls.find('.mejs-time-rail'),
				total = t.controls.find('.mejs-time-total'),
				others = rail.siblings();

			// find the size of all the other controls besides the rail
			others.each(function() {
				if ($(this).css('position') != 'absolute') {
					usedWidth += $(this).outerWidth(true);
				}
			});
			// fit the rail into the remaining space
			railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.outerWidth(false));

			rail.width(railWidth);
			total.width(railWidth - (total.outerWidth(true) - total.width()));
		},

		buildposter: function(player, controls, layers, media) {
			var poster =
				$('
'+
					''+
				'
')
					.appendTo(layers),
				posterUrl = player.$media.attr('poster');

			if (player.options.poster != '') {
				poster.find('img').attr('src',player.options.poster);
			} else if (posterUrl !== '' && posterUrl != null) {
				poster.find('img').attr('src',posterUrl);
			} else {
				poster.hide();
			}

			media.addEventListener('play',function() {
				poster.hide();
			}, false);
		},

		buildoverlay: function(player, controls, layers, media) {
			if (!player.isVideo)
				return;

			var overlay =
				$('
'+
					'

'+
				'
')
				.appendTo(layers)
				.click(function() {
					if (media.paused) {
						media.play();
					} else {
						media.pause();
					}
				});

			media.addEventListener('play',function() {
				overlay.hide();
			}, false);
			media.addEventListener('pause',function() {
				overlay.show();
			}, false);
		},

		findTracks: function() {
			var t = this,
				tracktags = t.$media.find('track');

			// store for use by plugins
			t.tracks = [];
			tracktags.each(function() {
				t.tracks.push({
					srclang: $(this).attr('srclang').toLowerCase(),
					src: $(this).attr('src'),
					kind: $(this).attr('kind'),
					entries: [],
					isLoaded: false
				});
			});
		},
		changeSkin: function(className) {
			this.container[0].className = 'mejs-container ' + className;
			this.setPlayerSize();
			this.setControlsSize();
		},
		play: function() {
			this.media.play();
		},
		pause: function() {
			this.media.pause();
		},
		load: function() {
			this.media.load();
		},
		setMuted: function(muted) {
			this.media.setMuted(muted);
		},
		setCurrentTime: function(time) {
			this.media.setCurrentTime(time);
		},
		getCurrentTime: function() {
			return this.media.currentTime;
		},
		setVolume: function(volume) {
			this.media.setVolume(volume);
		},
		getVolume: function() {
			return this.media.volume;
		},
		setSrc: function(src) {
			this.media.setSrc(src);
		}
	};

	// turn into jQuery plugin
	jQuery.fn.mediaelementplayer = function (options) {
		return this.each(function () {
			new mejs.MediaElementPlayer($(this), options);
		});
	};

	// push out to window
	window.MediaElementPlayer = mejs.MediaElementPlayer;

})(jQuery);
<commit_msg>- prevents Firefox from reloading the entire player - fixed error coded<commit_after>(function ($) {

	// default player values
	mejs.MepDefaults = {
		// url to poster (to fix iOS 3.x)
		poster: '',
		// default if the <video width> is not specified
		defaultVideoWidth: 480,
		// default if the <video height> is not specified
		defaultVideoHeight: 270,
		// if set, overrides <video width>
		videoWidth: -1,
		// if set, overrides <video height>
		videoHeight: -1,
		// width of audio player
		audioWidth: 400,
		// height of audio player
		audioHeight: 30,
		// initial volume when the player starts (overrided by user cookie)
		startVolume: 0.8,
		// useful for <audio> player loops
		loop: false,
		// resize to media dimensions
		enableAutosize: true,
		// features to show
		features: ['playpause','current','progress','duration','tracks','volume','fullscreen']
	};

	mejs.mepIndex = 0;

	// wraps a MediaElement object in player controls
	mejs.MediaElementPlayer = function($media, o) {
		// enforce object, even without "new" (via John Resig)
		if ( !(this instanceof mejs.MediaElementPlayer) ) {
			return new mejs.MediaElementPlayer($media, o);
		}

		var
			t = this,
			mf = mejs.MediaFeatures;

		t.$media = $($media);

		// check for existing player
		if (t.$media[0].player) {
			return t.$media[0].player;
		} else {
			t.$media[0].player = t;
		}

		t.options = $.extend({},mejs.MepDefaults,o);
		t.isVideo = (t.$media[0].tagName.toLowerCase() == 'video');

		if (mf.isiPad || mf.isiPhone) {
			// add controls and stop
			t.$media.attr('controls', 'controls');

			// fix Apple bug
			t.$media.removeAttr('poster');

			// override Apple's autoplay override for iPads
			if (mf.isiPad && t.$media[0].getAttribute('autoplay') !== null) {
				t.$media[0].load();
				t.$media[0].play();
			}

			// don't do the rest
			return;
		} else if (mf.isAndroid && t.isVideo) {

			// Android fails when there are multiple types
			// <video>
			// <source src="file.mp4" type="video/mp4" />
			// <source src="file.webm" type="video/webm" />
			// </video>
			if (t.$media.find('source').length > 0) {
				// find an mp4 and make it the root element source
				t.$media[0].src = t.$media.find('source[src$="mp4"]').attr('src');
			}

			// attach a click event to the video and hope Android can play it
			t.$media.click(function() {
				t.$media[0].play();
			});

			return;

		} else {

			// remove native controls and use MEJS
			t.$media.removeAttr('controls');
		}

		t.init();

		return t;
	};

	// actual player
	mejs.MediaElementPlayer.prototype = {
		init: function() {

			var
				t = this,
				meOptions = $.extend(true, {}, t.options, {
					success: function(media, domNode) { t.meReady(media, domNode); },
					error: function(e) { t.handleError(e);}
				});

			// unique ID
			t.id = 'mep_' + mejs.mepIndex++;

			// build container
			t.container =
				$('
'+
					'
'+
						'

'+
						'

'+
						'

'+
						'

'+
					'
' +
				'
')
				.addClass(t.$media[0].className)
				.insertBefore(t.$media);

			// move the <video/video> tag into the right spot
			t.container.find('.mejs-mediaelement').append(t.$media);

			// find parts
			t.controls = t.container.find('.mejs-controls');
			t.layers = t.container.find('.mejs-layers');

			// determine the size
			if (t.isVideo) {
				// priority = videoWidth (forced), width attribute, defaultVideoWidth
				t.width = (t.options.videoWidth > 0) ? t.options.videoWidth : (t.$media[0].getAttribute('width') !== null) ? t.$media.attr('width') : t.options.defaultVideoWidth;
				t.height = (t.options.videoHeight > 0) ? t.options.videoHeight : (t.$media[0].getAttribute('height') !== null) ? t.$media.attr('height') : t.options.defaultVideoHeight;
			} else {
				t.width = t.options.audioWidth;
				t.height = t.options.audioHeight;
			}

			// set the size, while we wait for the plugins to load below
			t.setPlayerSize(t.width, t.height);

			// create MediaElementShim
			meOptions.pluginWidth = t.height;
			meOptions.pluginHeight = t.width;
			mejs.MediaElement(t.$media[0], meOptions);
		},

		// Sets up all controls and events
		meReady: function(media, domNode) {

			var t = this,
				f,
				feature;

			// make sure it can't create itself again if a plugin reloads
			if (this.created)
				return;
			else
				this.created = true;

			t.media = media;
			t.domNode = domNode;

			// two built in features
			t.buildposter(t, t.controls, t.layers, t.media);
			t.buildoverlay(t, t.controls, t.layers, t.media);

			// grab for use by feautres
			t.findTracks();

			// add user-defined features/controls
			for (f in t.options.features) {
				feature = t.options.features[f];
				if (t['build' + feature]) {
					try {
						t['build' + feature](t, t.controls, t.layers, t.media);
					} catch (e) {
						// TODO: report control error
					}
				}
			}

			// reset all layers and controls
			t.setPlayerSize(t.width, t.height);
			t.setControlsSize();

			// controls fade
			if (t.isVideo) {
				// show/hide controls
				t.container
					.bind('mouseenter', function () {
						t.controls.css('visibility','visible');
						t.controls.stop(true, true).fadeIn(200);
					})
					.bind('mouseleave', function () {
						if (!t.media.paused) {
							t.controls.stop(true, true).fadeOut(200, function() {
								$(this).css('visibility','hidden');
								$(this).css('display','block');
							});
						}
					});

				// resizer
				if (t.options.enableAutosize) {
					t.media.addEventListener('loadedmetadata', function(e) {
						// if the <video height> was not set and the options.videoHeight was not set
						// then resize to the real dimensions
						if (t.options.videoHeight <= 0 && t.$media[0].getAttribute('height') === null && !isNaN(e.target.videoHeight)) {
							t.setPlayerSize(e.target.videoWidth, e.target.videoHeight);
							t.setControlsSize();
							t.media.setVideoSize(e.target.videoWidth, e.target.videoHeight);
						}
					}, false);
				}
			}

			// ended for all
			t.media.addEventListener('ended', function (e) {
				t.media.setCurrentTime(0);
				t.media.pause();

				if (t.options.loop) {
					t.media.play();
				} else {
					t.controls.css('visibility','visible');
				}
			}, true);

			// webkit has trouble doing this without a delay
			setTimeout(function () {
				t.setControlsSize();
				t.setPlayerSize(t.width, t.height);
			}, 50);

			if (t.options.success) {
				t.options.success(t.media, t.domNode);
			}
		},

		handleError: function(e) {
			// Tell user that the file cannot be played
			if (this.options.error) {
				this.options.error(e);
			}
		},

		setPlayerSize: function(width,height) {
			var t = this;

			// ie9 appears to need this (jQuery bug?)
			t.width = parseInt(width, 10);
			t.height = parseInt(height, 10);

			t.container
				.width(t.width)
				.height(t.height);

			t.layers.children('div.mejs-layer')
				.width(t.width)
				.height(t.height);
		},

		setControlsSize: function() {
			var t = this,
				usedWidth = 0,
				railWidth = 0,
				rail = t.controls.find('.mejs-time-rail'),
				total = t.controls.find('.mejs-time-total'),
				others = rail.siblings();

			// find the size of all the other controls besides the rail
			others.each(function() {
				if ($(this).css('position') != 'absolute') {
					usedWidth += $(this).outerWidth(true);
				}
			});
			// fit the rail into the remaining space
			railWidth = t.controls.width() - usedWidth - (rail.outerWidth(true) - rail.outerWidth(false));

			rail.width(railWidth);
			total.width(railWidth - (total.outerWidth(true) - total.width()));
		},

		buildposter: function(player, controls, layers, media) {
			var poster =
				$('
'+
					''+
				'
')
					.appendTo(layers),
				posterUrl = player.$media.attr('poster');

			if (player.options.poster != '') {
				poster.find('img').attr('src',player.options.poster);
			} else if (posterUrl !== '' && posterUrl != null) {
				poster.find('img').attr('src',posterUrl);
			} else {
				poster.hide();
			}

			media.addEventListener('play',function() {
				poster.hide();
			}, false);
		},

		buildoverlay: function(player, controls, layers, media) {
			if (!player.isVideo)
				return;

			var overlay =
				$('
'+
					'

'+
				'
')
				.appendTo(layers)
				.click(function() {
					if (media.paused) {
						media.play();
					} else {
						media.pause();
					}
				});

			media.addEventListener('play',function() {
				overlay.hide();
			}, false);
			media.addEventListener('pause',function() {
				overlay.show();
			}, false);
		},

		findTracks: function() {
			var t = this,
				tracktags = t.$media.find('track');

			// store for use by plugins
			t.tracks = [];
			tracktags.each(function() {
				t.tracks.push({
					srclang: $(this).attr('srclang').toLowerCase(),
					src: $(this).attr('src'),
					kind: $(this).attr('kind'),
					entries: [],
					isLoaded: false
				});
			});
		},
		changeSkin: function(className) {
			this.container[0].className = 'mejs-container ' + className;
			this.setPlayerSize();
			this.setControlsSize();
		},
		play: function() {
			this.media.play();
		},
		pause: function() {
			this.media.pause();
		},
		load: function() {
			this.media.load();
		},
		setMuted: function(muted) {
			this.media.setMuted(muted);
		},
		setCurrentTime: function(time) {
			this.media.setCurrentTime(time);
		},
		getCurrentTime: function() {
			return this.media.currentTime;
		},
		setVolume: function(volume) {
			this.media.setVolume(volume);
		},
		getVolume: function() {
			return this.media.volume;
		},
		setSrc: function(src) {
			this.media.setSrc(src);
		}
	};

	// turn into jQuery plugin
	jQuery.fn.mediaelementplayer = function (options) {
		return this.each(function () {
			new mejs.MediaElementPlayer($(this), options);
		});
	};

	// push out to window
	window.MediaElementPlayer = mejs.MediaElementPlayer;

})(jQuery);
<|endoftext|>


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

'use strict';

var Config = require('./config.json');
var ReactDOM = require('react-dom');
var assign = require('lodash/assign');
var isFunction = require('lodash/isFunction');

// declaring like this helps in unit test
// dependency injection using `rewire` module
var _window;
var _document;
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
  _window = window;
  _document = document;
}

// returns the data/state that was
// injected by server during rendering
var data = exports.data = function data() {
  // this file needs to be a external js file
  var element = document.getElementById(Config.client.markupId);
  // grab the contents from the script element
  var jsonString = element.textContent || element.innerText;
  // parse the text contents to JSON
  return JSON.parse(jsonString);
};

// the client side boot function
exports.boot = function boot(options, callback) {

  var React = require('react');
  var Router;
  var RouterComponent;
  var match;
  var browserHistory;

  try {
    Router = require('react-router');
    RouterComponent = Router.Router;
    match = Router.match;

    // compatibility for both `react-router` v2 and v1
    browserHistory = Router.browserHistory || require('history').createHistory();
  } catch (err) {
    if (!Router && options.routes) {
      throw new Error('asking to use react router for rendering, but no routes are provided');
    }
  }

  var router;
  var history;
  var location;
  var viewResolver = options.viewResolver;

  // pick up the state that was injected by server during rendering
  var props = data();
  var useRouter = (props.__meta.view === null);
  var mountNode = options.mountNode || _document;

  // wrap component with react-redux Proivder if redux is required
  var wrap = function(component) {
    if (options.reduxStoreInitiator && isFunction(options.reduxStoreInitiator)) {
      var initStore = options.reduxStoreInitiator;
      if (initStore.default) {
        initStore = initStore.default;
      }
      var store = initStore(props);
      var Provider = require('react-redux').Provider;
      return React.createElement(Provider, { store: store }, component);
    } else {
      return component;
    }
  };

  if (useRouter) {

    history = options.history || browserHistory;
    location = _window.location.pathname +
      _window.location.search + _window.location.hash;

    if (options.routes.default) {
      options.routes = options.routes.default;
    }

    // Wrap the 'render' function within a call to 'match'. This is a workaround to support
    // users using code splitting functionality
    match({ routes: options.routes, location: location }, function() {

      // for any component created by react-router, merge model data with the routerProps
      // NOTE: This may be imposing too large of an opinion?
      var routerComponent = React.createElement(RouterComponent, {
        createElement: function(Component, routerProps) {
          return React.createElement(Component, assign({}, props, routerProps));
        },

        routes: options.routes,
        history: history
      });

      // wrap routerComponent with redux provider
      ReactDOM.hydrate(wrap(routerComponent), mountNode);
    });

  } else {
    // get the file from viewResolver supplying it with a view name
    var view = viewResolver(props.__meta.view);

    // create a react view factory
    var viewFactory = React.createFactory(view);

    // render the factory on the client
    // doing this, sets up the event
    // listeners and stuff aka mounting views.
    ReactDOM.hydrate(wrap(viewFactory(props)), mountNode);
  }

  // call the callback with the data that was used for rendering
  return callback && callback(props, history);
};
<commit_msg>Choose render or hydrate based on method availability.<commit_after>/*-------------------------------------------------------------------------------------------------------------------*\
|  Copyright (C) 2017 PayPal                                                                                |
|                                                                                |
|  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance     |
|  with the License.                                                                                |
|                                                                                |
|  You may obtain a copy of the License at                                                                            |
|                                                                                |
|       http://www.apache.org/licenses/LICENSE-2.0                                                                    |
|                                                                                |
|  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed   |
|  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for  |
|  the specific language governing permissions and limitations under the License.                                     |
\*-------------------------------------------------------------------------------------------------------------------*/

'use strict';

var Config = require('./config.json');
var ReactDOM = require('react-dom');
var assign = require('lodash/assign');
var isFunction = require('lodash/isFunction');

// declaring like this helps in unit test
// dependency injection using `rewire` module
var _window;
var _document;
if (typeof window !== 'undefined' && typeof document !== 'undefined') {
  _window = window;
  _document = document;
}

// returns the data/state that was
// injected by server during rendering
var data = exports.data = function data() {
  // this file needs to be a external js file
  var element = document.getElementById(Config.client.markupId);
  // grab the contents from the script element
  var jsonString = element.textContent || element.innerText;
  // parse the text contents to JSON
  return JSON.parse(jsonString);
};

// the client side boot function
exports.boot = function boot(options, callback) {

  var React = require('react');
  var Router;
  var RouterComponent;
  var match;
  var browserHistory;

  try {
    Router = require('react-router');
    RouterComponent = Router.Router;
    match = Router.match;

    // compatibility for both `react-router` v2 and v1
    browserHistory = Router.browserHistory || require('history').createHistory();
  } catch (err) {
    if (!Router && options.routes) {
      throw new Error('asking to use react router for rendering, but no routes are provided');
    }
  }

  var router;
  var history;
  var location;
  var viewResolver = options.viewResolver;

  // pick up the state that was injected by server during rendering
  var props = data();
  var useRouter = (props.__meta.view === null);
  var mountNode = options.mountNode || _document;

  // wrap component with react-redux Proivder if redux is required
  var wrap = function(component) {
    if (options.reduxStoreInitiator && isFunction(options.reduxStoreInitiator)) {
      var initStore = options.reduxStoreInitiator;
      if (initStore.default) {
        initStore = initStore.default;
      }
      var store = initStore(props);
      var Provider = require('react-redux').Provider;
      return React.createElement(Provider, { store: store }, component);
    } else {
      return component;
    }
  };

  var renderMethod = ReactDOM.hydrate || ReactDOM.render;

  if (useRouter) {

    history = options.history || browserHistory;
    location = _window.location.pathname +
      _window.location.search + _window.location.hash;

    if (options.routes.default) {
      options.routes = options.routes.default;
    }

    // Wrap the 'render' function within a call to 'match'. This is a workaround to support
    // users using code splitting functionality
    match({ routes: options.routes, location: location }, function() {

      // for any component created by react-router, merge model data with the routerProps
      // NOTE: This may be imposing too large of an opinion?
      var routerComponent = React.createElement(RouterComponent, {
        createElement: function(Component, routerProps) {
          return React.createElement(Component, assign({}, props, routerProps));
        },

        routes: options.routes,
        history: history
      });

      // wrap routerComponent with redux provider
      renderMethod(wrap(routerComponent), mountNode);
    });

  } else {
    // get the file from viewResolver supplying it with a view name
    var view = viewResolver(props.__meta.view);

    // create a react view factory
    var viewFactory = React.createFactory(view);

    // render the factory on the client
    // doing this, sets up the event
    // listeners and stuff aka mounting views.
    renderMethod(wrap(viewFactory(props)), mountNode);
  }

  // call the callback with the data that was used for rendering
  return callback && callback(props, history);
};
<|endoftext|>


<commit_before>var Sink = (function () {
    var sink
    try {
        sink = new WebSocket('ws://localhost:5003/');
    } catch (e) {
        $('#con-btn').removeClass('btn-success').addClass('btn-danger');
        $('#con-glyph').removeClass('fa-check').addClass('fa-remove');
    }
    sink.onerror = function() {
        $('#con-btn').removeClass('btn-success').addClass('btn-danger');
        $('#con-glyph').removeClass('fa-check').addClass('fa-remove');
    };
    sink.onclose = function() {
        $('#con-btn').removeClass('btn-success').addClass('btn-danger');
        $('#con-glyph').removeClass('fa-check').addClass('fa-remove');
    };

    var parse = false;
    var parseService = "";
    var optionLanguage = 'all';

    var languages = [];
    var discoverResponse = [];
    var enabledServices = ["discover"];
    var availableServices = [];

    var triggerFunction = {};

    var products = {};

    function toHtmlString(content) {
        return sprintf('
%s
', JSON.stringify(content, null, 2).replace('<', '&lt').replace('>', '&gt'));
    }

    sink.onmessage = function (rawMessage) {
        if (parse) {
            var message = JSON.parse(rawMessage.data);
            if (message.product !== undefined) {
                processNewProduct(message);
            } else {
                acceptNewDiscoverResponse(message);
            }
            parse = false;
            parseService = "";
        } else {
            var index = enabledServices.indexOf(rawMessage.data);
            if (index > -1) {
                parse = true;
                parseService = rawMessage.data;
            }
        }
    };

    function processNewProduct(product) {
        product.service_id = parseService;
        var productForType = products[product.product];
        if (productForType === undefined || productForType === null) {
            products[product.product] = [product];
        } else {
            var index = -1;
            for (var i = 0; i < productForType.length; i++) {
                var existingProduct = productForType[i];
                if (existingProduct.service_id === product.service_id && (existingProduct.source !== product.source || existingProduct.version_id < product.version_id)) {
                    index = i;
                }
            }
            if (index > -1) {
                products[product.product][index] = product;
            } else {
                products[product.product].push(product);
            }
        }
        var tabID = '#tab-' + product.service_id;
        if ($(tabID).length > 0) {
            $(tabID).html(toHtmlString(product));
        } else {
            $('#products-tabs').append('
' + product.service_id + '
');
            $('#products-div').append('

');
        }
        Sink.trigger(product.product);
    }

    function acceptNewDiscoverResponse(response) {
        $('#discoverResponse').html(toHtmlString(response));
        discoverResponse = response;

        languages.forEach(function (language) {
            $('#editor-' + language).remove();
            $('#config-' + language).remove();
        });

        var foundLanguages = [];
        var foundServices = [];

        response.forEach(function (service) {
            if (foundLanguages.indexOf(service.language) == -1) {
                foundLanguages.push(service.language);
                $('#editor-languages').append(sprintf('
%s
', service.language, service.language));
                $('#config-languages').append(sprintf('
%s
', service.language, service.language));
            }
            foundServices.push(service);
        });

        var configMsg = Source.getConfigurationMessage();
        availableServices.forEach(function (service) {
            if (!foundServices.indexOf(service) > -1) {
                $('#row-' + service.service_id).remove();
                var serviceIndex = -1;
                configMsg.configure_services.forEach(function (config, index) {
                    if (config.service_id === service.service_id) {
                        serviceIndex = index;
                    }
                });
                configMsg.configure_services.splice(serviceIndex, 1);
            }
        });
        Source.setConfigurationMessage(configMsg);

        availableServices = foundServices;
        languages = foundLanguages;
        buildServiceOptions();
        buildConfigurationOptions();
    }

    function buildServiceOptions() {
        availableServices.forEach(function (service) {
            if (optionLanguage === 'all' || service.language === optionLanguage) {
                var tr = $('#row-' + service.service_id);
                if (tr.length === 0) {
                    var serviceStr = localStorage.getItem('selectedServices');
                    var services = (serviceStr === '' || serviceStr === null || serviceStr === undefined) ? [] : JSON.parse(serviceStr);
                    var checked = '';
                    if (services.indexOf(service.service_id) > -1) {
                        checked = 'checked';
                        enabledServices.push(service.service_id);
                    }
                    $('#services').append(sprintf(
                        '
' +
                        '' +
                        '
' +
                        '<input id="%s" type="checkbox" class="discoverOption styled" %s>' +
                        '' +
                        '
' +
                        '	' +
                        '%s	' +
                        '%s	' +
                        '%s	' +
                        '%s	' +
                        '
'
                        , service.service_id, service.service_id, checked, service.service_id,
                        service.language, service.product, service.label, service.description));
                }
            } else {
                $('#row-' + service.service_id).remove();
            }
        });
    }

    function buildConfigurationOptions() {
        var configMsg = Source.getConfigurationMessage();
        availableServices.forEach(function (service) {
            var panel = $('#options-' + service.service_id);
            var serviceConfig = [];
            var content = parseConfigurationOptions(service.options, service, serviceConfig, []);
            if (panel.length === 0) {
                $('#options').append(content);
            }
            configMsg.configure_services.push({service_id: service.service_id, configurations: serviceConfig});
        });
        Source.setConfigurationMessage(configMsg);
    }

    function parseConfigurationOptions(options, service, serviceConfig, required_options) {
        if (options !== undefined && options !== null) {
            var content = '

';
            options.forEach(function (option) {
                var id = service.service_id + '-' + option.option_id;
                var config = localStorage.getItem(id);
                var value;
                var disabled = '';
                if (required_options !== null && required_options !== undefined && required_options.length > 0) {
                    var acc = true;
                    required_options.forEach(function (required_option) {
                        acc = 'true' === localStorage.getItem(service.service_id + '-' + required_option) && acc;
                        $(document).on('change', '#' + service.service_id + '-' + required_option, function (e) {
                            if (e.target.checked) {
                                $('#' + id).prop('disabled', false);
                            } else {
                                $('#' + id).prop('disabled', true);
                            }
                        });
                    });
                    disabled = acc ? '' : 'disabled';
                }
                if (option.type === "number") {
                    value = (config === null || config === undefined || config === '') ? option.default_value : parseInt(config);
                    content += buildNumberOption(config, option, id, disabled, value);
                } else if (option.type === "text") {
                    value = (config === null || config === undefined) ? option.default_value : config;
                    content += buildTextOption(config, option, id, disabled, value);
                } else if (option.type === "boolean") {
                    value = (config === null || config === undefined) ? option.default_value : 'true' === config;
                    content += buildBooleanOption(config, option, id, disabled, value);
                } else if (option.type === "xor") {
                    value = (config === null || config === undefined || config === '') ? option.default_value : config;
                    content += buildXorOption(config, option, id, disabled, value);
                } else if (option.type === undefined && option.members !== undefined) {
                    content += buildGroupOption(option, required_options, service, serviceConfig);
                }

                if (option.type !== undefined && option.members === undefined) {
                    serviceConfig.push({option_id: option.option_id, value: value});
                }
            });
            content += '

';
            return content;
        }
    }

    function buildNumberOption(config, option, id, disabled, value) {
        localStorage.setItem(id, value);
        return sprintf(
            '
' +
            '<input type="number" class="config" id="%s" placeholder="%s" min="%s" max="%s" value="%s" %s> %s' +
            '
'
            , id, option.default_value, option.from, option.to, value, disabled, option.label
        );
    }

    function buildTextOption(config, option, id, disabled, value) {
        localStorage.setItem(id, value);
        return sprintf(
            '
' +
            '<input type="text" class="config" id="%s" placeholder="%s" value="%s" %s> %s' +
            '
'
            , id, option.default_value, value, disabled, option.label
        );
    }

    function buildBooleanOption(config, option, id, disabled, value) {
        localStorage.setItem(id, value);
        return sprintf(
            '
' +
            '<input type="checkbox" class="config styled" id="%s" %s %s>' +
            '%s' +
            '
'
            , id, value ? 'checked ' : '', disabled, id, option.label
        );
    }

    function buildXorOption(config, option, id, disabled, value) {
        localStorage.setItem(id, value);
        var content = sprintf(
            '
' +
            '<button id="%s" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" %s>' +
            '%s' +
            '' +
            '</button>' +
            '
'
            , id, disabled, id, value, id
        );
        option.values.forEach(function (xorOption, value) {
            content += sprintf(
                '
%s
'
                , id, xorOption, id, xorOption
            );
        });
        content += '

 ' + option.label;
        return content;
    }

    function buildGroupOption(option, required_options, service, serviceConfig) {
        required_options.push(option.required_option);
        var content = parseConfigurationOptions(option.members, service, serviceConfig, required_options);
        var index = required_options.indexOf(option.required_option);
        if (index > -1) {
            required_options.splice(index, 1);
        }
        return content;
    }

    return {
        getProducts: function () {
            return products;
        },
        getProductsByType: function (type) {
            return products[type];
        },
        getActiveProductsByType: function (type) {
            var enabledProductsByType = [];
            var productsByType = products[type];
            if (productsByType === undefined || productsByType === null) {
                return [];
            }
            productsByType.forEach(function (product) {
                var serviceAvailable = false;
                availableServices.forEach(function (service) {
                    if (service.service_id === product.service_id) {
                        serviceAvailable = true;
                    }
                });
                if (serviceAvailable && enabledServices.indexOf(product.service_id) > -1 && product.language === Source.getMessage().language) {
                    enabledProductsByType.push(product);
                }
            });
            return enabledProductsByType;
        },
        getProductByServiceID: function (serviceID) {
            for (var i in products) {
                for (var j in products[i]) {
                    if (products[i][j].service_id === serviceID) {
                        return products[i][j];
                    }
                }
            }
            return null;
        },
        resetProducts: function () {
            products = {};
        },
        onTypeTriggerFunction: function (productType, func) {
            var list = triggerFunction[productType];
            if (list === undefined || list === null) {
                triggerFunction[productType] = [func];
            } else {
                triggerFunction[productType].push(func);
            }
        },
        trigger: function (productType) {
            var list = triggerFunction[productType];
            if (list === undefined || list === null) {
                return;
            }
            triggerFunction[productType].forEach(function (func) {
                func();
            });
        },
        triggerAll: function () {
            for (var product in triggerFunction) {
                if (product === 'completions') {
                    continue;
                }
                triggerFunction[product].forEach(function (func) {
                    func();
                });
            }
        },
        setOptionsLanguage: function (language) {
            optionLanguage = language;
            buildServiceOptions();
        },
        enableService: function (serviceID) {
            var index = enabledServices.indexOf(serviceID);
            if (index == -1) {
                enabledServices.push(serviceID);
                var serviceStr = localStorage.getItem('selectedServices');
                var services = (serviceStr === '' || serviceStr === null || serviceStr === undefined) ? [] : JSON.parse(serviceStr);
                services.push(serviceID);
                localStorage.setItem('selectedServices', JSON.stringify(services));
            }
        },
        disableService: function (serviceID) {
            var index = enabledServices.indexOf(serviceID);
            if (index > -1) {
                enabledServices.splice(index, 1);
                var serviceStr = localStorage.getItem('selectedServices');
                var services = (serviceStr === '' || serviceStr === null || serviceStr === undefined) ? [] : JSON.parse(serviceStr);
                services.splice(services.indexOf(serviceID), 1);
                localStorage.setItem('selectedServices', JSON.stringify(services));
            }
        }
    };
})();<commit_msg>add automatic selection of new services, fixes #2<commit_after>var Sink = (function () {
    var sink
    try {
        sink = new WebSocket('ws://localhost:5003/');
    } catch (e) {
        $('#con-btn').removeClass('btn-success').addClass('btn-danger');
        $('#con-glyph').removeClass('fa-check').addClass('fa-remove');
    }
    sink.onerror = function() {
        $('#con-btn').removeClass('btn-success').addClass('btn-danger');
        $('#con-glyph').removeClass('fa-check').addClass('fa-remove');
    };
    sink.onclose = function() {
        $('#con-btn').removeClass('btn-success').addClass('btn-danger');
        $('#con-glyph').removeClass('fa-check').addClass('fa-remove');
    };

    var parse = false;
    var parseService = "";
    var optionLanguage = 'all';

    var languages = [];
    var discoverResponse = [];
    var enabledServices = ["discover"];
    var availableServices = [];

    var triggerFunction = {};

    var products = {};

    function toHtmlString(content) {
        return sprintf('
%s
', JSON.stringify(content, null, 2).replace('<', '&lt').replace('>', '&gt'));
    }

    sink.onmessage = function (rawMessage) {
        if (parse) {
            var message = JSON.parse(rawMessage.data);
            if (message.product !== undefined) {
                processNewProduct(message);
            } else {
                acceptNewDiscoverResponse(message);
            }
            parse = false;
            parseService = "";
        } else {
            var index = enabledServices.indexOf(rawMessage.data);
            if (index > -1) {
                parse = true;
                parseService = rawMessage.data;
            }
        }
    };

    function processNewProduct(product) {
        product.service_id = parseService;
        var productForType = products[product.product];
        if (productForType === undefined || productForType === null) {
            products[product.product] = [product];
        } else {
            var index = -1;
            for (var i = 0; i < productForType.length; i++) {
                var existingProduct = productForType[i];
                if (existingProduct.service_id === product.service_id && (existingProduct.source !== product.source || existingProduct.version_id < product.version_id)) {
                    index = i;
                }
            }
            if (index > -1) {
                products[product.product][index] = product;
            } else {
                products[product.product].push(product);
            }
        }
        var tabID = '#tab-' + product.service_id;
        if ($(tabID).length > 0) {
            $(tabID).html(toHtmlString(product));
        } else {
            $('#products-tabs').append('
' + product.service_id + '
');
            $('#products-div').append('

');
        }
        Sink.trigger(product.product);
    }

    function acceptNewDiscoverResponse(response) {
        $('#discoverResponse').html(toHtmlString(response));
        discoverResponse = response;

        languages.forEach(function (language) {
            $('#editor-' + language).remove();
            $('#config-' + language).remove();
        });

        var foundLanguages = [];
        var foundServices = [];

        response.forEach(function (service) {
            if (foundLanguages.indexOf(service.language) == -1) {
                foundLanguages.push(service.language);
                $('#editor-languages').append(sprintf('
%s
', service.language, service.language));
                $('#config-languages').append(sprintf('
%s
', service.language, service.language));
            }
            foundServices.push(service);
        });

        var configMsg = Source.getConfigurationMessage();
        availableServices.forEach(function (service) {
            if (!foundServices.indexOf(service) > -1) {
                $('#row-' + service.service_id).remove();
                var serviceIndex = -1;
                configMsg.configure_services.forEach(function (config, index) {
                    if (config.service_id === service.service_id) {
                        serviceIndex = index;
                    }
                });
                configMsg.configure_services.splice(serviceIndex, 1);
            }
        });
        Source.setConfigurationMessage(configMsg);

        availableServices = foundServices;
        languages = foundLanguages;
        buildServiceOptions();
        buildConfigurationOptions();
    }

    function buildServiceOptions() {
        availableServices.forEach(function (service) {
            if (optionLanguage === 'all' || service.language === optionLanguage) {
                var tr = $('#row-' + service.service_id);
                if (tr.length === 0) {
                    var services = localStorage.getItem('selectedServices');
                    services = (services === '' || services === null || services === undefined) ? [] : JSON.parse(services);
                    var knownServices = localStorage.getItem('knownServices');
                    knownServices = (knownServices === '' || knownServices === null || knownServices === undefined) ? [] : JSON.parse(knownServices);
                    var checked = '';
                    if (knownServices.indexOf(service.service_id) === -1) {
                        checked = 'checked';
                        var serviceStr = localStorage.getItem('selectedServices');
                        var selectedServices = (serviceStr === '' || serviceStr === null || serviceStr === undefined) ? [] : JSON.parse(serviceStr);
                        selectedServices.push(service.service_id);
                        localStorage.setItem('selectedServices', JSON.stringify(selectedServices));
                        knownServices.push(service.service_id);
                        localStorage.setItem('knownServices', JSON.stringify(knownServices));
                    } else if (services.indexOf(service.service_id) > -1) {
                        checked = 'checked';
                        enabledServices.push(service.service_id);
                    }
                    $('#services').append(sprintf(
                        '
' +
                        '' +
                        '
' +
                        '<input id="%s" type="checkbox" class="discoverOption styled" %s>' +
                        '' +
                        '
' +
                        '	' +
                        '%s	' +
                        '%s	' +
                        '%s	' +
                        '%s	' +
                        '
'
                        , service.service_id, service.service_id, checked, service.service_id,
                        service.language, service.product, service.label, service.description));
                }
            } else {
                $('#row-' + service.service_id).remove();
            }
        });
    }

    function buildConfigurationOptions() {
        var configMsg = Source.getConfigurationMessage();
        availableServices.forEach(function (service) {
            var panel = $('#options-' + service.service_id);
            var serviceConfig = [];
            var content = parseConfigurationOptions(service.options, service, serviceConfig, []);
            if (panel.length === 0) {
                $('#options').append(content);
            }
            configMsg.configure_services.push({service_id: service.service_id, configurations: serviceConfig});
        });
        Source.setConfigurationMessage(configMsg);
    }

    function parseConfigurationOptions(options, service, serviceConfig, required_options) {
        if (options !== undefined && options !== null) {
            var content = '

';
            options.forEach(function (option) {
                var id = service.service_id + '-' + option.option_id;
                var config = localStorage.getItem(id);
                var value;
                var disabled = '';
                if (required_options !== null && required_options !== undefined && required_options.length > 0) {
                    var acc = true;
                    required_options.forEach(function (required_option) {
                        acc = 'true' === localStorage.getItem(service.service_id + '-' + required_option) && acc;
                        $(document).on('change', '#' + service.service_id + '-' + required_option, function (e) {
                            if (e.target.checked) {
                                $('#' + id).prop('disabled', false);
                            } else {
                                $('#' + id).prop('disabled', true);
                            }
                        });
                    });
                    disabled = acc ? '' : 'disabled';
                }
                if (option.type === "number") {
                    value = (config === null || config === undefined || config === '') ? option.default_value : parseInt(config);
                    content += buildNumberOption(config, option, id, disabled, value);
                } else if (option.type === "text") {
                    value = (config === null || config === undefined) ? option.default_value : config;
                    content += buildTextOption(config, option, id, disabled, value);
                } else if (option.type === "boolean") {
                    value = (config === null || config === undefined) ? option.default_value : 'true' === config;
                    content += buildBooleanOption(config, option, id, disabled, value);
                } else if (option.type === "xor") {
                    value = (config === null || config === undefined || config === '') ? option.default_value : config;
                    content += buildXorOption(config, option, id, disabled, value);
                } else if (option.type === undefined && option.members !== undefined) {
                    content += buildGroupOption(option, required_options, service, serviceConfig);
                }

                if (option.type !== undefined && option.members === undefined) {
                    serviceConfig.push({option_id: option.option_id, value: value});
                }
            });
            content += '

';
            return content;
        }
    }

    function buildNumberOption(config, option, id, disabled, value) {
        localStorage.setItem(id, value);
        return sprintf(
            '
' +
            '<input type="number" class="config" id="%s" placeholder="%s" min="%s" max="%s" value="%s" %s> %s' +
            '
'
            , id, option.default_value, option.from, option.to, value, disabled, option.label
        );
    }

    function buildTextOption(config, option, id, disabled, value) {
        localStorage.setItem(id, value);
        return sprintf(
            '
' +
            '<input type="text" class="config" id="%s" placeholder="%s" value="%s" %s> %s' +
            '
'
            , id, option.default_value, value, disabled, option.label
        );
    }

    function buildBooleanOption(config, option, id, disabled, value) {
        localStorage.setItem(id, value);
        return sprintf(
            '
' +
            '<input type="checkbox" class="config styled" id="%s" %s %s>' +
            '%s' +
            '
'
            , id, value ? 'checked ' : '', disabled, id, option.label
        );
    }

    function buildXorOption(config, option, id, disabled, value) {
        localStorage.setItem(id, value);
        var content = sprintf(
            '
' +
            '<button id="%s" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" %s>' +
            '%s' +
            '' +
            '</button>' +
            '
'
            , id, disabled, id, value, id
        );
        option.values.forEach(function (xorOption, value) {
            content += sprintf(
                '
%s
'
                , id, xorOption, id, xorOption
            );
        });
        content += '

 ' + option.label;
        return content;
    }

    function buildGroupOption(option, required_options, service, serviceConfig) {
        required_options.push(option.required_option);
        var content = parseConfigurationOptions(option.members, service, serviceConfig, required_options);
        var index = required_options.indexOf(option.required_option);
        if (index > -1) {
            required_options.splice(index, 1);
        }
        return content;
    }

    return {
        getProducts: function () {
            return products;
        },
        getProductsByType: function (type) {
            return products[type];
        },
        getActiveProductsByType: function (type) {
            var enabledProductsByType = [];
            var productsByType = products[type];
            if (productsByType === undefined || productsByType === null) {
                return [];
            }
            productsByType.forEach(function (product) {
                var serviceAvailable = false;
                availableServices.forEach(function (service) {
                    if (service.service_id === product.service_id) {
                        serviceAvailable = true;
                    }
                });
                if (serviceAvailable && enabledServices.indexOf(product.service_id) > -1 && product.language === Source.getMessage().language) {
                    enabledProductsByType.push(product);
                }
            });
            return enabledProductsByType;
        },
        getProductByServiceID: function (serviceID) {
            for (var i in products) {
                for (var j in products[i]) {
                    if (products[i][j].service_id === serviceID) {
                        return products[i][j];
                    }
                }
            }
            return null;
        },
        resetProducts: function () {
            products = {};
        },
        onTypeTriggerFunction: function (productType, func) {
            var list = triggerFunction[productType];
            if (list === undefined || list === null) {
                triggerFunction[productType] = [func];
            } else {
                triggerFunction[productType].push(func);
            }
        },
        trigger: function (productType) {
            var list = triggerFunction[productType];
            if (list === undefined || list === null) {
                return;
            }
            triggerFunction[productType].forEach(function (func) {
                func();
            });
        },
        triggerAll: function () {
            for (var product in triggerFunction) {
                if (product === 'completions') {
                    continue;
                }
                triggerFunction[product].forEach(function (func) {
                    func();
                });
            }
        },
        setOptionsLanguage: function (language) {
            optionLanguage = language;
            buildServiceOptions();
        },
        enableService: function (serviceID) {
            var index = enabledServices.indexOf(serviceID);
            if (index == -1) {
                enabledServices.push(serviceID);
                var serviceStr = localStorage.getItem('selectedServices');
                var services = (serviceStr === '' || serviceStr === null || serviceStr === undefined) ? [] : JSON.parse(serviceStr);
                services.push(serviceID);
                localStorage.setItem('selectedServices', JSON.stringify(services));
            }
        },
        disableService: function (serviceID) {
            var index = enabledServices.indexOf(serviceID);
            if (index > -1) {
                enabledServices.splice(index, 1);
                var serviceStr = localStorage.getItem('selectedServices');
                var services = (serviceStr === '' || serviceStr === null || serviceStr === undefined) ? [] : JSON.parse(serviceStr);
                services.splice(services.indexOf(serviceID), 1);
                localStorage.setItem('selectedServices', JSON.stringify(services));
            }
        }
    };
})();<|endoftext|>


<commit_before>var Knox = require("knox");
var Async = require("async");

/**
 * Useful for overriding `knox` client methods.
 */
var noop = function(source, destination, headers, callback) {
    process.nextTick(function() {
        callback(null, {});
    });
};

/**
 * Returns a rate-limited `knox` client for `bucket`. If `dryRun` is passed,
 * return a non-client.
 */
module.exports = function(options) {
    var client = Knox.createClient({
        bucket: options.bucket,
        key: options.key,
        secret: options.secret,
    });

    // @jb: With Node v0.10.x, I've seen the 'error' event fire from `knox` requests
    //      after the error handler has been cleaned up. Bind our own handler to
    //      to track the trouble.
    var clientRequest = client.request;
    client.request = function(method, filename, headers) {
        var req = clientRequest.apply(client, arguments);
        req.on('error', function(err) {
            console.log('ERROR: %s %s %s', method, filename, err);
        });
        return req;
    };

    if (options.dryRun) {
        client.putFile = client.copyFile = noop;
        return client;
    }

    // Limit `putFile` to avoid opening too many files.
    var clientPutFile = client.putFile;

    var putFileQueue = Async.queue(function(task, callback) {
        var done = function(err, res) {
            return callback(err, res);
        };

        var request = clientPutFile.apply(client, [task.src, task.filename, task.headers, done]);
    }, 2);

    client.putFile = function(src, filename, headers, callback) {
        putFileQueue.push({
            src: src,
            filename: filename,
            headers: headers,
            callback: callback
        });
    };

    return client;
};<commit_msg>putFileQueue correctly calls the passed callback.<commit_after>var Knox = require("knox");
var Async = require("async");

/**
 * Useful for overriding `knox` client methods.
 */
var noop = function(source, destination, headers, callback) {
    process.nextTick(function() {
        callback(null, {});
    });
};

/**
 * Returns a rate-limited `knox` client for `bucket`. If `dryRun` is passed,
 * return a non-client.
 */
module.exports = function(options) {
    var client = Knox.createClient({
        bucket: options.bucket,
        key: options.key,
        secret: options.secret,
    });

    // @jb: With Node v0.10.x, I've seen the 'error' event fire from `knox` requests
    //      after the error handler has been cleaned up. Bind our own handler to
    //      to track the trouble.
    var clientRequest = client.request;
    client.request = function(method, filename, headers) {
        var req = clientRequest.apply(client, arguments);
        req.on('error', function(err) {
            console.log('ERROR: %s %s %s', method, filename, err);
        });
        return req;
    };

    if (options.dryRun) {
        client.putFile = client.copyFile = noop;
        return client;
    }

    // Limit `putFile` to avoid opening too many files.
    var clientPutFile = client.putFile;

    var putFileQueue = Async.queue(function(task, callback) {
        var done = function(err, res) {
            callback();
            task.callback(err, res)
        };

        var request = clientPutFile.apply(client, [task.src, task.filename, task.headers, done]);
    }, 2);

    client.putFile = function(src, filename, headers, callback) {
        putFileQueue.push({
            src: src,
            filename: filename,
            headers: headers,
            callback: callback
        });
    };

    return client;
};<|endoftext|>


<commit_before>/**
 * Client interface to the Hoodie server and CouchDB, an instance of this
 * will be passed to each worker so we can pool changes feed subscriptions.
 */

/**
 * TODO: The changes pooling is quite naive atm. There are certainly futher
 * optimizations that could be made. For example:
 *
 *  - If subscribed to all docs and another feed requests a filter we could use
 *    the single all docs feed and apply the filter locally.
 *  - If one feed requests include docs and another then requests the same
 *    resource without included docs we can strip them from the results locally
 *    (or just provide them anyway).
 *  - We can also detect when feeds requested with different since values are
 *    synchronized and drop down to a single feed.
 *  - If a feed is requested with since='now' and any existing feeds have a
 *    since update seq value that's lower than the current update seq for the
 *    db, we can simply use that feed from this point on.
 */

var url = require('url'),
    async = require('async'),
    couchr = require('couchr'),
    follow = require('follow'),
    db_updates = require('./db_updates'),
    _ = require('underscore');

/**
 * Creates a new client using the provided config and password
 */

// TODO: add callback so we can start listening to db events before starting
// the workers
exports.createClient = function (config, password) {
    return {
        couch: exports.createCouchClient(config, password)
    };
};

/**
 * Provides an authenticated interface to CouchDB with pooling
 * of change feed requests
 */

exports.createCouchClient = function (config, password) {
    var couch = {};

    var base_url = url.parse(config.couch.url);
    base_url.auth = 'admin:' + encodeURIComponent(password);

    function couchURL(path) {
        return url.resolve(base_url, path);
    }

    var methods = ['get', 'post', 'head', 'put', 'del', 'copy'];
    methods.forEach(function (method) {
        couch[method] = function (path, data, opt, callback) {
            return couchr[method](couchURL(path), data, opt, callback);
        };
    });

    // idle feeds pool
    var idle = [];

    // number of concurrent db feed refreshes
    var concurrency = 4;

    // the updated db queue, processed feeds are put back in the idle pool
    var updated = async.queue(function (db, callback) {

        async.mapSeries(db.requests, function (req, cb) {
            // don't do continuous or longpoll feeds
            req.query.feed = 'normal';
            // request the changes feed for the query
            couch.get(req.url + '/_changes', req.query, function (err, data) {
                if (err) {
                    // let the worker handle errors
                    req.callback(err);
                }
                else {
                    // update the since value so the next request
                    // continues from this point
                    req.query.since = data.last_seq;
                    data.results.forEach(function (r) {
                        req.callback(null, r);
                    });
                }
                return cb(null, req);
            });
        },
        function (err, requests) {
            if (err) {
                // we're passing errors to workers, so this shouldn't happen
                return callback(err);
            }
            db.requests = requests;
            // move the db to end of the idle list
            idle.push(db);
            return callback();
        });

    }, concurrency);

    // remove a db from the idle list
    function removeDB(db) {
        for (var i = 0; i < idle.length; i++) {
            if (idle[i].db === db) {
                return idle.splice(i, 1)[0];
            }
        }
    }

    // take a db off the idle list and queue it for a refresh
    function refreshDB(db) {
        var data = removeDB(db);
        // might not have any subscribers
        if (data) {
            updated.push(data);
        }
    }

    // periodically pop the oldest databases off the idle pool to check
    // we haven't missed anything
    setInterval(function () {
        var db = idle.shift();
        if (db) {
            updated.push(db);
        }
    }, 5000);

    couch.changes = function (db, query, callback) {
        // query parameter is optional
        if (!callback) {
            callback = query;
            query = {};
        }
        if (query.limit || query.descending) {
            // TODO: don't bother trying to pool these, just make request
        }
        var req = {
            // db name
            db: db,
            // authenticated url to db
            url: couchURL('/' + encodeURIComponent(db)),
            // used by the update queue workers
            callback: callback,
            // store the query parameters
            query: query
        };

        // adds the changes request to the pool and refreshes db
        function start() {
            exports.addToPool(idle, req);
            refreshDB(db);
        }

        // only show changes after subscribe time by default
        if (!query.hasOwnProperty('since') || query.since === 'now') {
            // update the since parameter before gettings changes
            couch.get(req.url, function (err, data) {
                if (err) {
                    return callback(err);
                }
                req.query.since = data.update_seq;
                start();
            });
        }
        else {
            // we already have a 'since' value
            start();
        }
    };

    db_updates.listen(base_url, function (err, data) {
        if (data.type === 'deleted') {
            removeDB(data.db_name);
        }
        else if (data.type === 'updated') {
            refreshDB(data.db_name);
        }
    });

    return couch;
};

/**
 * Adds a request to a pool
 */

exports.addToPool = function (pool, req) {
    var db = _.detect(pool, function (x) {
        return x.db === req.db;
    });
    if (db) {
        db.requests.push(req);
    }
    else {
        pool.push({db: req.db, requests: [req]});
    }
    return pool;
};
<commit_msg>refactor changes request pooling code a bit<commit_after>/**
 * Client interface to the Hoodie server and CouchDB, an instance of this
 * will be passed to each worker so we can pool changes feed subscriptions.
 */

var url = require('url'),
    async = require('async'),
    couchr = require('couchr'),
    follow = require('follow'),
    db_updates = require('./db_updates'),
    _ = require('underscore');

/**
 * Creates a new client using the provided config and password
 */

exports.createClient = function (config, password) {
    return {
        couch: exports.createCouchClient(config, password)
    };
};

/**
 * Provides an authenticated interface to CouchDB with pooling
 * of change feed requests
 */

exports.createCouchClient = function (config, password) {
    var couch = {};

    // add auth details to couch url
    var base_url = url.parse(config.couch.url);
    base_url.auth = 'admin:' + encodeURIComponent(password);

    // makes urls requested by workers authenticated by default
    function couchURL(path) {
        return url.resolve(base_url, path);
    }

    // wrap all HTTP methods from couchr
    var methods = ['get', 'post', 'head', 'put', 'del', 'copy'];
    methods.forEach(function (method) {
        couch[method] = function (path, data, opt, callback) {
            return couchr[method](couchURL(path), data, opt, callback);
        };
    });

    // idle feeds pool
    var idle = [];

    // number of concurrent db feed refreshes
    var concurrency = 4;

    // the updated db queue, processed feeds are put back in the idle pool
    var updated = async.queue(function (db, callback) {
        // make all requests associated with the db
        exports.doRequests(couch, db, function (err, db) {
            if (err) {
                return callback(err);
            }
            // add the db back into the idle list
            idle.push(db);
            // finish this task
            return callback();
        });
    }, concurrency);

    // periodically pop the oldest databases off the
    // idle pool to check we haven't missed anything
    setInterval(function () {
        exports.refreshOldest(updated, idle);
    }, 5000);

    couch.changes = function (db, query, callback) {
        // query parameter is optional
        if (!callback) {
            callback = query;
            query = {};
        }
        if (query.limit || query.descending || query.feed === 'normal') {
            // don't attempt to pool one-off requests
            var url = couchURL(encodeURIComponent(db) + '/_changes');
            return couch.get(url, q, callback);
        }

        // create a new request object
        var req = {
            // db name
            db: db,
            // authenticated url to db
            db_url: couchURL('/' + encodeURIComponent(db)),
            // used by the update queue workers
            callback: callback,
            // store the query parameters
            query: query
        };

        // make sure the request has a since parameter set
        exports.updateSince(couch, req, function (err, req) {
            if (err) {
                return callback(err);
            }
            // add the changes request to the pool
            exports.addToPool(idle, req);
            // queue the new request for immediate update
            exports.refreshDB(updated, idle, db);
        });
    };

    // start listening to db update events from couchdb
    db_updates.listen(base_url, function (err, data) {
        if (data.type === 'deleted') {
            exports.removeDB(idle, data.db_name);
        }
        else if (data.type === 'updated') {
            exports.refreshDB(updated, idle, data.db_name);
        }
    });

    return couch;
};

/**
 * Makes all requests registered for the provided db object,
 * returning an updated db object (with the requests including
 * the new since value).
 */

exports.doRequests = function (couch, db, callback) {
    // pre-apply the first argument of requestChanges
    var doRequest = _.partial(exports.requestChanges, couch);
    // make each request in series and return the updated request objects
    async.mapSeries(db.requests, doRequest, function (err, reqs) {
        if (err) {
            // we're passing errors to workers, so this shouldn't happen
            return callback(err);
        }
        // update the db object
        db.requests = reqs;
        return callback(null, db);
    });
};

/**
 * Makes a request to the changes feed, calling the request object's
 * callback with the results returning an updated request object with
 * the new since value.
 */

exports.requestChanges = function (couch, req, callback) {
    // don't do continuous or longpoll feeds
    req.query.feed = 'normal';
    // request the changes feed for the query
    couch.get(req.db_url + '/_changes', req.query, function (err, data) {
        if (err) {
            // let the worker handle errors
            req.callback(err);
        }
        else {
            // update the since value so the next request
            // continues from this point
            req.query.since = data.last_seq;
            data.results.forEach(function (r) {
                req.callback(null, r);
            });
        }
        return callback(null, req);
    });
};

/**
 * Adds a changes request to a pool
 */

exports.addToPool = function (pool, req) {
    var db = _.detect(pool, function (x) {
        return x.db === req.db;
    });
    if (db) {
        db.requests.push(req);
    }
    else {
        pool.push({db: req.db, requests: [req]});
    }
    return pool;
};

/**
 * Remove a db from the changes request pool
 */

exports.removeDB = function (pool, db) {
    for (var i = 0; i < pool.length; i++) {
        if (pool[i].db === db) {
            return pool.splice(i, 1)[0];
        }
    }
}

/**
 * Remove a db from the changes request pool and add it to
 * the refresh queue
 */

exports.refreshDB = function (queue, pool, db) {
    var data = exports.removeDB(pool, db);
    // might not have any subscribers
    if (data) {
        queue.push(data);
    }
}

/**
 * Move the oldest request (longest since last changes update) out
 * of the changes request pool and onto the the update queue
 */

exports.refreshOldest = function (queue, pool) {
    var db = pool.shift();
    if (db) {
        queue.push(db);
    }
};

/**
 * Ensure the request has a value set for the since parameter. If the
 * since parameter is missing or set to 'now', fetch the db-level URL
 * to update it to the current seq
 */

exports.updateSince = function (couch, req, callback) {
    if (!req.query.hasOwnProperty('since') || req.query.since === 'now') {
        // get the latest update seq from couchdb
        couch.get(req.db_url, function (err, data) {
            if (err) {
                return callback(err);
            }
            req.query.since = data.update_seq;
            return callback(null, req);
        });
    }
    else {
        // be consistently asynchronous
        return process.nextTick(function () {
            return callback(null, req);
        });
    }
};
<|endoftext|>


<commit_before>// Persistent storage (blocking, but quick)
const ConfigStore = require("configstore")
const store = new ConfigStore("subvertise")

// variables
let isActive = false
let currentUrl = ""
let nextHitTime = 0
let loopTimer = null
let hitTimer = null
let hitCount = null

// Elements
const browserEl = document.getElementById("url-frame")
const urlTextEl = document.getElementById("url-text")
const maxWaitTextEl = document.getElementById("max-wait-time-text")
const minWaitTextEl = document.getElementById("min-wait-time-text")
const proxyTextEl = document.getElementById("proxy-text")
const controlButtonEl = document.getElementById("control-button")

// Wrapper around storage set, incase we change it.
function storeGet(name, defaultValue) {
  let val = store.get(name)
  if (!val && defaultValue) {
    return defaultValue
  }
  return val
}

// Wrapper around storage get, incase we change it.
function storeSet(name, value) {
  store.set(name, value)
}

// Return a list of URLS from user storage
// this blocks, but it's quick
function getUrls() {
  let urlList = storeGet("urls", [
    "https://google.com",
    "https://reddit.com",
    "https://facebook.com",
    "https://yahoo.com",
    "https://myspace.com",
    "https://amazon.com"
  ])
  return urlList
}

function getRandomUrl() {
  let urls = getUrls()
  let randI = Math.floor(Math.random() * urls.length)
  return urls[randI]
}

function getMaxWaitTime() {
  return storeGet("maxWaitTime", 50);
}

function getMinWaitTime() {
  return storeGet("minWaitTime", 5);
}

function getRandomWait() {
  let maxWait = getMaxWaitTime() * 1000
  let minWait = getMinWaitTime() * 1000
  return Math.floor(Math.random() * (maxWait - minWait)) + minWait
}

function toggle() {
  if (isActive) stop()
  else start()
}

function stop() {
  isActive = false
  controlButtonEl.innerHTML = 'play_arrow'
}

function start() {
  isActive = true
  clearTimeout(loopTimer)
  loopTimer = setInterval(function() { mainLoop() }, 100)
  controlButtonEl.innerHTML = 'pause'
}

function doHit(url) {
  currentUrl = url
  browserEl.src = url
  hitCount++
}

function populatUi() {
  urlTextEl.value = getUrls().join("\n")
  maxWaitTextEl.value = getMaxWaitTime()
  minWaitTextEl.value = getMinWaitTime()
  proxyTextEl.value = store.get("proxyString","")
}

// Save #max-wait-time-text.value to store
function saveMaxWaitTime() {
  let maxWait = parseInt(maxWaitTextEl.value)
  if (maxWait <= getMinWaitTime()) {
    maxWait = getMinWaitTime() + 1
    maxWaitTextEl.value = maxWait
  }
  else if (maxWait > 300) {
    maxWait = 300
    maxWaitTextEl.value = maxWait
  }
  storeSet("maxWaitTime", maxWait)
}

// Save #min-wait-time-text.value to store
function saveMinWaitTime() {
  let minWait = parseInt(minWaitTextEl.value)
  if (minWait < 1) {
    minWait = 1
    minWaitTextEl.value = minWait
  }
  else if (minWait >= getMaxWaitTime()) {
    minWait = getMaxWaitTime() - 1
    minWaitTextEl.value = minWait
  }
  storeSet("minWaitTime", minWait)
}

// Save #proxy-text.value to store
function saveProxyText() {
  let proxyString = proxyTextEl.value
  if (proxyString.trim().length) {
    storeSet("proxyString", proxyString)
  }
  else {
    storeSet("proxyString", null)
  }
}

// Save #url-text.value to store
function saveUrlText() {
  let urls = urlTextEl.value.split("\n")
  let newUrls = []
  for (let i=0; i<urls.length; i++) {
    if (urls[i].length) newUrls.push(urls[i].trim())
  }
  storeSet("urls", newUrls)
}

// Runs every 100 milliseconds
function mainLoop() {
  if (isActive) {
    nextHitTime -= 100
    if (nextHitTime < 0) {
      doHit(getRandomUrl())
      nextHitTime = getRandomWait()
    }
  }
  updateUI()
}

// Update UI elements
function updateUI() {
  let cpEl = document.getElementById("currentUrl")
  let nhEl = document.getElementById("nextHitTime")
  cpEl.innerText = currentUrl
  nhEl.innerText = (Math.round(nextHitTime / 100) * 10) / 100
  // Hack for crashing webviews in Electron
  // webviews *cannot* be both hidden and working
  let tab = document.querySelector(".is-active")
  if (tab.id === "browser-link") {
    browserEl.style.zIndex = 10
  } else {
    browserEl.style.zIndex = -10
  }
}

window.onload = function() {
  populatUi()
}<commit_msg>Proxy string fix<commit_after>// Persistent storage (blocking, but quick)
const ConfigStore = require("configstore")
const store = new ConfigStore("subvertise")

// variables
let isActive = false
let currentUrl = ""
let nextHitTime = 0
let loopTimer = null
let hitTimer = null
let hitCount = null

// Elements
const browserEl = document.getElementById("url-frame")
const urlTextEl = document.getElementById("url-text")
const maxWaitTextEl = document.getElementById("max-wait-time-text")
const minWaitTextEl = document.getElementById("min-wait-time-text")
const proxyTextEl = document.getElementById("proxy-text")
const controlButtonEl = document.getElementById("control-button")

// Wrapper around storage set, incase we change it.
function storeGet(name, defaultValue) {
  let val = store.get(name)
  if (!val && defaultValue) {
    return defaultValue
  }
  return val
}

// Wrapper around storage get, incase we change it.
function storeSet(name, value) {
  store.set(name, value)
}

// Return a list of URLS from user storage
// this blocks, but it's quick
function getUrls() {
  let urlList = storeGet("urls", [
    "https://google.com",
    "https://reddit.com",
    "https://facebook.com",
    "https://yahoo.com",
    "https://myspace.com",
    "https://amazon.com"
  ])
  return urlList
}

function getRandomUrl() {
  let urls = getUrls()
  let randI = Math.floor(Math.random() * urls.length)
  return urls[randI]
}

function getMaxWaitTime() {
  return storeGet("maxWaitTime", 50);
}

function getMinWaitTime() {
  return storeGet("minWaitTime", 5);
}

function getRandomWait() {
  let maxWait = getMaxWaitTime() * 1000
  let minWait = getMinWaitTime() * 1000
  return Math.floor(Math.random() * (maxWait - minWait)) + minWait
}

function toggle() {
  if (isActive) stop()
  else start()
}

function stop() {
  isActive = false
  controlButtonEl.innerHTML = 'play_arrow'
}

function start() {
  isActive = true
  clearTimeout(loopTimer)
  loopTimer = setInterval(function() { mainLoop() }, 100)
  controlButtonEl.innerHTML = 'pause'
}

function doHit(url) {
  currentUrl = url
  browserEl.src = url
  hitCount++
}

function populatUi() {
  urlTextEl.value = getUrls().join("\n")
  maxWaitTextEl.value = getMaxWaitTime()
  minWaitTextEl.value = getMinWaitTime()
  proxyTextEl.value = storeGet("proxyString","")
}

// Save #max-wait-time-text.value to store
function saveMaxWaitTime() {
  let maxWait = parseInt(maxWaitTextEl.value)
  if (maxWait <= getMinWaitTime()) {
    maxWait = getMinWaitTime() + 1
    maxWaitTextEl.value = maxWait
  }
  else if (maxWait > 300) {
    maxWait = 300
    maxWaitTextEl.value = maxWait
  }
  storeSet("maxWaitTime", maxWait)
}

// Save #min-wait-time-text.value to store
function saveMinWaitTime() {
  let minWait = parseInt(minWaitTextEl.value)
  if (minWait < 1) {
    minWait = 1
    minWaitTextEl.value = minWait
  }
  else if (minWait >= getMaxWaitTime()) {
    minWait = getMaxWaitTime() - 1
    minWaitTextEl.value = minWait
  }
  storeSet("minWaitTime", minWait)
}

// Save #proxy-text.value to store
function saveProxyText() {
  let proxyString = proxyTextEl.value
  if (proxyString.trim().length) {
    storeSet("proxyString", proxyString)
  }
  else {
    storeSet("proxyString", null)
  }
}

// Save #url-text.value to store
function saveUrlText() {
  let urls = urlTextEl.value.split("\n")
  let newUrls = []
  for (let i=0; i<urls.length; i++) {
    if (urls[i].length) newUrls.push(urls[i].trim())
  }
  storeSet("urls", newUrls)
}

// Runs every 100 milliseconds
function mainLoop() {
  if (isActive) {
    nextHitTime -= 100
    if (nextHitTime < 0) {
      doHit(getRandomUrl())
      nextHitTime = getRandomWait()
    }
  }
  updateUI()
}

// Update UI elements
function updateUI() {
  let cpEl = document.getElementById("currentUrl")
  let nhEl = document.getElementById("nextHitTime")
  cpEl.innerText = currentUrl
  nhEl.innerText = (Math.round(nextHitTime / 100) * 10) / 100
  // Hack for crashing webviews in Electron
  // webviews *cannot* be both hidden and working
  let tab = document.querySelector(".is-active")
  if (tab.id === "browser-link") {
    browserEl.style.zIndex = 10
  } else {
    browserEl.style.zIndex = -10
  }
}

window.onload = function() {
  populatUi()
}<|endoftext|>


<commit_before>/**
 * File for combining modules into the main docusign object before exporting.
 *
 */

/**
 * @namespace Admin
 * @desc Public API for DocuSign Admin API
 */

/**
* @namespace Envelopes
* @desc Public API for DocuSign Envelopes API
*/

/**
* @namespace Folders
* @desc Public API for DocuSign Folders API
*/

/**
* @namespace Users
* @desc Public API for DocuSign Users API
*/

var Bluebird = require('bluebird');

// Local Imports
var admin = require('./components/admin');
var users = require('./components/users');
var auth = require('./components/auth');
var folders = require('./components/folders');
var envelopes = require('./components/envelopes');
var dsUtils = require('./dsUtils');

var log = dsUtils.log;
// @todo: add this to the main exports
var DocuSignError = dsUtils.DocuSignError;

// Create DocuSign Object
var docusign = (function () {
  function init (integratorKey, targetEnv, debug, callback) {
    return new Bluebird(function (resolve, reject) {
      targetEnv = targetEnv.toLowerCase();

      if (debug) {
        log('docusign starting init');
        process.env.dsDebug = true;
      } else {
        process.env.dsDebug = false;
      }

      if (targetEnv === 'demo') {
        process.env.targetEnv = 'demo';
      } else if (targetEnv === 'www' || targetEnv === 'live') {
        process.env.targetEnv = 'www';
      } else {
        return reject(new DocuSignError("Invalid environment value. 'Demo' or 'Live' are the only valid environments."));
      }

      if (integratorKey) {
        process.env.integratorKey = integratorKey;
      } else {
        return reject(new DocuSignError('Integrator key cannot be null or empty string.'));
      }

      resolve({message: 'successfully initialized'});
    }).asCallback(callback);
  }

  function createClientBase (authInfo, callback) {
    return new Bluebird(function (resolve, reject) {
      var accountId = authInfo.accountIdGuid;
      var baseUrl = authInfo.baseUrl;
      var accessToken = authInfo.accessToken;

      var adminApi = admin.init(accountId, baseUrl, accessToken);
      var envelopesApi = envelopes.init(accountId, baseUrl, accessToken);
      var foldersApi = folders.init(accountId, baseUrl, accessToken);
      var usersApi = users.init(accountId, baseUrl, accessToken);
      var logOut = auth.revokeOauthToken(accessToken, baseUrl);

      resolve({
        authInfo: authInfo,
        admin: adminApi,
        envelopes: envelopesApi,
        folders: foldersApi,
        users: usersApi,
        logOut: logOut
      });
    }).asCallback(callback);
  }

  function createClient (email, password, callback) {
    return auth.getAccountInfoAndToken(email, password).then(function (authInfo) {
      return createClientBase(authInfo).asCallback(callback);
    });
  }

  return {
    DocuSignError: DocuSignError,
    init: init,
    getAuthInfo: auth.getAccountInfoAndToken,
    createClientFromAuth: createClientBase,
    createClient: createClient
  };
})();

module.exports = docusign;
<commit_msg>remove old todo<commit_after>/**
 * File for combining modules into the main docusign object before exporting.
 *
 */

/**
 * @namespace Admin
 * @desc Public API for DocuSign Admin API
 */

/**
* @namespace Envelopes
* @desc Public API for DocuSign Envelopes API
*/

/**
* @namespace Folders
* @desc Public API for DocuSign Folders API
*/

/**
* @namespace Users
* @desc Public API for DocuSign Users API
*/

var Bluebird = require('bluebird');

// Local Imports
var admin = require('./components/admin');
var users = require('./components/users');
var auth = require('./components/auth');
var folders = require('./components/folders');
var envelopes = require('./components/envelopes');
var dsUtils = require('./dsUtils');

var log = dsUtils.log;
var DocuSignError = dsUtils.DocuSignError;

// Create DocuSign Object
var docusign = (function () {
  function init (integratorKey, targetEnv, debug, callback) {
    return new Bluebird(function (resolve, reject) {
      targetEnv = targetEnv.toLowerCase();

      if (debug) {
        log('docusign starting init');
        process.env.dsDebug = true;
      } else {
        process.env.dsDebug = false;
      }

      if (targetEnv === 'demo') {
        process.env.targetEnv = 'demo';
      } else if (targetEnv === 'www' || targetEnv === 'live') {
        process.env.targetEnv = 'www';
      } else {
        return reject(new DocuSignError("Invalid environment value. 'Demo' or 'Live' are the only valid environments."));
      }

      if (integratorKey) {
        process.env.integratorKey = integratorKey;
      } else {
        return reject(new DocuSignError('Integrator key cannot be null or empty string.'));
      }

      resolve({message: 'successfully initialized'});
    }).asCallback(callback);
  }

  function createClientBase (authInfo, callback) {
    return new Bluebird(function (resolve, reject) {
      var accountId = authInfo.accountIdGuid;
      var baseUrl = authInfo.baseUrl;
      var accessToken = authInfo.accessToken;

      var adminApi = admin.init(accountId, baseUrl, accessToken);
      var envelopesApi = envelopes.init(accountId, baseUrl, accessToken);
      var foldersApi = folders.init(accountId, baseUrl, accessToken);
      var usersApi = users.init(accountId, baseUrl, accessToken);
      var logOut = auth.revokeOauthToken(accessToken, baseUrl);

      resolve({
        authInfo: authInfo,
        admin: adminApi,
        envelopes: envelopesApi,
        folders: foldersApi,
        users: usersApi,
        logOut: logOut
      });
    }).asCallback(callback);
  }

  function createClient (email, password, callback) {
    return auth.getAccountInfoAndToken(email, password).then(function (authInfo) {
      return createClientBase(authInfo).asCallback(callback);
    });
  }

  return {
    DocuSignError: DocuSignError,
    init: init,
    getAuthInfo: auth.getAccountInfoAndToken,
    createClientFromAuth: createClientBase,
    createClient: createClient
  };
})();

module.exports = docusign;
<|endoftext|>