<commit_before>
//inject a matchRef, isRef, and a getRef function?
//could use the same pattern with objects.

//I don't really want to force __id__
//should be able to use anything, aslong as you

function shallowEqual (a, b) {
    if(isObject(a)
      && isObject(b)
      && (a.__id__ == b.__id__ || a === b))
      return true
    if(a && !b) return false
    return a == b
  }

function equal (a, b) {
  if(isObject(a) && isObject(b) && (a.__id__ == b.__id__ || a === b))
    return true
  if(a && !b) return false
  if(Array.isArray(a))
    if(a.length != b.length) return false

  if(a && 'object' == typeof a) {
    for(var i in a)
      if(!equal(a[i], b[i])) return false
    return true
  }
  return a == b
}

var adiff = require('adiff')({ equal: equal })

function getPath (obj, path) {
  if(!Array.isArray(path))
    return obj[path]
  for(var i in path) {
    obj = obj[path[i]]
  }
  return obj
}

function findRefs(obj, refs) {
  refs = refs || {}
  //add leaves before branches.
  //this will FAIL if there are circular references.

  if(!obj)
    return refs

  for(var k in obj) {
    if(obj[k] && 'object' == typeof obj[k])
      findRefs(obj[k], refs)
  }

  if(obj.__id__ && !refs[obj.__id__])
    refs[obj.__id__] = obj
  return refs
}

function toRef(v) {
  //TODO escape strings that happen to start with #*=
  var r
  if(r = isRef(v)) return '#*='+r
  return v
}

function isObject (o) {
  return o && 'object' == typeof o
}

function isRef(x) {
  return x ? x.__id__ : undefined
}

function sameRef(a, b) {
  return a && b && isRef(a) == isRef(b)
}

//traverse o, and replace every object with __id__ with a pointer.
//make diffing references easy.

exports.deref = function (o, mutate) {
  var refs = findRefs(o)
  var derefed = {}
  function deref (o, K) {
    if(isRef(o) && K != isRef(o))
      return toRef(o)

    var p = mutate ? o : Array.isArray(o) ? [] : {} //will copy the tree!
    for (var k in o) {
      var r
      if(isRef(o[k])) p[k] = toRef(o[k])
      else if(isObject(o[k])) p[k] = deref(o[k])
      else p[k] = o[k]
    }
    return p
  }

  refs.root = o
  for (var k in refs)
    refs[k] = deref(refs[k], k)
  return refs
}

exports.reref = function (refs, mutate) {

  function fromRef(v) {
    //TODO escape strings that happen to start with #*=
    if('string' == typeof v && /^#\*=/.test(v)) return refs[v.substring(3)]
      return v
  }

  function reref (o) { //will MUTATE the tree
    if(!isObject(o))
      return fromRef(o)

    var p = mutate ? o : Array.isArray(o) ? [] : {} //will copy the tree!
    for (var k in o) {
      if(isObject(o[k]))
         p[k] = reref(o[k])
      else
        p[k] = fromRef(o[k])
    }
    return p
  }
  //if the root is a ref. need a special case
  for (var k in refs) {
    refs[k] = reref(refs[k])
  }
  return refs.root
}

exports.diff = function (a, b) {

  var aRefs = exports.deref(a)
  var bRefs = exports.deref(b)

  var seen = []

  for (var k in aRefs)
    seen.push(k)

 function isSeen(o) {
    if(isRef(o)) return ~seen.indexOf(o.__id__)
    return true
  }
  function addSeen(o) {
    if(!isRef(o)) return o
    if(!isSeen(o)) seen.push(o.__id__)
    return o
  }

  // how to handle references?
  // this is necessary to handle objects in arrays nicely
  // otherwise mergeing an edit and a move is ambigous.  // will need to perform a topoligical sort of the refs and diff them first, in that order.
  // first, apply changes to all refs,
  // then traverse over the root object,

  function _diff (a, b, path) {
    path = path || []

    if(Array.isArray(a) && Array.isArray(b)) {
      var d = adiff.diff(a, b)
      if(d.length) delta.push(['splice', path, d])
      return delta
    }

// references to objects with ids are
// changed into strings of thier id.
// the string is prepended with '#*='
// to distinguish it from other strings
// if you use that string in your model,
// it will break.
// TODO escape strings so this is safe

   //ah, treat root like it's a __id__

   var isRoot = path.length === 1 && path[0] === 'root'

    for (var k in b) {
      // if both are nonRef objects, or are the same object, branch into them.

    if(isObject(a[k]) && isObject(b[k]) && sameRef(b[k], a[k]))
      _diff(a[k], b[k], path.concat(k))
    else if(b[k] !== a[k])
      delta.push(['set', path.concat(k), b[k]])
    }

    for (var k in a)
      if('undefined' == typeof b[k])
        delta.push(['del', path.concat(k)])
  }

  var delta = []
  _diff(aRefs, bRefs, [])

  if(delta.length)
    return delta
}

exports.patch = function (a, patch) {

  if(!patch) throw new Error('expected patch')

  a = cpy(a)
  var refs = exports.deref(a, true)
  refs.root = a

  function fromRef(v) {
    //TODO escape strings that happen to start with #*=
    if('string' == typeof v && /^#\*=/.test(v)) return refs[v.substring(3)]
      return cpy(v)
  }

  var methods = {
    set: function (key, value) {
      this[key] = fromRef(value) // incase this was a reference, remove it.
    },
    del: function (key) {
      delete this[key]
    },
    apl: function (key, changes) {
      _patch(this[key], changes)
    },
    splice: function (changes) {
      adiff.patch(this, changes, true)
      this.forEach(function (v, k, self) {
        self[k] = fromRef(v)
      })
    },
    sref: function (key, id) {
      this[key] = refs[id]
    }
  }

  function pathTo(a, p) {
    for (var i in p) a = a[p[i]]
    return a
  }

  patch.forEach(function (args) {
    args = args.slice()
    var method = args.shift()
    var path = args.shift().slice()
    var key
    if(method != 'splice') {
      key = path.pop()
      args.unshift(key)
    }
    var obj = pathTo(refs, path)
    methods[method].apply(obj, args)
  })

  return exports.reref(refs, true)
}

function cpy(o) {
  return JSON.parse(JSON.stringify(o))
}

exports.diff3 = function (a, o, b) {
  if(arguments.length == 1)
    o = a[1], b = a[2], a = a[0]
  var _a = exports.diff(o, a)
    , _b = exports.diff(o, b)

  function cmp (a, b) {
    //check if a[1] > b[1]
    if(!b)
      return 1

    var p = a[1], q = b[1]
    var i = 0
    while (p[i] === q[i] && p[i] != null)
      i++

    if(p[i] === q[i]) return 0
    return p[i] < q[i] ? -1 : 1
  }

  function isPrefix(a, b) {
    if(!b) return 1
    var p = a[1], q = b[1]
    var i = 0
    while (p[i] === q[i] && i < p.length && i < q.length)
      i++
    if(i == p.length || i == q.length) return 0
    return p[i] < q[i] ? -1 : 1
  }

  //merge two lists, which must be sorted.

  function cmpSp (a, b) {
    if(a[0] == b[0])
      return 0
    function max(k) {
      return k[0] + (k[1] >= 1 ? k[1] - 1 : 0)
    }
    if(max(a) < b[0] || max(b) < a[0])
      return a[0] - b[0]
    return 0
  }

  function resolveAry(a, b) {
    return a
  }

  function resolve(a, b) {
    if(a[1].length == b[1].length) {
      if(a[0] == b[0]) {
        if(a[0] == 'splice') {
          var R = merge(a[2], b[2], cmpSp, resolveAry)
          return ['splice', a[1].slice(), R]
        } else if(equal(a[2], b[2])) //same change both sides.
          return a
      }
    }
    return a
  }

  function merge(a, b, cmp, resolve) {
    var i = a.length - 1, j = b.length - 1, r = []
    while(~i && ~j) {
      var c = cmp(a[i], b[j])
      if(c > 0) r.push(a[i--])
      if(c < 0) r.push(b[j--])
      if(!c) {
        var R = resolve(a[i], b[j])
          j--, i--
        r.push(R)
      }
    }
    //finish off the list if there are any left over
    while(~i) r.push(a[i--])
    while(~j) r.push(b[j--])
    return r
  }

  _a.sort(cmp)
  _b.sort(cmp)

  return merge(_a, _b, isPrefix, resolve)
}
<commit_msg>this is done my `deref` now<commit_after>
//inject a matchRef, isRef, and a getRef function?
//could use the same pattern with objects.

//I don't really want to force __id__
//should be able to use anything, aslong as you

function shallowEqual (a, b) {
    if(isObject(a)
      && isObject(b)
      && (a.__id__ == b.__id__ || a === b))
      return true
    if(a && !b) return false
    return a == b
  }

function equal (a, b) {
  if(isObject(a) && isObject(b) && (a.__id__ == b.__id__ || a === b))
    return true
  if(a && !b) return false
  if(Array.isArray(a))
    if(a.length != b.length) return false

  if(a && 'object' == typeof a) {
    for(var i in a)
      if(!equal(a[i], b[i])) return false
    return true
  }
  return a == b
}

var adiff = require('adiff')({ equal: equal })

function getPath (obj, path) {
  if(!Array.isArray(path))
    return obj[path]
  for(var i in path) {
    obj = obj[path[i]]
  }
  return obj
}

function findRefs(obj, refs) {
  refs = refs || {}
  //add leaves before branches.
  //this will FAIL if there are circular references.

  if(!obj)
    return refs

  for(var k in obj) {
    if(obj[k] && 'object' == typeof obj[k])
      findRefs(obj[k], refs)
  }

  if(obj.__id__ && !refs[obj.__id__])
    refs[obj.__id__] = obj
  return refs
}

function toRef(v) {
  //TODO escape strings that happen to start with #*=
  var r
  if(r = isRef(v)) return '#*='+r
  return v
}

function isObject (o) {
  return o && 'object' == typeof o
}

function isRef(x) {
  return x ? x.__id__ : undefined
}

function sameRef(a, b) {
  return a && b && isRef(a) == isRef(b)
}

//traverse o, and replace every object with __id__ with a pointer.
//make diffing references easy.

exports.deref = function (o, mutate) {
  var refs = findRefs(o)
  var derefed = {}
  function deref (o, K) {
    if(isRef(o) && K != isRef(o))
      return toRef(o)

    var p = mutate ? o : Array.isArray(o) ? [] : {} //will copy the tree!
    for (var k in o) {
      var r
      if(isRef(o[k])) p[k] = toRef(o[k])
      else if(isObject(o[k])) p[k] = deref(o[k])
      else p[k] = o[k]
    }
    return p
  }

  refs.root = o
  for (var k in refs)
    refs[k] = deref(refs[k], k)
  return refs
}

exports.reref = function (refs, mutate) {

  function fromRef(v) {
    //TODO escape strings that happen to start with #*=
    if('string' == typeof v && /^#\*=/.test(v)) return refs[v.substring(3)]
      return v
  }

  function reref (o) { //will MUTATE the tree
    if(!isObject(o))
      return fromRef(o)

    var p = mutate ? o : Array.isArray(o) ? [] : {} //will copy the tree!
    for (var k in o) {
      if(isObject(o[k]))
         p[k] = reref(o[k])
      else
        p[k] = fromRef(o[k])
    }
    return p
  }
  //if the root is a ref. need a special case
  for (var k in refs) {
    refs[k] = reref(refs[k])
  }
  return refs.root
}

exports.diff = function (a, b) {

  var aRefs = exports.deref(a)
  var bRefs = exports.deref(b)

  var seen = []

  for (var k in aRefs)
    seen.push(k)

 function isSeen(o) {
    if(isRef(o)) return ~seen.indexOf(o.__id__)
    return true
  }
  function addSeen(o) {
    if(!isRef(o)) return o
    if(!isSeen(o)) seen.push(o.__id__)
    return o
  }

  // how to handle references?
  // this is necessary to handle objects in arrays nicely
  // otherwise mergeing an edit and a move is ambigous.  // will need to perform a topoligical sort of the refs and diff them first, in that order.
  // first, apply changes to all refs,
  // then traverse over the root object,

  function _diff (a, b, path) {
    path = path || []

    if(Array.isArray(a) && Array.isArray(b)) {
      var d = adiff.diff(a, b)
      if(d.length) delta.push(['splice', path, d])
      return delta
    }

// references to objects with ids are
// changed into strings of thier id.
// the string is prepended with '#*='
// to distinguish it from other strings
// if you use that string in your model,
// it will break.
// TODO escape strings so this is safe

   //ah, treat root like it's a __id__

   var isRoot = path.length === 1 && path[0] === 'root'

    for (var k in b) {
      // if both are nonRef objects, or are the same object, branch into them.

    if(isObject(a[k]) && isObject(b[k]) && sameRef(b[k], a[k]))
      _diff(a[k], b[k], path.concat(k))
    else if(b[k] !== a[k])
      delta.push(['set', path.concat(k), b[k]])
    }

    for (var k in a)
      if('undefined' == typeof b[k])
        delta.push(['del', path.concat(k)])
  }

  var delta = []
  _diff(aRefs, bRefs, [])

  if(delta.length)
    return delta
}

exports.patch = function (a, patch) {

  if(!patch) throw new Error('expected patch')

  a = cpy(a)
  var refs = exports.deref(a, true)
  refs.root = a

  var methods = {
    set: function (key, value) {
      this[key] = value // incase this was a reference, remove it.
    },
    del: function (key) {
      delete this[key]
    },
    apl: function (key, changes) {
      _patch(this[key], changes)
    },
    splice: function (changes) {
      adiff.patch(this, changes, true)
    },
    sref: function (key, id) {
      this[key] = refs[id]
    }
  }

  function pathTo(a, p) {
    for (var i in p) a = a[p[i]]
    return a
  }

  patch.forEach(function (args) {
    args = args.slice()
    var method = args.shift()
    var path = args.shift().slice()
    var key
    if(method != 'splice') {
      key = path.pop()
      args.unshift(key)
    }
    var obj = pathTo(refs, path)
    methods[method].apply(obj, args)
  })

  return exports.reref(refs, true)
}

function cpy(o) {
  return JSON.parse(JSON.stringify(o))
}

exports.diff3 = function (a, o, b) {
  if(arguments.length == 1)
    o = a[1], b = a[2], a = a[0]
  var _a = exports.diff(o, a)
    , _b = exports.diff(o, b)

  function cmp (a, b) {
    //check if a[1] > b[1]
    if(!b)
      return 1

    var p = a[1], q = b[1]
    var i = 0
    while (p[i] === q[i] && p[i] != null)
      i++

    if(p[i] === q[i]) return 0
    return p[i] < q[i] ? -1 : 1
  }

  function isPrefix(a, b) {
    if(!b) return 1
    var p = a[1], q = b[1]
    var i = 0
    while (p[i] === q[i] && i < p.length && i < q.length)
      i++
    if(i == p.length || i == q.length) return 0
    return p[i] < q[i] ? -1 : 1
  }

  //merge two lists, which must be sorted.

  function cmpSp (a, b) {
    if(a[0] == b[0])
      return 0
    function max(k) {
      return k[0] + (k[1] >= 1 ? k[1] - 1 : 0)
    }
    if(max(a) < b[0] || max(b) < a[0])
      return a[0] - b[0]
    return 0
  }

  function resolveAry(a, b) {
    return a
  }

  function resolve(a, b) {
    if(a[1].length == b[1].length) {
      if(a[0] == b[0]) {
        if(a[0] == 'splice') {
          var R = merge(a[2], b[2], cmpSp, resolveAry)
          return ['splice', a[1].slice(), R]
        } else if(equal(a[2], b[2])) //same change both sides.
          return a
      }
    }
    return a
  }

  function merge(a, b, cmp, resolve) {
    var i = a.length - 1, j = b.length - 1, r = []
    while(~i && ~j) {
      var c = cmp(a[i], b[j])
      if(c > 0) r.push(a[i--])
      if(c < 0) r.push(b[j--])
      if(!c) {
        var R = resolve(a[i], b[j])
          j--, i--
        r.push(R)
      }
    }
    //finish off the list if there are any left over
    while(~i) r.push(a[i--])
    while(~j) r.push(b[j--])
    return r
  }

  _a.sort(cmp)
  _b.sort(cmp)

  return merge(_a, _b, isPrefix, resolve)
}
<|endoftext|>


<commit_before>$(document).ready(function() {

	var date = new Date();
	var d = date.getDate();
	var m = date.getMonth();
	var y = date.getFullYear();

	$('#calendar').fullCalendar({
		header: {
			left: 'prevYear,prev,next,nextYear today',
			center: 'title',
			right: 'month,agendaWeek,agendaDay'

		},
		editable: false,
		defaultView: 'agendaWeek',
		allDaySlot: false,
		allDayDefault: false,
		firstDay: date.getDay(),
		eventBorderColor: 'black',
		windowResize: function(view) {
	        resizeMap();
	    },
		eventClick: function(calEvent, jsEvent, view) {
		  //This function should contain specific stuff like opening the event-based selection/description box etc
		  console.log('Event: ' + calEvent.title + ' & ID: ' + calEvent.id);
		  //$(this).css('background-color','#da4f49');
		},
		eventRender: function(event, element) {
			element.find('.fc-event-title').html(event.title);
		},
		viewRender: function(view, element) {
		 	console.log(view.name);
		},
		viewDisplay: function(view) {
	        try {
	            setTimeline();
	        } catch(err) {}
	    }
	});
	$('#calendar').fullCalendar('addEventSource', 'events/');
	resizeMap();
	$('#leftGroup').prependTo('.fc-header-left');
	$('#rightGroup').appendTo('.fc-header-right');

});

resizeMap = function () {
		var column_height = $(window).height();
		$('#calendar').fullCalendar('option', 'height', column_height - 40);
		//$("#calendar").css("height", + "px")
	};

function setTimeline(view) {
    var parentDiv = jQuery(".fc-agenda-slots:visible").parent();
    var timeline = parentDiv.children(".timeline");
    if (timeline.length == 0) { //if timeline isn't there, add it
        timeline = jQuery("
").addClass("timeline");
        parentDiv.prepend(timeline);
    }

    var curTime = new Date();

    var curCalView = jQuery("#calendar").fullCalendar('getView');
    if (curCalView.visStart < curTime && curCalView.visEnd > curTime) {
        timeline.show();
    } else {
        timeline.hide();
        return;
    }

    var curSeconds = (curTime.getHours() * 60 * 60) + (curTime.getMinutes() * 60) + curTime.getSeconds();
    var percentOfDay = curSeconds / 86400; //24 * 60 * 60 = 86400, # of seconds in a day
    var topLoc = Math.floor(parentDiv.height() * percentOfDay);

    timeline.css("top", topLoc + "px");

    if (curCalView.name == "agendaWeek") { //week view, don't want the timeline to go the whole way across
        var dayCol = jQuery(".fc-today:visible");
        var left = dayCol.position().left + 1;
        var width = dayCol.width()-2;
        timeline.css({
            left: left + "px",
            width: width + "px"
        });
    }

}<commit_msg>feature: lazyFetching efficiency, loads the month events first, then shows the week.<commit_after>$(document).ready(function() {

	var date = new Date();
	var d = date.getDate();
	var m = date.getMonth();
	var y = date.getFullYear();

	$('#calendar').fullCalendar({
		header: {
			left: 'prevYear,prev,next,nextYear today',
			center: 'title',
			right: 'month,agendaWeek,agendaDay'

		},
		editable: false,
		allDaySlot: false,
		allDayDefault: false,
		firstDay: date.getDay(),
		eventBorderColor: 'black',
		windowResize: function(view) {
	        resizeMap();
	    },
		eventClick: function(calEvent, jsEvent, view) {
		  //This function should contain specific stuff like opening the event-based selection/description box etc
		  console.log('Event: ' + calEvent.title + ' & ID: ' + calEvent.id);
		  //$(this).css('background-color','#da4f49');
		},
		eventRender: function(event, element) {
			element.find('.fc-event-title').html(event.title);
		},
		viewRender: function(view, element) {
		 	console.log(view.name);
		},
		viewDisplay: function(view) {
	        try {
	            setTimeline();
	        } catch(err) {}
	    }
	});
	$('#calendar').fullCalendar('addEventSource', 'events/');
	//Important: especially not using defaultView option of FullCalendar, for efficient use of lazyFetching.
	$('#calendar').fullCalendar('changeView', 'agendaWeek');
	//Loads the whole month events, and shows them from memory, instead of a new request for each prev/next click.
	resizeMap();
	$('#leftGroup').prependTo('.fc-header-left');
	$('#rightGroup').appendTo('.fc-header-right');

});

resizeMap = function () {
		var column_height = $(window).height();
		$('#calendar').fullCalendar('option', 'height', column_height - 40);
		//$("#calendar").css("height", + "px")
	};

function setTimeline(view) {
    var parentDiv = jQuery(".fc-agenda-slots:visible").parent();
    var timeline = parentDiv.children(".timeline");
    if (timeline.length == 0) { //if timeline isn't there, add it
        timeline = jQuery("
").addClass("timeline");
        parentDiv.prepend(timeline);
    }

    var curTime = new Date();

    var curCalView = jQuery("#calendar").fullCalendar('getView');
    if (curCalView.visStart < curTime && curCalView.visEnd > curTime) {
        timeline.show();
    } else {
        timeline.hide();
        return;
    }

    var curSeconds = (curTime.getHours() * 60 * 60) + (curTime.getMinutes() * 60) + curTime.getSeconds();
    var percentOfDay = curSeconds / 86400; //24 * 60 * 60 = 86400, # of seconds in a day
    var topLoc = Math.floor(parentDiv.height() * percentOfDay);

    timeline.css("top", topLoc + "px");

    if (curCalView.name == "agendaWeek") { //week view, don't want the timeline to go the whole way across
        var dayCol = jQuery(".fc-today:visible");
        var left = dayCol.position().left + 1;
        var width = dayCol.width()-2;
        timeline.css({
            left: left + "px",
            width: width + "px"
        });
    }

}<|endoftext|>


<commit_before>/* global require, module */
'use strict';

var mergeTrees  = require('broccoli-merge-trees');
var compileCompass = require('broccoli-compass');

function CompassCompilerPlugin(options, appName) {
  this.name    = 'ember-cli-compass-compiler';
  this.appName = appName;
  this.options = options || {};
  this.ext     = 'scss';
}

CompassCompilerPlugin.prototype.toTree = function(tree, inputPath, outputPath) {
  // broccoli-compass doesn't like leading slashes
  if (inputPath[0] === '/') { inputPath = inputPath.slice(1); }

  var options        = this.options;
  var mainFile       = options.mainFile       || (this.appName + '.' + this.ext);
  var outputStyle    = options.outputStyle    || 'compressed'; // or expanded
  var sassDir        = options.sassDir        || inputPath;
  var cssDir         = options.cssDir         || outputPath;
  var imagesDir      = options.imagesDir      || 'images';
  var fontsDir       = options.fontsDir       || 'fonts';
  var compassCommand = options.compassCommand || 'compass';

  var compassOptions = {
    outputStyle: outputStyle,
    require: options.require,
    importPath: options.importPath,
    sassDir: sassDir,
    imagesDir: imagesDir,
    fontsDir: fontsDir,
    cssDir: cssDir,
    compassCommand: compassCommand
  };

  tree = mergeTrees([tree, 'public'], {
    description: 'TreeMerger (stylesAndVendorAndPublic)'
  });

  return compileCompass(tree, inputPath + '/' + mainFile, compassOptions);
};

function EmberCLICompassCompiler(project) {
  this.project = project;
  this.name    = 'Ember CLI Compass Compiler';
}

EmberCLICompassCompiler.prototype.treeFor = function treeFor() {

};

EmberCLICompassCompiler.prototype.included = function included(app) {
  this.app     = app;
  var registry = this.app.registry;
  var plugin   = new CompassCompilerPlugin(this.app.options.compassOptions, this.app.name);
  registry.add('css', plugin);
};

module.exports = EmberCLICompassCompiler;
<commit_msg>Also strip the leading slash from the outputPath.<commit_after>/* global require, module */
'use strict';

var mergeTrees  = require('broccoli-merge-trees');
var compileCompass = require('broccoli-compass');

function CompassCompilerPlugin(options, appName) {
  this.name    = 'ember-cli-compass-compiler';
  this.appName = appName;
  this.options = options || {};
  this.ext     = 'scss';
}

CompassCompilerPlugin.prototype.toTree = function(tree, inputPath, outputPath) {
  // broccoli-compass doesn't like leading slashes
  if (inputPath[0] === '/') { inputPath = inputPath.slice(1); }
  if (outputPath[0] === '/') { outputPath = outputPath.slice(1); }

  var options        = this.options;
  var mainFile       = options.mainFile       || (this.appName + '.' + this.ext);
  var outputStyle    = options.outputStyle    || 'compressed'; // or expanded
  var sassDir        = options.sassDir        || inputPath;
  var cssDir         = options.cssDir         || outputPath;
  var imagesDir      = options.imagesDir      || 'images';
  var fontsDir       = options.fontsDir       || 'fonts';
  var compassCommand = options.compassCommand || 'compass';

  var compassOptions = {
    outputStyle: outputStyle,
    require: options.require,
    importPath: options.importPath,
    sassDir: sassDir,
    imagesDir: imagesDir,
    fontsDir: fontsDir,
    cssDir: cssDir,
    compassCommand: compassCommand
  };

  tree = mergeTrees([tree, 'public'], {
    description: 'TreeMerger (stylesAndVendorAndPublic)'
  });

  return compileCompass(tree, inputPath + '/' + mainFile, compassOptions);
};

function EmberCLICompassCompiler(project) {
  this.project = project;
  this.name    = 'Ember CLI Compass Compiler';
}

EmberCLICompassCompiler.prototype.treeFor = function treeFor() {

};

EmberCLICompassCompiler.prototype.included = function included(app) {
  this.app     = app;
  var registry = this.app.registry;
  var plugin   = new CompassCompilerPlugin(this.app.options.compassOptions, this.app.name);
  registry.add('css', plugin);
};

module.exports = EmberCLICompassCompiler;
<|endoftext|>


<commit_before>var pm = require('bindings')('pm.node'),
	EventEmitter = require('events').EventEmitter;

var notify = new EventEmitter();

pm.registerNotifications(function(msg) {
	notify.emit(msg);
});

notify.startMonitoring = pm.startMonitoring;
notify.stopMonitoring = pm.stopMonitoring;

module.exports = notify;<commit_msg>increase max listeners<commit_after>var pm = require('bindings')('pm.node'),
	EventEmitter = require('events').EventEmitter;

var notify = new EventEmitter();

notify.setMaxListeners(1000);

pm.registerNotifications(function(msg) {
	notify.emit(msg);
});

notify.startMonitoring = pm.startMonitoring;
notify.stopMonitoring = pm.stopMonitoring;

module.exports = notify;<|endoftext|>


<commit_before>#!/usr/bin/env node

const fs = require(`fs`);
const ArgumentParser = require(`argparse`).ArgumentParser;
const ansi = require(`./ansi`);

const argParser = new ArgumentParser({
  version: `2.0.0`,
  description: `The famous Matrix rain effect of falling green characters as a cli command`,
});

[
  {
    flags: [ `-d`, `--direction` ],
    opts: {
      choices: [`h`, `v`],
      defaultValue: `v`,
      help: `Change direction of rain. h=horizontal, v=vertical`,
    },
  },
  {
    flags: [ `-c`, `--color` ],
    opts: {
      choices: [`green`, `red`, `blue`, `yellow`, `magenta`, `cyan`, `white`],
      defaultValue: `green`,
      dest: `color`,
      help: `Rain color. NOTE: droplet start is always white`,
    },
  },
  {
    flags: [ `-k`, `--char-range` ],
    opts: {
      choices: [`ascii`, `binary`, `braille`, `emoji`, `kanji`],
      defaultValue: `ascii`,
      dest: `charRange`,
      help: `Use rain characters from char-range`,
    },
  },
  {
    flags: [ `-f`, `--file-path` ],
    opts: {
      dest: `filePath`,
      help: `Read characters from a file instead of random characters from char-range`,
    },
  },
].forEach(({flags, opts}) => argParser.addArgument(flags, opts));

// Simple string stream buffer + stdout flush at once
let outBuffer = [];
function write(chars) {
  return outBuffer.push(chars);
}

function flush() {
  process.stdout.write(outBuffer.join(``));
  return outBuffer = [];
}

function rand(start, end) {
  return start + Math.floor(Math.random() * (end - start));
}

class MatrixRain {
  constructor(opts) {
    this.transpose = opts.direction === `h`;
    this.color = opts.color;
    this.charRange = opts.charRange;
    this.maxSpeed = 20;
    this.colDroplets = [];
    this.numCols = 0;
    this.numRows = 0;

    // handle reading from file
    if (opts.filePath) {
      if (!fs.existsSync(opts.filePath)) {
        throw new Error(`${opts.filePath} doesn't exist`);
      }
      this.fileChars = fs.readFileSync(opts.filePath, `utf-8`).trim().split(``);
      this.filePos = 0;
      this.charRange = `file`;
    }
  }

  generateChars(len, charRange) {
    // by default charRange == ascii
    let chars = new Array(len);

    if (charRange === `ascii`) {
      for (let i = 0; i < len; i++) {
        chars[i] = String.fromCharCode(rand(0x21, 0x7E));
      }
    } else if (charRange === `braille`) {
      for (let i = 0; i < len; i++) {
        chars[i] = String.fromCharCode(rand(0x2840, 0x28ff));
      }
    } else if (charRange === `kanji`) {
      for (let i = 0; i < len; i++) {
        chars[i] = String.fromCharCode(rand(0x30a0, 0x30ff));
      }
    } else if (charRange === `emoji`) {
      // emojis are two character widths, so use a prefix
      const emojiPrefix = String.fromCharCode(0xd83d);
      for (let i = 0; i < len; i++) {
        chars[i] = emojiPrefix + String.fromCharCode(rand(0xde01, 0xde4a));
      }
    } else if (charRange === `file`) {
      for (let i = 0; i < len; i++, this.filePos++) {
        this.filePos = this.filePos < this.fileChars.length ? this.filePos : 0;
        chars[i] = this.fileChars[this.filePos];
      }
    }

    return chars;
  }

  makeDroplet(col) {
    return {
      col,
      alive: 0,
      curRow: rand(0, this.numRows),
      height: rand(this.numRows / 2, this.numRows),
      speed: rand(1, this.maxSpeed),
      chars: this.generateChars(this.numRows, this.charRange),
    };
  }

  resizeDroplets() {
    [this.numCols, this.numRows] = process.stdout.getWindowSize();

    // transpose for direction
    if (this.transpose) {
      [this.numCols, this.numRows] = [this.numRows, this.numCols];
    }

    // Create droplets per column
    // add/remove droplets to match column size
    if (this.numCols > this.colDroplets.length) {
      for (let col = this.colDroplets.length; col < this.numCols; ++col) {
        // make two droplets per row that start in random positions
        this.colDroplets.push([this.makeDroplet(col), this.makeDroplet(col)]);
      }
    } else {
      this.colDroplets.splice(this.numCols, this.colDroplets.length - this.numCols);
    }
  }

  writeAt(row, col, str, color) {
    // Only output if in viewport
    if (row >=0 && row < this.numRows && col >=0 && col < this.numCols) {
      const pos = this.transpose ? ansi.cursorPos(col, row) : ansi.cursorPos(row, col);
      write(`${pos}${color || ``}${str || ``}`);
    }
  }

  renderFrame() {
    const ansiColor = ansi.colors[`fg${this.color.charAt(0).toUpperCase()}${this.color.substr(1)}`]();

    for (const droplets of this.colDroplets) {
      for (const droplet of droplets) {
        const {curRow, col: curCol, height} = droplet;
        droplet.alive++;

        if (droplet.alive % droplet.speed === 0) {
          this.writeAt(curRow - 1, curCol, droplet.chars[curRow - 1], ansiColor);
          this.writeAt(curRow, curCol, droplet.chars[curRow], ansi.colors.fgWhite());
          this.writeAt(curRow - height, curCol, ` `);
          droplet.curRow++;
        }

        if (curRow - height > this.numRows) {
          // reset droplet
          Object.assign(droplet, this.makeDroplet(droplet.col), {curRow: 0});
        }
      }
    }

    flush();
  }
}

//// main ////

const args = argParser.parseArgs();
const matrixRain = new MatrixRain(args);

function start() {
  // clear terminal and use alt buffer
  process.stdin.setRawMode(true);
  write(ansi.useAltBuffer());
  write(ansi.cursorInvisible());
  write(ansi.colors.bgBlack());
  write(ansi.clearScreen());
  flush();
  matrixRain.resizeDroplets();
}

function stop() {
  write(ansi.cursorVisible());
  write(ansi.clearScreen());
  write(ansi.cursorHome());
  write(ansi.useNormalBuffer());
  flush();
  process.exit();
}

process.on(`SIGINT`, () => stop());
process.stdin.on(`data`, () => stop());
process.stdout.on(`resize`, () => matrixRain.resizeDroplets());
setInterval(() => matrixRain.renderFrame(), 16); // 60FPS

start();
<commit_msg>add tty check<commit_after>#!/usr/bin/env node

const fs = require(`fs`);
const ArgumentParser = require(`argparse`).ArgumentParser;
const ansi = require(`./ansi`);

const argParser = new ArgumentParser({
  version: `2.0.0`,
  description: `The famous Matrix rain effect of falling green characters as a cli command`,
});

[
  {
    flags: [ `-d`, `--direction` ],
    opts: {
      choices: [`h`, `v`],
      defaultValue: `v`,
      help: `Change direction of rain. h=horizontal, v=vertical`,
    },
  },
  {
    flags: [ `-c`, `--color` ],
    opts: {
      choices: [`green`, `red`, `blue`, `yellow`, `magenta`, `cyan`, `white`],
      defaultValue: `green`,
      dest: `color`,
      help: `Rain color. NOTE: droplet start is always white`,
    },
  },
  {
    flags: [ `-k`, `--char-range` ],
    opts: {
      choices: [`ascii`, `binary`, `braille`, `emoji`, `kanji`],
      defaultValue: `ascii`,
      dest: `charRange`,
      help: `Use rain characters from char-range`,
    },
  },
  {
    flags: [ `-f`, `--file-path` ],
    opts: {
      dest: `filePath`,
      help: `Read characters from a file instead of random characters from char-range`,
    },
  },
].forEach(({flags, opts}) => argParser.addArgument(flags, opts));

// Simple string stream buffer + stdout flush at once
let outBuffer = [];
function write(chars) {
  return outBuffer.push(chars);
}

function flush() {
  process.stdout.write(outBuffer.join(``));
  return outBuffer = [];
}

function rand(start, end) {
  return start + Math.floor(Math.random() * (end - start));
}

class MatrixRain {
  constructor(opts) {
    this.transpose = opts.direction === `h`;
    this.color = opts.color;
    this.charRange = opts.charRange;
    this.maxSpeed = 20;
    this.colDroplets = [];
    this.numCols = 0;
    this.numRows = 0;

    // handle reading from file
    if (opts.filePath) {
      if (!fs.existsSync(opts.filePath)) {
        throw new Error(`${opts.filePath} doesn't exist`);
      }
      this.fileChars = fs.readFileSync(opts.filePath, `utf-8`).trim().split(``);
      this.filePos = 0;
      this.charRange = `file`;
    }
  }

  generateChars(len, charRange) {
    // by default charRange == ascii
    let chars = new Array(len);

    if (charRange === `ascii`) {
      for (let i = 0; i < len; i++) {
        chars[i] = String.fromCharCode(rand(0x21, 0x7E));
      }
    } else if (charRange === `braille`) {
      for (let i = 0; i < len; i++) {
        chars[i] = String.fromCharCode(rand(0x2840, 0x28ff));
      }
    } else if (charRange === `kanji`) {
      for (let i = 0; i < len; i++) {
        chars[i] = String.fromCharCode(rand(0x30a0, 0x30ff));
      }
    } else if (charRange === `emoji`) {
      // emojis are two character widths, so use a prefix
      const emojiPrefix = String.fromCharCode(0xd83d);
      for (let i = 0; i < len; i++) {
        chars[i] = emojiPrefix + String.fromCharCode(rand(0xde01, 0xde4a));
      }
    } else if (charRange === `file`) {
      for (let i = 0; i < len; i++, this.filePos++) {
        this.filePos = this.filePos < this.fileChars.length ? this.filePos : 0;
        chars[i] = this.fileChars[this.filePos];
      }
    }

    return chars;
  }

  makeDroplet(col) {
    return {
      col,
      alive: 0,
      curRow: rand(0, this.numRows),
      height: rand(this.numRows / 2, this.numRows),
      speed: rand(1, this.maxSpeed),
      chars: this.generateChars(this.numRows, this.charRange),
    };
  }

  resizeDroplets() {
    [this.numCols, this.numRows] = process.stdout.getWindowSize();

    // transpose for direction
    if (this.transpose) {
      [this.numCols, this.numRows] = [this.numRows, this.numCols];
    }

    // Create droplets per column
    // add/remove droplets to match column size
    if (this.numCols > this.colDroplets.length) {
      for (let col = this.colDroplets.length; col < this.numCols; ++col) {
        // make two droplets per row that start in random positions
        this.colDroplets.push([this.makeDroplet(col), this.makeDroplet(col)]);
      }
    } else {
      this.colDroplets.splice(this.numCols, this.colDroplets.length - this.numCols);
    }
  }

  writeAt(row, col, str, color) {
    // Only output if in viewport
    if (row >=0 && row < this.numRows && col >=0 && col < this.numCols) {
      const pos = this.transpose ? ansi.cursorPos(col, row) : ansi.cursorPos(row, col);
      write(`${pos}${color || ``}${str || ``}`);
    }
  }

  renderFrame() {
    const ansiColor = ansi.colors[`fg${this.color.charAt(0).toUpperCase()}${this.color.substr(1)}`]();

    for (const droplets of this.colDroplets) {
      for (const droplet of droplets) {
        const {curRow, col: curCol, height} = droplet;
        droplet.alive++;

        if (droplet.alive % droplet.speed === 0) {
          this.writeAt(curRow - 1, curCol, droplet.chars[curRow - 1], ansiColor);
          this.writeAt(curRow, curCol, droplet.chars[curRow], ansi.colors.fgWhite());
          this.writeAt(curRow - height, curCol, ` `);
          droplet.curRow++;
        }

        if (curRow - height > this.numRows) {
          // reset droplet
          Object.assign(droplet, this.makeDroplet(droplet.col), {curRow: 0});
        }
      }
    }

    flush();
  }
}

//// main ////

const args = argParser.parseArgs();
const matrixRain = new MatrixRain(args);

function start() {
  if (!process.stdout.isTTY) {
    console.error(`Error: Output is not a text terminal`);
    process.exit(1);
  }

  // clear terminal and use alt buffer
  process.stdin.setRawMode(true);
  write(ansi.useAltBuffer());
  write(ansi.cursorInvisible());
  write(ansi.colors.bgBlack());
  write(ansi.clearScreen());
  flush();
  matrixRain.resizeDroplets();
}

function stop() {
  write(ansi.cursorVisible());
  write(ansi.clearScreen());
  write(ansi.cursorHome());
  write(ansi.useNormalBuffer());
  flush();
  process.exit();
}

process.on(`SIGINT`, () => stop());
process.stdin.on(`data`, () => stop());
process.stdout.on(`resize`, () => matrixRain.resizeDroplets());
setInterval(() => matrixRain.renderFrame(), 16); // 60FPS

start();
<|endoftext|>


<commit_before>'use strict';
const fs = require('fs');
const path = require('path');

const handlebars = require('handlebars');
const mkdirp = require('mkdirp');
const globby = require('globby');
const Promise = require('pinkie-promise');

const QGenError = require('./lib/qgen-error');
const isFileOrDir = require('./lib/file-helpers').isFileOrDir;
const promptIfFileExists = require('./lib/prompt-helpers').promptIfFileExists;
const constants = require('./constants');

const DEFAULT_DESTINATION = './';

const renderTemplate = (src, context) => {
	// Encoding is set as 'utf8' to get the return value as string
	const fileContents = fs.readFileSync(src, 'utf8');

	const hbsTemplate = handlebars.compile(fileContents);

	return hbsTemplate(context);
};

const writeToFile = (filePath, content) => {
	if (isFileOrDir(path.dirname(filePath)) !== 'directory') {
		mkdirp.sync(path.dirname(filePath));
	}
	fs.writeFileSync(filePath, content);
	return Promise.resolve();
};

const renderToFile = (src, dest, config) => {
	const renderedContent = renderTemplate(src, config);
	return writeToFile(dest, renderedContent);
};

const generateFilePathFromConfig = (filePath, options) => {
	let renderedFilePath = filePath;
	const filenameRegex = /__([^_\W]+)__/g;

	renderedFilePath = filePath.replace(filenameRegex, (m, p) => {
		return options[p] ? options[p] : `__${p}__`;
	});

	return renderedFilePath;
};

const getTemplateConfig = (config, templateName) => {
	let templateConfig = config;

	// Process the additional config specific
	// to the given template
	if (config.templates && config.templates[templateName]) {
		const overrides = {
			templates: undefined
		};

		if (config.templates &&
				config.templates[templateName] &&
				config.templates[templateName].dest) {
			overrides.dest = config.templates[templateName].dest;
		}

		if (config.dest !== DEFAULT_DESTINATION) {
			overrides.dest = config.dest;
		}

		templateConfig = Object.assign({}, config.templates[templateName], config, overrides);
	}

	return templateConfig;
};

module.exports = (templateName, destination, options) => {
	const defaultOptions = {
		dest: DEFAULT_DESTINATION,
		cwd: process.cwd(),
		directory: 'qgen-templates',
		config: './qgen.json'
	};

	let configfileOptions = {};
	let configfilePath = path.join(defaultOptions.cwd, defaultOptions.config);
	if (options.config) {
		configfilePath = options.config;
	}
	// Read the configfile if exists
	if (isFileOrDir(configfilePath) === 'file') {
		configfileOptions = require(configfilePath); // eslint-disable-line import/no-dynamic-require
	}

	const config = Object.assign(defaultOptions, configfileOptions, options);

	if (isFileOrDir(config.directory) !== 'directory') {
		return Promise.reject(new QGenError(`qGen templates directory '${config.directory}' not found.`));
	}

	let returnVal;
	const templateRelPath = path.join(config.directory, templateName);

	const file = isFileOrDir(path.join(config.cwd, templateRelPath));

	// Overwrite current config with template specific config
	const templateConfig = getTemplateConfig(config, templateName);

	// Override dest with dest from CLI
	if (destination) {
		templateConfig.dest = destination;
	}

	if (file === 'directory') {
		returnVal = globby(['**/*'], {
			cwd: path.join(config.cwd, templateRelPath),
			nodir: true
		})
			.then(files => {
				let overwriteAllFiles = false;
				const filesCount = files.length;

				const fileObjects = files.map(filePath => {
					const destFilePath = generateFilePathFromConfig(filePath, config);

					return {
						src: path.join(templateConfig.cwd, templateConfig.directory, templateName, filePath),
						dest: path.join(templateConfig.cwd, templateConfig.dest, destFilePath),
						config: templateConfig
					};
				});

				// This recursive is to make the inquirer prompt work
				// in sequential. May be there is a better way to do this.
				function recursivelyProcessFile(i) {
					let _r = Promise.resolve();
					if (i < filesCount) {
						if (overwriteAllFiles) {
							_r = renderToFile(fileObjects[i].src, fileObjects[i].dest, fileObjects[i].config).then(() => {
								return recursivelyProcessFile(i + 1);
							});
						} else {
							_r = promptIfFileExists(fileObjects[i].dest).then(overwrite => {
								if (overwrite === constants.OVERWRITE_ALL) {
									overwriteAllFiles = true;
								}

								if (overwrite === constants.WRITE ||
										overwrite === constants.OVERWRITE ||
										overwriteAllFiles) {
									return renderToFile(fileObjects[i].src, fileObjects[i].dest, fileObjects[i].config).then(() => {
										return recursivelyProcessFile(i + 1);
									});
								}
							});
						}
					}
					return _r;
				}

				return recursivelyProcessFile(0);
			});
	} else if (file === 'file') {
		const srcAbsolutePath = path.join(templateConfig.cwd, templateRelPath);
		const destAbsolutePath = path.join(templateConfig.cwd, templateConfig.dest, templateName);

		returnVal = promptIfFileExists(destAbsolutePath).then(overwrite => {
			let _r;
			if (overwrite === constants.WRITE ||
					overwrite === constants.OVERWRITE ||
					overwrite === constants.OVERWRITE_ALL) {
				_r = renderToFile(srcAbsolutePath, destAbsolutePath, templateConfig);
			} else {
				_r = Promise.reject(new QGenError(constants.ABORT));
			}
			return _r;
		});

		return returnVal;
	} else {
		returnVal = Promise.reject(new QGenError(`Template '${templateRelPath}' not found.`, file.message, file));
	}

	return returnVal;
};
<commit_msg>make globby syncronous<commit_after>'use strict';
const fs = require('fs');
const path = require('path');

const handlebars = require('handlebars');
const mkdirp = require('mkdirp');
const globby = require('globby');
const Promise = require('pinkie-promise');

const QGenError = require('./lib/qgen-error');
const isFileOrDir = require('./lib/file-helpers').isFileOrDir;
const promptIfFileExists = require('./lib/prompt-helpers').promptIfFileExists;
const constants = require('./constants');

const DEFAULT_DESTINATION = './';

const renderTemplate = (src, context) => {
	// Encoding is set as 'utf8' to get the return value as string
	const fileContents = fs.readFileSync(src, 'utf8');

	const hbsTemplate = handlebars.compile(fileContents);

	return hbsTemplate(context);
};

const writeToFile = (filePath, content) => {
	if (isFileOrDir(path.dirname(filePath)) !== 'directory') {
		mkdirp.sync(path.dirname(filePath));
	}
	fs.writeFileSync(filePath, content);
	return Promise.resolve();
};

const renderToFile = (src, dest, config) => {
	const renderedContent = renderTemplate(src, config);
	return writeToFile(dest, renderedContent);
};

const generateFilePathFromConfig = (filePath, options) => {
	let renderedFilePath = filePath;
	const filenameRegex = /__([^_\W]+)__/g;

	renderedFilePath = filePath.replace(filenameRegex, (m, p) => {
		return options[p] ? options[p] : `__${p}__`;
	});

	return renderedFilePath;
};

const getTemplateConfig = (config, templateName) => {
	let templateConfig = config;

	// Process the additional config specific
	// to the given template
	if (config.templates && config.templates[templateName]) {
		const overrides = {
			templates: undefined
		};

		if (config.templates &&
				config.templates[templateName] &&
				config.templates[templateName].dest) {
			overrides.dest = config.templates[templateName].dest;
		}

		if (config.dest !== DEFAULT_DESTINATION) {
			overrides.dest = config.dest;
		}

		templateConfig = Object.assign({}, config.templates[templateName], config, overrides);
	}

	return templateConfig;
};

module.exports = (templateName, destination, options) => {
	const defaultOptions = {
		dest: DEFAULT_DESTINATION,
		cwd: process.cwd(),
		directory: 'qgen-templates',
		config: './qgen.json'
	};

	let configfileOptions = {};
	let configfilePath = path.join(defaultOptions.cwd, defaultOptions.config);
	if (options.config) {
		configfilePath = options.config;
	}
	// Read the configfile if exists
	if (isFileOrDir(configfilePath) === 'file') {
		configfileOptions = require(configfilePath); // eslint-disable-line import/no-dynamic-require
	}

	const config = Object.assign(defaultOptions, configfileOptions, options);

	if (isFileOrDir(config.directory) !== 'directory') {
		return Promise.reject(new QGenError(`qGen templates directory '${config.directory}' not found.`));
	}

	let returnVal;
	const templateRelPath = path.join(config.directory, templateName);

	const file = isFileOrDir(path.join(config.cwd, templateRelPath));

	// Overwrite current config with template specific config
	const templateConfig = getTemplateConfig(config, templateName);

	// Override dest with dest from CLI
	if (destination) {
		templateConfig.dest = destination;
	}

	if (file === 'directory') {
		const files = globby.sync(['**/*'], {
			cwd: path.join(config.cwd, templateRelPath),
			nodir: true
		});

		let overwriteAllFiles = false;
		const filesCount = files.length;

		const fileObjects = files.map(filePath => {
			const destFilePath = generateFilePathFromConfig(filePath, config);

			return {
				src: path.join(templateConfig.cwd, templateConfig.directory, templateName, filePath),
				dest: path.join(templateConfig.cwd, templateConfig.dest, destFilePath),
				config: templateConfig
			};
		});

		// This recursive is to make the inquirer prompt work
		// in sequential. May be there is a better way to do this.
		function recursivelyProcessFile(i) {
			let _r = Promise.resolve();
			if (i < filesCount) {
				if (overwriteAllFiles) {
					_r = renderToFile(fileObjects[i].src, fileObjects[i].dest, fileObjects[i].config).then(() => {
						return recursivelyProcessFile(i + 1);
					});
				} else {
					_r = promptIfFileExists(fileObjects[i].dest).then(overwrite => {
						if (overwrite === constants.OVERWRITE_ALL) {
							overwriteAllFiles = true;
						}

						if (overwrite === constants.WRITE ||
								overwrite === constants.OVERWRITE ||
								overwriteAllFiles) {
							return renderToFile(fileObjects[i].src, fileObjects[i].dest, fileObjects[i].config).then(() => {
								return recursivelyProcessFile(i + 1);
							});
						}
					});
				}
			}
			return _r;
		}

		return recursivelyProcessFile(0);

	} else if (file === 'file') {
		const srcAbsolutePath = path.join(templateConfig.cwd, templateRelPath);
		const destAbsolutePath = path.join(templateConfig.cwd, templateConfig.dest, templateName);

		returnVal = promptIfFileExists(destAbsolutePath).then(overwrite => {
			let _r;
			if (overwrite === constants.WRITE ||
					overwrite === constants.OVERWRITE ||
					overwrite === constants.OVERWRITE_ALL) {
				_r = renderToFile(srcAbsolutePath, destAbsolutePath, templateConfig);
			} else {
				_r = Promise.reject(new QGenError(constants.ABORT));
			}
			return _r;
		});

		return returnVal;
	} else {
		returnVal = Promise.reject(new QGenError(`Template '${templateRelPath}' not found.`, file.message, file));
	}

	return returnVal;
};
<|endoftext|>


<commit_before>/*
 * grunt-webpcss
 * https://github.com/lexich/webpcss-transform
 *
 * Copyright (c) 2014 Efremov Alexey
 * Licensed under the MIT license.
 */
'use strict';

var postcss = require('postcss');
var _ = require('lodash');

function processor (_options){
  var options = _.defaults(_options || {},{
    baseClass: ".webp",
    replace_from: /\.(png|jpg|jpeg)/,
    replace_to: ".webp"
  });
  return function (css){
    var nodes = [];
    css.eachDecl(function(rule, data) {
    if(rule.prop.indexOf("background") === 0 && rule._value.indexOf("url") >= 0 ){
      var selector = "";
      var selectors = rule.parent.selector.split(',');
      for(var index in selectors){
        if(!!selector){ selector += ", "; }
        selector += options.baseClass + " " + selectors[index].trim();
      }
      var rx = options.replace_from;
      if(!_.isRegExp(options.replace_from)){ rx = new RegExp(rx); }
      var value = rule._value.replace(rx,options.replace_to);
      var prop = rule.prop;
      if( value.indexOf(",") === -1 && /url[ ]*\((.+)\)/g.exec(value) ){
        value = "url(" + RegExp.$1 + ");";
        prop = "background-image";
      }
      var new_rule = postcss.rule({selector:selector});
      new_rule.append({
        prop:prop,
        value: value
      });
      nodes.push(new_rule);
    }
    });
    for(var n=0; n < nodes.length; n++){
      css.append(nodes[n]);
    }
  };
}

function transform (data, options){
  return postcss(processor(options)).process(data).css;
}

module.exports.processor = processor;
module.exports.transform = transform;
<commit_msg>fix bug if extention isn't support<commit_after>/*
 * grunt-webpcss
 * https://github.com/lexich/webpcss-transform
 *
 * Copyright (c) 2014 Efremov Alexey
 * Licensed under the MIT license.
 */
'use strict';

var postcss = require('postcss');
var _ = require('lodash');

function processor (_options){
  var options = _.defaults(_options || {},{
    baseClass: ".webp",
    replace_from: /\.(png|jpg|jpeg)/,
    replace_to: ".webp"
  });
  return function (css){
    var nodes = [];
    css.eachDecl(function(rule, data) {
    if(rule.prop.indexOf("background") === 0 && rule._value.indexOf("url") >= 0 ){
      var selector = "";
      var selectors = rule.parent.selector.split(',');
      for(var index in selectors){
        if(!!selector){ selector += ", "; }
        selector += options.baseClass + " " + selectors[index].trim();
      }
      var rx = options.replace_from;
      if(!_.isRegExp(options.replace_from)){ rx = new RegExp(rx); }
      var value = rule._value.replace(rx,options.replace_to);
      if(value === rule.value){ return; }
      var prop = rule.prop;
      if( value.indexOf(",") === -1 && /url[ ]*\((.+)\)/g.exec(value) ){
        value = "url(" + RegExp.$1 + ");";
        prop = "background-image";
      }
      var new_rule = postcss.rule({selector:selector});
      new_rule.append({
        prop:prop,
        value: value
      });
      nodes.push(new_rule);
    }
    });
    for(var n=0; n < nodes.length; n++){
      css.append(nodes[n]);
    }
  };
}

function transform (data, options){
  return postcss(processor(options)).process(data).css;
}

module.exports.processor = processor;
module.exports.transform = transform;
<|endoftext|>


<commit_before>'use strict';
var extend = require('shallow-object-extend');
var isArray = require('isarray');
var isObject = require('isobject');

// Generate unique ID
var generateUniqueNumber = function() {
  var unique = 0;

  return {
    next: function() {
      return ++unique;
    },
    empty: function() {
      unique = 0;
    }
  };
};

var generator = generateUniqueNumber();

// Recursive tree traversal
var traverse = function(options) {
  var result = null;
  var object = options.object;
  var childrenProperty = options.childrenProperty;
  var predicate = options.predicate;
  var modifier = options.modifier;
  var parent = options.parent;

  if (isArray(object)) {
    for (var i = 0; i < object.length; i++) {
      result = traverse({
        object: object[i],
        childrenProperty: childrenProperty,
        predicate: predicate,
        modifier: modifier,
        parent: parent
      });

      if (result) {
        break ;
      }
    }
  }

  if (isObject(object)) {

    if (modifier) {
      object = modifier(object, parent);
    }

    if (predicate(object)) {
      return object;
    }

    if (object[childrenProperty]) {
      result = traverse({
        object: object[childrenProperty],
        childrenProperty: childrenProperty,
        predicate: predicate,
        modifier: modifier,
        parent: object.__id
      });

    }
  }

  return result;
};

var findNode = function(options) {
  var path = [];

  // Assign custom ids to each tree node to identify relationships between
  // nodes later
  var modifier = function(object, parent) {
    object.__id = generator.next();

    if (parent) {
      object.__parent = parent;
    }

    path.push(object);

    return object;
  };

  options = extend({
    // Callback that takes every node and its parent (if node is nested)
    // as arguments. It should return a node.
    modifier: modifier
  }, options);

  var result = traverse(options);

  return { result: result, path: path };
};

var findParentNodes = function(nodes, node) {
  var result = [];

  if (node) {
    result.push(node);
  }

  if (!nodes) {
    return result;
  }

  while (node.__parent) {
    nodes.forEach(function(item) {
      if (item.__id !== node.__parent) {
        return ;
      }
      node = item;
      result.push(node);
    });
  }

  return result;
};

/**
 * ancestors
 * Recursively find and return a nested node and all its ancestors (parents)
 * from a tree
 *
 * @name ancestors
 * @function
 * @param {Object} options An object containing the following fields:
 *
 *  - `data` (Array): An array of data
 *  - `childrenProperty` (String): A name of a property that contains nested
 * nodes. Default: 'children'
 *  - `predicate` (Function): Filter criteria
 *
 * @return {Array} Matched node and its ancestors
 */

module.exports = function ancestors(options) {
  options = extend({
    childrenProperty: 'children'
  }, options);

  if (!isArray(options.data)) {
    throw new TypeError('Expected array');
  }

  generator.empty();

  var searchResults = findNode({
    object: options.data,
    childrenProperty: options.childrenProperty,
    predicate: options.predicate
  });

  return findParentNodes(searchResults.path, searchResults.result);
};
<commit_msg>Fix infinite loop problem<commit_after>'use strict';
var extend = require('shallow-object-extend');
var isArray = require('isarray');
var isObject = require('isobject');

// Generate unique ID
var generateUniqueNumber = function() {
  var unique = 0;

  return {
    next: function() {
      return ++unique;
    },
    empty: function() {
      unique = 0;
    }
  };
};

var generator = generateUniqueNumber();

// Recursive tree traversal
var traverse = function(options) {
  var result = null;
  var object = options.object;
  var childrenProperty = options.childrenProperty;
  var predicate = options.predicate;
  var modifier = options.modifier;
  var parent = options.parent;

  if (isArray(object)) {
    for (var i = 0; i < object.length; i++) {
      result = traverse({
        object: object[i],
        childrenProperty: childrenProperty,
        predicate: predicate,
        modifier: modifier,
        parent: parent
      });

      if (result) {
        break ;
      }
    }
  }

  if (isObject(object)) {

    if (modifier) {
      object = modifier(object, parent);
    }

    if (predicate(object)) {
      return object;
    }

    if (object[childrenProperty]) {
      result = traverse({
        object: object[childrenProperty],
        childrenProperty: childrenProperty,
        predicate: predicate,
        modifier: modifier,
        parent: object.__id
      });

    }
  }

  return result;
};

var findNode = function(options) {
  var path = [];

  // Assign custom ids to each tree node to identify relationships between
  // nodes later
  var modifier = function(object, parent) {
    object.__id = generator.next();

    if (parent) {
      object.__parent = parent;
    }

    // Every node during tree traversal is being added to an array
    // It helps to represent tree structure as a plain list (since each node
    // has own unique id and pointer to a parent node) and find parent using
    // iteration instead of recursion
    path.push(object);

    return object;
  };

  options = extend({
    // Callback that takes every node and its parent (if node is nested)
    // as arguments. It should return a node.
    modifier: modifier
  }, options);

  var result = traverse(options);

  return { result: result, path: path };
};

// Take
var findParentNodes = function(nodes, node) {
  var result = [];

  if (node) {
    result.push(node);
  }

  if (!nodes) {
    return result;
  }

  while (node.__parent) {
    var matchedNode;

    nodes.forEach(function(item) {
      if (item.__id !== node.__parent) {
        return ;
      }

      node = matchedNode = item;
      result.push(node);
    });

    if (!matchedNode) {
      break ;
    }
  }

  return result;
};

/**
 * ancestors
 * Recursively find and return a nested node and all its ancestors (parents)
 * from a tree
 *
 * @name ancestors
 * @function
 * @param {Object} options An object containing the following fields:
 *
 *  - `data` (Array): An array of data
 *  - `childrenProperty` (String): A name of a property that contains nested
 * nodes. Default: 'children'
 *  - `predicate` (Function): Filter criteria
 *
 * @return {Array} Matched node and its ancestors
 */

module.exports = function ancestors(options) {
  options = extend({
    childrenProperty: 'children'
  }, options);

  if (!isArray(options.data)) {
    throw new TypeError('Expected array');
  }

  generator.empty();

  var searchResults = findNode({
    object: options.data,
    childrenProperty: options.childrenProperty,
    predicate: options.predicate
  });

  return findParentNodes(searchResults.path, searchResults.result);
};
<|endoftext|>


<commit_before>import {CompositeDisposable, Disposable} from 'event-kit';

import path from 'path';

import React from 'react';
import ReactDom from 'react-dom';
import {autobind} from 'core-decorators';

import {mkdirs} from './helpers';
import WorkdirCache from './models/workdir-cache';
import WorkdirContext, {absentWorkdirContext} from './models/workdir-context';
import WorkdirContextPool from './models/workdir-context-pool';
import Repository from './models/repository';
import StyleCalculator from './models/style-calculator';
import RootController from './controllers/root-controller';
import IssueishPaneItem from './atom-items/issueish-pane-item';
import StubItem from './atom-items/stub-item';
import Switchboard from './switchboard';
import yardstick from './yardstick';
import GitTimingsView from './views/git-timings-view';
import AsyncQueue from './async-queue';

const defaultState = {
  firstRun: true,
  resolutionProgressByPath: {},
};

export default class GithubPackage {
  constructor(workspace, project, commandRegistry, notificationManager, tooltips, styles, config,
      confirm, getLoadSettings) {
    this.workspace = workspace;
    this.project = project;
    this.commandRegistry = commandRegistry;
    this.notificationManager = notificationManager;
    this.tooltips = tooltips;
    this.config = config;
    this.styles = styles;

    this.styleCalculator = new StyleCalculator(this.styles, this.config);
    this.confirm = confirm;
    this.useLegacyPanels = false;

    const criteria = {
      projectPathCount: this.project.getPaths().length,
      initPathCount: (getLoadSettings().initialPaths || []).length,
    };

    this.activeContextQueue = new AsyncQueue();
    this.activeContext = WorkdirContext.guess(criteria);
    this.workdirCache = new WorkdirCache();
    this.contextPool = new WorkdirContextPool({
      window,
      workspace,
      promptCallback: query => this.controller.promptForCredentials(query),
    });

    this.switchboard = new Switchboard();

    // Handle events from all resident contexts.
    this.subscriptions = new CompositeDisposable(
      this.contextPool.onDidChangeWorkdirOrHead(context => {
        this.refreshAtomGitRepository(context.getWorkingDirectory());
      }),
      this.contextPool.onDidUpdateRepository(context => {
        this.switchboard.didUpdateRepository(context.getRepository());
      }),
      this.contextPool.onDidDestroyRepository(context => {
        if (context === this.activeContext) {
          this.setActiveContext(absentWorkdirContext);
        }
      }),
    );

    this.setupYardstick();
  }

  setupYardstick() {
    const stagingSeries = ['stageLine', 'stageHunk', 'unstageLine', 'unstageHunk'];

    this.subscriptions.add(
      // Staging and unstaging operations
      this.switchboard.onDidBeginStageOperation(payload => {
        if (payload.stage && payload.line) {
          yardstick.begin('stageLine');
        } else if (payload.stage && payload.hunk) {
          yardstick.begin('stageHunk');
        } else if (payload.unstage && payload.line) {
          yardstick.begin('unstageLine');
        } else if (payload.unstage && payload.hunk) {
          yardstick.begin('unstageHunk');
        }
      }),
      this.switchboard.onDidUpdateRepository(() => {
        yardstick.mark(stagingSeries, 'update-repository');
      }),
      this.switchboard.onDidFinishRender(context => {
        if (context === 'RootController.showFilePatchForPath') {
          yardstick.finish(stagingSeries);
        }
      }),

      // Active context changes
      this.switchboard.onDidScheduleActiveContextUpdate(() => {
        yardstick.begin('activeContextChange');
      }),
      this.switchboard.onDidBeginActiveContextUpdate(() => {
        yardstick.mark('activeContextChange', 'queue-wait');
      }),
      this.switchboard.onDidFinishContextChangeRender(() => {
        yardstick.mark('activeContextChange', 'render');
      }),
      this.switchboard.onDidFinishActiveContextUpdate(() => {
        yardstick.finish('activeContextChange');
      }),
    );
  }

  activate(state = {}) {
    this.savedState = {...defaultState, ...state};

    if (!this.workspace.getLeftDock || this.config.get('github.useLegacyPanels')) {
      this.useLegacyPanels = true;
    }

    this.subscriptions.add(
      atom.config.onDidChange('github.useLegacyPanels', ({newValue}) => {
        if (newValue) {
          this.useLegacyPanels = true;
        } else {
          // Only use new docks if they exist
          this.useLegacyPanels = !this.workspace.getLeftDock;
        }

        this.rerender();
      }),
      this.project.onDidChangePaths(this.scheduleActiveContextUpdate),
      this.workspace.onDidChangeActivePaneItem(this.scheduleActiveContextUpdate),
      this.styleCalculator.startWatching(
        'github-package-styles',
        ['editor.fontSize', 'editor.fontFamily', 'editor.lineHeight'],
        config => `
          .github-FilePatchView {
            font-size: 1.1em;
          }

          .github-HunkView-line {
            font-size: ${config.get('editor.fontSize')}px;
            font-family: ${config.get('editor.fontFamily')};
            line-height: ${config.get('editor.lineHeight')};
          }
        `,
      ),
      this.workspace.addOpener(uri => {
        if (uri === 'atom-github://debug/timings') {
          return this.createGitTimingsView();
        } else {
          return null;
        }
      }),
      this.workspace.addOpener(IssueishPaneItem.opener),
    );

    this.scheduleActiveContextUpdate(this.savedState);
    this.rerender();
  }

  serialize() {
    const activeRepository = this.getActiveRepository();
    const activeRepositoryPath = activeRepository ? activeRepository.getWorkingDirectoryPath() : null;

    return {
      activeRepositoryPath,
      gitController: this.controller.serialize(),
      firstRun: false,
    };
  }

  @autobind
  rerender(callback) {
    if (this.workspace.isDestroyed()) {
      return;
    }

    if (!this.element) {
      this.element = document.createElement('div');
      this.subscriptions.add(new Disposable(() => {
        try {
          ReactDom.unmountComponentAtNode(this.element);
        } catch (err) {
          /* eslint-disable no-console */
          console.error('Could not unmount RootController; DOM node did not contain a React app. Error was:');
          console.error(err);
          /* eslint-enable no-console */
        }
        delete this.element;
      }));
    }

    ReactDom.render(
      <RootController
        ref={c => { this.controller = c; }}
        workspace={this.workspace}
        commandRegistry={this.commandRegistry}
        notificationManager={this.notificationManager}
        tooltips={this.tooltips}
        config={this.config}
        confirm={this.confirm}
        activeWorkingDirectory={this.getActiveWorkdir()}
        repository={this.getActiveRepository()}
        resolutionProgress={this.getActiveResolutionProgress()}
        statusBar={this.statusBar}
        savedState={this.savedState.gitController}
        createRepositoryForProjectPath={this.createRepositoryForProjectPath}
        cloneRepositoryForProjectPath={this.cloneRepositoryForProjectPath}
        switchboard={this.switchboard}
        useLegacyPanels={this.useLegacyPanels}
        firstRun={this.savedState.firstRun}
      />, this.element, callback,
    );
  }

  async deactivate() {
    this.subscriptions.dispose();
    this.contextPool.clear();
    await yardstick.flush();
  }

  @autobind
  consumeStatusBar(statusBar) {
    this.statusBar = statusBar;
    this.rerender();
  }

  @autobind
  createGitTimingsView() {
    return GitTimingsView.createPaneItem();
  }

  @autobind
  createIssueishPaneItem({uri}) {
    return IssueishPaneItem.opener(uri);
  }

  @autobind
  createGitTabControllerStub() {
    return StubItem.create('git-tab-controller', {
      title: 'Git',
    });
  }

  @autobind
  createGithubTabControllerStub() {
    return StubItem.create('github-tab-controller', {
      title: 'GitHub (alpha)',
    });
  }

  @autobind
  async createRepositoryForProjectPath(projectPath) {
    await mkdirs(projectPath);

    const repository = this.contextPool.add(projectPath).getRepository();
    await repository.init();
    this.workdirCache.invalidate(projectPath);

    if (!this.project.contains(projectPath)) {
      this.project.addPath(projectPath);
    }

    await this.scheduleActiveContextUpdate();
  }

  @autobind
  async cloneRepositoryForProjectPath(remoteUrl, projectPath) {
    const context = this.contextPool.getContext(projectPath);
    const repository = context.isPresent() ? context.getRepository() : new Repository(projectPath);

    await repository.clone(remoteUrl);
    this.workdirCache.invalidate(projectPath);

    this.project.addPath(projectPath);

    await this.scheduleActiveContextUpdate();
  }

  getActiveWorkdir() {
    return this.activeContext.getWorkingDirectory();
  }

  getActiveRepository() {
    return this.activeContext.getRepository();
  }

  getActiveResolutionProgress() {
    return this.activeContext.getResolutionProgress();
  }

  getContextPool() {
    return this.contextPool;
  }

  getSwitchboard() {
    return this.switchboard;
  }

  @autobind
  async scheduleActiveContextUpdate(savedState = {}) {
    this.switchboard.didScheduleActiveContextUpdate();
    await this.activeContextQueue.push(this.updateActiveContext.bind(this, savedState), {parallel: false});
  }

  /**
   * Derive the git working directory context that should be used for the package's git operations based on the current
   * state of the Atom workspace. In priority, this prefers:
   *
   * - A git working directory that contains the active pane item.
   * - A git working directory corresponding to a single Project.
   * - When initially activating the package, the working directory that was active when the package was last
   *   serialized.
   * - The current context, unchanged, which may be a `NullWorkdirContext`.
   *
   * First updates the pool of resident contexts to match all git working directories that correspond to open
   * projects and pane items.
   */
  async getNextContext(savedState) {
    const workdirs = new Set(
      await Promise.all(
        this.project.getPaths().map(async projectPath => {
          const workdir = await this.workdirCache.find(projectPath);
          return workdir || projectPath;
        }),
      ),
    );

    const activeItemPath = pathForPaneItem(this.workspace.getActivePaneItem());
    let activeItemWorkdir = null;
    if (activeItemPath) {
      activeItemWorkdir = await this.workdirCache.find(activeItemPath);
    }

    if (activeItemWorkdir && !this.project.contains(activeItemPath)) {
      workdirs.add(activeItemWorkdir);
    }

    this.contextPool.set(workdirs, savedState);

    if (activeItemPath) {
      // Prefer an active item
      return this.contextPool.getContext(activeItemWorkdir || activeItemPath);
    }

    if (this.project.getPaths().length === 1) {
      // Single project
      const projectPath = this.project.getPaths()[0];
      const activeWorkingDir = await this.workdirCache.find(projectPath);
      return this.contextPool.getContext(activeWorkingDir || projectPath);
    }

    if (this.project.getPaths().length === 0 && !this.activeContext.getRepository().isUndetermined()) {
      // No projects. Revert to the absent context unless we've guessed that more projects are on the way.
      return absentWorkdirContext;
    }

    // Restore models from saved state. Will return a NullWorkdirContext if this path is not presently
    // resident in the pool.
    const savedWorkingDir = savedState.activeRepositoryPath;
    if (savedWorkingDir) {
      return this.contextPool.getContext(savedWorkingDir);
    }

    return this.activeContext;
  }

  setActiveContext(nextActiveContext) {
    if (nextActiveContext !== this.activeContext) {
      this.activeContext = nextActiveContext;
      this.rerender(() => {
        this.switchboard.didFinishContextChangeRender();
        this.switchboard.didFinishActiveContextUpdate();
      });
    } else {
      this.switchboard.didFinishActiveContextUpdate();
    }
  }

  async updateActiveContext(savedState = {}) {
    if (this.workspace.isDestroyed()) {
      return;
    }

    this.switchboard.didBeginActiveContextUpdate();

    const nextActiveContext = await this.getNextContext(savedState);
    this.setActiveContext(nextActiveContext);
  }

  refreshAtomGitRepository(workdir) {
    const atomGitRepo = this.project.getRepositories().find(repo => {
      return repo && path.normalize(repo.getWorkingDirectory()) === workdir;
    });
    return atomGitRepo ? atomGitRepo.refreshStatus() : Promise.resolve();
  }
}

function pathForPaneItem(paneItem) {
  if (!paneItem) {
    return null;
  }

  // Likely GitHub package provided pane item
  if (typeof paneItem.getWorkingDirectory === 'function') {
    return paneItem.getWorkingDirectory();
  }

  // TextEditor-like
  if (typeof paneItem.getPath === 'function') {
    return paneItem.getPath();
  }

  // Oh well
  return null;
}
<commit_msg>:fire: unnecessary try/catch<commit_after>import {CompositeDisposable, Disposable} from 'event-kit';

import path from 'path';

import React from 'react';
import ReactDom from 'react-dom';
import {autobind} from 'core-decorators';

import {mkdirs} from './helpers';
import WorkdirCache from './models/workdir-cache';
import WorkdirContext, {absentWorkdirContext} from './models/workdir-context';
import WorkdirContextPool from './models/workdir-context-pool';
import Repository from './models/repository';
import StyleCalculator from './models/style-calculator';
import RootController from './controllers/root-controller';
import IssueishPaneItem from './atom-items/issueish-pane-item';
import StubItem from './atom-items/stub-item';
import Switchboard from './switchboard';
import yardstick from './yardstick';
import GitTimingsView from './views/git-timings-view';
import AsyncQueue from './async-queue';

const defaultState = {
  firstRun: true,
  resolutionProgressByPath: {},
};

export default class GithubPackage {
  constructor(workspace, project, commandRegistry, notificationManager, tooltips, styles, config,
      confirm, getLoadSettings) {
    this.workspace = workspace;
    this.project = project;
    this.commandRegistry = commandRegistry;
    this.notificationManager = notificationManager;
    this.tooltips = tooltips;
    this.config = config;
    this.styles = styles;

    this.styleCalculator = new StyleCalculator(this.styles, this.config);
    this.confirm = confirm;
    this.useLegacyPanels = false;

    const criteria = {
      projectPathCount: this.project.getPaths().length,
      initPathCount: (getLoadSettings().initialPaths || []).length,
    };

    this.activeContextQueue = new AsyncQueue();
    this.activeContext = WorkdirContext.guess(criteria);
    this.workdirCache = new WorkdirCache();
    this.contextPool = new WorkdirContextPool({
      window,
      workspace,
      promptCallback: query => this.controller.promptForCredentials(query),
    });

    this.switchboard = new Switchboard();

    // Handle events from all resident contexts.
    this.subscriptions = new CompositeDisposable(
      this.contextPool.onDidChangeWorkdirOrHead(context => {
        this.refreshAtomGitRepository(context.getWorkingDirectory());
      }),
      this.contextPool.onDidUpdateRepository(context => {
        this.switchboard.didUpdateRepository(context.getRepository());
      }),
      this.contextPool.onDidDestroyRepository(context => {
        if (context === this.activeContext) {
          this.setActiveContext(absentWorkdirContext);
        }
      }),
    );

    this.setupYardstick();
  }

  setupYardstick() {
    const stagingSeries = ['stageLine', 'stageHunk', 'unstageLine', 'unstageHunk'];

    this.subscriptions.add(
      // Staging and unstaging operations
      this.switchboard.onDidBeginStageOperation(payload => {
        if (payload.stage && payload.line) {
          yardstick.begin('stageLine');
        } else if (payload.stage && payload.hunk) {
          yardstick.begin('stageHunk');
        } else if (payload.unstage && payload.line) {
          yardstick.begin('unstageLine');
        } else if (payload.unstage && payload.hunk) {
          yardstick.begin('unstageHunk');
        }
      }),
      this.switchboard.onDidUpdateRepository(() => {
        yardstick.mark(stagingSeries, 'update-repository');
      }),
      this.switchboard.onDidFinishRender(context => {
        if (context === 'RootController.showFilePatchForPath') {
          yardstick.finish(stagingSeries);
        }
      }),

      // Active context changes
      this.switchboard.onDidScheduleActiveContextUpdate(() => {
        yardstick.begin('activeContextChange');
      }),
      this.switchboard.onDidBeginActiveContextUpdate(() => {
        yardstick.mark('activeContextChange', 'queue-wait');
      }),
      this.switchboard.onDidFinishContextChangeRender(() => {
        yardstick.mark('activeContextChange', 'render');
      }),
      this.switchboard.onDidFinishActiveContextUpdate(() => {
        yardstick.finish('activeContextChange');
      }),
    );
  }

  activate(state = {}) {
    this.savedState = {...defaultState, ...state};

    if (!this.workspace.getLeftDock || this.config.get('github.useLegacyPanels')) {
      this.useLegacyPanels = true;
    }

    this.subscriptions.add(
      atom.config.onDidChange('github.useLegacyPanels', ({newValue}) => {
        if (newValue) {
          this.useLegacyPanels = true;
        } else {
          // Only use new docks if they exist
          this.useLegacyPanels = !this.workspace.getLeftDock;
        }

        this.rerender();
      }),
      this.project.onDidChangePaths(this.scheduleActiveContextUpdate),
      this.workspace.onDidChangeActivePaneItem(this.scheduleActiveContextUpdate),
      this.styleCalculator.startWatching(
        'github-package-styles',
        ['editor.fontSize', 'editor.fontFamily', 'editor.lineHeight'],
        config => `
          .github-FilePatchView {
            font-size: 1.1em;
          }

          .github-HunkView-line {
            font-size: ${config.get('editor.fontSize')}px;
            font-family: ${config.get('editor.fontFamily')};
            line-height: ${config.get('editor.lineHeight')};
          }
        `,
      ),
      this.workspace.addOpener(uri => {
        if (uri === 'atom-github://debug/timings') {
          return this.createGitTimingsView();
        } else {
          return null;
        }
      }),
      this.workspace.addOpener(IssueishPaneItem.opener),
    );

    this.scheduleActiveContextUpdate(this.savedState);
    this.rerender();
  }

  serialize() {
    const activeRepository = this.getActiveRepository();
    const activeRepositoryPath = activeRepository ? activeRepository.getWorkingDirectoryPath() : null;

    return {
      activeRepositoryPath,
      gitController: this.controller.serialize(),
      firstRun: false,
    };
  }

  @autobind
  rerender(callback) {
    if (this.workspace.isDestroyed()) {
      return;
    }

    if (!this.element) {
      this.element = document.createElement('div');
      this.subscriptions.add(new Disposable(() => {
        ReactDom.unmountComponentAtNode(this.element);
        delete this.element;
      }));
    }

    ReactDom.render(
      <RootController
        ref={c => { this.controller = c; }}
        workspace={this.workspace}
        commandRegistry={this.commandRegistry}
        notificationManager={this.notificationManager}
        tooltips={this.tooltips}
        config={this.config}
        confirm={this.confirm}
        activeWorkingDirectory={this.getActiveWorkdir()}
        repository={this.getActiveRepository()}
        resolutionProgress={this.getActiveResolutionProgress()}
        statusBar={this.statusBar}
        savedState={this.savedState.gitController}
        createRepositoryForProjectPath={this.createRepositoryForProjectPath}
        cloneRepositoryForProjectPath={this.cloneRepositoryForProjectPath}
        switchboard={this.switchboard}
        useLegacyPanels={this.useLegacyPanels}
        firstRun={this.savedState.firstRun}
      />, this.element, callback,
    );
  }

  async deactivate() {
    this.subscriptions.dispose();
    this.contextPool.clear();
    await yardstick.flush();
  }

  @autobind
  consumeStatusBar(statusBar) {
    this.statusBar = statusBar;
    this.rerender();
  }

  @autobind
  createGitTimingsView() {
    return GitTimingsView.createPaneItem();
  }

  @autobind
  createIssueishPaneItem({uri}) {
    return IssueishPaneItem.opener(uri);
  }

  @autobind
  createGitTabControllerStub() {
    return StubItem.create('git-tab-controller', {
      title: 'Git',
    });
  }

  @autobind
  createGithubTabControllerStub() {
    return StubItem.create('github-tab-controller', {
      title: 'GitHub (alpha)',
    });
  }

  @autobind
  async createRepositoryForProjectPath(projectPath) {
    await mkdirs(projectPath);

    const repository = this.contextPool.add(projectPath).getRepository();
    await repository.init();
    this.workdirCache.invalidate(projectPath);

    if (!this.project.contains(projectPath)) {
      this.project.addPath(projectPath);
    }

    await this.scheduleActiveContextUpdate();
  }

  @autobind
  async cloneRepositoryForProjectPath(remoteUrl, projectPath) {
    const context = this.contextPool.getContext(projectPath);
    const repository = context.isPresent() ? context.getRepository() : new Repository(projectPath);

    await repository.clone(remoteUrl);
    this.workdirCache.invalidate(projectPath);

    this.project.addPath(projectPath);

    await this.scheduleActiveContextUpdate();
  }

  getActiveWorkdir() {
    return this.activeContext.getWorkingDirectory();
  }

  getActiveRepository() {
    return this.activeContext.getRepository();
  }

  getActiveResolutionProgress() {
    return this.activeContext.getResolutionProgress();
  }

  getContextPool() {
    return this.contextPool;
  }

  getSwitchboard() {
    return this.switchboard;
  }

  @autobind
  async scheduleActiveContextUpdate(savedState = {}) {
    this.switchboard.didScheduleActiveContextUpdate();
    await this.activeContextQueue.push(this.updateActiveContext.bind(this, savedState), {parallel: false});
  }

  /**
   * Derive the git working directory context that should be used for the package's git operations based on the current
   * state of the Atom workspace. In priority, this prefers:
   *
   * - A git working directory that contains the active pane item.
   * - A git working directory corresponding to a single Project.
   * - When initially activating the package, the working directory that was active when the package was last
   *   serialized.
   * - The current context, unchanged, which may be a `NullWorkdirContext`.
   *
   * First updates the pool of resident contexts to match all git working directories that correspond to open
   * projects and pane items.
   */
  async getNextContext(savedState) {
    const workdirs = new Set(
      await Promise.all(
        this.project.getPaths().map(async projectPath => {
          const workdir = await this.workdirCache.find(projectPath);
          return workdir || projectPath;
        }),
      ),
    );

    const activeItemPath = pathForPaneItem(this.workspace.getActivePaneItem());
    let activeItemWorkdir = null;
    if (activeItemPath) {
      activeItemWorkdir = await this.workdirCache.find(activeItemPath);
    }

    if (activeItemWorkdir && !this.project.contains(activeItemPath)) {
      workdirs.add(activeItemWorkdir);
    }

    this.contextPool.set(workdirs, savedState);

    if (activeItemPath) {
      // Prefer an active item
      return this.contextPool.getContext(activeItemWorkdir || activeItemPath);
    }

    if (this.project.getPaths().length === 1) {
      // Single project
      const projectPath = this.project.getPaths()[0];
      const activeWorkingDir = await this.workdirCache.find(projectPath);
      return this.contextPool.getContext(activeWorkingDir || projectPath);
    }

    if (this.project.getPaths().length === 0 && !this.activeContext.getRepository().isUndetermined()) {
      // No projects. Revert to the absent context unless we've guessed that more projects are on the way.
      return absentWorkdirContext;
    }

    // Restore models from saved state. Will return a NullWorkdirContext if this path is not presently
    // resident in the pool.
    const savedWorkingDir = savedState.activeRepositoryPath;
    if (savedWorkingDir) {
      return this.contextPool.getContext(savedWorkingDir);
    }

    return this.activeContext;
  }

  setActiveContext(nextActiveContext) {
    if (nextActiveContext !== this.activeContext) {
      this.activeContext = nextActiveContext;
      this.rerender(() => {
        this.switchboard.didFinishContextChangeRender();
        this.switchboard.didFinishActiveContextUpdate();
      });
    } else {
      this.switchboard.didFinishActiveContextUpdate();
    }
  }

  async updateActiveContext(savedState = {}) {
    if (this.workspace.isDestroyed()) {
      return;
    }

    this.switchboard.didBeginActiveContextUpdate();

    const nextActiveContext = await this.getNextContext(savedState);
    this.setActiveContext(nextActiveContext);
  }

  refreshAtomGitRepository(workdir) {
    const atomGitRepo = this.project.getRepositories().find(repo => {
      return repo && path.normalize(repo.getWorkingDirectory()) === workdir;
    });
    return atomGitRepo ? atomGitRepo.refreshStatus() : Promise.resolve();
  }
}

function pathForPaneItem(paneItem) {
  if (!paneItem) {
    return null;
  }

  // Likely GitHub package provided pane item
  if (typeof paneItem.getWorkingDirectory === 'function') {
    return paneItem.getWorkingDirectory();
  }

  // TextEditor-like
  if (typeof paneItem.getPath === 'function') {
    return paneItem.getPath();
  }

  // Oh well
  return null;
}
<|endoftext|>


<commit_before>/**
 * @memberof Marbles
 * @mixin
 * @desc Manages a state object. You must define `state` {Object} and `__changeListeners` {Array} on the object this is mixed into.
 */
var State = {
	/**
	 * @method
	 * @param {function} handler Function to call when the state object changes
	 */
	addChangeListener: function (handler) {
		this.__changeListeners.push(handler);
	},

	/**
	 * @method
	 * @param {function} handler
	 * @desc Prevents handler from being called for future changes
	 */
	removeChangeListener: function (handler) {
		this.__changeListeners = this.__changeListeners.filter(function (fn) {
			return fn !== handler;
		});
	},

	/**
	 * @method
	 * @param {Object} newState
	 * @desc Copies properties of newState to the existing state object
	 */
	setState: function (newState) {
		this.willUpdate();
		var state = this.state;
		Object.keys(newState).forEach(function (key) {
			state[key] = newState[key];
		});
		this.handleChange();
		this.didUpdate();
	},

	/**
	 * @method
	 * @param {Object} newState
	 * @desc Replaces the existing state object with newState
	 */
	replaceState: function (newState) {
		this.willUpdate();
		this.state = newState;
		this.handleChange();
		this.didUpdate();
	},

	handleChange: function () {
		this.__changeListeners.forEach(function (handler) {
			handler();
		});
	},

	/**
	 * @method
	 * @desc Called before state object is mutated
	 */
	willUpdate: function () {},

	/**
	 * @method
	 * @desc Called after state object is mutated
	 */
	didUpdate: function () {}
};

export default State;
<commit_msg>state: Refactor<commit_after>/**
 * @memberof Marbles
 * @mixin
 * @desc Manages a state object. You must define `state` {Object} and `__changeListeners` {Array} on the object this is mixed into.
 */
var State = {
	/**
	 * @method
	 * @param {function} handler Function to call when the state object changes
	 */
	addChangeListener: function (handler) {
		this.__changeListeners.push(handler);
	},

	/**
	 * @method
	 * @param {function} handler
	 * @desc Prevents handler from being called for future changes
	 */
	removeChangeListener: function (handler) {
		this.__changeListeners = this.__changeListeners.filter(function (fn) {
			return fn !== handler;
		});
	},

	/**
	 * @method
	 * @param {function} changeFn
	 * @desc Calls `willUpdate`, the passed in function, `handleChange`, then `didUpdate`
	 */
	withChange: function (changeFn) {
		this.willUpdate();
		changeFn.call(this);
		this.handleChange();
		this.didUpdate();
	},

	/**
	 * @method
	 * @param {Object} newState
	 * @desc Copies properties of newState to the existing state object
	 */
	setState: function (newState) {
		this.withChange(function () {
			var state = this.state;
			Object.keys(newState).forEach(function (key) {
				state[key] = newState[key];
			});
		});
	},

	/**
	 * @method
	 * @param {Object} newState
	 * @desc Replaces the existing state object with newState
	 */
	replaceState: function (newState) {
		this.withChange(function () {
			this.state = newState;
		});
	},

	handleChange: function () {
		this.__changeListeners.forEach(function (handler) {
			handler();
		});
	},

	/**
	 * @method
	 * @desc Called before state object is mutated
	 */
	willUpdate: function () {},

	/**
	 * @method
	 * @desc Called after state object is mutated
	 */
	didUpdate: function () {}
};

export default State;
<|endoftext|>


<commit_before>/*
 * grunt
 * https://github.com/cowboy/grunt
 *
 * Copyright (c) 2012 "Cowboy" Ben Alman
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 */

var grunt = require('../grunt');
var template = module.exports = {};

var dateformat = require('dateformat');

// Miscellanous template helpers

template.today = function(format) {
  return dateformat(new Date(), format);
};

template.stripBanner = function(src) {
  return src.replace(/^\s*\/\*[^!][\s\S]*?\*\/\s*/, '');
};

// Set underscore template delimiters.
template.delimiters = function(mode) {
  var modes = {
    // The underscore default template syntax should be a pretty sane default.
    default: {
      // Used by grunt.
      opener:       '<%',
      // Used by underscore.
      evaluate:     /<%([\s\S]+?)%>/g,
      interpolate:  /<%=([\s\S]+?)%>/g,
      escape:       /<%-([\s\S]+?)%>/g
    },
    // The "init" task needs separate delimiters to avoid conflicts, so the <>
    // are replaced with {}. Otherwise, they behave the same.
    init: {
      // Used by grunt.
      opener:       '{%',
      // Used by underscore.
      evaluate:     /\{%([\s\S]+?)%\}/g,
      interpolate:  /\{%=([\s\S]+?)%\}/g,
      escape:       /\{%-([\s\S]+?)%\}/g
    }
  };
  var settings = modes[mode in modes ? mode : 'default'];
  grunt.utils._.templateSettings = settings;
  // Get opener character for grunt to use.
  var opener = settings.opener;
  // Remove it from the underscore object and return it.
  delete settings.opener;
  return opener;
};

// Process template + data with underscore.
template.process = function(template, data, mode) {
  // Set delimiters, and get a opening match character.
  var opener = grunt.template.delimiters(mode);
  // Initialize data to config data if omitted.
  if (!data) { data = grunt.config() || {}; }
  // Add a reference to grunt onto the data object.
  data.grunt = grunt;
  // As long as template contains template tags, render it and get the result,
  // otherwise just use the template string.
  try {
    while (template.indexOf(opener) >= 0) {
      template = grunt.utils._.template(template)(data);
    }
  } catch (e) {
    grunt.fail.warn('An error occurred while processing a template (' + e.message + ').');
  }
  // Normalize linefeeds and return.
  return grunt.utils.normalizelf(template);
};
<commit_msg>Avoid mutating passed-in data object.<commit_after>/*
 * grunt
 * https://github.com/cowboy/grunt
 *
 * Copyright (c) 2012 "Cowboy" Ben Alman
 * Licensed under the MIT license.
 * http://benalman.com/about/license/
 */

var grunt = require('../grunt');
var template = module.exports = {};

var dateformat = require('dateformat');

// Miscellanous template helpers

template.today = function(format) {
  return dateformat(new Date(), format);
};

template.stripBanner = function(src) {
  return src.replace(/^\s*\/\*[^!][\s\S]*?\*\/\s*/, '');
};

// Set underscore template delimiters.
template.delimiters = function(mode) {
  var modes = {
    // The underscore default template syntax should be a pretty sane default.
    default: {
      // Used by grunt.
      opener:       '<%',
      // Used by underscore.
      evaluate:     /<%([\s\S]+?)%>/g,
      interpolate:  /<%=([\s\S]+?)%>/g,
      escape:       /<%-([\s\S]+?)%>/g
    },
    // The "init" task needs separate delimiters to avoid conflicts, so the <>
    // are replaced with {}. Otherwise, they behave the same.
    init: {
      // Used by grunt.
      opener:       '{%',
      // Used by underscore.
      evaluate:     /\{%([\s\S]+?)%\}/g,
      interpolate:  /\{%=([\s\S]+?)%\}/g,
      escape:       /\{%-([\s\S]+?)%\}/g
    }
  };
  var settings = modes[mode in modes ? mode : 'default'];
  grunt.utils._.templateSettings = settings;
  // Get opener character for grunt to use.
  var opener = settings.opener;
  // Remove it from the underscore object and return it.
  delete settings.opener;
  return opener;
};

// Process template + data with underscore.
template.process = function(template, data, mode) {
  // Set delimiters, and get a opening match character.
  var opener = grunt.template.delimiters(mode);
  // Clone data, initializing to config data or empty object if omitted.
  data = Object.create(data || grunt.config() || {});
  // Add a reference to grunt so grunt-stuff can be accessed.
  data.grunt = grunt;
  try {
    // As long as template contains template tags, render it and get the result,
    // otherwise just use the template string.
    while (template.indexOf(opener) >= 0) {
      template = grunt.utils._.template(template)(data);
    }
  } catch (e) {
    grunt.fail.warn('An error occurred while processing a template (' + e.message + ').');
  }
  // Normalize linefeeds and return.
  return grunt.utils.normalizelf(template);
};
<|endoftext|>