(function(){var require = function (file, cwd) { var resolved = require.resolve(file, cwd || '/'); var mod = require.modules[resolved]; if (!mod) throw new Error( 'Failed to resolve module ' + file + ', tried ' + resolved ); var cached = require.cache[resolved]; var res = cached? cached.exports : mod(); return res; }; require.paths = []; require.modules = {}; require.cache = {}; require.extensions = [".js",".coffee",".json"]; require._core = { 'assert': true, 'events': true, 'fs': true, 'path': true, 'vm': true }; require.resolve = (function () { return function (x, cwd) { if (!cwd) cwd = '/'; if (require._core[x]) return x; var path = require.modules.path(); cwd = path.resolve('/', cwd); var y = cwd || '/'; if (x.match(/^(?:\.\.?\/|\/)/)) { var m = loadAsFileSync(path.resolve(y, x)) || loadAsDirectorySync(path.resolve(y, x)); if (m) return m; } var n = loadNodeModulesSync(x, y); if (n) return n; throw new Error("Cannot find module '" + x + "'"); function loadAsFileSync (x) { x = path.normalize(x); if (require.modules[x]) { return x; } for (var i = 0; i < require.extensions.length; i++) { var ext = require.extensions[i]; if (require.modules[x + ext]) return x + ext; } } function loadAsDirectorySync (x) { x = x.replace(/\/+$/, ''); var pkgfile = path.normalize(x + '/package.json'); if (require.modules[pkgfile]) { var pkg = require.modules[pkgfile](); var b = pkg.browserify; if (typeof b === 'object' && b.main) { var m = loadAsFileSync(path.resolve(x, b.main)); if (m) return m; } else if (typeof b === 'string') { var m = loadAsFileSync(path.resolve(x, b)); if (m) return m; } else if (pkg.main) { var m = loadAsFileSync(path.resolve(x, pkg.main)); if (m) return m; } } return loadAsFileSync(x + '/index'); } function loadNodeModulesSync (x, start) { var dirs = nodeModulesPathsSync(start); for (var i = 0; i < dirs.length; i++) { var dir = dirs[i]; var m = loadAsFileSync(dir + '/' + x); if (m) return m; var n = loadAsDirectorySync(dir + '/' + x); if (n) return n; } var m = loadAsFileSync(x); if (m) return m; } function nodeModulesPathsSync (start) { var parts; if (start === '/') parts = [ '' ]; else parts = path.normalize(start).split('/'); var dirs = []; for (var i = parts.length - 1; i >= 0; i--) { if (parts[i] === 'node_modules') continue; var dir = parts.slice(0, i + 1).join('/') + '/node_modules'; dirs.push(dir); } return dirs; } }; })(); require.alias = function (from, to) { var path = require.modules.path(); var res = null; try { res = require.resolve(from + '/package.json', '/'); } catch (err) { res = require.resolve(from, '/'); } var basedir = path.dirname(res); var keys = (Object.keys || function (obj) { var res = []; for (var key in obj) res.push(key); return res; })(require.modules); for (var i = 0; i < keys.length; i++) { var key = keys[i]; if (key.slice(0, basedir.length + 1) === basedir + '/') { var f = key.slice(basedir.length); require.modules[to + f] = require.modules[basedir + f]; } else if (key === basedir) { require.modules[to] = require.modules[basedir]; } } }; (function () { var process = {}; var global = typeof window !== 'undefined' ? window : {}; var definedProcess = false; require.define = function (filename, fn) { if (!definedProcess && require.modules.__browserify_process) { process = require.modules.__browserify_process(); definedProcess = true; } var dirname = require._core[filename] ? '' : require.modules.path().dirname(filename) ; var require_ = function (file) { var requiredModule = require(file, dirname); var cached = require.cache[require.resolve(file, dirname)]; if (cached && cached.parent === null) { cached.parent = module_; } return requiredModule; }; require_.resolve = function (name) { return require.resolve(name, dirname); }; require_.modules = require.modules; require_.define = require.define; require_.cache = require.cache; var module_ = { id : filename, filename: filename, exports : {}, loaded : false, parent: null }; require.modules[filename] = function () { require.cache[filename] = module_; fn.call( module_.exports, require_, module_, module_.exports, dirname, filename, process, global ); module_.loaded = true; return module_.exports; }; }; })(); require.define("path",function(require,module,exports,__dirname,__filename,process,global){function filter (xs, fn) { var res = []; for (var i = 0; i < xs.length; i++) { if (fn(xs[i], i, xs)) res.push(xs[i]); } return res; } // resolves . and .. elements in a path array with directory names there // must be no slashes, empty elements, or device names (c:\) in the array // (so also no leading and trailing slashes - it does not distinguish // relative and absolute paths) function normalizeArray(parts, allowAboveRoot) { // if the path tries to go above the root, `up` ends up > 0 var up = 0; for (var i = parts.length; i >= 0; i--) { var last = parts[i]; if (last == '.') { parts.splice(i, 1); } else if (last === '..') { parts.splice(i, 1); up++; } else if (up) { parts.splice(i, 1); up--; } } // if the path is allowed to go above the root, restore leading ..s if (allowAboveRoot) { for (; up--; up) { parts.unshift('..'); } } return parts; } // Regex to split a filename into [*, dir, basename, ext] // posix version var splitPathRe = /^(.+\/(?!$)|\/)?((?:.+?)?(\.[^.]*)?)$/; // path.resolve([from ...], to) // posix version exports.resolve = function() { var resolvedPath = '', resolvedAbsolute = false; for (var i = arguments.length; i >= -1 && !resolvedAbsolute; i--) { var path = (i >= 0) ? arguments[i] : process.cwd(); // Skip empty and invalid entries if (typeof path !== 'string' || !path) { continue; } resolvedPath = path + '/' + resolvedPath; resolvedAbsolute = path.charAt(0) === '/'; } // At this point the path should be resolved to a full absolute path, but // handle relative paths to be safe (might happen when process.cwd() fails) // Normalize the path resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { return !!p; }), !resolvedAbsolute).join('/'); return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; }; // path.normalize(path) // posix version exports.normalize = function(path) { var isAbsolute = path.charAt(0) === '/', trailingSlash = path.slice(-1) === '/'; // Normalize the path path = normalizeArray(filter(path.split('/'), function(p) { return !!p; }), !isAbsolute).join('/'); if (!path && !isAbsolute) { path = '.'; } if (path && trailingSlash) { path += '/'; } return (isAbsolute ? '/' : '') + path; }; // posix version exports.join = function() { var paths = Array.prototype.slice.call(arguments, 0); return exports.normalize(filter(paths, function(p, index) { return p && typeof p === 'string'; }).join('/')); }; exports.dirname = function(path) { var dir = splitPathRe.exec(path)[1] || ''; var isWindows = false; if (!dir) { // No dirname return '.'; } else if (dir.length === 1 || (isWindows && dir.length <= 3 && dir.charAt(1) === ':')) { // It is just a slash or a drive letter with a slash return dir; } else { // It is a full dirname, strip trailing slash return dir.substring(0, dir.length - 1); } }; exports.basename = function(path, ext) { var f = splitPathRe.exec(path)[2] || ''; // TODO: make this comparison case-insensitive on windows? if (ext && f.substr(-1 * ext.length) === ext) { f = f.substr(0, f.length - ext.length); } return f; }; exports.extname = function(path) { return splitPathRe.exec(path)[3] || ''; }; }); require.define("__browserify_process",function(require,module,exports,__dirname,__filename,process,global){var process = module.exports = {}; process.nextTick = (function () { var canSetImmediate = typeof window !== 'undefined' && window.setImmediate; var canPost = typeof window !== 'undefined' && window.postMessage && window.addEventListener ; if (canSetImmediate) { return function (f) { return window.setImmediate(f) }; } if (canPost) { var queue = []; window.addEventListener('message', function (ev) { if (ev.source === window && ev.data === 'browserify-tick') { ev.stopPropagation(); if (queue.length > 0) { var fn = queue.shift(); fn(); } } }, true); return function nextTick(fn) { queue.push(fn); window.postMessage('browserify-tick', '*'); }; } return function nextTick(fn) { setTimeout(fn, 0); }; })(); process.title = 'browser'; process.browser = true; process.env = {}; process.argv = []; process.binding = function (name) { if (name === 'evals') return (require)('vm') else throw new Error('No such module. (Possibly not yet loaded)') }; (function () { var cwd = '/'; var path; process.cwd = function () { return cwd }; process.chdir = function (dir) { if (!path) path = require('path'); cwd = path.resolve(dir, cwd); }; })(); }); require.define("/animationFactory.js",function(require,module,exports,__dirname,__filename,process,global){/****************** * This class is responsible for a lot of the heavy lifting around creating an animation at a certain state in time. * The tricky thing is that when a new commit has to be "born," say in the middle of a rebase * or something, it must animate out from the parent position to it's birth position. * These two positions though may not be where the commit finally ends up. So we actually need to take a snapshot of the tree, * store all those positions, take a snapshot of the tree after a layout refresh afterwards, and then animate between those two spots. * and then essentially animate the entire tree too. */ // essentially a static class function AnimationFactory() { } AnimationFactory.prototype.genCommitBirthAnimation = function(animationQueue, commit, gitVisuals) { if (!animationQueue) { throw new Error("Need animation queue to add closure to!"); } var time = GRAPHICS.defaultAnimationTime * 1.0; var bounceTime = time * 2; // essentially refresh the entire tree, but do a special thing for the commit var visNode = commit.get('visNode'); var animation = function() { // this takes care of refs and all that jazz, and updates all the positions gitVisuals.refreshTree(time); visNode.setBirth(); visNode.parentInFront(); gitVisuals.visBranchesFront(); visNode.animateUpdatedPosition(bounceTime, 'bounce'); visNode.animateOutgoingEdges(time); }; animationQueue.add(new Animation({ closure: animation, duration: Math.max(time, bounceTime) })); }; AnimationFactory.prototype.overrideOpacityDepth2 = function(attr, opacity) { opacity = (opacity === undefined) ? 1 : opacity; var newAttr = {}; _.each(attr, function(partObj, partName) { newAttr[partName] = {}; _.each(partObj, function(val, key) { if (key == 'opacity') { newAttr[partName][key] = opacity; } else { newAttr[partName][key] = val; } }); }); return newAttr; }; AnimationFactory.prototype.overrideOpacityDepth3 = function(snapShot, opacity) { var newSnap = {}; _.each(snapShot, function(visObj, visID) { newSnap[visID] = this.overrideOpacityDepth2(visObj, opacity); }, this); return newSnap; }; AnimationFactory.prototype.genCommitBirthClosureFromSnapshot = function(step, gitVisuals) { var time = GRAPHICS.defaultAnimationTime * 1.0; var bounceTime = time * 1.5; var visNode = step.newCommit.get('visNode'); var afterAttrWithOpacity = this.overrideOpacityDepth2(step.afterSnapshot[visNode.getID()]); var afterSnapWithOpacity = this.overrideOpacityDepth3(step.afterSnapshot); var animation = function() { visNode.setBirthFromSnapshot(step.beforeSnapshot); visNode.parentInFront(); gitVisuals.visBranchesFront(); visNode.animateToAttr(afterAttrWithOpacity, bounceTime, 'bounce'); visNode.animateOutgoingEdgesToAttr(afterSnapWithOpacity, bounceTime); }; return animation; }; AnimationFactory.prototype.refreshTree = function(animationQueue, gitVisuals) { animationQueue.add(new Animation({ closure: function() { gitVisuals.refreshTree(); } })); }; AnimationFactory.prototype.rebaseAnimation = function(animationQueue, rebaseResponse, gitEngine, gitVisuals) { this.rebaseHighlightPart(animationQueue, rebaseResponse, gitEngine); this.rebaseBirthPart(animationQueue, rebaseResponse, gitEngine, gitVisuals); }; AnimationFactory.prototype.rebaseHighlightPart = function(animationQueue, rebaseResponse, gitEngine) { var fullTime = GRAPHICS.defaultAnimationTime * 0.66; var slowTime = fullTime * 2.0; // we want to highlight all the old commits var oldCommits = rebaseResponse.toRebaseArray; // we are either highlighting to a visBranch or a visNode var visBranch = rebaseResponse.destinationBranch.get('visBranch'); if (!visBranch) { // in the case where we rebase onto a commit visBranch = rebaseResponse.destinationBranch.get('visNode'); } _.each(oldCommits, function(oldCommit) { var visNode = oldCommit.get('visNode'); animationQueue.add(new Animation({ closure: function() { visNode.highlightTo(visBranch, slowTime, 'easeInOut'); }, duration: fullTime * 1.5 })); }, this); this.delay(animationQueue, fullTime * 2); }; AnimationFactory.prototype.rebaseBirthPart = function(animationQueue, rebaseResponse, gitEngine, gitVisuals) { var rebaseSteps = rebaseResponse.rebaseSteps; var newVisNodes = []; _.each(rebaseSteps, function(step) { var visNode = step.newCommit.get('visNode'); newVisNodes.push(visNode); visNode.setOpacity(0); visNode.setOutgoingEdgesOpacity(0); }, this); var previousVisNodes = []; _.each(rebaseSteps, function(rebaseStep, index) { var toOmit = newVisNodes.slice(index + 1); var snapshotPart = this.genFromToSnapshotAnimation( rebaseStep.beforeSnapshot, rebaseStep.afterSnapshot, toOmit, previousVisNodes, gitVisuals ); var birthPart = this.genCommitBirthClosureFromSnapshot(rebaseStep, gitVisuals); var animation = function() { snapshotPart(); birthPart(); }; animationQueue.add(new Animation({ closure: animation, duration: GRAPHICS.defaultAnimationTime * 1.5 })); previousVisNodes.push(rebaseStep.newCommit.get('visNode')); }, this); // need to delay to let bouncing finish this.delay(animationQueue); this.refreshTree(animationQueue, gitVisuals); }; AnimationFactory.prototype.delay = function(animationQueue, time) { time = time || GRAPHICS.defaultAnimationTime; animationQueue.add(new Animation({ closure: function() { }, duration: time })); }; AnimationFactory.prototype.genSetAllCommitOpacities = function(visNodes, opacity) { // need to slice for closure var nodesToAnimate = visNodes.slice(0); return function() { _.each(nodesToAnimate, function(visNode) { visNode.setOpacity(opacity); visNode.setOutgoingEdgesOpacity(opacity); }); }; }; AnimationFactory.prototype.stripObjectsFromSnapshot = function(snapShot, toOmit) { var ids = []; _.each(toOmit, function(obj) { ids.push(obj.getID()); }); var newSnapshot = {}; _.each(snapShot, function(val, key) { if (_.include(ids, key)) { // omit return; } newSnapshot[key] = val; }, this); return newSnapshot; }; AnimationFactory.prototype.genFromToSnapshotAnimation = function( beforeSnapshot, afterSnapshot, commitsToOmit, commitsToFixOpacity, gitVisuals) { // we want to omit the commit outgoing edges var toOmit = []; _.each(commitsToOmit, function(visNode) { toOmit.push(visNode); toOmit = toOmit.concat(visNode.get('outgoingEdges')); }); var fixOpacity = function(obj) { if (!obj) { return; } _.each(obj, function(attr, partName) { obj[partName].opacity = 1; }); }; // HORRIBLE loop to fix opacities all throughout the snapshot _.each([beforeSnapshot, afterSnapshot], function(snapShot) { _.each(commitsToFixOpacity, function(visNode) { fixOpacity(snapShot[visNode.getID()]); _.each(visNode.get('outgoingEdges'), function(visEdge) { fixOpacity(snapShot[visEdge.getID()]); }); }); }); return function() { gitVisuals.animateAllFromAttrToAttr(beforeSnapshot, afterSnapshot, toOmit); }; }; exports.AnimationFactory = AnimationFactory; }); require.define("/main.js",function(require,module,exports,__dirname,__filename,process,global){var AnimationFactory = require('./animationFactory').AnimationFactory; /** * Globals */ var events = _.clone(Backbone.Events); var ui = null; var animationFactory = null; /** * Static Classes */ animationFactory = new AnimationFactory(); /////////////////////////////////////////////////////////////////////// $(document).ready(function(){ ui = new UI(); mainVis = new Visualization({ el: $('#canvasWrapper')[0] }); if (/\?demo/.test(window.location.href)) { setTimeout(function() { events.trigger('submitCommandValueFromEvent', "gc; git checkout HEAD~1; git commit; git checkout -b bugFix; gc; gc; git rebase master; git checkout master; gc; gc; git merge bugFix"); }, 500); } }); function UI() { // static classes this.commandCollection = new CommandCollection(); this.commandBuffer = new CommandBuffer({ collection: this.commandCollection }); this.commandPromptView = new CommandPromptView({ el: $('#commandLineBar'), collection: this.commandCollection }); this.commandLineHistoryView = new CommandLineHistoryView({ el: $('#commandLineHistory'), collection: this.commandCollection }); $('#commandTextField').focus(); } exports.events = events; exports.ui = ui; exports.animationFactory = animationFactory; }); require("/main.js"); require.define("/animationFactory.js",function(require,module,exports,__dirname,__filename,process,global){/****************** * This class is responsible for a lot of the heavy lifting around creating an animation at a certain state in time. * The tricky thing is that when a new commit has to be "born," say in the middle of a rebase * or something, it must animate out from the parent position to it's birth position. * These two positions though may not be where the commit finally ends up. So we actually need to take a snapshot of the tree, * store all those positions, take a snapshot of the tree after a layout refresh afterwards, and then animate between those two spots. * and then essentially animate the entire tree too. */ // essentially a static class function AnimationFactory() { } AnimationFactory.prototype.genCommitBirthAnimation = function(animationQueue, commit, gitVisuals) { if (!animationQueue) { throw new Error("Need animation queue to add closure to!"); } var time = GRAPHICS.defaultAnimationTime * 1.0; var bounceTime = time * 2; // essentially refresh the entire tree, but do a special thing for the commit var visNode = commit.get('visNode'); var animation = function() { // this takes care of refs and all that jazz, and updates all the positions gitVisuals.refreshTree(time); visNode.setBirth(); visNode.parentInFront(); gitVisuals.visBranchesFront(); visNode.animateUpdatedPosition(bounceTime, 'bounce'); visNode.animateOutgoingEdges(time); }; animationQueue.add(new Animation({ closure: animation, duration: Math.max(time, bounceTime) })); }; AnimationFactory.prototype.overrideOpacityDepth2 = function(attr, opacity) { opacity = (opacity === undefined) ? 1 : opacity; var newAttr = {}; _.each(attr, function(partObj, partName) { newAttr[partName] = {}; _.each(partObj, function(val, key) { if (key == 'opacity') { newAttr[partName][key] = opacity; } else { newAttr[partName][key] = val; } }); }); return newAttr; }; AnimationFactory.prototype.overrideOpacityDepth3 = function(snapShot, opacity) { var newSnap = {}; _.each(snapShot, function(visObj, visID) { newSnap[visID] = this.overrideOpacityDepth2(visObj, opacity); }, this); return newSnap; }; AnimationFactory.prototype.genCommitBirthClosureFromSnapshot = function(step, gitVisuals) { var time = GRAPHICS.defaultAnimationTime * 1.0; var bounceTime = time * 1.5; var visNode = step.newCommit.get('visNode'); var afterAttrWithOpacity = this.overrideOpacityDepth2(step.afterSnapshot[visNode.getID()]); var afterSnapWithOpacity = this.overrideOpacityDepth3(step.afterSnapshot); var animation = function() { visNode.setBirthFromSnapshot(step.beforeSnapshot); visNode.parentInFront(); gitVisuals.visBranchesFront(); visNode.animateToAttr(afterAttrWithOpacity, bounceTime, 'bounce'); visNode.animateOutgoingEdgesToAttr(afterSnapWithOpacity, bounceTime); }; return animation; }; AnimationFactory.prototype.refreshTree = function(animationQueue, gitVisuals) { animationQueue.add(new Animation({ closure: function() { gitVisuals.refreshTree(); } })); }; AnimationFactory.prototype.rebaseAnimation = function(animationQueue, rebaseResponse, gitEngine, gitVisuals) { this.rebaseHighlightPart(animationQueue, rebaseResponse, gitEngine); this.rebaseBirthPart(animationQueue, rebaseResponse, gitEngine, gitVisuals); }; AnimationFactory.prototype.rebaseHighlightPart = function(animationQueue, rebaseResponse, gitEngine) { var fullTime = GRAPHICS.defaultAnimationTime * 0.66; var slowTime = fullTime * 2.0; // we want to highlight all the old commits var oldCommits = rebaseResponse.toRebaseArray; // we are either highlighting to a visBranch or a visNode var visBranch = rebaseResponse.destinationBranch.get('visBranch'); if (!visBranch) { // in the case where we rebase onto a commit visBranch = rebaseResponse.destinationBranch.get('visNode'); } _.each(oldCommits, function(oldCommit) { var visNode = oldCommit.get('visNode'); animationQueue.add(new Animation({ closure: function() { visNode.highlightTo(visBranch, slowTime, 'easeInOut'); }, duration: fullTime * 1.5 })); }, this); this.delay(animationQueue, fullTime * 2); }; AnimationFactory.prototype.rebaseBirthPart = function(animationQueue, rebaseResponse, gitEngine, gitVisuals) { var rebaseSteps = rebaseResponse.rebaseSteps; var newVisNodes = []; _.each(rebaseSteps, function(step) { var visNode = step.newCommit.get('visNode'); newVisNodes.push(visNode); visNode.setOpacity(0); visNode.setOutgoingEdgesOpacity(0); }, this); var previousVisNodes = []; _.each(rebaseSteps, function(rebaseStep, index) { var toOmit = newVisNodes.slice(index + 1); var snapshotPart = this.genFromToSnapshotAnimation( rebaseStep.beforeSnapshot, rebaseStep.afterSnapshot, toOmit, previousVisNodes, gitVisuals ); var birthPart = this.genCommitBirthClosureFromSnapshot(rebaseStep, gitVisuals); var animation = function() { snapshotPart(); birthPart(); }; animationQueue.add(new Animation({ closure: animation, duration: GRAPHICS.defaultAnimationTime * 1.5 })); previousVisNodes.push(rebaseStep.newCommit.get('visNode')); }, this); // need to delay to let bouncing finish this.delay(animationQueue); this.refreshTree(animationQueue, gitVisuals); }; AnimationFactory.prototype.delay = function(animationQueue, time) { time = time || GRAPHICS.defaultAnimationTime; animationQueue.add(new Animation({ closure: function() { }, duration: time })); }; AnimationFactory.prototype.genSetAllCommitOpacities = function(visNodes, opacity) { // need to slice for closure var nodesToAnimate = visNodes.slice(0); return function() { _.each(nodesToAnimate, function(visNode) { visNode.setOpacity(opacity); visNode.setOutgoingEdgesOpacity(opacity); }); }; }; AnimationFactory.prototype.stripObjectsFromSnapshot = function(snapShot, toOmit) { var ids = []; _.each(toOmit, function(obj) { ids.push(obj.getID()); }); var newSnapshot = {}; _.each(snapShot, function(val, key) { if (_.include(ids, key)) { // omit return; } newSnapshot[key] = val; }, this); return newSnapshot; }; AnimationFactory.prototype.genFromToSnapshotAnimation = function( beforeSnapshot, afterSnapshot, commitsToOmit, commitsToFixOpacity, gitVisuals) { // we want to omit the commit outgoing edges var toOmit = []; _.each(commitsToOmit, function(visNode) { toOmit.push(visNode); toOmit = toOmit.concat(visNode.get('outgoingEdges')); }); var fixOpacity = function(obj) { if (!obj) { return; } _.each(obj, function(attr, partName) { obj[partName].opacity = 1; }); }; // HORRIBLE loop to fix opacities all throughout the snapshot _.each([beforeSnapshot, afterSnapshot], function(snapShot) { _.each(commitsToFixOpacity, function(visNode) { fixOpacity(snapShot[visNode.getID()]); _.each(visNode.get('outgoingEdges'), function(visEdge) { fixOpacity(snapShot[visEdge.getID()]); }); }); }); return function() { gitVisuals.animateAllFromAttrToAttr(beforeSnapshot, afterSnapshot, toOmit); }; }; exports.AnimationFactory = AnimationFactory; }); require("/animationFactory.js"); })();