<commit_before>const RangeFinder = require('./range-finder')

// This was taken from Recess: https://github.com/twitter/recess
const propertyOrder = [
  'position',
  'top',
  'right',
  'bottom',
  'left',
  'z-index',
  'display',
  'float',
  'width',
  'height',
  'max-width',
  'max-height',
  'min-width',
  'min-height',
  'padding',
  'padding-top',
  'padding-right',
  'padding-bottom',
  'padding-left',
  'margin',
  'margin-top',
  'margin-right',
  'margin-bottom',
  'margin-left',
  'margin-collapse',
  'margin-top-collapse',
  'margin-right-collapse',
  'margin-bottom-collapse',
  'margin-left-collapse',
  'overflow',
  'overflow-x',
  'overflow-y',
  'clip',
  'clear',
  'font',
  'font-family',
  'font-size',
  'font-smoothing',
  'osx-font-smoothing',
  'font-style',
  'font-weight',
  'hyphens',
  'src',
  'line-height',
  'letter-spacing',
  'word-spacing',
  'color',
  'text-align',
  'text-decoration',
  'text-indent',
  'text-overflow',
  'text-rendering',
  'text-size-adjust',
  'text-shadow',
  'text-transform',
  'word-break',
  'word-wrap',
  'white-space',
  'vertical-align',
  'list-style',
  'list-style-type',
  'list-style-position',
  'list-style-image',
  'pointer-events',
  'cursor',
  'background',
  'background-attachment',
  'background-color',
  'background-image',
  'background-position',
  'background-repeat',
  'background-size',
  'border',
  'border-collapse',
  'border-top',
  'border-right',
  'border-bottom',
  'border-left',
  'border-color',
  'border-image',
  'border-top-color',
  'border-right-color',
  'border-bottom-color',
  'border-left-color',
  'border-spacing',
  'border-style',
  'border-top-style',
  'border-right-style',
  'border-bottom-style',
  'border-left-style',
  'border-width',
  'border-top-width',
  'border-right-width',
  'border-bottom-width',
  'border-left-width',
  'border-radius',
  'border-top-right-radius',
  'border-bottom-right-radius',
  'border-bottom-left-radius',
  'border-top-left-radius',
  'border-radius-topright',
  'border-radius-bottomright',
  'border-radius-bottomleft',
  'border-radius-topleft',
  'content',
  'quotes',
  'outline',
  'outline-offset',
  'opacity',
  'filter',
  'visibility',
  'size',
  'zoom',
  'transform',
  'box-align',
  'box-flex',
  'box-orient',
  'box-pack',
  'box-shadow',
  'box-sizing',
  'table-layout',
  'animation',
  'animation-delay',
  'animation-duration',
  'animation-iteration-count',
  'animation-name',
  'animation-play-state',
  'animation-timing-function',
  'animation-fill-mode',
  'transition',
  'transition-delay',
  'transition-duration',
  'transition-property',
  'transition-timing-function',
  'background-clip',
  'backface-visibility',
  'resize',
  'appearance',
  'user-select',
  'interpolation-mode',
  'direction',
  'marks',
  'page',
  'set-link-source',
  'unicode-bidi',
  'speak'
];

module.exports = {
  activate () {
    atom.commands.add('atom-text-editor:not([mini])', {
      'sort-css:sort' () {
        sortLines(atom.workspace.getActiveTextEditor())
      }
    })
  }
}

function sortTextLines (editor, sorter) {
  const sortableRanges = RangeFinder.rangesFor(editor)
  sortableRanges.forEach((range) => {
    const textLines = editor.getTextInBufferRange(range).split(/\r?\n/g)
    const sortedTextLines = sorter(textLines)
    editor.setTextInBufferRange(range, sortedTextLines.join('\n'))
  })
}

function sortLines (editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort((a, b) => {
      const propertyA = a.trim().split(':')[0];
      const propertyB = b.trim().split(':')[0];

      const aIndex = propertyOrder.indexOf(propertyA);
      const bIndex = propertyOrder.indexOf(propertyB);

      if (aIndex !== -1 && bIndex !== -1) {
        if (aIndex < bIndex) {
          return -1;
        }

        if (aIndex > bIndex) {
          return 1;
        }
      }

      return 0;
    })
  );
}
<commit_msg>Add prefix handling<commit_after>// This code is based on Recess: https://github.com/twitter/recess

const RangeFinder = require('./range-finder')

const vendorPrefixes = [
  '-webkit-',
  '-khtml-',
  '-epub-',
  '-moz-',
  '-ms-',
  '-o-'
];

const vendorPrefixRegExp = new RegExp(
  '^('
  + vendorPrefixes.join('|').replace(/[-[\]{}()*+?.,\\^$#\s]/g, "\\$&")
  + ')'
);

const hackPrefixes = [
  '_',  // IE 7
  '*'  // IE 6
];

const hackPrefixRegExp = new RegExp(
  '^('
  + hackPrefixes.join('|').replace(/[-[\]{}()*+?.,\\^$#\s]/g, "\\$&")
  + ')'
);

const properties = [
  'position',
  'top',
  'right',
  'bottom',
  'left',
  'z-index',
  'display',
  'float',
  'width',
  'height',
  'max-width',
  'max-height',
  'min-width',
  'min-height',
  'padding',
  'padding-top',
  'padding-right',
  'padding-bottom',
  'padding-left',
  'margin',
  'margin-top',
  'margin-right',
  'margin-bottom',
  'margin-left',
  'margin-collapse',
  'margin-top-collapse',
  'margin-right-collapse',
  'margin-bottom-collapse',
  'margin-left-collapse',
  'overflow',
  'overflow-x',
  'overflow-y',
  'clip',
  'clear',
  'font',
  'font-family',
  'font-size',
  'font-smoothing',
  'osx-font-smoothing',
  'font-style',
  'font-weight',
  'hyphens',
  'src',
  'line-height',
  'letter-spacing',
  'word-spacing',
  'color',
  'text-align',
  'text-decoration',
  'text-indent',
  'text-overflow',
  'text-rendering',
  'text-size-adjust',
  'text-shadow',
  'text-transform',
  'word-break',
  'word-wrap',
  'white-space',
  'vertical-align',
  'list-style',
  'list-style-type',
  'list-style-position',
  'list-style-image',
  'pointer-events',
  'cursor',
  'background',
  'background-attachment',
  'background-color',
  'background-image',
  'background-position',
  'background-repeat',
  'background-size',
  'border',
  'border-collapse',
  'border-top',
  'border-right',
  'border-bottom',
  'border-left',
  'border-color',
  'border-image',
  'border-top-color',
  'border-right-color',
  'border-bottom-color',
  'border-left-color',
  'border-spacing',
  'border-style',
  'border-top-style',
  'border-right-style',
  'border-bottom-style',
  'border-left-style',
  'border-width',
  'border-top-width',
  'border-right-width',
  'border-bottom-width',
  'border-left-width',
  'border-radius',
  'border-top-right-radius',
  'border-bottom-right-radius',
  'border-bottom-left-radius',
  'border-top-left-radius',
  'border-radius-topright',
  'border-radius-bottomright',
  'border-radius-bottomleft',
  'border-radius-topleft',
  'content',
  'quotes',
  'outline',
  'outline-offset',
  'opacity',
  'filter',
  'visibility',
  'size',
  'zoom',
  'transform',
  'box-align',
  'box-flex',
  'box-orient',
  'box-pack',
  'box-shadow',
  'box-sizing',
  'table-layout',
  'animation',
  'animation-delay',
  'animation-duration',
  'animation-iteration-count',
  'animation-name',
  'animation-play-state',
  'animation-timing-function',
  'animation-fill-mode',
  'transition',
  'transition-delay',
  'transition-duration',
  'transition-property',
  'transition-timing-function',
  'background-clip',
  'backface-visibility',
  'resize',
  'appearance',
  'user-select',
  'interpolation-mode',
  'direction',
  'marks',
  'page',
  'set-link-source',
  'unicode-bidi',
  'speak'
];

function sortTextLines(editor, sort) {
  const sortableRanges = RangeFinder.rangesFor(editor);

  sortableRanges.forEach((range) => {
    const textLines = editor.getTextInBufferRange(range).split(/\r?\n/g);
    const sortedTextLines = sort(textLines);
    editor.setTextInBufferRange(range, sortedTextLines.join('\n'));
  });
}

function getProperty(line) {
  let property = line;

  // Trim whitespace.
  property = property.trim();

  // Trim the colon and anything after.
  const propertyParts = property.split(':');
  property = propertyParts[0];

  return property;
}

function getSortScore(line) {
  const property = getProperty(line);

  // Get the property stripped of any prefix.
  let rootProperty = property.replace(vendorPrefixRegExp, '');
  rootProperty = rootProperty.replace(hackPrefixRegExp, '');

  let score = properties.indexOf(rootProperty);

  // Adjust the score based on prefixes.
  const vendorPrefixMatch = vendorPrefixRegExp.exec(property);
  if (vendorPrefixMatch) {
    score += vendorPrefixes.indexOf(RegExp.$1);
  } else {
    score += vendorPrefixes.length + 1;
  }
  const hackPrefixMatch = hackPrefixRegExp.exec(property);
  if (hackPrefixMatch) {
    score += hackPrefixes.indexOf(RegExp.$1);
  }

  return score;
}

function sortLines(editor) {
  sortTextLines(editor,
    (textLines) => textLines.sort(
      (line1, line2) => {
        let score1 = getSortScore(line1);
        let score2 = getSortScore(line2);

        if (score1 !== -1 && score2 !== -1) {
          if (score1 < score2) {
            return -1;
          }

          if (score1 > score2) {
            return 1;
          }
        }

        return 0;
      }
    )
  );
}

module.exports = {
  activate () {
    atom.commands.add('atom-text-editor:not([mini])', {
      'sort-css:sort' () {
        sortLines(atom.workspace.getActiveTextEditor())
      }
    })
  }
}
<|endoftext|>


<commit_before>
yScales = []

var quicktest = function(svg, data, Plottable) {
  function getY(d) { return d.y};

  var dataseries = data[0].slice(0, 20);
  var dataseries_top = data[1].slice(0, 20);
  for (var i = 0; i < 20; ++i) {
    dataseries_top[i].x = dataseries[i].x;
    dataseries_top[i].y += dataseries[i].y;
  }
  console.log("SUM:", d3.sum(dataseries, getY), d3.sum(dataseries_top, getY));

  var xScale = new Plottable.Scale.Linear();
  var xAxis = new Plottable.Axis.XAxis(xScale, "bottom");

  var yScale = new Plottable.Scale.Linear();
  yScales.push(yScale);
  var yAxis = new Plottable.Axis.YAxis(yScale, "left");

  var y0Accessor = function(d, i) { return dataseries[i].y; }

  var renderAreaD1 = new Plottable.Plot.Area(dataseries, xScale, yScale);
  var renderAreaD2 = new Plottable.Plot.Area(dataseries_top, xScale, yScale).project("y0", y0Accessor, yScale);

  var fillAccessor = function() { return "steelblue"; }
  var fillAccessorTop = function() { return "pink"; }
  renderAreaD1.project("fill", fillAccessor)
  renderAreaD2.project("fill", fillAccessorTop)

  var gridlines = new Plottable.Component.Gridlines(xScale, yScale);
  var renderGroup = new Plottable.Component.Group([gridlines, renderAreaD1, renderAreaD2]);

  var chart = new Plottable.Template.StandardChart()
                  .center(renderGroup).xAxis(xAxis).yAxis(yAxis)
                  .renderTo(svg);
}

quicktest.quicktestName = "areaRenderer";
quicktest.categories = ["area", "basic"];
quicktests.push(quicktest);
<commit_msg>Update basic_area.js<commit_after>
yScales = []

var quicktest = function(svg, data, Plottable) {
  function getY(d) { return d.y};

  var dataseries = data[0].slice(0, 20);
  var dataseries_top = data[1].slice(0, 20);
  for (var i = 0; i < 20; ++i) {
    dataseries_top[i].x = dataseries[i].x;
    dataseries_top[i].y += dataseries[i].y;
  }
  console.log("SUM:", d3.sum(dataseries, getY), d3.sum(dataseries_top, getY));

  var xScale = new Plottable.Scale.Linear();
  var xAxis = new Plottable.Axis.XAxis(xScale, "bottom");

  var yScale = new Plottable.Scale.Linear();
  yScales.push(yScale);
  var yAxis = new Plottable.Axis.YAxis(yScale, "left");

  var y0Accessor = function(d, i) { return dataseries[i].y; }

  var renderAreaD1 = new Plottable.Plot.Area(dataseries, xScale, yScale);
  var renderAreaD2 = new Plottable.Plot.Area(dataseries_top, xScale, yScale).project("y0", y0Accessor, yScale);

  var fillAccessor = function() { return "steelblue"; }
  var fillAccessorTop = function() { return "pink"; }
  renderAreaD1.project("fill", fillAccessor)
  renderAreaD2.project("fill", fillAccessorTop)

  var gridlines = new Plottable.Component.Gridlines(xScale, yScale);
  var renderGroup = new Plottable.Component.Group([gridlines, renderAreaD1, renderAreaD2]);

  var chart = new Plottable.Template.StandardChart()
                  .center(renderGroup).xAxis(xAxis).yAxis(yAxis)
                  .renderTo(svg);
}

quicktest.quicktestName = "basic_area";
quicktests.push(quicktest);
<|endoftext|>


<commit_before>
if (!_)
	throw {name:'RequiresException', message:'Requires underscore.js'};

// Perhaps the '.__' prefix can be changed to a random string, unique per
// page load.

Model = (function()
{
	// NOTE: These can be individual per Handle.  Why did I do it this way?
	var listeners = {};

	var special = {
		delete:{}
	};

	// NOTE: Playing around with another private var.
	var onEvent = function(handle,eventName,func,args)
	{
		listeners[handle.__id][eventName].push({func:func,args:args});
	};

	var offEvent = function(handle,eventName,func)
	{
		var events = listeners[handle.__id][eventName]
		var funcs = events.map(function(a){return a.func});

		var index = funcs.indexOf(func);

		console.log(index,funcs);

		if (index >= 0)
			listeners[handle.__id][eventName].splice(index,1);

		return index >= 0;
	};

	// NOTE: I want these Handle objects to remain *independent* of Model
	//   instances, though...  Will think through, later.
	function Handle(ob)
	{
		var self = this;
		var handle = this;

		// ob effectively holds a mirror copy of... everthing.  There's a reason I'm
		// using it, and testing has revealed that reason as valid.  But exactly what
		// is that reason...?  Was it the leaf node Handles?
		ob = (typeof ob === 'object' ?
				(Array.isArray(ob) ? ob.slice() : _.extend({},ob)): ob)

		// Assign immutable id.
		Object.defineProperty(this,'__id',{
			enumerable:false,
			configurable:false,
			writable:false,
			value:_.uniqueId()
		});

		// Add listeners entry, with arrays of event callbacks.
		//
		// NOTE: In the event that the listeners object is moved to a private,
		//   per-Handle var, this... will likely not change much, now that I
		//   think about it.
		listeners[this.__id] = {change:[],delete:[],all:[]};

		// Assign add-event-listener function.
		Object.defineProperty(this,'$on',{
			enumerable:false,
			configurable:false,
			value:function(eventName,func,args)
			{ onEvent(self,eventName,func,args); }
		});

		// Assign remove-event-listener function.
		Object.defineProperty(this,'$off',{
			enumerable:false,
			configurable:false,
			value:function(eventName,func)
			{
				return offEvent(self,eventName,func);
			}
		});

		// Assign basic JSON-object export function.
		Object.defineProperty(this,'$',{
			enumerable:false,
			configurable:false,
			get:function()
			{
				if (typeof ob !== 'object')
					return ob;

				var ret = (Array.isArray(ob) ? [] : {});
				for (var p in ob)
					ret[p] = ob[p].$;
				return ret;
			}
		});

		if (typeof ob !== 'object')
			this.valueOf = function()
			{ console.log('val?',ob); return ob; };

		if (typeof ob === 'object')
		for (var p in ob)
		{
			//ob[p] = (typeof ob[p] === 'object' ? new Handle(ob[p]) : ob[p]);
			ob[p] = new Handle(ob[p]);
			ob[p].__parent = this;

			// NOTE: Put this here for private access to its parent while
			//   retaining its given property name.
			Object.defineProperty(ob[p],'$delete',{
				enumerable:false,
				configurable:false,
				value:(function(k){return function(){ self[k] = special.delete }})(p)
			});

			Object.defineProperty(this,p,{
				enumerable:true,
				configurable:true,
				get:(function(k){return function(){return ob[k]}})(p),
				set:(function(k){return function(val)
				{
					var oldHandle = ob[k];
					var newHandle;

					if (val == special.delete)
					{
						// NOTE: Deletion needs to go somewhere more accissible.  Now that
						//   there's a proper $delete method, this ought go somewhere more
						//   sensible.

						listeners[oldHandle.__id].delete.map(function(action)
						{
							action.func(oldHandle.$);
						});

						listeners[oldHandle.__id].all.map(function(action)
						{
							action.func('delete',[oldHandle.$]);
						});

						// NOTE: WAAAAIT!
						//   This must recurse.  It needs to recurse.
						//   Or does it?  What if something else is using these?
						//
						//   You know what?  This is all based on the idea of a unified
						//   object model, meaning there is only *one* root object for
						//   each of these.  Modifying a Handle *should* invalidate all
						//   the Handles below it.
						//*
						for (var x in oldHandle)
							if (oldHandle[x] instanceof Handle)
								oldHandle[x] = special.delete;
						//*/

						// NOTE: There is another concern, however.  In the event that a
						//   Handle is assigned another object structure, creating more
						//   handles, ought paths/values matching between the recursed
						//   deleted old and the new created Handle be applied to the new,
						//   as well?
						//
						//   By values, I mean things held by private Model vars,
						//   like the listeners object.
						//
						//   Ultimately, that depends on whether the object is being
						//   *replaced* or *modified*.  How might we distinguish between
						//   the two?
						//
						//   Maybe... replace = new M.Hanlde({}), modify = {}.
						//   Or visa-versa.  Could work either way.
						//
						//   Save this for a later commit.  Or better yet, make a github
						//   Issue.

						// Remove events from listeners object.
						delete listeners[oldHandle.__id];
						delete ob[k];
						delete self[k];
						return;
					}

					// NOTE: Replace-vs-Modify logic will have to change this, here.
					newHandle = (val instanceof Handle ? val : new Handle(val));
					ob[k] = newHandle;

					// Modify listeners object.
					// - Copy oldHandle's listeners over to newHandle's.
					// - Remove oldHandle's listeners.
					_.extend(listeners[newHandle.__id],listeners[oldHandle.__id]);
					delete listeners[oldHandle.__id];

					// Run change event listeners.
					listeners[ob[k].__id].change.map(function(action)
					{
						action.func(val,oldHandle.$,action.args);
					});

					// Run 'all' event listeners.
					listeners[ob[k].__id].all.map(function(action)
					{
						action.func('change',[val,oldHandle.$,action.args]);
					});

					// Should events also bubble up...?

					console.log('returning',ob[k]);
					return ob[k];
				}})(p)
			});
		}
	}

	function Model(params)
	{
		var Model = {};

		if (params)
		{

		}

		this.Handle = Handle;

		/*
		Object.defineProperty(this,'Delete',{
			enumerable:false,
			configurable:false,
			writable:false,
			value:special.delete
		});
		//*/
	};

	return Model;
})();

<commit_msg>Handle now works off a Model-internel generic Object-to-handle factory function<commit_after>
if (!_)
	throw {name:'RequiresException', message:'Requires underscore.js'};

// Perhaps the '.__' prefix can be changed to a random string, unique per
// page load.

Model = (function()
{
	// NOTE: These can be individual per Handle.  Why did I do it this way?
	var listeners = {};

	var special = {
		delete:{}
	};

	// NOTE: Playing around with another private var.
	var onEvent = function(handle,eventName,func,args)
	{
		listeners[handle.__id][eventName].push({func:func,args:args});
	};

	var offEvent = function(handle,eventName,func)
	{
		var events = listeners[handle.__id][eventName]
		var funcs = events.map(function(a){return a.func});

		var index = funcs.indexOf(func);

		console.log(index,funcs);

		if (index >= 0)
			listeners[handle.__id][eventName].splice(index,1);

		return index >= 0;
	};

	function Handle(ob)
	{
		makeHandle(this,ob);
	}

	// NOTE: I want these Handle objects to remain *independent* of Model
	//   instances, though...  Will think through, later.
	function makeHandle(handle,ob)
	{
		var self = handle;
		var handle = handle;

		// ob effectively holds a mirror copy of... everthing.  There's a reason I'm
		// using it, and testing has revealed that reason as valid.  But exactly what
		// is that reason...?  Was it the leaf node Handles?
		ob = (typeof ob === 'object' ?
				(Array.isArray(ob) ? ob.slice() : _.extend({},ob)): ob)

		// Assign immutable id.
		Object.defineProperty(handle,'__id',{
			enumerable:false,
			configurable:false,
			writable:false,
			value:_.uniqueId()
		});

		// Add listeners entry, with arrays of event callbacks.
		//
		// NOTE: In the event that the listeners object is moved to a private,
		//   per-Handle var, this... will likely not change much, now that I
		//   think about it.
		listeners[handle.__id] = {change:[],delete:[],all:[]};

		// Assign add-event-listener function.
		Object.defineProperty(handle,'$on',{
			enumerable:false,
			configurable:false,
			value:function(eventName,func,args)
			{ onEvent(self,eventName,func,args); }
		});

		// Assign remove-event-listener function.
		Object.defineProperty(handle,'$off',{
			enumerable:false,
			configurable:false,
			value:function(eventName,func)
			{
				return offEvent(self,eventName,func);
			}
		});

		// Assign basic JSON-object export function.
		Object.defineProperty(handle,'$',{
			enumerable:false,
			configurable:false,
			get:function()
			{
				if (typeof ob !== 'object')
					return ob;

				var ret = (Array.isArray(ob) ? [] : {});
				for (var p in ob)
					ret[p] = ob[p].$;
				return ret;
			}
		});

		if (typeof ob !== 'object')
		{
			// NOTE: Looks like defining properties on Number/String/Boolean is
			//   considered acting on primitives, and is not permitted.  Guess
			//   creating unique literal value Handles won't be possible.

			handle.valueOf = function()
			{ console.log('val?',ob); return ob; };
		}

		if (typeof ob === 'object')
		for (var p in ob)
		{
			//ob[p] = (typeof ob[p] === 'object' ? new Handle(ob[p]) : ob[p]);
			//ob[p] = new Handle(ob[p]);
			ob[p] = makeHandle({},ob[p]);
			ob[p].__parent = handle;

			// NOTE: Put this here for private access to its parent while
			//   retaining its given property name.
			Object.defineProperty(ob[p],'$delete',{
				enumerable:false,
				configurable:false,
				value:(function(k){return function(){ self[k] = special.delete }})(p)
			});

			Object.defineProperty(handle,p,{
				enumerable:true,
				configurable:true,
				get:(function(k){return function(){return ob[k]}})(p),
				set:(function(k){return function(val)
				{
					var oldHandle = ob[k];
					var newHandle;

					if (val == special.delete)
					{
						// NOTE: Deletion needs to go somewhere more accissible.  Now that
						//   there's a proper $delete method, this ought go somewhere more
						//   sensible.

						listeners[oldHandle.__id].delete.map(function(action)
						{
							action.func(oldHandle.$);
						});

						listeners[oldHandle.__id].all.map(function(action)
						{
							action.func('delete',[oldHandle.$]);
						});

						// NOTE: WAAAAIT!
						//   This must recurse.  It needs to recurse.
						//   Or does it?  What if something else is using these?
						//
						//   You know what?  This is all based on the idea of a unified
						//   object model, meaning there is only *one* root object for
						//   each of these.  Modifying a Handle *should* invalidate all
						//   the Handles below it.
						//*
						for (var x in oldHandle)
							if (oldHandle[x] instanceof Handle)
								oldHandle[x] = special.delete;
						//*/

						// NOTE: There is another concern, however.  In the event that a
						//   Handle is assigned another object structure, creating more
						//   handles, ought paths/values matching between the recursed
						//   deleted old and the new created Handle be applied to the new,
						//   as well?
						//
						//   By values, I mean things held by private Model vars,
						//   like the listeners object.
						//
						//   Ultimately, that depends on whether the object is being
						//   *replaced* or *modified*.  How might we distinguish between
						//   the two?
						//
						//   Maybe... replace = new M.Hanlde({}), modify = {}.
						//   Or visa-versa.  Could work either way.
						//
						//   Save this for a later commit.  Or better yet, make a github
						//   Issue.

						// Remove events from listeners object.
						delete listeners[oldHandle.__id];
						delete ob[k];
						delete self[k];
						return;
					}

					// NOTE: Replace-vs-Modify logic will have to change this, here.
					//newHandle = (val instanceof Handle ? val : new Handle(val));
					newHandle = (val instanceof Handle ? val : makeHandle({},val));
					ob[k] = newHandle;

					// Modify listeners object.
					// - Copy oldHandle's listeners over to newHandle's.
					// - Remove oldHandle's listeners.
					_.extend(listeners[newHandle.__id],listeners[oldHandle.__id]);
					delete listeners[oldHandle.__id];

					// Run change event listeners.
					listeners[ob[k].__id].change.map(function(action)
					{
						action.func(val,oldHandle.$,action.args);
					});

					// Run 'all' event listeners.
					listeners[ob[k].__id].all.map(function(action)
					{
						action.func('change',[val,oldHandle.$,action.args]);
					});

					// Should events also bubble up...?

					console.log('returning',ob[k]);
					return ob[k];
				}})(p)
			});
		}

		return handle;
	}

	function Model(params)
	{
		var Model = {};

		if (params)
		{

		}

		this.Handle = Handle;

		/*
		Object.defineProperty(this,'Delete',{
			enumerable:false,
			configurable:false,
			writable:false,
			value:special.delete
		});
		//*/
	};

	return Model;
})();

<|endoftext|>


<commit_before>import _ from 'lodash'
import https from 'https'
import axios from 'axios'
import * as task from './task'
import pipe from './pipe'
import pipes from './pipes'
import connections from './connections'

var base_url = 'https://www.flex.io/api/v1'

var cfg = {
  token: '',
  baseUrl: 'https://www.flex.io/api/v1',
  insecure: false,
  debug: false
}

export default {
  // see `../build/webpack.dist.js`
  version: VERSION,

  // allow all tasks exports from `./task/index.js`
  task,

  setup(token, params) {
    cfg = _.assign({}, { token }, params)
    this._createHttp()
    return this
  },

  getConfig() {
    return _.assign({}, cfg)
  },

  http() {
    if (!this._http)
      this._createHttp()

    return this._http
  },

  pipe()        { return pipe()        },
  pipes()       { return pipes()       },
  connections() { return connections() },

  _createHttp() {
    // axios instance options with base url and auth token
    var axios_opts = {
      baseURL: cfg.baseUrl,
      headers: { 'Authorization': 'Bearer ' + cfg.token }
    }

    // if the `insecure` flag is set, allow unauthorized HTTPS calls
    if (cfg.insecure === true)
    {
      _.assign(axios_opts, {
        httpsAgent: new https.Agent({
          rejectUnauthorized: false
        })
      })
    }

    this._http = axios.create(axios_opts)
  }
}
<commit_msg>Use `process.env.NODE_TLS_REJECT_UNAUTHORIZED` to make insecure calls.<commit_after>import _ from 'lodash'
import axios from 'axios'
import * as task from './task'
import pipe from './pipe'
import pipes from './pipes'
import connections from './connections'

var base_url = 'https://www.flex.io/api/v1'

var cfg = {
  token: '',
  baseUrl: 'https://www.flex.io/api/v1',
  insecure: false,
  debug: false
}

export default {
  // see `../build/webpack.dist.js`
  version: VERSION,

  // allow all tasks exports from `./task/index.js`
  task,

  setup(token, params) {
    cfg = _.assign({}, { token }, params)
    this._createHttp()
    return this
  },

  getConfig() {
    return _.assign({}, cfg)
  },

  http() {
    if (!this._http)
      this._createHttp()

    return this._http
  },

  pipe()        { return pipe()        },
  pipes()       { return pipes()       },
  connections() { return connections() },

  _createHttp() {
    // axios instance options with base url and auth token
    var axios_opts = {
      baseURL: cfg.baseUrl,
      headers: { 'Authorization': 'Bearer ' + cfg.token }
    }

    // TODO: try to figure out a better way to do this...

    // if the `insecure` flag is set, allow unauthorized HTTPS calls
    if (cfg.insecure === true)
      process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"

    this._http = axios.create(axios_opts)
  }
}
<|endoftext|>


<commit_before>/**
 * Simple format function borrowed from PureMask.js
 * {@link https://github.com/romulobrasil/PureMask.js}
 *
 * @param {String} data String to mask (input value)
 * @param {String} [mask] Mask format, like `####-##`
 * @returns {string} Formatted text
 */
export default function (data, mask){
  // don't do anything if mask is undefined/null/etc
  if(!mask) return data;

  const maskStartRegExp = /^([^#ANX]+)/;

  if (data.length == 1 && maskStartRegExp.test(mask)) {
    data = maskStartRegExp.exec(mask)[0] + data;
  }

  let text = '';
  for (let i = 0, x = 1; x && i < mask.length; ++i) {
    let c = data.charAt(i);
    let m = mask.charAt(i);

    switch (m) {
      case '#' : if (/\d/.test(c))        {text += c;} else {x = 0;} break;
      case 'A' : if (/[a-z]/i.test(c))    {text += c;} else {x = 0;} break;
      case 'N' : if (/[a-z0-9]/i.test(c)) {text += c;} else {x = 0;} break;
      case 'X' : text += c; break;
      default  :
        text += m;

        // preserve characters that are in the same spot we need to insert a mask
        // character by shifting the data over to the right (issue #5, & #7)
        if (c && c !== m) {
          data = ' ' + data;
        }

        break;
    }
  }
  return text;
}
<commit_msg>Adds optional character to mask<commit_after>/**
 * Simple format function borrowed from PureMask.js
 * {@link https://github.com/romulobrasil/PureMask.js}
 *
 * @param {String} data String to mask (input value)
 * @param {String} [mask] Mask format, like `####-##`
 * @returns {string} Formatted text
 */
export default function (data, mask){
  // don't do anything if mask is undefined/null/etc
  if(!mask) return data;

  const maskStartRegExp = /^([^#ANX]+)/;

  if (data.length == 1 && maskStartRegExp.test(mask)) {
    data = maskStartRegExp.exec(mask)[0] + data;
  }

  let text = '';

  // Adds a char offset to allow testing on optional values
  var cOffset = 0;

  // Cleans data to  avoid value loss on dynamic mask changing
  for (var i = 0; i < mask.length; i++) {
    var m = mask.charAt(i)
    switch(m) {
      case '#' : break;
      case 'A' : break;
      case '?' : break;
      case 'N' : break;
      case 'X' : break;
      default : data = data.replace(m, '')
    }
  }
  for (let i = 0, x = 1; x && i < mask.length; ++i) {
    // Uses the optional mask character offset
    let c = data.charAt(i - cOffset);
    let m = mask.charAt(i);

    switch (m) {
      case '#' : if (/\d/.test(c))        {text += c;} else {x = 0;} break;
      case 'A' : if (/[a-z]/i.test(c))    {text += c;} else {x = 0;} break;
      case 'N' : if (/[a-z0-9]/i.test(c)) {text += c;} else {x = 0;} break;
      // Skips testing if optional field is specified
      case '?' : cOffset++; break;
      case 'X' : text += c; break;
      default  :
        text += m;

        // preserve characters that are in the same spot we need to insert a mask
        // character by shifting the data over to the right (issue #5, & #7)
        if (c && c !== m) {
          data = ' ' + data;
        }

        break;
    }
  }
  return text;
}
<|endoftext|>


<commit_before>class AutoCompleteClab{

	beforeRegister(){
		this.is = "autocomplete-clab";
		this.properties = {
			label:{
				type:String,
				value:null
			},
			name:{
				type:String,
				value:'auto complete'
			},
			value:{
				type:Object
			},
			disabled:{
				type:Boolean,
				value:false
			},
			options:{
				type: Array
			},
			url:{
				type:String
			},
			results:{
				type:Array,
				notify:true
			},
			optionsFn: {
				type: Function,
				observer: '_setOptions'
			},
			hideHints:{
				type:Boolean,
				value:false
			},
			resultAsObj:{
				type:Boolean,
				value:false
			},
			// Min amount of characters to start searching for hints
			minChar:{
				type:Number,
				value:3
			},
			// How many LIs are visible without scrolling (=> sets max-height of OL)
			maxInView:{
				type:Number,
				value:2
			},

			/*----------
			  PRIVATE
			----------*/
			inputString:{
				type:String,
				readonly: true
			},
			liHeight:{
				type:String,
				value:null,
				readonly: true
			}
		};
	}

	// http://jsonplaceholder.typicode.com/todos

	attached(){
		this.list=this.querySelector('.options-list');
		this.results=[];
		this.currentHint=undefined;

		/*if(this.options!=undefined){
			this.options.forEach((opt,i)=>{
				opt.show=false;
			});
		}*/
		if(this.value!=undefined){ this._setValue(this.value, true); }

		this.querySelector('input-clab input').addEventListener('blur',this._handleBlur.bind(this));
		this.addEventListener('mousedown', this._handleClick);
		this.addEventListener('mouseup', (evt)=>{ this.dontHide=false; });
	}

	/*----------
	EVENT HANDLERS
	----------*/
	_handleHints(evt){
		// If Enter
		if(evt.keyCode==13 && this.currentHint!=undefined){
			let i=this._getIndex(this.currentHint, this.options);
			this._setValue(this.options[i]);
			this.querySelector('input-clab input').blur();
			this.results=[];
			return;
		}

		//If Arrows
		if(this.results.length>0 && evt.keyCode==38 && this.currentHint!=undefined){
			evt.preventDefault();
			this._handleArrows('up');
			return;
		}
		if(this.results.length>0 && evt.keyCode==40 && this.currentHint!=undefined){
			evt.preventDefault();
			this._handleArrows('down');
			return;
		}

		// If typing
		if(this.inputString.length>this.minChar){

			if(this.url!=undefined && this.options==undefined){
				fetch(this.url).then(res=>{
					return res.json();
				}).then(obj=>{
					this.set('options',obj);
					//console.log(this.options);
					this._searchForHints();
				});
			} else {
				this._searchForHints();
			}

		} else {
			if(this.list.classList.contains('active')) this.list.classList.remove('active');
		}
	}

	_searchForHints(){
		let search=this.inputString;
		this.results=[];

		this.options.forEach((opt, i)=>{
			if(opt.label.search(search)>-1){
				//this.set('options.'+i+'.show', true);
				this.querySelectorAll('.options-list li')[i].classList.add('show');
				this.results.push(this.options[i]);
			} else {
				//this.set('options.'+i+'.show', false);
				this.querySelectorAll('.options-list li')[i].classList.remove('show');
			}
		});

		if(this.results.length>0){
			if(!this.hideHints){
				this.async(()=>{
					this._setListHeight(this.results.length);
				},100);
			}
			this._highlightEl(this._getIdxForHighlight(this.results, search));
			//this.fire('sendRes',this.results);

		} else {
			if(this.list.classList.contains('active')) this.list.classList.remove('active');
			this.currentHint=undefined;
		}
	}

	_handleBlur(evt){
		if(this.dontHide){
			evt.preventDefault();
			return;

		}
		if(evt){
			this._closeList();
			if(this.value==undefined || this.value.label!=this.inputString){
				this.inputString='';
			}
		}
	}

	_handleClick(evt){
		//console.log(evt.target);
		if(evt.target.localName=='ol'){
			this.dontHide=true;

		} else if(evt.target.localName=='li'){
			this.dontHide=false;
			let i=evt.target.getAttribute('data-index');
			this._setValue(this.options[i]);

		} else {
			this.dontHide=false;
		}
	}

	/*----------
	FUNCTIONS
	----------*/
	_setValue(obj){
		this.set('value', obj);
		this.inputString=this.value.label;
		this.currentHint=undefined;

		if(this.resultAsObj)
			this.fire('change', this.value);
		else
			this.fire('change', {'value':this.inputString});
	}

	_highlightEl(idx){
		let i = idx;
		this.async(()=>{
			Array.from(this.querySelectorAll('.options-list li')).forEach(el=>{
				if(el.getAttribute('data-index')==i){
					el.classList.add('selected');
				} else {
					el.classList.remove('selected');
				}
			});
		},100);
	}

	_getIdxForHighlight(res, search){
		let exists=false;
		let idx;
		res.forEach((item,i)=>{
			if(item.label===search){
				exists=true;
				idx = this._getIndex(item, this.options);
				this.currentHint=item;
			}
		});
		if(!exists){
			idx = this._getIndex(res[0], this.options);
			this.currentHint=res[0];
		}
		return idx;
	}

	_handleArrows(type){
		let HIdx=this._getIndex(this.currentHint, this.results);
		let toSel;

		if(type==='up'){
			toSel=this.results[HIdx-1];
			if(typeof toSel == 'object'){
				this.currentHint=toSel;
				this._highlightEl(this._getIndex(toSel, this.options));
				this.querySelector('.options-list').scrollTop-=this.liHeight;

			} else { return; }

		} else if(type==='down'){
			toSel=this.results[HIdx+1];
			if(typeof toSel == 'object'){
				this.currentHint=toSel;
				this._highlightEl(this._getIndex(toSel, this.options));
				this.querySelector('.options-list').scrollTop+=this.liHeight;

			} else { return; }
		}
	}

	_closeList(){
		this.list.classList.remove('active');
		Array.from(this.querySelectorAll('.options-list li')).forEach(el=>{
			el.classList.remove('selected');
		});
	}

	_fetchJSON(url){
		fetch(url).then(res=>{
			return res.json();
		}).then(obj=>{
			this.set('options',obj);
		});
	}

	/*----------
	OBSERVERS
	----------*/
	_setOptions(promise){
		promise().then((resp) => {
			this.options = resp;
			//this.liHeight = this.$.list.children[0].clientHeight;
		});
	}

	/*----------
	UTILS
	----------*/
	_getHeight(el){
		return el.clientHeight;
	}

	_getIndex(item, items){
		return items.indexOf(item);
	}

	_setListHeight(elemsShown){
		if(this.liHeight===null) {
			this.list.classList.add('hidden');
			this.liHeight = this._getHeight(this.querySelectorAll('.options-list li')[0]);
			this.list.style.maxHeight=(this.liHeight*this.maxInView)+'px';
			this.list.classList.remove('hidden');
		}
		console.log(this.liHeight);
		this.list.style.height=(this.liHeight*elemsShown)+'px';
		this.list.classList.add('active');
	}

	_dashify(str){
		return str.replace(/ /g,'-');
	}

	_viewLabel(label) {
		if(label.length>0) return true; else return false;
	}

}

Polymer(AutoCompleteClab);<commit_msg>small fix<commit_after>class AutoCompleteClab{

	beforeRegister(){
		this.is = "autocomplete-clab";
		this.properties = {
			label:{
				type:String,
				value:null
			},
			name:{
				type:String,
				value:'auto complete'
			},
			value:{
				type:Object
			},
			disabled:{
				type:Boolean,
				value:false
			},
			options:{
				type: Array
			},
			url:{
				type:String
			},
			results:{
				type:Array,
				notify:true
			},
			optionsFn: {
				type: Function,
				observer: '_setOptions'
			},
			hideHints:{
				type:Boolean,
				value:false
			},
			resultAsObj:{
				type:Boolean,
				value:false
			},
			// Min amount of characters to start searching for hints
			minChar:{
				type:Number,
				value:3
			},
			// How many LIs are visible without scrolling (=> sets max-height of OL)
			maxInView:{
				type:Number,
				value:2
			},

			/*----------
			  PRIVATE
			----------*/
			inputString:{
				type:String,
				readonly: true
			},
			liHeight:{
				type:String,
				value:null,
				readonly: true
			}
		};
	}

	// http://jsonplaceholder.typicode.com/todos

	attached(){
		this.list=this.querySelector('.options-list');
		this.results=[];
		this.currentHint=undefined;

		/*if(this.options!=undefined){
			this.options.forEach((opt,i)=>{
				opt.show=false;
			});
		}*/
		if(this.value!=undefined){ this._setValue(this.value, true); }

		this.querySelector('input-clab input').addEventListener('blur',this._handleBlur.bind(this));
		this.addEventListener('mousedown', this._handleClick);
		this.addEventListener('mouseup', (evt)=>{ this.dontHide=false; });
	}

	/*----------
	EVENT HANDLERS
	----------*/
	_handleHints(evt){
		// If Enter
		if(evt.keyCode==13 && this.currentHint!=undefined){
			let i=this._getIndex(this.currentHint, this.options);
			this._setValue(this.options[i]);
			this.querySelector('input-clab input').blur();
			this.results=[];
			return;
		}

		//If Arrows
		if(this.results.length>0 && evt.keyCode==38 && this.currentHint!=undefined){
			evt.preventDefault();
			this._handleArrows('up');
			return;
		}
		if(this.results.length>0 && evt.keyCode==40 && this.currentHint!=undefined){
			evt.preventDefault();
			this._handleArrows('down');
			return;
		}

		// If typing
		if(this.inputString.length>this.minChar){

			if(this.url!=undefined && this.options==undefined){
				fetch(this.url).then(res=>{
					return res.json();
				}).then(obj=>{
					this.set('options',obj);
					//console.log(this.options);
					this._searchForHints();
				});
			} else {
				this._searchForHints();
			}

		} else {
			if(this.list.classList.contains('active')) this.list.classList.remove('active');
		}
	}

	_searchForHints(){
		let search=this.inputString;
		this.results=[];

		this.options.forEach((opt, i)=>{
			if(opt.label.search(search)>-1){
				//this.set('options.'+i+'.show', true);
				this.querySelectorAll('.options-list li')[i].classList.add('show');
				this.results.push(this.options[i]);
			} else {
				//this.set('options.'+i+'.show', false);
				this.querySelectorAll('.options-list li')[i].classList.remove('show');
			}
		});

		if(this.results.length>0){
			if(!this.hideHints){
				this.async(()=>{
					this._setListHeight(this.results.length);
				},100);
			}
			this._highlightEl(this._getIdxForHighlight(this.results, search));
			//this.fire('sendRes',this.results);

		} else {
			if(this.list.classList.contains('active')) this.list.classList.remove('active');
			this.currentHint=undefined;
		}
	}

	_handleBlur(evt){
		if(this.dontHide){
			evt.preventDefault();
			return;

		}
		if(evt){
			this._closeList();
			if(this.value==undefined || this.value.label!=this.inputString){
				this.inputString='';
			}
		}
	}

	_handleClick(evt){
		//console.log(evt.target);
		if(evt.target.localName=='ol'){
			this.dontHide=true;

		} else if(evt.target.localName=='li'){
			this.dontHide=false;
			let i=evt.target.getAttribute('data-index');
			this._setValue(this.options[i]);

		} else {
			this.dontHide=false;
		}
	}

	/*----------
	FUNCTIONS
	----------*/
	_setValue(obj){
		this.set('value', obj);
		this.inputString=this.value.label;
		this.currentHint=undefined;

		if(this.resultAsObj)
			this.fire('change', this.value);
		else
			this.fire('change', {'value':this.inputString});
	}

	_highlightEl(idx){
		let i = idx;
		this.async(()=>{
			Array.from(this.querySelectorAll('.options-list li')).forEach(el=>{
				if(el.getAttribute('data-index')==i){
					el.classList.add('selected');
				} else {
					el.classList.remove('selected');
				}
			});
		},100);
	}

	_getIdxForHighlight(res, search){
		let exists=false;
		let idx;
		res.forEach((item,i)=>{
			if(item.label===search){
				exists=true;
				idx = this._getIndex(item, this.options);
				this.currentHint=item;
			}
		});
		if(!exists){
			idx = this._getIndex(res[0], this.options);
			this.currentHint=res[0];
		}
		return idx;
	}

	_handleArrows(type){
		let HIdx=this._getIndex(this.currentHint, this.results);
		let toSel;

		if(type==='up'){
			toSel=this.results[HIdx-1];
			if(typeof toSel == 'object'){
				this.currentHint=toSel;
				this._highlightEl(this._getIndex(toSel, this.options));
				this.querySelector('.options-list').scrollTop-=this.liHeight;

			} else { return; }

		} else if(type==='down'){
			toSel=this.results[HIdx+1];
			if(typeof toSel == 'object'){
				this.currentHint=toSel;
				this._highlightEl(this._getIndex(toSel, this.options));
				this.querySelector('.options-list').scrollTop+=this.liHeight;

			} else { return; }
		}
	}

	_closeList(){
		this.list.classList.remove('active');
		Array.from(this.querySelectorAll('.options-list li')).forEach(el=>{
			el.classList.remove('selected');
		});
	}

	_fetchJSON(url){
		fetch(url).then(res=>{
			return res.json();
		}).then(obj=>{
			this.set('options',obj);
		});
	}

	/*----------
	OBSERVERS
	----------*/
	_setOptions(promise){
		promise().then((resp) => {
			this.options = resp;
			//this.liHeight = this.$.list.children[0].clientHeight;
		});
	}

	/*----------
	UTILS
	----------*/
	_getHeight(el){
		return el.clientHeight;
	}

	_getIndex(item, items){
		return items.indexOf(item);
	}

	_setListHeight(elemsShown){
		if(this.liHeight===null) {
			this.list.classList.add('hidden');
			this.liHeight = this._getHeight(this.querySelectorAll('.options-list li.show')[0]);
			this.list.style.maxHeight=(this.liHeight*this.maxInView)+'px';
			this.list.classList.remove('hidden');
		}
		this.list.style.height=(this.liHeight*elemsShown)+'px';
		this.list.classList.add('active');
	}

	_dashify(str){
		return str.replace(/ /g,'-');
	}

	_viewLabel(label) {
		if(label.length>0) return true; else return false;
	}

}

Polymer(AutoCompleteClab);<|endoftext|>


<commit_before>/**
 * @license
 * Realtime Utils 1.0.0
 * https://developers.google.com/drive/realtime/
 * Copyright 2015 Seth Howard, Google Inc. All Rights Reserved.
 * Realtime Utils may be freely distributed under the Apache 2.0 license.
 *
 * 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.
 */

/**
 * @fileoverview Common utility functionality for the Google Drive Realtime API,
 * including authorization and file loading.
 */

/**
 * Create the utils namespace
 */
window.utils = {};

/** @constructor
 *
 * @param {!Object} options for the realtime utility. One key is mandatory:
 *
 *  1) "clientId" the client id from the APIs console.
 *
 */
utils.RealtimeUtils = function(options) {
  this.init(options);
};

utils.RealtimeUtils.prototype = {

  /**
   * clientId for this realtime application.
   * @type {!string}
   */
  clientId: null,

  /**
   * MimeType for this realtime application.
   * @type {!string}
   */
  mimeType: 'application/vnd.google-apps.drive-sdk',

  /**
   * The interval at which the oauth token will attempt to be refreshed.
   * @type {!string}
   */
  refreshInterval: 1800000, // 30 minutes

  /**
   * Required scopes.
   * @type {!Array<string>}
   */
  scopes: [
    'https://www.googleapis.com/auth/drive.install',
    'https://www.googleapis.com/auth/drive.file'
  ],

  /**
   * Initializes RealtimeUtils
   * @param {Object} options containing required utiltiy keys.
   * @private
   */
  init: function(options) {
    this.mergeOptions(options);
    this.authorizer = new utils.RealtimeAuthorizer(this);
    this.createRealtimeFile = this.createRealtimeFile.bind(this);
  },

  /**
   * Kicks off the authorization process
   * @param {!Function} onAuthComplete callback invoked after authorizing.
   * @param {!boolean} usePopup true if authentication via a popup window.
   * @export
   */
  authorize: function(onAuthComplete, usePopup) {
    this.authorizer.start(onAuthComplete, usePopup);
  },

  /**
   * Merges passed in options with default options.
   * @param {Object} options that will be merged with existing options.
   * @private
   */
  mergeOptions: function(options) {
    for (var option in options) {
      this[option] = options[option];
    }
  },

  /**
   * Examines url query parameters for a specific parameter.
   * @param {!string} urlParam to search for in url parameters.
   * @return {?(string)} returns match as a string of null if no match.
   * @export
   */
  getParam: function(urlParam) {
    var regExp = new RegExp(urlParam + '=(.*?)($|&)', 'g');
    var match = window.location.search.match(regExp);
    if (match && match.length) {
      match = match[0];
      match = match.replace(urlParam + '=', '').replace('&', '');
    } else {
      match = null;
    }
    return match;
  },

  /**
   * Creates a new realtime file.
   * @param {!string} title for the new realtime document.
   * @param {Function} callback to be executed once the file has been created.
   * @export
   */
  createRealtimeFile: function(title, callback) {
    var that = this;
    window.gapi.client.load('drive', 'v2', function() {
      var insertHash = {
        'resource': {
          mimeType: that.mimeType,
          title: title
        }
      };
      window.gapi.client.drive.files.insert(insertHash).execute(callback);
    });
  },

  /**
   * Loads an existing realtime file.
   * @param {!string} documentId for the document to load.
   * @param {!function(gapi.drive.realtime.Document): undefined} onFileLoaded
   *     to be executed once the file has been loaded.
   * @param {!function(gapi.drive.realtime.Model): undefined} initializeModel
   *     will be executed if this is the first time this file has been loaded.
   * @export
   */
  load: function(documentId, onFileLoaded, initializeModel) {
    var that = this;
    window.gapi.drive.realtime.load(documentId, function(doc) {
      window.doc = doc;  // Debugging purposes
      onFileLoaded(doc);
    }, initializeModel, this.onError);
  },

  /**
   * Handles errors that occurred during document load.
   * @param {gapi.drive.realtime.Error} error containing specific realtime
   *     details.
   * @private
   */
  onError: function(error) {
    if (error.type == window.gapi.drive.realtime.ErrorType
        .TOKEN_REFRESH_REQUIRED) {
      this.authorizer.authorize(function() {
        console.log('Error, auth refreshed');
      }, false);
    } else if (error.type == window.gapi.drive.realtime.ErrorType
        .CLIENT_ERROR) {
      alert('An Error happened: ' + error.message);
      window.location.href = '/';
    } else if (error.type == window.gapi.drive.realtime.ErrorType.NOT_FOUND) {
      alert('The file was not found. It does not exist or you do not have ' +
        'read access to the file.');
      window.location.href = '/';
    } else if (error.type == window.gapi.drive.realtime.ErrorType.FORBIDDEN) {
      alert('You do not have access to this file. Try having the owner share' +
        'it with you from Google Drive.');
      window.location.href = '/';
    }
  }
};

/** @constructor
  *
  * @param {utils.RealtimeUtils} realtimeUtil that owns this
  *     RealtimeAuthorizer instance.
  *
  */
utils.RealtimeAuthorizer = function(realtimeUtil) {
  this.util = realtimeUtil;
  this.handleAuthResult = this.handleAuthResult.bind(this);
  this.token = null;
};

utils.RealtimeAuthorizer.prototype = {

  /**
   * Starts the authorizer
   * @param {!Function} onAuthComplete callback invoked after authorizing.
   * @param {boolean} usePopup true if authentication via a popup window.
   * @export
   */
  start: function(onAuthComplete, usePopup) {
    var that = this;
    var serverUrl = this.util.getParam('serverUrl');
    var apiUrl;
    var config = {};
    if (serverUrl) {
      switch (serverUrl) {
        case 'sandbox':
          apiUrl = 'https://drive.sandbox.google.com/otservice';
          serverUrl = this.apiUrl;
          break;
        case 'canary':
          apiUrl = 'https://drive.google.com/otservice/canary';
          serverUrl = 'https://drive.google.com/otservice';
          break;
        case 'scary':
          apiUrl = 'https://drive.google.com/otservice/scary';
          serverUrl = 'https://drive.google.com/otservice';
          break;
      }
      config['drive-realtime'] = { 'server' : apiUrl };
    }
    var that = this;
    window.gapi.load('auth:client,drive-realtime,drive-share', {
      config: config,
      callback: function() {
        if (that.serverUrl) {
          gapi.drive.realtime.setServerAddress(that.serverUrl);
        }
        that.authorize(onAuthComplete, usePopup);
      }
    });
    if (this.authTimer) {
      window.clearTimeout(this.authTimer);
    }
    this.refreshAuth();
  },

  /**
   * Attempts to authorize.
   * @param {!Function} onAuthComplete callback invoked after authorizing.
   * @param {boolean} usePopup true if authentication via a popup window.
   * @private
   */
  authorize: function(onAuthComplete, usePopup) {
    this.onAuthComplete = onAuthComplete;
    // Try with no popups first.
    window.gapi.auth.authorize({
      client_id: this.util.clientId,
      scope: this.util.scopes,
      immediate: !usePopup
    }, this.handleAuthResult);
  },

  /**
   * Handles the auth result before invoking the user supplied callback.
   * @param {Object} authResult from the drive service containing details about
   *     this authorization attempt.
   * @private
   */
  handleAuthResult: function(authResult) {
    if (authResult && !authResult.error) {
      this.token = authResult.access_token;
    }
    this.onAuthComplete(authResult);
  },

  /**
   * Sets a timer that will refreshes the oauth token after an interval.
   * @private
   */
  refreshAuth: function() {
    var that = this;
    this.authTimer = setTimeout(function() {
      that.authorize(function() {
        console.log('Refreshed Auth Token');
      }, false);
      that.refreshAuth();
    }, this.util.refreshInterval);
  }
};
<commit_msg>Cleared out serverUrl if not correctly specified.<commit_after>/**
 * @license
 * Realtime Utils 1.0.0
 * https://developers.google.com/drive/realtime/
 * Copyright 2015 Seth Howard, Google Inc. All Rights Reserved.
 * Realtime Utils may be freely distributed under the Apache 2.0 license.
 *
 * 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.
 */

/**
 * @fileoverview Common utility functionality for the Google Drive Realtime API,
 * including authorization and file loading.
 */

/**
 * Create the utils namespace
 */
window.utils = {};

/** @constructor
 *
 * @param {!Object} options for the realtime utility. One key is mandatory:
 *
 *  1) "clientId" the client id from the APIs console.
 *
 */
utils.RealtimeUtils = function(options) {
  this.init(options);
};

utils.RealtimeUtils.prototype = {

  /**
   * clientId for this realtime application.
   * @type {!string}
   */
  clientId: null,

  /**
   * MimeType for this realtime application.
   * @type {!string}
   */
  mimeType: 'application/vnd.google-apps.drive-sdk',

  /**
   * The interval at which the oauth token will attempt to be refreshed.
   * @type {!string}
   */
  refreshInterval: 1800000, // 30 minutes

  /**
   * Required scopes.
   * @type {!Array<string>}
   */
  scopes: [
    'https://www.googleapis.com/auth/drive.install',
    'https://www.googleapis.com/auth/drive.file'
  ],

  /**
   * Initializes RealtimeUtils
   * @param {Object} options containing required utiltiy keys.
   * @private
   */
  init: function(options) {
    this.mergeOptions(options);
    this.authorizer = new utils.RealtimeAuthorizer(this);
    this.createRealtimeFile = this.createRealtimeFile.bind(this);
  },

  /**
   * Kicks off the authorization process
   * @param {!Function} onAuthComplete callback invoked after authorizing.
   * @param {!boolean} usePopup true if authentication via a popup window.
   * @export
   */
  authorize: function(onAuthComplete, usePopup) {
    this.authorizer.start(onAuthComplete, usePopup);
  },

  /**
   * Merges passed in options with default options.
   * @param {Object} options that will be merged with existing options.
   * @private
   */
  mergeOptions: function(options) {
    for (var option in options) {
      this[option] = options[option];
    }
  },

  /**
   * Examines url query parameters for a specific parameter.
   * @param {!string} urlParam to search for in url parameters.
   * @return {?(string)} returns match as a string of null if no match.
   * @export
   */
  getParam: function(urlParam) {
    var regExp = new RegExp(urlParam + '=(.*?)($|&)', 'g');
    var match = window.location.search.match(regExp);
    if (match && match.length) {
      match = match[0];
      match = match.replace(urlParam + '=', '').replace('&', '');
    } else {
      match = null;
    }
    return match;
  },

  /**
   * Creates a new realtime file.
   * @param {!string} title for the new realtime document.
   * @param {Function} callback to be executed once the file has been created.
   * @export
   */
  createRealtimeFile: function(title, callback) {
    var that = this;
    window.gapi.client.load('drive', 'v2', function() {
      var insertHash = {
        'resource': {
          mimeType: that.mimeType,
          title: title
        }
      };
      window.gapi.client.drive.files.insert(insertHash).execute(callback);
    });
  },

  /**
   * Loads an existing realtime file.
   * @param {!string} documentId for the document to load.
   * @param {!function(gapi.drive.realtime.Document): undefined} onFileLoaded
   *     to be executed once the file has been loaded.
   * @param {!function(gapi.drive.realtime.Model): undefined} initializeModel
   *     will be executed if this is the first time this file has been loaded.
   * @export
   */
  load: function(documentId, onFileLoaded, initializeModel) {
    var that = this;
    window.gapi.drive.realtime.load(documentId, function(doc) {
      window.doc = doc;  // Debugging purposes
      onFileLoaded(doc);
    }, initializeModel, this.onError);
  },

  /**
   * Handles errors that occurred during document load.
   * @param {gapi.drive.realtime.Error} error containing specific realtime
   *     details.
   * @private
   */
  onError: function(error) {
    if (error.type == window.gapi.drive.realtime.ErrorType
        .TOKEN_REFRESH_REQUIRED) {
      this.authorizer.authorize(function() {
        console.log('Error, auth refreshed');
      }, false);
    } else if (error.type == window.gapi.drive.realtime.ErrorType
        .CLIENT_ERROR) {
      alert('An Error happened: ' + error.message);
      window.location.href = '/';
    } else if (error.type == window.gapi.drive.realtime.ErrorType.NOT_FOUND) {
      alert('The file was not found. It does not exist or you do not have ' +
        'read access to the file.');
      window.location.href = '/';
    } else if (error.type == window.gapi.drive.realtime.ErrorType.FORBIDDEN) {
      alert('You do not have access to this file. Try having the owner share' +
        'it with you from Google Drive.');
      window.location.href = '/';
    }
  }
};

/** @constructor
  *
  * @param {utils.RealtimeUtils} realtimeUtil that owns this
  *     RealtimeAuthorizer instance.
  *
  */
utils.RealtimeAuthorizer = function(realtimeUtil) {
  this.util = realtimeUtil;
  this.handleAuthResult = this.handleAuthResult.bind(this);
  this.token = null;
};

utils.RealtimeAuthorizer.prototype = {

  /**
   * Starts the authorizer
   * @param {!Function} onAuthComplete callback invoked after authorizing.
   * @param {boolean} usePopup true if authentication via a popup window.
   * @export
   */
  start: function(onAuthComplete, usePopup) {
    var that = this;
    var serverUrl = this.util.getParam('serverUrl');
    var apiUrl;
    var config = {};
    if (serverUrl) {
      switch (serverUrl) {
        case 'sandbox':
          apiUrl = 'https://drive.sandbox.google.com/otservice';
          serverUrl = this.apiUrl;
          break;
        case 'canary':
          apiUrl = 'https://drive.google.com/otservice/canary';
          serverUrl = 'https://drive.google.com/otservice';
          break;
        case 'scary':
          apiUrl = 'https://drive.google.com/otservice/scary';
          serverUrl = 'https://drive.google.com/otservice';
          break;
        default:
          serverUrl = null;
      }
      config['drive-realtime'] = { 'server' : apiUrl };
    }
    var that = this;
    window.gapi.load('auth:client,drive-realtime,drive-share', {
      config: config,
      callback: function() {
        if (that.serverUrl) {
          gapi.drive.realtime.setServerAddress(that.serverUrl);
        }
        that.authorize(onAuthComplete, usePopup);
      }
    });
    if (this.authTimer) {
      window.clearTimeout(this.authTimer);
    }
    this.refreshAuth();
  },

  /**
   * Attempts to authorize.
   * @param {!Function} onAuthComplete callback invoked after authorizing.
   * @param {boolean} usePopup true if authentication via a popup window.
   * @private
   */
  authorize: function(onAuthComplete, usePopup) {
    this.onAuthComplete = onAuthComplete;
    // Try with no popups first.
    window.gapi.auth.authorize({
      client_id: this.util.clientId,
      scope: this.util.scopes,
      immediate: !usePopup
    }, this.handleAuthResult);
  },

  /**
   * Handles the auth result before invoking the user supplied callback.
   * @param {Object} authResult from the drive service containing details about
   *     this authorization attempt.
   * @private
   */
  handleAuthResult: function(authResult) {
    if (authResult && !authResult.error) {
      this.token = authResult.access_token;
    }
    this.onAuthComplete(authResult);
  },

  /**
   * Sets a timer that will refreshes the oauth token after an interval.
   * @private
   */
  refreshAuth: function() {
    var that = this;
    this.authTimer = setTimeout(function() {
      that.authorize(function() {
        console.log('Refreshed Auth Token');
      }, false);
      that.refreshAuth();
    }, this.util.refreshInterval);
  }
};
<|endoftext|>


<commit_before>/**
 * @method identity
 * @param {*} a
 * @return {*}
 */
export function identity(a) {
    return a;
}

/**
 * @method trace
 * @param {*} a
 * @return {*}
 */
export function trace(a) {
    const isArrayMap = (a) => Array.isArray(a) && (typeof a[0] === 'object');
    (isArrayMap(a) ? console.table : console.log)(a);
    return identity(a);
}

/**
 * @method curry
 * @param {Function} f
 * @return {Function}
 */
export function curry(f) {

    const argArity = f.length;

    return function curried(...a) {

        if (a.length >= argArity) {
            return f(...a);
        }

        return (...b) => {
            return curried(...[...a, ...b]);
        };

    };

}

/**
 * @method partial
 * @param {Function} f
 * @param {Array} a
 * @return {Function}
 */
export function partial(f, ...a) {
    return f.bind(null, ...a);
}

/**
 * @method compose
 * @param {Function[]} fs
 * @return {Function}
 */
export function compose(...fs) {
    return a => fs.reduceRight((acc, f) => f(acc), a);
}

/**
 * @method memoize
 * @param {Function} fn
 * @return {Function}
 */
export function memoize(fn) {

    const cache = new Map();

    return (...args) => {

        const key    = JSON.stringify(args);
        const cached = cache.get(key);

        return cached ? cached : (() => {
            const value = fn(...args);
            cache.set(key, value);
            return value;
        })();

    };

}
<commit_msg>Maintaining  keyword in  function<commit_after>/**
 * @method identity
 * @param {*} a
 * @return {*}
 */
export function identity(a) {
    return a;
}

/**
 * @method trace
 * @param {*} a
 * @return {*}
 */
export function trace(a) {
    const isArrayMap = (a) => Array.isArray(a) && (typeof a[0] === 'object');
    (isArrayMap(a) ? console.table : console.log)(a);
    return identity(a);
}

/**
 * @method curry
 * @param {Function} f
 * @return {Function}
 */
export function curry(f) {

    const argArity = f.length;

    return function curried(...a) {

        if (a.length >= argArity) {
            return f(...a);
        }

        return (...b) => {
            return curried(...[...a, ...b]);
        };

    };

}

/**
 * @method partial
 * @param {Function} f
 * @param {Array} a
 * @return {Function}
 */
export function partial(f, ...a) {
    return f.bind(null, ...a);
}

/**
 * @method compose
 * @param {Function[]} fns
 * @return {Function}
 */
export function compose(...fns) {

    return function(a) {
        return fns.reduceRight((acc, fn) => fn.call(this, acc), a);
    };

}

/**
 * @method memoize
 * @param {Function} fn
 * @return {Function}
 */
export function memoize(fn) {

    const cache = new Map();

    return (...args) => {

        const key    = JSON.stringify(args);
        const cached = cache.get(key);

        return cached ? cached : (() => {
            const value = fn(...args);
            cache.set(key, value);
            return value;
        })();

    };

}
<|endoftext|>


<commit_before>/************************************
 *
 *  Copyright (c) 2013 AnsibleWorks, Inc.
 *
 *  config.js
 *
 *  Gobal configuration variables for controlling application behavior.
 *
 */

var $AnsibleConfig =
{
   tooltip_delay: {show: 500, hide: 100},   // Default number of milliseconds to delay displaying/hiding tooltips

   debug_mode: true,                        // Enable console logging messages

   password_strength: 45,             // User password strength. Integer between 0 and 100, 100 being impossibly strong.
                                      // This value controls progress bar colors:
                                      //   0 to password_strength - 15 = red;
                                      //   password_strength - 15 to password_strength = yellow
                                      //   > password_strength = green
                                      // It also controls password validation. Passwords are rejected if the score is not > password_strength.

   session_timeout: 15                // Number of seconds before an inactive session is automatically timed out and forced to log in again.
                                      // Separate from time out value set in API.
   }
<commit_msg>Set default config.js timeout to 1800 seconds.<commit_after>/************************************
 *
 *  Copyright (c) 2013 AnsibleWorks, Inc.
 *
 *  config.js
 *
 *  Gobal configuration variables for controlling application behavior.
 *
 */

var $AnsibleConfig =
{
   tooltip_delay: {show: 500, hide: 100},   // Default number of milliseconds to delay displaying/hiding tooltips

   debug_mode: true,                        // Enable console logging messages

   password_strength: 45,             // User password strength. Integer between 0 and 100, 100 being impossibly strong.
                                      // This value controls progress bar colors:
                                      //   0 to password_strength - 15 = red;
                                      //   password_strength - 15 to password_strength = yellow
                                      //   > password_strength = green
                                      // It also controls password validation. Passwords are rejected if the score is not > password_strength.

   session_timeout: 1800              // Number of seconds before an inactive session is automatically timed out and forced to log in again.
                                      // Separate from time out value set in API.
   }
<|endoftext|>


<commit_before>"use strict";
/**
 * todo: chart height as option
 *
 */
var $ = require("jquery"), utils = require("./utils.js"), yUtils = require("yasgui-utils");

var root = module.exports = function(yasr) {
  var options = $.extend(true, {}, root.defaults);
  var id = yasr.container.closest("[id]").attr("id");

  var chartWrapper = null;
  var editor = null;

  var initEditor = function(callback) {
    var google = require("google");
    editor = new google.visualization.ChartEditor();
    google.visualization.events.addListener(editor, "ok", function() {
      var tmp;
      chartWrapper = editor.getChartWrapper();
      tmp = chartWrapper.getDataTable();
      chartWrapper.setDataTable(null);
      //ugly: need to parse json string to json obj again, as google chart does not provide access to object directly
      options.chartConfig = JSON.parse(chartWrapper.toJSON());
      //remove container ID though, for portability
      if (options.chartConfig.containerId) delete options.chartConfig["containerId"];
      yasr.store();
      chartWrapper.setDataTable(tmp);
      var wrapperId = id + "_gchartWrapper";
      var $wrapper = $("#" + wrapperId);
      chartWrapper.setOption("width", $wrapper.width());
      chartWrapper.setOption("height", $wrapper.height());
      chartWrapper.draw();
      yasr.updateHeader();
    });
    if (callback) callback();
  };

  return {
    name: "Google Chart",
    hideFromSelection: false,
    priority: 7,
    options: options,
    getPersistentSettings: function() {
      return {
        chartConfig: options.chartConfig,
        motionChartState: options.motionChartState
      };
    },
    setPersistentSettings: function(persSettings) {
      if (persSettings["chartConfig"]) options.chartConfig = persSettings["chartConfig"];
      if (persSettings["motionChartState"]) options.motionChartState = persSettings["motionChartState"];
    },
    canHandleResults: function(yasr) {
      var results, variables;
      return (results = yasr.results) != null && (variables = results.getVariables()) && variables.length > 0;
    },
    getDownloadInfo: function() {
      if (!yasr.results) return null;
      var svgEl = yasr.resultsContainer.find("svg");
      if (svgEl.length > 0) {
        return {
          getContent: function() {
            if (svgEl[0].outerHTML) {
              return svgEl[0].outerHTML;
            } else {
              //outerHTML not supported. use workaround
              return $("
").append(svgEl.clone()).html();
            }
          },
          filename: "queryResults.svg",
          contentType: "image/svg+xml",
          buttonTitle: "Download SVG Image"
        };
      }
      //ok, not a svg. is it a table?
      var $table = yasr.resultsContainer.find(".google-visualization-table-table");
      if ($table.length > 0) {
        return {
          getContent: function() {
            return $table.tableToCsv();
          },
          filename: "queryResults.csv",
          contentType: "text/csv",
          buttonTitle: "Download as CSV"
        };
      }
    },
    getEmbedHtml: function() {
      if (!yasr.results) return null;

      var svgEl = yasr.resultsContainer
        .find("svg")
        .clone() //create clone, as we'd like to remove height/width attributes
        .removeAttr("height")
        .removeAttr("width")
        .css("height", "")
        .css("width", "");
      if (svgEl.length == 0) return null;

      var htmlString = svgEl[0].outerHTML;
      if (!htmlString) {
        //outerHTML not supported. use workaround
        htmlString = $("
").append(svgEl.clone()).html();
      }
      //wrap in div, so users can more easily tune width/height
      //don't use jquery, so we can easily influence indentation
      return '
\n' + htmlString + "\n
";
    },
    draw: function(_customOpts) {
      var customOpts = $.extend(true, {}, options, _customOpts);
      var doDraw = function() {
        //clear previous results (if any)
        yasr.resultsContainer.empty();
        var wrapperId = id + "_gchartWrapper";

        yasr.resultsContainer
          .append(
            $("<button>", {
              class: "openGchartBtn yasr_btn"
            })
              .text("Chart Config")
              .click(function() {
                editor.openDialog(chartWrapper);
              })
          )
          .append(
            $("
", {
              id: wrapperId,
              class: "gchartWrapper"
            })
          );
        var dataTable = new google.visualization.DataTable();
        //clone, because we'll be manipulating the literals types
        var jsonResults = $.extend(true, {}, yasr.results.getAsJson());
        jsonResults.head.vars.forEach(function(variable) {
          var type = "string";
          try {
            type = utils.getGoogleTypeForBindings(jsonResults.results.bindings, variable);
          } catch (e) {
            if (e instanceof require("./exceptions.js").GoogleTypeException) {
              yasr.warn(e.toHtml());
            } else {
              throw e;
            }
          }
          dataTable.addColumn(type, variable);
        });
        var usedPrefixes = null;
        if (yasr.options.getUsedPrefixes) {
          usedPrefixes = typeof yasr.options.getUsedPrefixes == "function"
            ? yasr.options.getUsedPrefixes(yasr)
            : yasr.options.getUsedPrefixes;
        }
        jsonResults.results.bindings.forEach(function(binding) {
          var row = [];
          jsonResults.head.vars.forEach(function(variable, columnId) {
            row.push(utils.castGoogleType(binding[variable], usedPrefixes, dataTable.getColumnType(columnId)));
          });
          dataTable.addRow(row);
        });
        if (customOpts.chartConfig && customOpts.chartConfig.chartType) {
          customOpts.chartConfig.containerId = wrapperId;
          chartWrapper = new google.visualization.ChartWrapper(customOpts.chartConfig);
          if (chartWrapper.getChartType() === "MotionChart" && customOpts.motionChartState) {
            chartWrapper.setOption("state", customOpts.motionChartState);
            google.visualization.events.addListener(chartWrapper, "ready", function() {
              var motionChart;
              motionChart = chartWrapper.getChart();
              google.visualization.events.addListener(motionChart, "statechange", function() {
                customOpts.motionChartState = motionChart.getState();
                yasr.store();
              });
            });
          }
          chartWrapper.setDataTable(dataTable);
        } else {
          chartWrapper = new google.visualization.ChartWrapper({
            chartType: "Table",
            dataTable: dataTable,
            containerId: wrapperId
          });
        }
        var $wrapper = $("#" + wrapperId);
        chartWrapper.setOption("width", $wrapper.width());
        chartWrapper.setOption("height", $wrapper.height());
        chartWrapper.draw();
        google.visualization.events.addListener(chartWrapper, "ready", yasr.updateHeader);
      };

      if (!require("google") || !require("google").visualization || !editor) {
        require("./gChartLoader.js")
          .on("done", function() {
            initEditor();
            doDraw();
          })
          .on("error", function() {
            //TODO: disable or something?
          })
          .googleLoad();
      } else {
        //everything (editor as well) is already initialized
        doDraw();
      }
    }
  };
};
root.defaults = {
  height: "100%",
  width: "100%",
  persistencyId: "gchart",
  chartConfig: null,
  motionChartState: null
};

function deepEq$(x, y, type) {
  var toString = ({}).toString,
    hasOwnProperty = ({}).hasOwnProperty,
    has = function(obj, key) {
      return hasOwnProperty.call(obj, key);
    };
  var first = true;
  return eq(x, y, []);

  function eq(a, b, stack) {
    var className, length, size, result, alength, blength, r, key, ref, sizeB;
    if (a == null || b == null) {
      return a === b;
    }
    if (a.__placeholder__ || b.__placeholder__) {
      return true;
    }
    if (a === b) {
      return a !== 0 || 1 / a == 1 / b;
    }
    className = toString.call(a);
    if (toString.call(b) != className) {
      return false;
    }
    switch (className) {
      case "[object String]":
        return a == String(b);
      case "[object Number]":
        return a != +a ? b != +b : a == 0 ? 1 / a == 1 / b : a == +b;
      case "[object Date]":
      case "[object Boolean]":
        return +a == +b;
      case "[object RegExp]":
        return a.source == b.source &&
          a.global == b.global &&
          a.multiline == b.multiline &&
          a.ignoreCase == b.ignoreCase;
    }
    if (typeof a != "object" || typeof b != "object") {
      return false;
    }
    length = stack.length;
    while (length--) {
      if (stack[length] == a) {
        return true;
      }
    }
    stack.push(a);
    size = 0;
    result = true;
    if (className == "[object Array]") {
      alength = a.length;
      blength = b.length;
      if (first) {
        switch (type) {
          case "===":
            result = alength === blength;
            break;
          case "<==":
            result = alength <= blength;
            break;
          case "<<=":
            result = alength < blength;
            break;
        }
        size = alength;
        first = false;
      } else {
        result = alength === blength;
        size = alength;
      }
      if (result) {
        while (size--) {
          if (!(result = size in a == size in b && eq(a[size], b[size], stack))) {
            break;
          }
        }
      }
    } else {
      if ("constructor" in a != "constructor" in b || a.constructor != b.constructor) {
        return false;
      }
      for (key in a) {
        if (has(a, key)) {
          size++;
          if (!(result = has(b, key) && eq(a[key], b[key], stack))) {
            break;
          }
        }
      }
      if (result) {
        sizeB = 0;
        for (key in b) {
          if (has(b, key)) {
            ++sizeB;
          }
        }
        if (first) {
          if (type === "<<=") {
            result = size < sizeB;
          } else if (type === "<==") {
            result = size <= sizeB;
          } else {
            result = size === sizeB;
          }
        } else {
          first = false;
          result = size === sizeB;
        }
      }
    }
    stack.pop();
    return result;
  }
}
<commit_msg>Introduce selecthandler call back<commit_after>"use strict";
/**
 * todo: chart height as option
 *
 */
var $ = require("jquery"), utils = require("./utils.js"), yUtils = require("yasgui-utils");

var root = module.exports = function(yasr) {
  var options = $.extend(true, {}, root.defaults);
  var id = yasr.container.closest("[id]").attr("id");

  var chartWrapper = null;
  var editor = null;

  var initEditor = function(callback) {
    var google = require("google");
    editor = new google.visualization.ChartEditor();
    google.visualization.events.addListener(editor, "ok", function() {
      var tmp;
      chartWrapper = editor.getChartWrapper();
      tmp = chartWrapper.getDataTable();
      chartWrapper.setDataTable(null);
      //ugly: need to parse json string to json obj again, as google chart does not provide access to object directly
      options.chartConfig = JSON.parse(chartWrapper.toJSON());
      //remove container ID though, for portability
      if (options.chartConfig.containerId) delete options.chartConfig["containerId"];
      yasr.store();
      chartWrapper.setDataTable(tmp);
      var wrapperId = id + "_gchartWrapper";
      var $wrapper = $("#" + wrapperId);
      chartWrapper.setOption("width", $wrapper.width());
      chartWrapper.setOption("height", $wrapper.height());
      chartWrapper.draw();
      yasr.updateHeader();
    });
    if (callback) callback();
  };

  return {
    name: "Google Chart",
    hideFromSelection: false,
    priority: 7,
    options: options,
    getPersistentSettings: function() {
      return {
        chartConfig: options.chartConfig,
        motionChartState: options.motionChartState
      };
    },
    setPersistentSettings: function(persSettings) {
      if (persSettings["chartConfig"]) options.chartConfig = persSettings["chartConfig"];
      if (persSettings["motionChartState"]) options.motionChartState = persSettings["motionChartState"];
    },
    canHandleResults: function(yasr) {
      var results, variables;
      return (results = yasr.results) != null && (variables = results.getVariables()) && variables.length > 0;
    },
    getDownloadInfo: function() {
      if (!yasr.results) return null;
      var svgEl = yasr.resultsContainer.find("svg");
      if (svgEl.length > 0) {
        return {
          getContent: function() {
            if (svgEl[0].outerHTML) {
              return svgEl[0].outerHTML;
            } else {
              //outerHTML not supported. use workaround
              return $("
").append(svgEl.clone()).html();
            }
          },
          filename: "queryResults.svg",
          contentType: "image/svg+xml",
          buttonTitle: "Download SVG Image"
        };
      }
      //ok, not a svg. is it a table?
      var $table = yasr.resultsContainer.find(".google-visualization-table-table");
      if ($table.length > 0) {
        return {
          getContent: function() {
            return $table.tableToCsv();
          },
          filename: "queryResults.csv",
          contentType: "text/csv",
          buttonTitle: "Download as CSV"
        };
      }
    },
    getEmbedHtml: function() {
      if (!yasr.results) return null;

      var svgEl = yasr.resultsContainer
        .find("svg")
        .clone() //create clone, as we'd like to remove height/width attributes
        .removeAttr("height")
        .removeAttr("width")
        .css("height", "")
        .css("width", "");
      if (svgEl.length == 0) return null;

      var htmlString = svgEl[0].outerHTML;
      if (!htmlString) {
        //outerHTML not supported. use workaround
        htmlString = $("
").append(svgEl.clone()).html();
      }
      //wrap in div, so users can more easily tune width/height
      //don't use jquery, so we can easily influence indentation
      return '
\n' + htmlString + "\n
";
    },
    draw: function(_customOpts) {
      var customOpts = $.extend(true, {}, options, _customOpts);
      var doDraw = function() {
        //clear previous results (if any)
        yasr.resultsContainer.empty();
        var wrapperId = id + "_gchartWrapper";

        yasr.resultsContainer
          .append(
            $("<button>", {
              class: "openGchartBtn yasr_btn"
            })
              .text("Chart Config")
              .click(function() {
                editor.openDialog(chartWrapper);
              })
          )
          .append(
            $("
", {
              id: wrapperId,
              class: "gchartWrapper"
            })
          );
        var dataTable = new google.visualization.DataTable();
        //clone, because we'll be manipulating the literals types
        var jsonResults = $.extend(true, {}, yasr.results.getAsJson());
        jsonResults.head.vars.forEach(function(variable) {
          var type = "string";
          try {
            type = utils.getGoogleTypeForBindings(jsonResults.results.bindings, variable);
          } catch (e) {
            if (e instanceof require("./exceptions.js").GoogleTypeException) {
              yasr.warn(e.toHtml());
            } else {
              throw e;
            }
          }
          dataTable.addColumn(type, variable);
        });
        var usedPrefixes = null;
        if (yasr.options.getUsedPrefixes) {
          usedPrefixes = typeof yasr.options.getUsedPrefixes == "function"
            ? yasr.options.getUsedPrefixes(yasr)
            : yasr.options.getUsedPrefixes;
        }
        jsonResults.results.bindings.forEach(function(binding) {
          var row = [];
          jsonResults.head.vars.forEach(function(variable, columnId) {
            row.push(utils.castGoogleType(binding[variable], usedPrefixes, dataTable.getColumnType(columnId)));
          });
          dataTable.addRow(row);
        });
        if (customOpts.chartConfig && customOpts.chartConfig.chartType) {
          customOpts.chartConfig.containerId = wrapperId;
          chartWrapper = new google.visualization.ChartWrapper(customOpts.chartConfig);
          if (chartWrapper.getChartType() === "MotionChart" && customOpts.motionChartState) {
            chartWrapper.setOption("state", customOpts.motionChartState);
            google.visualization.events.addListener(chartWrapper, "ready", function() {
              var motionChart;
              motionChart = chartWrapper.getChart();
              google.visualization.events.addListener(motionChart, "statechange", function() {
                customOpts.motionChartState = motionChart.getState();
                yasr.store();
              });
            });
          }
          chartWrapper.setDataTable(dataTable);
        } else {
          chartWrapper = new google.visualization.ChartWrapper({
            chartType: "Table",
            dataTable: dataTable,
            containerId: wrapperId
          });
        }
        var $wrapper = $("#" + wrapperId);
        chartWrapper.setOption("width", $wrapper.width());
        chartWrapper.setOption("height", $wrapper.height());
        chartWrapper.draw();
        // introduce handler
        if ( customOpts.selectHandler && typeof(customOpts.selectHandler) == 'function')
				   google.visualization.events.addListener(chartWrapper, "select", function() { customOpts.selectHandler(chartWrapper,jsonResults); });

        google.visualization.events.addListener(chartWrapper, "ready", yasr.updateHeader);
      };

      if (!require("google") || !require("google").visualization || !editor) {
        require("./gChartLoader.js")
          .on("done", function() {
            initEditor();
            doDraw();
          })
          .on("error", function() {
            //TODO: disable or something?
          })
          .googleLoad();
      } else {
        //everything (editor as well) is already initialized
        doDraw();
      }
    }
  };
};
root.defaults = {
  height: "100%",
  width: "100%",
  persistencyId: "gchart",
  chartConfig: null,
  motionChartState: null
};

function deepEq$(x, y, type) {
  var toString = ({}).toString,
    hasOwnProperty = ({}).hasOwnProperty,
    has = function(obj, key) {
      return hasOwnProperty.call(obj, key);
    };
  var first = true;
  return eq(x, y, []);

  function eq(a, b, stack) {
    var className, length, size, result, alength, blength, r, key, ref, sizeB;
    if (a == null || b == null) {
      return a === b;
    }
    if (a.__placeholder__ || b.__placeholder__) {
      return true;
    }
    if (a === b) {
      return a !== 0 || 1 / a == 1 / b;
    }
    className = toString.call(a);
    if (toString.call(b) != className) {
      return false;
    }
    switch (className) {
      case "[object String]":
        return a == String(b);
      case "[object Number]":
        return a != +a ? b != +b : a == 0 ? 1 / a == 1 / b : a == +b;
      case "[object Date]":
      case "[object Boolean]":
        return +a == +b;
      case "[object RegExp]":
        return a.source == b.source &&
          a.global == b.global &&
          a.multiline == b.multiline &&
          a.ignoreCase == b.ignoreCase;
    }
    if (typeof a != "object" || typeof b != "object") {
      return false;
    }
    length = stack.length;
    while (length--) {
      if (stack[length] == a) {
        return true;
      }
    }
    stack.push(a);
    size = 0;
    result = true;
    if (className == "[object Array]") {
      alength = a.length;
      blength = b.length;
      if (first) {
        switch (type) {
          case "===":
            result = alength === blength;
            break;
          case "<==":
            result = alength <= blength;
            break;
          case "<<=":
            result = alength < blength;
            break;
        }
        size = alength;
        first = false;
      } else {
        result = alength === blength;
        size = alength;
      }
      if (result) {
        while (size--) {
          if (!(result = size in a == size in b && eq(a[size], b[size], stack))) {
            break;
          }
        }
      }
    } else {
      if ("constructor" in a != "constructor" in b || a.constructor != b.constructor) {
        return false;
      }
      for (key in a) {
        if (has(a, key)) {
          size++;
          if (!(result = has(b, key) && eq(a[key], b[key], stack))) {
            break;
          }
        }
      }
      if (result) {
        sizeB = 0;
        for (key in b) {
          if (has(b, key)) {
            ++sizeB;
          }
        }
        if (first) {
          if (type === "<<=") {
            result = size < sizeB;
          } else if (type === "<==") {
            result = size <= sizeB;
          } else {
            result = size === sizeB;
          }
        } else {
          first = false;
          result = size === sizeB;
        }
      }
    }
    stack.pop();
    return result;
  }
}
<|endoftext|>


<commit_before>const { exec } = require('child_process');
const { promisify } = require('util');

const promiseExec = promisify(exec);

const setCwd = async ({ dispatch, action, tab }) => {
  const newCwd = await promiseExec(
    `lsof -p ${tab.pid} | grep cwd | tr -s ' ' | cut -d ' ' -f9-`);
  // Since Node v8, return type of a promisified exec has changed:
  // https://github.com/nodejs/node/commit/fe5ca3ff27
  const cwd = typeof newCwd === 'string' ? newCwd.trim() : newCwd.stdout.trim();
  dispatch({
    type: 'SESSION_SET_CWD',
    cwd,
  });
};

// For Windows Support:
// the final excluded character () is an odd character
// that was added to the end of the line by posh-hg/posh-git
const directoryRegex = /([a-zA-Z]:[^\:\[\]\?\"\<\>\|]+)/mi;

const windowsSetCwd = ({ dispatch, action, tab, curTabId }) => {
  const newCwd = directoryRegex.exec(action.data);
  if (newCwd) {
    const cwd = newCwd[0];
    if (tab.cwd !== cwd && action.uid === curTabId) {
      dispatch({
        type: 'SESSION_SET_CWD',
        cwd,
      });
    }
    tab.cwd = cwd;
  }
};

module.exports = {
  setCwd,
  windowsSetCwd,
}
<commit_msg>Fix sporadic delay (#69)<commit_after>const { exec } = require('child_process');
const { promisify } = require('util');

const promiseExec = promisify(exec);

const setCwd = async ({ dispatch, action, tab }) => {
  const newCwd = await promiseExec(
    `lsof -a -p ${tab.pid} -d cwd -Fn | tail -1 | sed 's/.//'`);
  // Since Node v8, return type of a promisified exec has changed:
  // https://github.com/nodejs/node/commit/fe5ca3ff27
  const cwd = typeof newCwd === 'string' ? newCwd.trim() : newCwd.stdout.trim();
  dispatch({
    type: 'SESSION_SET_CWD',
    cwd,
  });
};

// For Windows Support:
// the final excluded character () is an odd character
// that was added to the end of the line by posh-hg/posh-git
const directoryRegex = /([a-zA-Z]:[^\:\[\]\?\"\<\>\|]+)/mi;

const windowsSetCwd = ({ dispatch, action, tab, curTabId }) => {
  const newCwd = directoryRegex.exec(action.data);
  if (newCwd) {
    const cwd = newCwd[0];
    if (tab.cwd !== cwd && action.uid === curTabId) {
      dispatch({
        type: 'SESSION_SET_CWD',
        cwd,
      });
    }
    tab.cwd = cwd;
  }
};

module.exports = {
  setCwd,
  windowsSetCwd,
}
<|endoftext|>