aboutsummaryrefslogtreecommitdiffstats
path: root/git_deps/html
diff options
context:
space:
mode:
Diffstat (limited to 'git_deps/html')
-rw-r--r--git_deps/html/.gitignore2
-rw-r--r--git_deps/html/css/animate.css3158
-rw-r--r--git_deps/html/css/git-deps-tips.css79
-rw-r--r--git_deps/html/css/git-deps.css93
-rw-r--r--git_deps/html/git-deps.html41
-rw-r--r--git_deps/html/js/.gitignore1
-rw-r--r--git_deps/html/js/fullscreen.js48
-rw-r--r--git_deps/html/js/git-deps-data.coffee108
-rw-r--r--git_deps/html/js/git-deps-graph.coffee595
-rw-r--r--git_deps/html/js/git-deps-layout.coffee253
-rw-r--r--git_deps/html/js/git-deps-noty.coffee32
-rw-r--r--git_deps/html/package.json54
-rw-r--r--git_deps/html/test.json442
-rw-r--r--git_deps/html/tip-template.html11
14 files changed, 4917 insertions, 0 deletions
diff --git a/git_deps/html/.gitignore b/git_deps/html/.gitignore
new file mode 100644
index 0000000..68b9e27
--- /dev/null
+++ b/git_deps/html/.gitignore
@@ -0,0 +1,2 @@
+node_modules/
+bower_components/
diff --git a/git_deps/html/css/animate.css b/git_deps/html/css/animate.css
new file mode 100644
index 0000000..f784ce8
--- /dev/null
+++ b/git_deps/html/css/animate.css
@@ -0,0 +1,3158 @@
+@charset "UTF-8";
+/*!
+Animate.css - http://daneden.me/animate
+Licensed under the MIT license - http://opensource.org/licenses/MIT
+
+Copyright (c) 2014 Daniel Eden
+*/
+
+.animated {
+ -webkit-animation-duration: 1s;
+ animation-duration: 1s;
+ -webkit-animation-fill-mode: both;
+ animation-fill-mode: both;
+}
+
+.animated.infinite {
+ -webkit-animation-iteration-count: infinite;
+ animation-iteration-count: infinite;
+}
+
+.animated.hinge {
+ -webkit-animation-duration: 2s;
+ animation-duration: 2s;
+}
+
+@-webkit-keyframes bounce {
+ 0%, 20%, 53%, 80%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ -webkit-transform: translate3d(0,0,0);
+ transform: translate3d(0,0,0);
+ }
+
+ 40%, 43% {
+ -webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ -webkit-transform: translate3d(0, -30px, 0);
+ transform: translate3d(0, -30px, 0);
+ }
+
+ 70% {
+ -webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ -webkit-transform: translate3d(0, -15px, 0);
+ transform: translate3d(0, -15px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0,-4px,0);
+ transform: translate3d(0,-4px,0);
+ }
+}
+
+@keyframes bounce {
+ 0%, 20%, 53%, 80%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ -webkit-transform: translate3d(0,0,0);
+ transform: translate3d(0,0,0);
+ }
+
+ 40%, 43% {
+ -webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ -webkit-transform: translate3d(0, -30px, 0);
+ transform: translate3d(0, -30px, 0);
+ }
+
+ 70% {
+ -webkit-transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ transition-timing-function: cubic-bezier(0.755, 0.050, 0.855, 0.060);
+ -webkit-transform: translate3d(0, -15px, 0);
+ transform: translate3d(0, -15px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0,-4px,0);
+ transform: translate3d(0,-4px,0);
+ }
+}
+
+.bounce {
+ -webkit-animation-name: bounce;
+ animation-name: bounce;
+ -webkit-transform-origin: center bottom;
+ -ms-transform-origin: center bottom;
+ transform-origin: center bottom;
+}
+
+@-webkit-keyframes flash {
+ 0%, 50%, 100% {
+ opacity: 1;
+ }
+
+ 25%, 75% {
+ opacity: 0;
+ }
+}
+
+@keyframes flash {
+ 0%, 50%, 100% {
+ opacity: 1;
+ }
+
+ 25%, 75% {
+ opacity: 0;
+ }
+}
+
+.flash {
+ -webkit-animation-name: flash;
+ animation-name: flash;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes pulse {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.05, 1.05, 1.05);
+ transform: scale3d(1.05, 1.05, 1.05);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes pulse {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.05, 1.05, 1.05);
+ transform: scale3d(1.05, 1.05, 1.05);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.pulse {
+ -webkit-animation-name: pulse;
+ animation-name: pulse;
+}
+
+@-webkit-keyframes rubberBand {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 30% {
+ -webkit-transform: scale3d(1.25, 0.75, 1);
+ transform: scale3d(1.25, 0.75, 1);
+ }
+
+ 40% {
+ -webkit-transform: scale3d(0.75, 1.25, 1);
+ transform: scale3d(0.75, 1.25, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.15, 0.85, 1);
+ transform: scale3d(1.15, 0.85, 1);
+ }
+
+ 65% {
+ -webkit-transform: scale3d(.95, 1.05, 1);
+ transform: scale3d(.95, 1.05, 1);
+ }
+
+ 75% {
+ -webkit-transform: scale3d(1.05, .95, 1);
+ transform: scale3d(1.05, .95, 1);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes rubberBand {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 30% {
+ -webkit-transform: scale3d(1.25, 0.75, 1);
+ transform: scale3d(1.25, 0.75, 1);
+ }
+
+ 40% {
+ -webkit-transform: scale3d(0.75, 1.25, 1);
+ transform: scale3d(0.75, 1.25, 1);
+ }
+
+ 50% {
+ -webkit-transform: scale3d(1.15, 0.85, 1);
+ transform: scale3d(1.15, 0.85, 1);
+ }
+
+ 65% {
+ -webkit-transform: scale3d(.95, 1.05, 1);
+ transform: scale3d(.95, 1.05, 1);
+ }
+
+ 75% {
+ -webkit-transform: scale3d(1.05, .95, 1);
+ transform: scale3d(1.05, .95, 1);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.rubberBand {
+ -webkit-animation-name: rubberBand;
+ animation-name: rubberBand;
+}
+
+@-webkit-keyframes shake {
+ 0%, 100% {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+
+ 10%, 30%, 50%, 70%, 90% {
+ -webkit-transform: translate3d(-10px, 0, 0);
+ transform: translate3d(-10px, 0, 0);
+ }
+
+ 20%, 40%, 60%, 80% {
+ -webkit-transform: translate3d(10px, 0, 0);
+ transform: translate3d(10px, 0, 0);
+ }
+}
+
+@keyframes shake {
+ 0%, 100% {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+
+ 10%, 30%, 50%, 70%, 90% {
+ -webkit-transform: translate3d(-10px, 0, 0);
+ transform: translate3d(-10px, 0, 0);
+ }
+
+ 20%, 40%, 60%, 80% {
+ -webkit-transform: translate3d(10px, 0, 0);
+ transform: translate3d(10px, 0, 0);
+ }
+}
+
+.shake {
+ -webkit-animation-name: shake;
+ animation-name: shake;
+}
+
+@-webkit-keyframes swing {
+ 20% {
+ -webkit-transform: rotate3d(0, 0, 1, 15deg);
+ transform: rotate3d(0, 0, 1, 15deg);
+ }
+
+ 40% {
+ -webkit-transform: rotate3d(0, 0, 1, -10deg);
+ transform: rotate3d(0, 0, 1, -10deg);
+ }
+
+ 60% {
+ -webkit-transform: rotate3d(0, 0, 1, 5deg);
+ transform: rotate3d(0, 0, 1, 5deg);
+ }
+
+ 80% {
+ -webkit-transform: rotate3d(0, 0, 1, -5deg);
+ transform: rotate3d(0, 0, 1, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: rotate3d(0, 0, 1, 0deg);
+ transform: rotate3d(0, 0, 1, 0deg);
+ }
+}
+
+@keyframes swing {
+ 20% {
+ -webkit-transform: rotate3d(0, 0, 1, 15deg);
+ transform: rotate3d(0, 0, 1, 15deg);
+ }
+
+ 40% {
+ -webkit-transform: rotate3d(0, 0, 1, -10deg);
+ transform: rotate3d(0, 0, 1, -10deg);
+ }
+
+ 60% {
+ -webkit-transform: rotate3d(0, 0, 1, 5deg);
+ transform: rotate3d(0, 0, 1, 5deg);
+ }
+
+ 80% {
+ -webkit-transform: rotate3d(0, 0, 1, -5deg);
+ transform: rotate3d(0, 0, 1, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: rotate3d(0, 0, 1, 0deg);
+ transform: rotate3d(0, 0, 1, 0deg);
+ }
+}
+
+.swing {
+ -webkit-transform-origin: top center;
+ -ms-transform-origin: top center;
+ transform-origin: top center;
+ -webkit-animation-name: swing;
+ animation-name: swing;
+}
+
+@-webkit-keyframes tada {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 10%, 20% {
+ -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
+ transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 30%, 50%, 70%, 90% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 40%, 60%, 80% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes tada {
+ 0% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+
+ 10%, 20% {
+ -webkit-transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
+ transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 30%, 50%, 70%, 90% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 40%, 60%, 80% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+ transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 100% {
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.tada {
+ -webkit-animation-name: tada;
+ animation-name: tada;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes wobble {
+ 0% {
+ -webkit-transform: none;
+ transform: none;
+ }
+
+ 15% {
+ -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ }
+
+ 30% {
+ -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 45% {
+ -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 60% {
+ -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes wobble {
+ 0% {
+ -webkit-transform: none;
+ transform: none;
+ }
+
+ 15% {
+ -webkit-transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ transform: translate3d(-25%, 0, 0) rotate3d(0, 0, 1, -5deg);
+ }
+
+ 30% {
+ -webkit-transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ transform: translate3d(20%, 0, 0) rotate3d(0, 0, 1, 3deg);
+ }
+
+ 45% {
+ -webkit-transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ transform: translate3d(-15%, 0, 0) rotate3d(0, 0, 1, -3deg);
+ }
+
+ 60% {
+ -webkit-transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ transform: translate3d(10%, 0, 0) rotate3d(0, 0, 1, 2deg);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ transform: translate3d(-5%, 0, 0) rotate3d(0, 0, 1, -1deg);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.wobble {
+ -webkit-animation-name: wobble;
+ animation-name: wobble;
+}
+
+@-webkit-keyframes bounceIn {
+ 0%, 20%, 40%, 60%, 80%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 20% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1);
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 40% {
+ -webkit-transform: scale3d(.9, .9, .9);
+ transform: scale3d(.9, .9, .9);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(1.03, 1.03, 1.03);
+ transform: scale3d(1.03, 1.03, 1.03);
+ }
+
+ 80% {
+ -webkit-transform: scale3d(.97, .97, .97);
+ transform: scale3d(.97, .97, .97);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+@keyframes bounceIn {
+ 0%, 20%, 40%, 60%, 80%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 20% {
+ -webkit-transform: scale3d(1.1, 1.1, 1.1);
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 40% {
+ -webkit-transform: scale3d(.9, .9, .9);
+ transform: scale3d(.9, .9, .9);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(1.03, 1.03, 1.03);
+ transform: scale3d(1.03, 1.03, 1.03);
+ }
+
+ 80% {
+ -webkit-transform: scale3d(.97, .97, .97);
+ transform: scale3d(.97, .97, .97);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: scale3d(1, 1, 1);
+ transform: scale3d(1, 1, 1);
+ }
+}
+
+.bounceIn {
+ -webkit-animation-name: bounceIn;
+ animation-name: bounceIn;
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+}
+
+@-webkit-keyframes bounceInDown {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -3000px, 0);
+ transform: translate3d(0, -3000px, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 25px, 0);
+ transform: translate3d(0, 25px, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0, 5px, 0);
+ transform: translate3d(0, 5px, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes bounceInDown {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -3000px, 0);
+ transform: translate3d(0, -3000px, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 25px, 0);
+ transform: translate3d(0, 25px, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0, 5px, 0);
+ transform: translate3d(0, 5px, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.bounceInDown {
+ -webkit-animation-name: bounceInDown;
+ animation-name: bounceInDown;
+}
+
+@-webkit-keyframes bounceInLeft {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-3000px, 0, 0);
+ transform: translate3d(-3000px, 0, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(25px, 0, 0);
+ transform: translate3d(25px, 0, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(-10px, 0, 0);
+ transform: translate3d(-10px, 0, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(5px, 0, 0);
+ transform: translate3d(5px, 0, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes bounceInLeft {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-3000px, 0, 0);
+ transform: translate3d(-3000px, 0, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(25px, 0, 0);
+ transform: translate3d(25px, 0, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(-10px, 0, 0);
+ transform: translate3d(-10px, 0, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(5px, 0, 0);
+ transform: translate3d(5px, 0, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.bounceInLeft {
+ -webkit-animation-name: bounceInLeft;
+ animation-name: bounceInLeft;
+}
+
+@-webkit-keyframes bounceInRight {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(3000px, 0, 0);
+ transform: translate3d(3000px, 0, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(-25px, 0, 0);
+ transform: translate3d(-25px, 0, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(10px, 0, 0);
+ transform: translate3d(10px, 0, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(-5px, 0, 0);
+ transform: translate3d(-5px, 0, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes bounceInRight {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(3000px, 0, 0);
+ transform: translate3d(3000px, 0, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(-25px, 0, 0);
+ transform: translate3d(-25px, 0, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(10px, 0, 0);
+ transform: translate3d(10px, 0, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(-5px, 0, 0);
+ transform: translate3d(-5px, 0, 0);
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.bounceInRight {
+ -webkit-animation-name: bounceInRight;
+ animation-name: bounceInRight;
+}
+
+@-webkit-keyframes bounceInUp {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 3000px, 0);
+ transform: translate3d(0, 3000px, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, -20px, 0);
+ transform: translate3d(0, -20px, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(0, 10px, 0);
+ transform: translate3d(0, 10px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0, -5px, 0);
+ transform: translate3d(0, -5px, 0);
+ }
+
+ 100% {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+@keyframes bounceInUp {
+ 0%, 60%, 75%, 90%, 100% {
+ -webkit-transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ transition-timing-function: cubic-bezier(0.215, 0.610, 0.355, 1.000);
+ }
+
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 3000px, 0);
+ transform: translate3d(0, 3000px, 0);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, -20px, 0);
+ transform: translate3d(0, -20px, 0);
+ }
+
+ 75% {
+ -webkit-transform: translate3d(0, 10px, 0);
+ transform: translate3d(0, 10px, 0);
+ }
+
+ 90% {
+ -webkit-transform: translate3d(0, -5px, 0);
+ transform: translate3d(0, -5px, 0);
+ }
+
+ 100% {
+ -webkit-transform: translate3d(0, 0, 0);
+ transform: translate3d(0, 0, 0);
+ }
+}
+
+.bounceInUp {
+ -webkit-animation-name: bounceInUp;
+ animation-name: bounceInUp;
+}
+
+@-webkit-keyframes bounceOut {
+ 20% {
+ -webkit-transform: scale3d(.9, .9, .9);
+ transform: scale3d(.9, .9, .9);
+ }
+
+ 50%, 55% {
+ opacity: 1;
+ -webkit-transform: scale3d(1.1, 1.1, 1.1);
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+}
+
+@keyframes bounceOut {
+ 20% {
+ -webkit-transform: scale3d(.9, .9, .9);
+ transform: scale3d(.9, .9, .9);
+ }
+
+ 50%, 55% {
+ opacity: 1;
+ -webkit-transform: scale3d(1.1, 1.1, 1.1);
+ transform: scale3d(1.1, 1.1, 1.1);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+}
+
+.bounceOut {
+ -webkit-animation-name: bounceOut;
+ animation-name: bounceOut;
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+}
+
+@-webkit-keyframes bounceOutDown {
+ 20% {
+ -webkit-transform: translate3d(0, 10px, 0);
+ transform: translate3d(0, 10px, 0);
+ }
+
+ 40%, 45% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, -20px, 0);
+ transform: translate3d(0, -20px, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+}
+
+@keyframes bounceOutDown {
+ 20% {
+ -webkit-transform: translate3d(0, 10px, 0);
+ transform: translate3d(0, 10px, 0);
+ }
+
+ 40%, 45% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, -20px, 0);
+ transform: translate3d(0, -20px, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+}
+
+.bounceOutDown {
+ -webkit-animation-name: bounceOutDown;
+ animation-name: bounceOutDown;
+}
+
+@-webkit-keyframes bounceOutLeft {
+ 20% {
+ opacity: 1;
+ -webkit-transform: translate3d(20px, 0, 0);
+ transform: translate3d(20px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+}
+
+@keyframes bounceOutLeft {
+ 20% {
+ opacity: 1;
+ -webkit-transform: translate3d(20px, 0, 0);
+ transform: translate3d(20px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+}
+
+.bounceOutLeft {
+ -webkit-animation-name: bounceOutLeft;
+ animation-name: bounceOutLeft;
+}
+
+@-webkit-keyframes bounceOutRight {
+ 20% {
+ opacity: 1;
+ -webkit-transform: translate3d(-20px, 0, 0);
+ transform: translate3d(-20px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+}
+
+@keyframes bounceOutRight {
+ 20% {
+ opacity: 1;
+ -webkit-transform: translate3d(-20px, 0, 0);
+ transform: translate3d(-20px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+}
+
+.bounceOutRight {
+ -webkit-animation-name: bounceOutRight;
+ animation-name: bounceOutRight;
+}
+
+@-webkit-keyframes bounceOutUp {
+ 20% {
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ 40%, 45% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 20px, 0);
+ transform: translate3d(0, 20px, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+}
+
+@keyframes bounceOutUp {
+ 20% {
+ -webkit-transform: translate3d(0, -10px, 0);
+ transform: translate3d(0, -10px, 0);
+ }
+
+ 40%, 45% {
+ opacity: 1;
+ -webkit-transform: translate3d(0, 20px, 0);
+ transform: translate3d(0, 20px, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+}
+
+.bounceOutUp {
+ -webkit-animation-name: bounceOutUp;
+ animation-name: bounceOutUp;
+}
+
+@-webkit-keyframes fadeIn {
+ 0% {opacity: 0;}
+ 100% {opacity: 1;}
+}
+
+@keyframes fadeIn {
+ 0% {opacity: 0;}
+ 100% {opacity: 1;}
+}
+
+.fadeIn {
+ -webkit-animation-name: fadeIn;
+ animation-name: fadeIn;
+}
+
+@-webkit-keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInDown {
+ -webkit-animation-name: fadeInDown;
+ animation-name: fadeInDown;
+}
+
+@-webkit-keyframes fadeInDownBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInDownBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInDownBig {
+ -webkit-animation-name: fadeInDownBig;
+ animation-name: fadeInDownBig;
+}
+
+@-webkit-keyframes fadeInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInLeft {
+ -webkit-animation-name: fadeInLeft;
+ animation-name: fadeInLeft;
+}
+
+@-webkit-keyframes fadeInLeftBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInLeftBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInLeftBig {
+ -webkit-animation-name: fadeInLeftBig;
+ animation-name: fadeInLeftBig;
+}
+
+@-webkit-keyframes fadeInRight {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInRight {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInRight {
+ -webkit-animation-name: fadeInRight;
+ animation-name: fadeInRight;
+}
+
+@-webkit-keyframes fadeInRightBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInRightBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInRightBig {
+ -webkit-animation-name: fadeInRightBig;
+ animation-name: fadeInRightBig;
+}
+
+@-webkit-keyframes fadeInUp {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 100%, 0);
+ transform: translate3d(0, 100%, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInUp {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 100%, 0);
+ transform: translate3d(0, 100%, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInUp {
+ -webkit-animation-name: fadeInUp;
+ animation-name: fadeInUp;
+}
+
+@-webkit-keyframes fadeInUpBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes fadeInUpBig {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.fadeInUpBig {
+ -webkit-animation-name: fadeInUpBig;
+ animation-name: fadeInUpBig;
+}
+
+@-webkit-keyframes fadeOut {
+ 0% {opacity: 1;}
+ 100% {opacity: 0;}
+}
+
+@keyframes fadeOut {
+ 0% {opacity: 1;}
+ 100% {opacity: 0;}
+}
+
+.fadeOut {
+ -webkit-animation-name: fadeOut;
+ animation-name: fadeOut;
+}
+
+@-webkit-keyframes fadeOutDown {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 100%, 0);
+ transform: translate3d(0, 100%, 0);
+ }
+}
+
+@keyframes fadeOutDown {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 100%, 0);
+ transform: translate3d(0, 100%, 0);
+ }
+}
+
+.fadeOutDown {
+ -webkit-animation-name: fadeOutDown;
+ animation-name: fadeOutDown;
+}
+
+@-webkit-keyframes fadeOutDownBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+}
+
+@keyframes fadeOutDownBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, 2000px, 0);
+ transform: translate3d(0, 2000px, 0);
+ }
+}
+
+.fadeOutDownBig {
+ -webkit-animation-name: fadeOutDownBig;
+ animation-name: fadeOutDownBig;
+}
+
+@-webkit-keyframes fadeOutLeft {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+}
+
+@keyframes fadeOutLeft {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0);
+ transform: translate3d(-100%, 0, 0);
+ }
+}
+
+.fadeOutLeft {
+ -webkit-animation-name: fadeOutLeft;
+ animation-name: fadeOutLeft;
+}
+
+@-webkit-keyframes fadeOutLeftBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+}
+
+@keyframes fadeOutLeftBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(-2000px, 0, 0);
+ transform: translate3d(-2000px, 0, 0);
+ }
+}
+
+.fadeOutLeftBig {
+ -webkit-animation-name: fadeOutLeftBig;
+ animation-name: fadeOutLeftBig;
+}
+
+@-webkit-keyframes fadeOutRight {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+}
+
+@keyframes fadeOutRight {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0);
+ transform: translate3d(100%, 0, 0);
+ }
+}
+
+.fadeOutRight {
+ -webkit-animation-name: fadeOutRight;
+ animation-name: fadeOutRight;
+}
+
+@-webkit-keyframes fadeOutRightBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+}
+
+@keyframes fadeOutRightBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(2000px, 0, 0);
+ transform: translate3d(2000px, 0, 0);
+ }
+}
+
+.fadeOutRightBig {
+ -webkit-animation-name: fadeOutRightBig;
+ animation-name: fadeOutRightBig;
+}
+
+@-webkit-keyframes fadeOutUp {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+}
+
+@keyframes fadeOutUp {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -100%, 0);
+ transform: translate3d(0, -100%, 0);
+ }
+}
+
+.fadeOutUp {
+ -webkit-animation-name: fadeOutUp;
+ animation-name: fadeOutUp;
+}
+
+@-webkit-keyframes fadeOutUpBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+}
+
+@keyframes fadeOutUpBig {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(0, -2000px, 0);
+ transform: translate3d(0, -2000px, 0);
+ }
+}
+
+.fadeOutUpBig {
+ -webkit-animation-name: fadeOutUpBig;
+ animation-name: fadeOutUpBig;
+}
+
+@-webkit-keyframes flip {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+ transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+ }
+
+ 50% {
+ -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+ transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) scale3d(.95, .95, .95);
+ transform: perspective(400px) scale3d(.95, .95, .95);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+}
+
+@keyframes flip {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -360deg);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+ transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -190deg);
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+ }
+
+ 50% {
+ -webkit-transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+ transform: perspective(400px) translate3d(0, 0, 150px) rotate3d(0, 1, 0, -170deg);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) scale3d(.95, .95, .95);
+ transform: perspective(400px) scale3d(.95, .95, .95);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+ }
+}
+
+.animated.flip {
+ -webkit-backface-visibility: visible;
+ backface-visibility: visible;
+ -webkit-animation-name: flip;
+ animation-name: flip;
+}
+
+@-webkit-keyframes flipInX {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ }
+
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+}
+
+@keyframes flipInX {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ }
+
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 10deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+}
+
+.flipInX {
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+ -webkit-animation-name: flipInX;
+ animation-name: flipInX;
+}
+
+@-webkit-keyframes flipInY {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ }
+
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+}
+
+@keyframes flipInY {
+ 0% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ opacity: 0;
+ }
+
+ 40% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -20deg);
+ -webkit-transition-timing-function: ease-in;
+ transition-timing-function: ease-in;
+ }
+
+ 60% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 10deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -5deg);
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+}
+
+.flipInY {
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+ -webkit-animation-name: flipInY;
+ animation-name: flipInY;
+}
+
+@-webkit-keyframes flipOutX {
+ 0% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+
+ 30% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ opacity: 0;
+ }
+}
+
+@keyframes flipOutX {
+ 0% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+
+ 30% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, -20deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ transform: perspective(400px) rotate3d(1, 0, 0, 90deg);
+ opacity: 0;
+ }
+}
+
+.flipOutX {
+ -webkit-animation-name: flipOutX;
+ animation-name: flipOutX;
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+}
+
+@-webkit-keyframes flipOutY {
+ 0% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+
+ 30% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ opacity: 0;
+ }
+}
+
+@keyframes flipOutY {
+ 0% {
+ -webkit-transform: perspective(400px);
+ transform: perspective(400px);
+ }
+
+ 30% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, -15deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ transform: perspective(400px) rotate3d(0, 1, 0, 90deg);
+ opacity: 0;
+ }
+}
+
+.flipOutY {
+ -webkit-backface-visibility: visible !important;
+ backface-visibility: visible !important;
+ -webkit-animation-name: flipOutY;
+ animation-name: flipOutY;
+ -webkit-animation-duration: .75s;
+ animation-duration: .75s;
+}
+
+@-webkit-keyframes lightSpeedIn {
+ 0% {
+ -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
+ transform: translate3d(100%, 0, 0) skewX(-30deg);
+ opacity: 0;
+ }
+
+ 60% {
+ -webkit-transform: skewX(20deg);
+ transform: skewX(20deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: skewX(-5deg);
+ transform: skewX(-5deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes lightSpeedIn {
+ 0% {
+ -webkit-transform: translate3d(100%, 0, 0) skewX(-30deg);
+ transform: translate3d(100%, 0, 0) skewX(-30deg);
+ opacity: 0;
+ }
+
+ 60% {
+ -webkit-transform: skewX(20deg);
+ transform: skewX(20deg);
+ opacity: 1;
+ }
+
+ 80% {
+ -webkit-transform: skewX(-5deg);
+ transform: skewX(-5deg);
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.lightSpeedIn {
+ -webkit-animation-name: lightSpeedIn;
+ animation-name: lightSpeedIn;
+ -webkit-animation-timing-function: ease-out;
+ animation-timing-function: ease-out;
+}
+
+@-webkit-keyframes lightSpeedOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
+ transform: translate3d(100%, 0, 0) skewX(30deg);
+ opacity: 0;
+ }
+}
+
+@keyframes lightSpeedOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: translate3d(100%, 0, 0) skewX(30deg);
+ transform: translate3d(100%, 0, 0) skewX(30deg);
+ opacity: 0;
+ }
+}
+
+.lightSpeedOut {
+ -webkit-animation-name: lightSpeedOut;
+ animation-name: lightSpeedOut;
+ -webkit-animation-timing-function: ease-in;
+ animation-timing-function: ease-in;
+}
+
+@-webkit-keyframes rotateIn {
+ 0% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: rotate3d(0, 0, 1, -200deg);
+ transform: rotate3d(0, 0, 1, -200deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateIn {
+ 0% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: rotate3d(0, 0, 1, -200deg);
+ transform: rotate3d(0, 0, 1, -200deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateIn {
+ -webkit-animation-name: rotateIn;
+ animation-name: rotateIn;
+}
+
+@-webkit-keyframes rotateInDownLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateInDownLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateInDownLeft {
+ -webkit-animation-name: rotateInDownLeft;
+ animation-name: rotateInDownLeft;
+}
+
+@-webkit-keyframes rotateInDownRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateInDownRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateInDownRight {
+ -webkit-animation-name: rotateInDownRight;
+ animation-name: rotateInDownRight;
+}
+
+@-webkit-keyframes rotateInUpLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateInUpLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateInUpLeft {
+ -webkit-animation-name: rotateInUpLeft;
+ animation-name: rotateInUpLeft;
+}
+
+@-webkit-keyframes rotateInUpRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -90deg);
+ transform: rotate3d(0, 0, 1, -90deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+@keyframes rotateInUpRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -90deg);
+ transform: rotate3d(0, 0, 1, -90deg);
+ opacity: 0;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: none;
+ transform: none;
+ opacity: 1;
+ }
+}
+
+.rotateInUpRight {
+ -webkit-animation-name: rotateInUpRight;
+ animation-name: rotateInUpRight;
+}
+
+@-webkit-keyframes rotateOut {
+ 0% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: rotate3d(0, 0, 1, 200deg);
+ transform: rotate3d(0, 0, 1, 200deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOut {
+ 0% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: center;
+ transform-origin: center;
+ -webkit-transform: rotate3d(0, 0, 1, 200deg);
+ transform: rotate3d(0, 0, 1, 200deg);
+ opacity: 0;
+ }
+}
+
+.rotateOut {
+ -webkit-animation-name: rotateOut;
+ animation-name: rotateOut;
+}
+
+@-webkit-keyframes rotateOutDownLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOutDownLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 45deg);
+ transform: rotate3d(0, 0, 1, 45deg);
+ opacity: 0;
+ }
+}
+
+.rotateOutDownLeft {
+ -webkit-animation-name: rotateOutDownLeft;
+ animation-name: rotateOutDownLeft;
+}
+
+@-webkit-keyframes rotateOutDownRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOutDownRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+}
+
+.rotateOutDownRight {
+ -webkit-animation-name: rotateOutDownRight;
+ animation-name: rotateOutDownRight;
+}
+
+@-webkit-keyframes rotateOutUpLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOutUpLeft {
+ 0% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: left bottom;
+ transform-origin: left bottom;
+ -webkit-transform: rotate3d(0, 0, 1, -45deg);
+ transform: rotate3d(0, 0, 1, -45deg);
+ opacity: 0;
+ }
+}
+
+.rotateOutUpLeft {
+ -webkit-animation-name: rotateOutUpLeft;
+ animation-name: rotateOutUpLeft;
+}
+
+@-webkit-keyframes rotateOutUpRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 90deg);
+ transform: rotate3d(0, 0, 1, 90deg);
+ opacity: 0;
+ }
+}
+
+@keyframes rotateOutUpRight {
+ 0% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform-origin: right bottom;
+ transform-origin: right bottom;
+ -webkit-transform: rotate3d(0, 0, 1, 90deg);
+ transform: rotate3d(0, 0, 1, 90deg);
+ opacity: 0;
+ }
+}
+
+.rotateOutUpRight {
+ -webkit-animation-name: rotateOutUpRight;
+ animation-name: rotateOutUpRight;
+}
+
+@-webkit-keyframes hinge {
+ 0% {
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ }
+
+ 20%, 60% {
+ -webkit-transform: rotate3d(0, 0, 1, 80deg);
+ transform: rotate3d(0, 0, 1, 80deg);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ }
+
+ 40%, 80% {
+ -webkit-transform: rotate3d(0, 0, 1, 60deg);
+ transform: rotate3d(0, 0, 1, 60deg);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: translate3d(0, 700px, 0);
+ transform: translate3d(0, 700px, 0);
+ opacity: 0;
+ }
+}
+
+@keyframes hinge {
+ 0% {
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ }
+
+ 20%, 60% {
+ -webkit-transform: rotate3d(0, 0, 1, 80deg);
+ transform: rotate3d(0, 0, 1, 80deg);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ }
+
+ 40%, 80% {
+ -webkit-transform: rotate3d(0, 0, 1, 60deg);
+ transform: rotate3d(0, 0, 1, 60deg);
+ -webkit-transform-origin: top left;
+ transform-origin: top left;
+ -webkit-animation-timing-function: ease-in-out;
+ animation-timing-function: ease-in-out;
+ opacity: 1;
+ }
+
+ 100% {
+ -webkit-transform: translate3d(0, 700px, 0);
+ transform: translate3d(0, 700px, 0);
+ opacity: 0;
+ }
+}
+
+.hinge {
+ -webkit-animation-name: hinge;
+ animation-name: hinge;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes rollIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+ transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+@keyframes rollIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+ transform: translate3d(-100%, 0, 0) rotate3d(0, 0, 1, -120deg);
+ }
+
+ 100% {
+ opacity: 1;
+ -webkit-transform: none;
+ transform: none;
+ }
+}
+
+.rollIn {
+ -webkit-animation-name: rollIn;
+ animation-name: rollIn;
+}
+
+/* originally authored by Nick Pettit - https://github.com/nickpettit/glide */
+
+@-webkit-keyframes rollOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+ transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+ }
+}
+
+@keyframes rollOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+ transform: translate3d(100%, 0, 0) rotate3d(0, 0, 1, 120deg);
+ }
+}
+
+.rollOut {
+ -webkit-animation-name: rollOut;
+ animation-name: rollOut;
+}
+
+@-webkit-keyframes zoomIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 50% {
+ opacity: 1;
+ }
+}
+
+@keyframes zoomIn {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 50% {
+ opacity: 1;
+ }
+}
+
+.zoomIn {
+ -webkit-animation-name: zoomIn;
+ animation-name: zoomIn;
+}
+
+@-webkit-keyframes zoomInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomInDown {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, -1000px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomInDown {
+ -webkit-animation-name: zoomInDown;
+ animation-name: zoomInDown;
+}
+
+@-webkit-keyframes zoomInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);
+ transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomInLeft {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);
+ transform: scale3d(.1, .1, .1) translate3d(-1000px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(10px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomInLeft {
+ -webkit-animation-name: zoomInLeft;
+ animation-name: zoomInLeft;
+}
+
+@-webkit-keyframes zoomInRight {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);
+ transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomInRight {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);
+ transform: scale3d(.1, .1, .1) translate3d(1000px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(-10px, 0, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomInRight {
+ -webkit-animation-name: zoomInRight;
+ animation-name: zoomInRight;
+}
+
+@-webkit-keyframes zoomInUp {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomInUp {
+ 0% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, 1000px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 60% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomInUp {
+ -webkit-animation-name: zoomInUp;
+ animation-name: zoomInUp;
+}
+
+@-webkit-keyframes zoomOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 50% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 100% {
+ opacity: 0;
+ }
+}
+
+@keyframes zoomOut {
+ 0% {
+ opacity: 1;
+ }
+
+ 50% {
+ opacity: 0;
+ -webkit-transform: scale3d(.3, .3, .3);
+ transform: scale3d(.3, .3, .3);
+ }
+
+ 100% {
+ opacity: 0;
+ }
+}
+
+.zoomOut {
+ -webkit-animation-name: zoomOut;
+ animation-name: zoomOut;
+}
+
+@-webkit-keyframes zoomOutDown {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);
+ -webkit-transform-origin: center bottom;
+ transform-origin: center bottom;
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomOutDown {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, -60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, 2000px, 0);
+ -webkit-transform-origin: center bottom;
+ transform-origin: center bottom;
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomOutDown {
+ -webkit-animation-name: zoomOutDown;
+ animation-name: zoomOutDown;
+}
+
+@-webkit-keyframes zoomOutLeft {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translate3d(-2000px, 0, 0);
+ transform: scale(.1) translate3d(-2000px, 0, 0);
+ -webkit-transform-origin: left center;
+ transform-origin: left center;
+ }
+}
+
+@keyframes zoomOutLeft {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(42px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translate3d(-2000px, 0, 0);
+ transform: scale(.1) translate3d(-2000px, 0, 0);
+ -webkit-transform-origin: left center;
+ transform-origin: left center;
+ }
+}
+
+.zoomOutLeft {
+ -webkit-animation-name: zoomOutLeft;
+ animation-name: zoomOutLeft;
+}
+
+@-webkit-keyframes zoomOutRight {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translate3d(2000px, 0, 0);
+ transform: scale(.1) translate3d(2000px, 0, 0);
+ -webkit-transform-origin: right center;
+ transform-origin: right center;
+ }
+}
+
+@keyframes zoomOutRight {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);
+ transform: scale3d(.475, .475, .475) translate3d(-42px, 0, 0);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale(.1) translate3d(2000px, 0, 0);
+ transform: scale(.1) translate3d(2000px, 0, 0);
+ -webkit-transform-origin: right center;
+ transform-origin: right center;
+ }
+}
+
+.zoomOutRight {
+ -webkit-animation-name: zoomOutRight;
+ animation-name: zoomOutRight;
+}
+
+@-webkit-keyframes zoomOutUp {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);
+ -webkit-transform-origin: center bottom;
+ transform-origin: center bottom;
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+@keyframes zoomOutUp {
+ 40% {
+ opacity: 1;
+ -webkit-transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ transform: scale3d(.475, .475, .475) translate3d(0, 60px, 0);
+ -webkit-animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ animation-timing-function: cubic-bezier(0.550, 0.055, 0.675, 0.190);
+ }
+
+ 100% {
+ opacity: 0;
+ -webkit-transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);
+ transform: scale3d(.1, .1, .1) translate3d(0, -2000px, 0);
+ -webkit-transform-origin: center bottom;
+ transform-origin: center bottom;
+ -webkit-animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ animation-timing-function: cubic-bezier(0.175, 0.885, 0.320, 1);
+ }
+}
+
+.zoomOutUp {
+ -webkit-animation-name: zoomOutUp;
+ animation-name: zoomOutUp;
+}
+
+@-webkit-keyframes slideInDown {
+ 0% {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+@keyframes slideInDown {
+ 0% {
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+.slideInDown {
+ -webkit-animation-name: slideInDown;
+ animation-name: slideInDown;
+}
+
+@-webkit-keyframes slideInLeft {
+ 0% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+@keyframes slideInLeft {
+ 0% {
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+.slideInLeft {
+ -webkit-animation-name: slideInLeft;
+ animation-name: slideInLeft;
+}
+
+@-webkit-keyframes slideInRight {
+ 0% {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+@keyframes slideInRight {
+ 0% {
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+}
+
+.slideInRight {
+ -webkit-animation-name: slideInRight;
+ animation-name: slideInRight;
+}
+
+@-webkit-keyframes slideInUp {
+ 0% {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+@keyframes slideInUp {
+ 0% {
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ visibility: visible;
+ }
+
+ 100% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+}
+
+.slideInUp {
+ -webkit-animation-name: slideInUp;
+ animation-name: slideInUp;
+}
+
+@-webkit-keyframes slideOutDown {
+ 0% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ }
+}
+
+@keyframes slideOutDown {
+ 0% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateY(100%);
+ transform: translateY(100%);
+ }
+}
+
+.slideOutDown {
+ -webkit-animation-name: slideOutDown;
+ animation-name: slideOutDown;
+}
+
+@-webkit-keyframes slideOutLeft {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ }
+}
+
+@keyframes slideOutLeft {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateX(-100%);
+ transform: translateX(-100%);
+ }
+}
+
+.slideOutLeft {
+ -webkit-animation-name: slideOutLeft;
+ animation-name: slideOutLeft;
+}
+
+@-webkit-keyframes slideOutRight {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ }
+}
+
+@keyframes slideOutRight {
+ 0% {
+ -webkit-transform: translateX(0);
+ transform: translateX(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateX(100%);
+ transform: translateX(100%);
+ }
+}
+
+.slideOutRight {
+ -webkit-animation-name: slideOutRight;
+ animation-name: slideOutRight;
+}
+
+@-webkit-keyframes slideOutUp {
+ 0% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ }
+}
+
+@keyframes slideOutUp {
+ 0% {
+ -webkit-transform: translateY(0);
+ transform: translateY(0);
+ }
+
+ 100% {
+ visibility: hidden;
+ -webkit-transform: translateY(-100%);
+ transform: translateY(-100%);
+ }
+}
+
+.slideOutUp {
+ -webkit-animation-name: slideOutUp;
+ animation-name: slideOutUp;
+}
diff --git a/git_deps/html/css/git-deps-tips.css b/git_deps/html/css/git-deps-tips.css
new file mode 100644
index 0000000..909badb
--- /dev/null
+++ b/git_deps/html/css/git-deps-tips.css
@@ -0,0 +1,79 @@
+.d3-tip {
+ line-height: 1;
+ padding: 5px;
+ background: rgba(247, 251, 252, 0.9);
+ font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
+ border-radius: 2px;
+ pointer-events: none;
+ border: 1px solid #e5e5e5;
+}
+
+/* Creates a small triangle extender for the tooltip */
+.d3-tip:after {
+ box-sizing: border-box;
+ display: inline;
+ font-size: 10px;
+ width: 100%;
+ line-height: 1;
+ color: rgba(0, 0, 0, 0.8);
+ position: absolute;
+ pointer-events: none;
+}
+
+/* Northward tooltips */
+.d3-tip.n:after {
+ content: "\25BC";
+ margin: -1px 0 0 0;
+ top: 100%;
+ left: 0;
+ text-align: center;
+}
+
+/* Eastward tooltips */
+.d3-tip.e:after {
+ content: "\25C0";
+ margin: -4px 0 0 0;
+ top: 50%;
+ left: -8px;
+}
+
+/* Southward tooltips */
+.d3-tip.s:after {
+ content: "\25B2";
+ margin: 0 0 1px 0;
+ top: -8px;
+ left: 0;
+ text-align: center;
+}
+
+/* Westward tooltips */
+.d3-tip.w:after {
+ content: "\25B6";
+ margin: -4px 0 0 -1px;
+ top: 50%;
+ left: 100%;
+}
+
+.d3-tip p.commit-title {
+ font-weight: bold;
+ color: #4e575b;
+ font-size: 15px;
+ margin: 0.5em 0;
+}
+
+.d3-tip .commit-describe {
+ font-size: 12px;
+ margin: 0.5em 0;
+}
+
+.d3-tip .commit-meta {
+ color: #979a9c;
+ font-size: 11px;
+}
+
+.d3-tip .commit-body pre {
+ color: #596063;
+ margin: 0.5em 0;
+ /* padding-left: 8px; */
+ /* border-left: 1px solid #e5e5e5; */
+}
diff --git a/git_deps/html/css/git-deps.css b/git_deps/html/css/git-deps.css
new file mode 100644
index 0000000..ea21821
--- /dev/null
+++ b/git_deps/html/css/git-deps.css
@@ -0,0 +1,93 @@
+body {
+ font-family: Helvetica, arial, freesans, clean, sans-serif, 'Segoe UI Emoji', 'Segoe UI Symbol';
+ width: 100vw;
+ height: 100vh;
+ margin: 0px;
+}
+
+#page {
+ margin: 8px;
+ display: flex; /* use the flex model */
+ flex-direction: column;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+}
+
+h1 {
+ margin: 0;
+ background: rgb(128, 150, 174);
+ color: white;
+ padding: 0.3em;
+}
+
+#top p {
+ margin-right: 320px; /* Avoid overlap with noty boxes */
+}
+
+#svg-container {
+ flex: 1;
+ border: 1px solid #ccc; /* width has to be half of SVG_MARGIN */
+}
+
+rect.background {
+ fill: white;
+ cursor: all-scroll;
+}
+
+g.node rect {
+ stroke: #e5e5e5;
+ stroke-width: 2px;
+ cursor: pointer; /* move is semantically better but looks the same as all-scroll */
+}
+
+g.node rect.explored {
+ fill: rgba(206, 236, 221, 0.54);
+}
+
+g.node rect.unexplored {
+ fill: rgba(242, 242, 255, 0.54);
+}
+
+g.node text {
+ /* fill: black; */
+ fill: #295b8c;
+ font-size: 15px;
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
+ font-weight: bold;
+ text-anchor: middle;
+ alignment-baseline: middle;
+ cursor: pointer;
+ pointer-events: none;
+}
+
+.plus-icon use {
+ display: none;
+}
+
+.plus-icon:hover use {
+ display: visible;
+}
+
+.link {
+ fill: none;
+ stroke-width: 2px;
+ opacity: 0.4;
+ marker-end: url(#end-arrow);
+}
+
+.commitish input {
+ font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace;
+}
+
+.commit-ref {
+ font-weight: bold;
+ color: #26894d;
+}
+
+.noty_text p {
+ margin-top: 6px;
+ margin-bottom: 6px;
+}
diff --git a/git_deps/html/git-deps.html b/git_deps/html/git-deps.html
new file mode 100644
index 0000000..3bf053c
--- /dev/null
+++ b/git_deps/html/git-deps.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+ <meta charset="utf-8" />
+ <title>git commit dependency graph</title>
+
+ <script language="javascript" type="text/javascript" src="node_modules/d3/d3.min.js"></script>
+ <script language="javascript" type="text/javascript" src="js/bundle.js"></script>
+
+ <link rel="stylesheet" type="text/css" href="css/animate.css" />
+ <link rel="stylesheet" type="text/css" href="css/git-deps.css" />
+ <link rel="stylesheet" type="text/css" href="css/git-deps-tips.css" />
+</head>
+
+<body>
+ <div id="page">
+ <div id="top">
+ <h1>git commit dependency graph</h1>
+
+ <p>
+ Use mouse-wheel to zoom.
+ Drag background to pan.
+ Hover over a commit for more information.
+ Click a commit's plus icon to find dependencies of that commit.
+ </p>
+
+ <form class="commitish" action="#">
+ Detect dependencies for:
+ <input type="text" name="commitish" size="20"
+ value="master" autofocus />
+ <button>Submit</button>
+ <button type="button" onclick="full_screen_click()">Full screen</button>
+ <button type="button" onclick="zoom_to_fit()">Zoom to fit (or double click)</button>
+ </form>
+ </div>
+
+ <div id="svg-container" />
+ </div>
+</body>
+</html>
diff --git a/git_deps/html/js/.gitignore b/git_deps/html/js/.gitignore
new file mode 100644
index 0000000..0e804e3
--- /dev/null
+++ b/git_deps/html/js/.gitignore
@@ -0,0 +1 @@
+bundle.js
diff --git a/git_deps/html/js/fullscreen.js b/git_deps/html/js/fullscreen.js
new file mode 100644
index 0000000..6d8f3d8
--- /dev/null
+++ b/git_deps/html/js/fullscreen.js
@@ -0,0 +1,48 @@
+
+function endFullScreen(oncancel) {
+ if (!RunPrefixMethod(document, "FullScreen") && !RunPrefixMethod(document, "IsFullScreen")) {
+ oncancel();
+ }
+}
+function fullScreen(e, oncancel) {
+ if (RunPrefixMethod(document, "FullScreen") || RunPrefixMethod(document, "IsFullScreen")) {
+ RunPrefixMethod(document, "CancelFullScreen");
+ }
+ else {
+ RunPrefixMethod(e, "RequestFullScreen");
+ e.setAttribute("width", screen.width);
+ e.setAttribute("height", screen.height);
+ }
+ if (arguments.length > 1) {
+ var f = function () { endFullScreen(oncancel); };
+ document.addEventListener("fullscreenchange", f, false);
+ document.addEventListener("mozfullscreenchange", f, false);
+ document.addEventListener("webkitfullscreenchange", f, false);
+ }
+}
+
+var pfx = ["webkit", "moz", "ms", "o", ""];
+function RunPrefixMethod(obj, method) {
+
+ var p = 0, m, t;
+ while (p < pfx.length && !obj[m]) {
+ m = method;
+ if (pfx[p] == "") {
+ m = m.substr(0, 1).toLowerCase() + m.substr(1);
+ }
+ m = pfx[p] + m;
+ t = typeof obj[m];
+ if (t != "undefined") {
+ pfx = [pfx[p]];
+ return (t == "function" ? obj[m]() : obj[m]);
+ }
+ p++;
+ }
+}
+
+function isFullScreen() {
+ var fullscreenEnabled = document.fullscreenEnabled || document.mozFullScreenEnabled || document.webkitFullscreenEnabled;
+ return fullscreenEnabled;
+}
+
+module.exports = fullScreen;
diff --git a/git_deps/html/js/git-deps-data.coffee b/git_deps/html/js/git-deps-data.coffee
new file mode 100644
index 0000000..34715a3
--- /dev/null
+++ b/git_deps/html/js/git-deps-data.coffee
@@ -0,0 +1,108 @@
+# The list of nodes and links to feed into WebCola.
+# These will be dynamically built as we retrieve them via XHR.
+nodes = []
+links = []
+
+# WebCola requires links to refer to nodes by index within the
+# nodes array, so as nodes are dynamically added, we need to
+# be able to retrieve their index efficiently in order to add
+# links to/from them. This also allows us to avoid adding the
+# same node twice.
+node_index = {}
+
+# Track dependencies in a hash of hashes which maps parents to
+# children to booleans. Constraints will be added to try to keep
+# siblings at the same y position. For this we need to track
+# siblings, which we do by mapping each parent to an array of its
+# siblings in this hash. It also enables us to deduplicate links
+# across multiple XHRs.
+deps = {}
+
+# Track dependences in reverse in a hash of hashes which maps children
+# to parents to booleans. This allows us to highlight parents when
+# the mouse hovers over a child, and know when we can safely remove
+# a commit due to its sole parent being deleted.
+rdeps = {}
+
+# Returns 1 iff a node was added, otherwise 0.
+add_node = (commit) ->
+ if commit.sha1 of node_index
+ n = node commit.sha1
+ n.explored ||= commit.explored
+ return 0
+
+ nodes.push commit
+ node_index[commit.sha1] = nodes.length - 1
+ return 1
+
+# Returns 1 iff a dependency was added, otherwise 0.
+add_dependency = (parent_sha1, child_sha1) ->
+ deps[parent_sha1] = {} unless parent_sha1 of deps
+
+ # We've already got this link, presumably
+ # from a previous XHR.
+ return 0 if child_sha1 of deps[parent_sha1]
+ deps[parent_sha1][child_sha1] = true
+ add_link parent_sha1, child_sha1
+ return 1
+
+# Returns 1 iff a reverse dependency was added, otherwise 0.
+add_rev_dependency = (child_sha1, parent_sha1) ->
+ rdeps[child_sha1] = {} unless child_sha1 of rdeps
+
+ # We've already got this link, presumably
+ # from a previous XHR.
+ return 0 if parent_sha1 of rdeps[child_sha1]
+ rdeps[child_sha1][parent_sha1] = true
+ return 1
+
+add_link = (parent_sha1, child_sha1) ->
+ pi = node_index[parent_sha1]
+ ci = node_index[child_sha1]
+ link =
+ source: pi
+ target: ci
+ value: 1 # no idea what WebCola needs this for
+
+ links.push link
+ return
+
+# Returns true iff new data was added.
+add_data = (data) ->
+ new_nodes = 0
+ new_deps = 0
+ for commit in data.commits
+ new_nodes += add_node(commit)
+
+ for dep in data.dependencies
+ new_deps += add_dependency(dep.parent, dep.child)
+ add_rev_dependency(dep.child, dep.parent)
+
+ if new_nodes > 0 or new_deps > 0
+ return [
+ new_nodes
+ new_deps
+ data.query
+ ]
+
+ return false
+
+node = (sha1) ->
+ i = node_index[sha1]
+ unless i?
+ console.error "No index for SHA1 '#{sha1}'"
+ return null
+ return nodes[i]
+
+module.exports =
+ # Variables (N.B. if these variables are reinitialised at any
+ # point, the values here will become stale and require updating)
+ nodes: nodes
+ links: links
+ node_index: node_index
+ deps: deps
+ rdeps: rdeps
+
+ # Functions
+ add: add_data
+ node: node
diff --git a/git_deps/html/js/git-deps-graph.coffee b/git_deps/html/js/git-deps-graph.coffee
new file mode 100644
index 0000000..7ad6827
--- /dev/null
+++ b/git_deps/html/js/git-deps-graph.coffee
@@ -0,0 +1,595 @@
+jQuery = require "jquery"
+$ = jQuery
+d3 = require "d3"
+d3tip = require "d3-tip"
+d3tip d3
+
+# Hacky workaround:
+# https://github.com/tgdwyer/WebCola/issues/145#issuecomment-271316856
+window.d3 = d3
+
+cola = require "webcola"
+
+global.gdn = require "./git-deps-noty.coffee"
+global.gdd = require "./git-deps-data.coffee"
+global.gdl = require "./git-deps-layout.coffee"
+
+fullScreen = require "./fullscreen"
+
+SVG_MARGIN = 2 # space around <svg>, matching #svg-container border
+RECT_MARGIN = 14 # space in between <rects>
+PADDING = 5 # space in between <text> label and <rect> border
+EDGE_ROUTING_MARGIN = 3
+PLUS_ICON_WIDTH = 14
+
+svg_width = 960
+svg_height = 800
+old_svg_height = undefined
+old_svg_width = undefined
+
+color = d3.scale.category20()
+
+global.d3cola = cola.d3adaptor()
+d3cola
+ .flowLayout("y", 100)
+ .avoidOverlaps(true)
+ #.linkDistance(60)
+ #.symmetricDiffLinkLengths(30)
+ #.jaccardLinkLengths(100)
+
+# d3 visualization elements
+container = undefined
+svg = undefined
+fg = undefined
+nodes = undefined
+paths = undefined
+tip = undefined
+tip_template = undefined
+zoom = undefined
+
+options = undefined # Options will be retrieved from web server
+
+jQuery ->
+ d3.json "options", (error, data) ->
+ options = data
+ gdl.debug = options.debug
+
+ d3.html "tip-template.html", (error, html) ->
+ tip_template = html
+
+ #setup_default_form_values();
+ $("form.commitish").submit (event) ->
+ event.preventDefault()
+ add_commitish $(".commitish input").val()
+
+ init_svg()
+
+setup_default_form_values = ->
+ $("input[type=text]").each(->
+ $(this).val $(this).attr("defaultValue")
+ $(this).css color: "grey"
+ ).focus(->
+ if $(this).val() is $(this).attr("defaultValue")
+ $(this).val ""
+ $(this).css color: "black"
+ ).blur ->
+ if $(this).val() is ""
+ $(this).val $(this).attr("defaultValue")
+ $(this).css color: "grey"
+
+resize_window = ->
+ calculate_svg_size_from_container()
+ fit_svg_to_container()
+ redraw true
+
+redraw = (transition) ->
+ # if mouse down then we are dragging not panning
+ # if nodeMouseDown
+ # return
+ ((if transition then fg.transition() else fg))
+ .attr "transform",
+ "translate(#{zoom.translate()}) scale(#{zoom.scale()})"
+
+graph_bounds = ->
+ x = Number.POSITIVE_INFINITY
+ X = Number.NEGATIVE_INFINITY
+ y = Number.POSITIVE_INFINITY
+ Y = Number.NEGATIVE_INFINITY
+ fg.selectAll(".node").each (d) ->
+ x = Math.min(x, d.x - d.width / 2)
+ y = Math.min(y, d.y - d.height / 2)
+ X = Math.max(X, d.x + d.width / 2)
+ Y = Math.max(Y, d.y + d.height / 2)
+ return {} =
+ x: x
+ X: X
+ y: y
+ Y: Y
+
+fit_svg_to_container = ->
+ svg.attr("width", svg_width).attr("height", svg_height)
+
+full_screen_cancel = ->
+ svg_width = old_svg_width
+ svg_height = old_svg_height
+ fit_svg_to_container()
+ #zoom_to_fit();
+ resize_window()
+
+full_screen_click = ->
+ fullScreen container.node(), full_screen_cancel
+ fit_svg_to_container()
+ resize_window()
+ #zoom_to_fit();
+ return false
+
+zoom_to_fit = ->
+ b = graph_bounds()
+ w = b.X - b.x
+ h = b.Y - b.y
+ cw = svg.attr("width")
+ ch = svg.attr("height")
+ s = Math.min(cw / w, ch / h)
+ tx = -b.x * s + (cw / s - w) * s / 2
+ ty = -b.y * s + (ch / s - h) * s / 2
+ zoom.translate([tx, ty]).scale s
+ redraw true
+ return false
+
+window.full_screen_click = full_screen_click
+window.zoom_to_fit = zoom_to_fit
+
+add_commitish = (commitish) ->
+ tip.hide() if tip?
+ draw_graph commitish
+
+calculate_svg_size_from_container = ->
+ old_svg_width = svg_width
+ old_svg_height = svg_height
+ svg_width = container.node().offsetWidth - SVG_MARGIN
+ svg_height = container.node().offsetHeight - SVG_MARGIN
+
+init_svg = ->
+ container = d3.select("#svg-container")
+ calculate_svg_size_from_container()
+ svg = container.append("svg")
+ .attr("width", svg_width)
+ .attr("height", svg_height)
+ d3cola.size [svg_width, svg_height]
+
+ d3.select(window).on "resize", resize_window
+
+ zoom = d3.behavior.zoom()
+
+ svg.append("rect")
+ .attr("class", "background")
+ .attr("width", "100%")
+ .attr("height", "100%")
+ .call(zoom.on("zoom", redraw))
+ .on("dblclick.zoom", zoom_to_fit)
+
+ fg = svg.append("g")
+ svg_defs fg
+
+update_cola = ->
+ d3cola
+ .nodes(gdd.nodes)
+ .links(gdd.links)
+ .constraints(gdl.constraints)
+
+draw_graph = (commitish) ->
+ d3.json "deps.json/" + commitish, (error, data) ->
+ if error
+ details = JSON.parse(error.responseText)
+ gdn.error details.message
+ return
+
+ new_data = gdd.add(data)
+
+ unless new_data
+ gdn.warn "No new commits or dependencies found!"
+ update_rect_explored()
+ return
+ new_data_notification new_data
+ focus_commitish_input()
+
+ gdl.build_constraints()
+ update_cola()
+
+ paths = fg.selectAll(".link")
+ .data(gdd.links, link_key)
+ paths.enter().append("svg:path")
+ .attr("class", "link")
+ .attr("stroke", (d) -> color(link_key(d)))
+ nodes = fg.selectAll(".node")
+ .data(gdd.nodes, (d) -> d.sha1)
+ global.nodes = nodes
+
+ g_enter = nodes.enter().append("g")
+ .attr("class", "node")
+ # Questionable attempt to use dagre layout as starting positions
+ # https://github.com/tgdwyer/WebCola/issues/63
+ nodes.each (d, i) ->
+ n = gdl.node d.sha1
+ d.x = n.x
+ d.y = n.y
+ nodes.attr "transform", (d) ->
+ translate d.x, d.y
+
+ # N.B. has to be done on the update selection, i.e. *after* the enter!
+ nodes.call(d3cola.drag)
+
+ init_tip() unless tip?
+ # Event handlers need to be updated every time new nodes are added.
+ init_tip_event_handlers(nodes)
+
+ [rects, labels] = draw_new_nodes fg, g_enter
+ position_nodes(rects, labels)
+ update_rect_explored()
+
+focus_commitish_input = () ->
+ d3.select('.commitish input').node().focus()
+
+# Required for object constancy: http://bost.ocks.org/mike/constancy/ ...
+link_key = (link) ->
+ source = sha1_of_link_pointer(link.source)
+ target = sha1_of_link_pointer(link.target)
+ return source + " " + target
+
+# ... but even though link sources and targets are initially fed in
+# as indices into the nodes array, webcola then replaces the indices
+# with references to the node objects. So we have to deal with both
+# cases when ensuring we are uniquely identifying each link.
+sha1_of_link_pointer = (pointer) ->
+ return pointer.sha1 if typeof (pointer) is "object"
+ return gdd.nodes[pointer].sha1
+
+init_tip = () ->
+ tip = d3.tip().attr("class", "d3-tip").html(tip_html)
+ global.tip = tip
+ fg.call tip
+
+# A wrapper around tip.show is required to perform multiple visual
+# actions when the mouse hovers over a node; however even if the only
+# action required was to show the tool tip, the wrapper would still be
+# required in order to work around something which looks like a bug in
+# d3 or d3-tip. tip.show is defined as:
+#
+# function() {
+# var args = Array.prototype.slice.call(arguments)
+# if(args[args.length - 1] instanceof SVGElement) target = args.pop()
+# ...
+#
+# and there's also:
+#
+# function getScreenBBox() {
+# var targetel = target || d3.event.target;
+# ...
+#
+# which I'm guessing normally uses d3.event.target. However for some
+# reason when using tip.show as the dragend handler, d3.event.target
+# points to a function rather than the expected DOM element, which
+# appears to be exactly the same problem described here:
+#
+# http://stackoverflow.com/questions/12934731/d3-event-targets
+#
+# However I tried rects.call ... instead of nodes.call as suggested in
+# that SO article, but it resulted in the callback not being triggered
+# at all. By *always* providing the exact SVGElement the tip is
+# supposed to target, the desired behaviour is obtained. If
+# node_mouseover is only used in tip_dragend_handler then the target
+# gets memoised, and a normal hover-based tip.show shows the target
+# last shown by a drag, rather than the node being hovered over.
+# Weird, and annoying.
+node_mouseover = (d, i) ->
+ tip.show d, i, nodes[0][i]
+ highlight_nodes d3.select(nodes[0][i]), false
+ highlight_parents(d, i, true)
+ highlight_children(d, i, true)
+
+node_mouseout = (d, i) ->
+ tip.hide d, i, nodes[0][i]
+ highlight_nodes d3.select(nodes[0][i]), false
+ highlight_parents(d, i, false)
+ highlight_children(d, i, false)
+
+highlight_parents = (d, i, highlight) ->
+ sha1 = gdd.nodes[i].sha1
+ parents = nodes.filter (d, i) ->
+ d.sha1 of (gdd.rdeps[sha1] || {})
+ highlight_nodes parents, highlight, 'rgb(74, 200, 148)'
+
+highlight_children = (d, i, highlight) ->
+ sha1 = gdd.nodes[i].sha1
+ children = nodes.filter (d, i) ->
+ d.sha1 of (gdd.deps[sha1] || {})
+ highlight_nodes children, highlight, 'rgb(128, 197, 247)'
+
+highlight_nodes = (selection, highlight, colour='#c0c0c0') ->
+ selection.selectAll('rect')
+ .transition()
+ .ease('cubic-out')
+ .duration(200)
+ .style('stroke', if highlight then colour else '#e5e5e5')
+ .style('stroke-width', if highlight then '4px' else '2px')
+
+tip_dragend_handler = (d, i, elt) ->
+ focus_commitish_input()
+ node_mouseover d, i
+
+init_tip_event_handlers = (selection) ->
+ # We have to reuse the same drag object, otherwise only one
+ # of the event handlers will work.
+ drag = d3cola.drag()
+ hide_tip_on_drag = drag.on("drag", tip.hide)
+ on_dragend = drag.on("dragend", tip_dragend_handler)
+ selection.call hide_tip_on_drag
+ selection.call on_dragend
+
+draw_new_nodes = (fg, g_enter) ->
+ rects = g_enter.append('rect')
+ .attr('rx', 5)
+ .attr('ry', 5)
+ .on('dblclick', (d) -> launch_viewer d)
+
+ labels = g_enter.append('text').text((d) ->
+ d.name
+ ).each((d) ->
+ b = @getBBox()
+
+ # Calculate width/height of rectangle from text bounding box.
+ d.rect_width = b.width + 2 * PADDING
+ d.rect_height = b.height + 2 * PADDING
+
+ # Now set the node width/height as used by cola for
+ # positioning. This has to include the margin
+ # outside the rectangle.
+ d.width = d.rect_width + 2 * RECT_MARGIN
+ d.height = d.rect_height + 2 * RECT_MARGIN
+ )
+
+ return [rects, labels]
+
+explore_node = (d) ->
+ if d.explored
+ gdn.warn "Commit #{d.name} already explored"
+ else
+ add_commitish d.sha1
+
+launch_viewer = (d) ->
+ window.location.assign "gitfile://#{options.repo_path}##{d.sha1}"
+
+new_data_notification = (new_data) ->
+ new_nodes = new_data[0]
+ new_deps = new_data[1]
+ query = new_data[2]
+ notification =
+ if query.revspec == query.tip_sha1
+ "Analysed dependencies of #{query.revspec}"
+ else if query.revisions.length == 1
+ "<span class=\"commit-ref\">#{query.revspec}</span>
+ resolved as #{query.tip_abbrev}"
+ else
+ "<span class=\"commit-ref\">#{query.revspec}</span>
+ expanded; tip is #{query.tip_abbrev}"
+ notification += "<p>#{new_nodes} new commit"
+ notification += "s" unless new_nodes == 1
+ notification += "; #{new_deps} new " +
+ (if new_deps == 1 then "dependency" else "dependencies")
+ notification += "</p>"
+
+ gdn.success notification
+
+svg_defs = () ->
+ # define arrow markers for graph links
+ defs = svg.insert("svg:defs")
+
+ defs.append("svg:marker")
+ .attr("id", "end-arrow")
+ .attr("viewBox", "0 -5 10 10")
+ .attr("refX", 6)
+ .attr("markerWidth", 6)
+ .attr("markerHeight", 6)
+ .attr("orient", "auto")
+ .append("svg:path")
+ .attr("d", "M0,-5L10,0L0,5")
+ .attr("fill", "#000")
+
+ plus_icon = defs.append("svg:symbol")
+ .attr("id", "plus-icon")
+ .attr("viewBox", "-51 -51 102 102") # allow for stroke-width 1
+ # border
+ plus_icon.append("svg:rect")
+ .attr("width", 100)
+ .attr("height", 100)
+ .attr("fill", "#295b8c")
+ .attr("stroke", "rgb(106, 136, 200)")
+ .attr("x", -50)
+ .attr("y", -50)
+ .attr("rx", 20)
+ .attr("ry", 20)
+ # plus sign
+ plus_icon.append("svg:path")
+ .attr("d", "M-30,0 H30 M0,-30 V30")
+ .attr("stroke", "white")
+ .attr("stroke-width", 10)
+ .attr("stroke-linecap", "round")
+
+ # Uncomment to see a large version:
+ # fg.append("use")
+ # .attr("class", "plus-icon")
+ # .attr("xlink:href", "#plus-icon")
+ # .attr("width", "200")
+ # .attr("height", "200")
+ # .attr("x", 400)
+ # .attr("y", 200)
+
+position_nodes = (rects, labels) ->
+ rects
+ .attr("width", (d, i) -> d.rect_width)
+ .attr("height", (d, i) -> d.rect_height)
+ .on("mouseover", node_mouseover)
+ .on("mouseout", node_mouseout)
+
+ # Centre labels
+ labels
+ .attr("x", (d) -> d.rect_width / 2)
+ .attr("y", (d) -> d.rect_height / 2)
+ .on("mouseover", node_mouseover)
+ .on("mouseout", node_mouseout)
+
+ d3cola.start 10, 20, 20
+ d3cola.on "tick", tick_handler
+
+ # d3cola.on "end", routeEdges
+
+ # turn on overlap avoidance after first convergence
+ # d3cola.on("end", () ->
+ # unless d3cola.avoidOverlaps
+ # gdd.nodes.forEach((v) ->
+ # v.width = v.height = 10
+ # d3cola.avoidOverlaps true
+ # d3cola.start
+
+update_rect_explored = () ->
+ d3.selectAll(".node rect").attr "class", (d) ->
+ if d.explored then "explored" else "unexplored"
+ nodes.each (d) ->
+ existing_icon = d3.select(this).select("use.plus-icon")
+ if d.explored
+ existing_icon.remove()
+ else if existing_icon.empty()
+ add_plus_icon this
+
+add_plus_icon = (node_element) ->
+ n = d3.select(node_element)
+ rw = node_element.__data__.rect_width
+ rh = node_element.__data__.rect_height
+
+ icon = n.insert('use')
+ .attr('class', 'plus-icon')
+ .attr('xlink:href', '#plus-icon')
+ .attr('x', rw/2)
+ .attr('y', rh - PLUS_ICON_WIDTH/2)
+ .attr('width', 0)
+ .attr('height', 0)
+ icon
+ .on('mouseover', (d, i) -> icon_ease_in icon, rw)
+ .on('mouseout', (d, i) -> icon_ease_out icon, rw)
+ .on('click', (d) -> explore_node d)
+
+ n
+ .on('mouseover', (d, i) -> icon_ease_in icon, rw)
+ .on('mouseout', (d, i) -> icon_ease_out icon, rw)
+
+icon_ease_in = (icon, rw) ->
+ icon.transition()
+ .ease('cubic-out')
+ .duration(200)
+ .attr('width', PLUS_ICON_WIDTH)
+ .attr('height', PLUS_ICON_WIDTH)
+ .attr('x', rw/2 - PLUS_ICON_WIDTH/2)
+
+icon_ease_out = (icon, rw) ->
+ icon.transition()
+ .attr(rw/2 - PLUS_ICON_WIDTH/2)
+ .ease('cubic-out')
+ .duration(200)
+ .attr('width', 0)
+ .attr('height', 0)
+ .attr('x', rw/2)
+
+tip_html = (d) ->
+ fragment = $(tip_template).clone()
+ top = fragment.find("#fragment")
+ title = top.find("p.commit-title")
+ title.text d.title
+
+ if d.refs
+ title.append " <span />"
+ refs = title.children().first()
+ refs.addClass("commit-describe commit-ref")
+ .text(d.refs.join(" "))
+
+ top.find("span.commit-author").text(d.author_name)
+ date = new Date(d.author_time * 1000)
+ top.find("time.commit-time")
+ .attr("datetime", date.toISOString())
+ .text(date)
+ pre = top.find(".commit-body pre").text(d.body)
+
+ if options.debug
+ # deps = gdd.deps[d.sha1]
+ # if deps
+ # sha1s = [gdd.node(sha1).name for name, bool of deps]
+ # top.append("<br />Dependencies: " + sha1s.join(", "));
+ index = gdd.node_index[d.sha1]
+ debug = "<br />node index: " + index
+ dagre_node = gdl.graph.node(d.sha1)
+ debug += "<br />dagre: (#{dagre_node.x}, #{dagre_node.y})"
+ top.append debug
+
+ # Javascript *sucks*. There's no way to get the outerHTML of a
+ # document fragment, so you have to wrap the whole thing in a
+ # single parent and then look that up via children[0].
+ return fragment[0].children[0].outerHTML
+
+translate = (x, y) ->
+ "translate(#{x},#{y})"
+
+tick_handler = ->
+ nodes.each (d) ->
+ # cola sets the bounds property which is a Rectangle
+ # representing the space which other nodes should not
+ # overlap. The innerBounds property seems to tell
+ # cola the Rectangle which is the visible part of the
+ # node, minus any blank margin.
+ d.innerBounds = d.bounds.inflate(-RECT_MARGIN)
+
+ nodes.attr "transform", (d) ->
+ translate d.innerBounds.x, d.innerBounds.y
+
+ paths.each (d) ->
+ @parentNode.insertBefore this, this if isIE()
+
+ paths.attr "d", (d) ->
+ # Undocumented: https://github.com/tgdwyer/WebCola/issues/52
+ route = cola.makeEdgeBetween \
+ d.source.innerBounds,
+ d.target.innerBounds,
+ # This value is related to but not equal to the
+ # distance of arrow tip from object it points at:
+ 5
+
+ lineData = [
+ {x: route.sourceIntersection.x, y: route.sourceIntersection.y},
+ {x: route.arrowStart.x, y: route.arrowStart.y}
+ ]
+ return lineFunction lineData
+
+lineFunction = d3.svg.line()
+ .x((d) -> d.x)
+ .y((d) -> d.y)
+ .interpolate("linear")
+
+routeEdges = ->
+ d3cola.prepareEdgeRouting EDGE_ROUTING_MARGIN
+ paths.attr "d", (d) ->
+ lineFunction d3cola.routeEdge(d)
+ # show visibility graph
+ # (g) ->
+ # if d.source.id == 10 and d.target.id === 11
+ # g.E.forEach (e) =>
+ # vis.append("line").attr("x1", e.source.p.x).attr("y1", e.source.p.y)
+ # .attr("x2", e.target.p.x).attr("y2", e.target.p.y)
+ # .attr("stroke", "green")
+
+ if isIE()
+ paths.each (d) ->
+ @parentNode.insertBefore this, this
+
+isIE = ->
+ (navigator.appName is "Microsoft Internet Explorer") or
+ ((navigator.appName is "Netscape") and
+ ((new RegExp "Trident/.*rv:([0-9]{1,}[.0-9]{0,})")
+ .exec(navigator.userAgent)?))
diff --git a/git_deps/html/js/git-deps-layout.coffee b/git_deps/html/js/git-deps-layout.coffee
new file mode 100644
index 0000000..8b8cd05
--- /dev/null
+++ b/git_deps/html/js/git-deps-layout.coffee
@@ -0,0 +1,253 @@
+DEBUG = false
+
+MIN_ROW_GAP = 60
+MIN_NODE_X_GAP = 100 # presumably includes the node width
+MAX_NODE_X_GAP = 300
+MAX_NODE_Y_GAP = 80
+
+dagre = require "dagre"
+
+gdd = require "./git-deps-data.coffee"
+
+# The list of constraints to feed into WebCola.
+constraints = []
+
+# Group nodes by row, as assigned by the y coordinates returned from
+# dagre's layout(). This will map a y coordinate onto all nodes
+# within that row.
+row_groups = {}
+
+debug = (msg) ->
+ if exports.debug
+ console.log msg
+
+dagre_layout = ->
+ g = new dagre.graphlib.Graph()
+ exports.graph = g
+
+ # Set an object for the graph label
+ g.setGraph {}
+
+ # Default to assigning a new object as a label for each new edge.
+ g.setDefaultEdgeLabel -> {}
+
+ for node in gdd.nodes
+ g.setNode node.sha1,
+ label: node.name
+ width: node.rect_width or 70
+ height: node.rect_height or 30
+
+ for parent_sha1, children of gdd.deps
+ for child_sha1, bool of children
+ g.setEdge parent_sha1, child_sha1
+
+ dagre.layout g
+ return g
+
+dagre_row_groups = ->
+ g = dagre_layout()
+ row_groups = {}
+ exports.row_groups = row_groups
+ for sha1 in g.nodes()
+ x = g.node(sha1).x
+ y = g.node(sha1).y
+ row_groups[y] = [] unless y of row_groups
+ row_groups[y].push
+ sha1: sha1
+ x: x
+
+ for y, nodes of row_groups
+ nodes.sort (n) -> -n.x
+
+ return row_groups
+
+build_constraints = ->
+ row_groups = dagre_row_groups()
+ debug "build_constraints"
+ for y, row_nodes of row_groups
+ debug y
+ debug row_nodes
+
+ constraints.length = 0 # FIXME: only rebuild constraints which changed
+
+ # We want alignment constraints between all nodes which dagre
+ # assigned the same y value.
+ #row_alignment_constraints(row_groups)
+
+ # We need separation constraints ensuring that the left-to-right
+ # ordering within each row assigned by dagre is preserved.
+ for y, row_nodes of row_groups
+ # No point having an alignment group with only one node in.
+ continue if row_nodes.length <= 1
+
+ # Multiple constraints per row.
+ debug "ordering for row y=#{y}"
+ row_node_ordering_constraints(row_nodes)
+ debug_constraints()
+
+ # We need separation constraints ensuring that the top-to-bottom
+ # ordering assigned by dagre is preserved. Since all nodes within
+ # a single row are already constrained to the same y coordinate
+ # from above, one would have hoped it would be enough to only have
+ # separation between a single node in adjacent rows:
+ #
+ # row_ordering_constraints(row_groups)
+
+ # However, due to https://github.com/tgdwyer/WebCola/issues/61
+ # there is more flexibility for y-coordinates within a row than we
+ # want, so instead we order rows using dependencies.
+ dependency_ordering_constraints()
+
+debug_constraints = (cs = constraints) ->
+ for c in cs
+ debug c
+ return
+
+row_alignment_constraints = (row_groups) ->
+ row_alignment_constraint(row_nodes) \
+ for y, row_nodes of row_groups when row_nodes.length > 1
+
+row_alignment_constraint = (row_nodes) ->
+ debug 'row_alignment_constraint'
+ # A standard alignment constraint (one per row) is too strict
+ # because it doesn't give cola enough "wiggle room":
+ #
+ # constraint =
+ # axis: "y"
+ # type: "alignment"
+ # offsets: []
+ #
+ # for node in row_nodes
+ # constraint.offsets.push
+ # node: gdd.node_index[node.sha1],
+ # offset: 0
+ #
+ # constraints.push constraint
+ #
+ # So instead we use vertical min/max separation constraints:
+ i = 0
+ while i < row_nodes.length - 1
+ left = row_nodes[i]
+ right = row_nodes[i+1]
+ mm = max_unordered_separation_constraints \
+ 'y', MAX_NODE_Y_GAP,
+ gdd.node_index[left.sha1],
+ gdd.node_index[right.sha1]
+ exports.constraints = constraints = constraints.concat mm
+ i++
+ debug_constraints()
+ return
+
+row_node_ordering_constraints = (row_nodes) ->
+ debug 'row_node_ordering_constraints'
+ i = 0
+ while i < row_nodes.length - 1
+ left = row_nodes[i]
+ right = row_nodes[i+1]
+ left_i = gdd.node_index[left.sha1]
+ right_i = gdd.node_index[right.sha1]
+ debug " #{left_i} < #{right_i} (#{left.x} < #{right.x})"
+ # mm = min_max_ordered_separation_constraints \
+ # 'x', MIN_NODE_X_GAP, MAX_NODE_X_GAP, left_i, right_i
+ min = min_separation_constraint \
+ 'x', MIN_NODE_X_GAP, left_i, right_i
+ exports.constraints = constraints = constraints.concat min
+ i++
+ return
+
+row_ordering_constraints = (row_groups) ->
+ debug 'row_ordering_constraints'
+ row_y_coords = Object.keys(row_groups).sort()
+
+ i = 0
+ while i < row_y_coords.length - 1
+ upper_y = row_y_coords[i]
+ lower_y = row_y_coords[i + 1]
+ upper_node = row_groups[upper_y][0]
+ lower_node = row_groups[lower_y][0]
+ constraints.push \
+ min_separation_constraint \
+ 'y', MIN_ROW_GAP,
+ gdd.node_index[upper_node.sha1],
+ gdd.node_index[lower_node.sha1]
+
+ i++
+ debug_constraints()
+ return
+
+dependency_ordering_constraints = () ->
+ debug 'dependency_ordering_constraints'
+
+ for parent_sha1, children of gdd.deps
+ child_sha1s = Object.keys(children).sort (sha1) -> node(sha1).x
+ dependency_ordering_constraint(parent_sha1, child_sha1s[0])
+ len = child_sha1s.length
+ if len > 1
+ dependency_ordering_constraint(parent_sha1, child_sha1s[len-1])
+ if len > 2
+ middle = Math.floor(len / 2)
+ dependency_ordering_constraint(parent_sha1, child_sha1s[middle])
+
+ debug_constraints()
+ return
+
+dependency_ordering_constraint = (parent_sha1, child_sha1) ->
+ constraints.push \
+ min_separation_constraint \
+ 'y', MIN_ROW_GAP,
+ gdd.node_index[parent_sha1],
+ gdd.node_index[child_sha1]
+
+##################################################################
+# helpers
+
+# Uses approach explained here:
+# https://github.com/tgdwyer/WebCola/issues/62#issuecomment-69571870
+min_max_ordered_separation_constraints = (axis, min, max, left, right) ->
+ return [
+ min_separation_constraint(axis, min, left, right),
+ max_separation_constraint(axis, max, left, right)
+ ]
+
+# https://github.com/tgdwyer/WebCola/issues/66
+max_unordered_separation_constraints = (axis, max, left, right) ->
+ return [
+ max_separation_constraint(axis, max, left, right),
+ max_separation_constraint(axis, max, right, left)
+ ]
+
+min_separation_constraint = (axis, gap, left, right) ->
+ {} =
+ axis: axis
+ gap: gap
+ left: left
+ right: right
+
+# We use a negative gap and reverse the inequality, in order to
+# achieve a maximum rather than minimum separation gap. However this
+# does not prevent the nodes from overlapping or even swapping order.
+# For that you also need a min_separation_constraint, but it's more
+# convenient to use min_max_ordered_separation_constraints. See
+# https://github.com/tgdwyer/WebCola/issues/62#issuecomment-69571870
+# for more details.
+max_separation_constraint = (axis, gap, left, right) ->
+ {} =
+ axis: axis
+ gap: -gap
+ left: right
+ right: left
+
+node = (sha1) ->
+ exports.graph.node sha1
+
+module.exports = exports =
+ # Variables have to be exported every time they're assigned,
+ # since assignment creates a new object and associated reference
+
+ # Functions
+ build_constraints: build_constraints
+ debug_constraints: debug_constraints
+ node: node
+
+ # Variables
+ debug: DEBUG
diff --git a/git_deps/html/js/git-deps-noty.coffee b/git_deps/html/js/git-deps-noty.coffee
new file mode 100644
index 0000000..cec2b08
--- /dev/null
+++ b/git_deps/html/js/git-deps-noty.coffee
@@ -0,0 +1,32 @@
+noty = require "noty"
+
+# Different noty types:
+# alert, success, error, warning, information, confirmation
+noty_error = (text) -> notyfication "error", text
+noty_warn = (text) -> notyfication "warning", text
+noty_success = (text) -> notyfication "success", text
+noty_info = (text) -> notyfication "information", text
+noty_debug = (text) -> notyfication "information", text
+
+# "notyfication" - haha, did you see what I did there?
+notyfication = (type, text) ->
+ noty(
+ text: text
+ type: type
+ layout: "topRight"
+ theme: "relax"
+ maxVisible: 15
+ timeout: 30000 # ms
+ animation:
+ open: "animated bounceInUp" # Animate.css class names
+ close: "animated bounceOutUp" # Animate.css class names
+ easing: "swing" # unavailable - no need
+ speed: 500 # unavailable - no need
+ )
+
+module.exports =
+ error: noty_error
+ warn: noty_warn
+ success: noty_success
+ info: noty_info
+ debug: noty_debug
diff --git a/git_deps/html/package.json b/git_deps/html/package.json
new file mode 100644
index 0000000..d4dfcd7
--- /dev/null
+++ b/git_deps/html/package.json
@@ -0,0 +1,54 @@
+{
+ "name": "git-deps",
+ "version": "0.1.0",
+ "authors": [
+ "Adam Spiers"
+ ],
+ "description": "tool for performing automatic analysis of dependencies between git commits",
+ "main": "git-deps",
+ "keywords": [
+ "git",
+ "dependency",
+ "analysis",
+ "scm",
+ "graphing",
+ "visualization"
+ ],
+ "license": "GPL-2.0",
+ "homepage": "https://github.com/aspiers/git-deps",
+ "private": true,
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ],
+ "dependencies": {
+ "d3-tip": "~0.6.6",
+ "d3": "~3.5.3",
+ "webcola": "aspiers/WebCola#git-deps-master",
+ "jquery": "~2.1.3",
+ "noty": "~v2.4.1",
+ "browserify": "*",
+ "coffeeify" : "~1.0.0",
+ "dagre": "~0.7.1"
+ },
+ "devDependencies": {
+ "watchify": "*"
+ },
+ "directories": {
+ "test": "test"
+ },
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/aspiers/git-deps"
+ },
+ "author": "Adam Spiers",
+ "bugs": {
+ "url": "https://github.com/aspiers/git-deps/issues"
+ }
+}
diff --git a/git_deps/html/test.json b/git_deps/html/test.json
new file mode 100644
index 0000000..3d73289
--- /dev/null
+++ b/git_deps/html/test.json
@@ -0,0 +1,442 @@
+{
+ "commits": [
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": 0,
+ "author_time": 1420486941,
+ "body": "This creates the JSON which will eventually be consumed by\nthe Javascript visualizer.\n",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420487137,
+ "describe": "tags/test-0",
+ "name": "2b6d591",
+ "separator": "\n",
+ "sha": "2b6d5915f6433b9eb1685751b82cfbebcbb37981",
+ "title": "add JSON listener"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384447153,
+ "body": "Automatic git commit dependency inference tool.\n\nOriginally committed to:\n\n https://github.com/aspiers/git-config/blob/master/bin/git-deps\n\nand then split off into this repository via git filter-branch\nand other hackery, preserving history.\n",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420476874,
+ "describe": "",
+ "name": "b196757",
+ "separator": "\n",
+ "sha": "b1967573e81a8100a4cc778936de0ba0a8a8f5cb",
+ "title": "first prototype of git-deps"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384471712,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477027,
+ "describe": "",
+ "name": "3a1dd42",
+ "separator": "\n",
+ "sha": "3a1dd42fd6114a634ba7cf037ce61e2aee76db73",
+ "title": "add logging and recursion"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384563102,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477027,
+ "describe": "",
+ "name": "3374b84",
+ "separator": "\n",
+ "sha": "3374b8419a45d91d3c0631be11c8cf893b272217",
+ "title": "add listener classes"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": 0,
+ "author_time": 1420483579,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420483579,
+ "describe": "",
+ "name": "ff82dda",
+ "separator": "\n",
+ "sha": "ff82dda196947650bd497301e61b282753193564",
+ "title": "fix a bunch of PEP8 issues"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384579026,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "8d44254",
+ "separator": "\n",
+ "sha": "8d442544a20b706b996d66ab390a16fd97b48d6d",
+ "title": "use new-style classes"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384452615,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477027,
+ "describe": "",
+ "name": "b144bfd",
+ "separator": "\n",
+ "sha": "b144bfd5feb327ef7ce0c26bbfb6f4da573abfe5",
+ "title": "refactor into new DependencyDetector class"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": 0,
+ "author_time": 1420482533,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420482533,
+ "describe": "",
+ "name": "e406002",
+ "separator": "\n",
+ "sha": "e40600230d1c3059485437bd4d5690d61c9edb2f",
+ "title": "don't show \"[False]\" default for boolean options"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384650040,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "4f27a1e",
+ "separator": "\n",
+ "sha": "4f27a1ee2b5fd63a58311a20e2aed0a24eda8da2",
+ "title": "add --exclude-commits"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384656388,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "824f84c",
+ "separator": "\n",
+ "sha": "824f84cd594254d0c87f330b855153fc5ffe5ad3",
+ "title": "add installation instructions"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384579202,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "6240939",
+ "separator": "\n",
+ "sha": "62409395e260ad01f9ae7b84869f5516ef80c7aa",
+ "title": "output dependencies as soon as they're found"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384654780,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "5071249",
+ "separator": "\n",
+ "sha": "5071249715e82dcf3c1db12eec28c1232aba2142",
+ "title": "avoid adding entries to TODO queue multiple times"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384566591,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477027,
+ "describe": "",
+ "name": "6e86e8b",
+ "separator": "\n",
+ "sha": "6e86e8b7f648bd6a3a6d3216aa5899414b65cbed",
+ "title": "don't crash on commits which only add files"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384563081,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477027,
+ "describe": "",
+ "name": "acc24a4",
+ "separator": "\n",
+ "sha": "acc24a404d82061bbc6db5afb146d83bf131830b",
+ "title": "add --context-lines"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384567428,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "5ec5ccb",
+ "separator": "\n",
+ "sha": "5ec5ccbdff508014c61ae9d18f3366a15c0f2689",
+ "title": "add first line of commits to debug"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384563342,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477027,
+ "describe": "",
+ "name": "f2cddb4",
+ "separator": "\n",
+ "sha": "f2cddb4aa00de4ddff2cdca251758e25e95e04ad",
+ "title": "tweaks to improve debugging"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384651799,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "1b66efa",
+ "separator": "\n",
+ "sha": "1b66efa173a19a8b4c0c47274a1b9cdd8b9912af",
+ "title": "improve help text"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384567528,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "80c247f",
+ "separator": "\n",
+ "sha": "80c247fd21a1e7f476d1c8ba289498e216eff3dc",
+ "title": "--help: put short options first"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384567489,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "2ebcb2b",
+ "separator": "\n",
+ "sha": "2ebcb2b6081e32e9a463519525bd432287b24520",
+ "title": "improve --help for --context-lines"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384636660,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "f7bf058",
+ "separator": "\n",
+ "sha": "f7bf058439fd7499aad7a10418a9f516e6949fbc",
+ "title": "allow multiple dependents on ARGV, and fix usage string"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384612401,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "2a05400",
+ "separator": "\n",
+ "sha": "2a05400e232e14f0d4c1cbfb548a0871ea57bd44",
+ "title": "ignore KeyboardInterrupt"
+ },
+ {
+ "author_mail": "git@adamspiers.org",
+ "author_name": "Adam Spiers",
+ "author_offset": -300,
+ "author_time": 1384652004,
+ "body": "",
+ "committer_mail": "git@adamspiers.org",
+ "committer_name": "Adam Spiers",
+ "committer_offset": 0,
+ "committer_time": 1420477028,
+ "describe": "",
+ "name": "4364944",
+ "separator": "\n",
+ "sha": "43649442f49876ad22051b085a9258f39bbcd5c6",
+ "title": "fix error message"
+ }
+ ],
+ "dependencies": [
+ {
+ "child": "b1967573e81a8100a4cc778936de0ba0a8a8f5cb",
+ "parent": "2b6d5915f6433b9eb1685751b82cfbebcbb37981"
+ },
+ {
+ "child": "3a1dd42fd6114a634ba7cf037ce61e2aee76db73",
+ "parent": "2b6d5915f6433b9eb1685751b82cfbebcbb37981"
+ },
+ {
+ "child": "3374b8419a45d91d3c0631be11c8cf893b272217",
+ "parent": "2b6d5915f6433b9eb1685751b82cfbebcbb37981"
+ },
+ {
+ "child": "ff82dda196947650bd497301e61b282753193564",
+ "parent": "2b6d5915f6433b9eb1685751b82cfbebcbb37981"
+ },
+ {
+ "child": "8d442544a20b706b996d66ab390a16fd97b48d6d",
+ "parent": "2b6d5915f6433b9eb1685751b82cfbebcbb37981"
+ },
+ {
+ "child": "b144bfd5feb327ef7ce0c26bbfb6f4da573abfe5",
+ "parent": "2b6d5915f6433b9eb1685751b82cfbebcbb37981"
+ },
+ {
+ "child": "e40600230d1c3059485437bd4d5690d61c9edb2f",
+ "parent": "2b6d5915f6433b9eb1685751b82cfbebcbb37981"
+ },
+ {
+ "child": "4f27a1ee2b5fd63a58311a20e2aed0a24eda8da2",
+ "parent": "2b6d5915f6433b9eb1685751b82cfbebcbb37981"
+ },
+ {
+ "child": "824f84cd594254d0c87f330b855153fc5ffe5ad3",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "62409395e260ad01f9ae7b84869f5516ef80c7aa",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "5071249715e82dcf3c1db12eec28c1232aba2142",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "6e86e8b7f648bd6a3a6d3216aa5899414b65cbed",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "acc24a404d82061bbc6db5afb146d83bf131830b",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "5ec5ccbdff508014c61ae9d18f3366a15c0f2689",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "f2cddb4aa00de4ddff2cdca251758e25e95e04ad",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "1b66efa173a19a8b4c0c47274a1b9cdd8b9912af",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "80c247fd21a1e7f476d1c8ba289498e216eff3dc",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "2ebcb2b6081e32e9a463519525bd432287b24520",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "f7bf058439fd7499aad7a10418a9f516e6949fbc",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "2a05400e232e14f0d4c1cbfb548a0871ea57bd44",
+ "parent": "ff82dda196947650bd497301e61b282753193564"
+ },
+ {
+ "child": "43649442f49876ad22051b085a9258f39bbcd5c6",
+ "parent": "5071249715e82dcf3c1db12eec28c1232aba2142"
+ }
+ ]
+}
diff --git a/git_deps/html/tip-template.html b/git_deps/html/tip-template.html
new file mode 100644
index 0000000..1362574
--- /dev/null
+++ b/git_deps/html/tip-template.html
@@ -0,0 +1,11 @@
+<div id="fragment">
+ <p class="commit-title" />
+ <div class="commit-meta">
+ <span class="commit-author"></span>
+ authored on
+ <time class="commit-time" is="relative-time" />
+ </div>
+ <div class="commit-body">
+ <pre />
+ </div>
+</div>