Index: /extensions/TakeATour/admin.php
===================================================================
--- /extensions/TakeATour/admin.php	(revision 27995)
+++ /extensions/TakeATour/admin.php	(revision 27995)
@@ -0,0 +1,22 @@
+<?php
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+global $template, $conf, $user, $page;
+
+load_language('plugin.lang', PHPWG_PLUGINS_PATH .'TakeATour/');
+$template->assign(
+  array(
+    'F_ACTION' => get_root_url().'admin.php',
+    )
+  );
+/*
+$template->func_combine_css(array(
+	'path' => 'plugins/TakeATour/template/admin.css',
+	)
+);*/
+
+$template->set_filename('plugin_admin_content', dirname(__FILE__) .'/tpl/admin.tpl');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+
+?>
Index: /extensions/TakeATour/css/bootstrap-essential.css
===================================================================
--- /extensions/TakeATour/css/bootstrap-essential.css	(revision 27995)
+++ /extensions/TakeATour/css/bootstrap-essential.css	(revision 27995)
@@ -0,0 +1,220 @@
+.tooltip {
+  position: absolute;
+  z-index: 1030;
+  display: block;
+  font-size: 12px;
+  line-height: 1.4;
+  visibility: visible;
+  filter: alpha(opacity=0);
+  opacity: 0;
+}
+.tooltip.in {
+  filter: alpha(opacity=90);
+  opacity: .9;
+}
+.tooltip.top {
+  padding: 5px 0;
+  margin-top: -3px;
+}
+.tooltip.right {
+  padding: 0 5px;
+  margin-left: 3px;
+}
+.tooltip.bottom {
+  padding: 5px 0;
+  margin-top: 3px;
+}
+.tooltip.left {
+  padding: 0 5px;
+  margin-left: -3px;
+}
+.tooltip-inner {
+  max-width: 200px;
+  padding: 3px 8px;
+  color: #fff;
+  text-align: center;
+  text-decoration: none;
+  background-color: #000;
+  border-radius: 4px;
+}
+.tooltip-arrow {
+  position: absolute;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.tooltip.top .tooltip-arrow {
+  bottom: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-left .tooltip-arrow {
+  bottom: 0;
+  left: 5px;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.top-right .tooltip-arrow {
+  right: 5px;
+  bottom: 0;
+  border-width: 5px 5px 0;
+  border-top-color: #000;
+}
+.tooltip.right .tooltip-arrow {
+  top: 50%;
+  left: 0;
+  margin-top: -5px;
+  border-width: 5px 5px 5px 0;
+  border-right-color: #000;
+}
+.tooltip.left .tooltip-arrow {
+  top: 50%;
+  right: 0;
+  margin-top: -5px;
+  border-width: 5px 0 5px 5px;
+  border-left-color: #000;
+}
+.tooltip.bottom .tooltip-arrow {
+  top: 0;
+  left: 50%;
+  margin-left: -5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-left .tooltip-arrow {
+  top: 0;
+  left: 5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.tooltip.bottom-right .tooltip-arrow {
+  top: 0;
+  right: 5px;
+  border-width: 0 5px 5px;
+  border-bottom-color: #000;
+}
+.popover {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: 1010;
+  display: none;
+  max-width: 276px;
+  padding: 1px;
+  text-align: left;
+  white-space: normal;
+  background-color: #fff;
+  background-clip: padding-box;
+  border: 1px solid #ccc;
+  border: 1px solid rgba(0, 0, 0, .2);
+  border-radius: 6px;
+  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+          box-shadow: 0 5px 10px rgba(0, 0, 0, .2);
+}
+.popover.top {
+  margin-top: -10px;
+}
+.popover.right {
+  margin-left: 10px;
+}
+.popover.bottom {
+  margin-top: 10px;
+}
+.popover.left {
+  margin-left: -10px;
+}
+.popover-title {
+  padding: 8px 14px;
+  margin: 0;
+  font-size: 14px;
+  font-weight: normal;
+  line-height: 18px;
+  background-color: #f7f7f7;
+  border-bottom: 1px solid #ebebeb;
+  border-radius: 5px 5px 0 0;
+}
+.popover-content {
+  padding: 9px 14px;
+}
+.popover .arrow,
+.popover .arrow:after {
+  position: absolute;
+  display: block;
+  width: 0;
+  height: 0;
+  border-color: transparent;
+  border-style: solid;
+}
+.popover .arrow {
+  border-width: 11px;
+}
+.popover .arrow:after {
+  content: "";
+  border-width: 10px;
+}
+.popover.top .arrow {
+  bottom: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-color: #999;
+  border-top-color: rgba(0, 0, 0, .25);
+  border-bottom-width: 0;
+}
+.popover.top .arrow:after {
+  bottom: 1px;
+  margin-left: -10px;
+  content: " ";
+  border-top-color: #fff;
+  border-bottom-width: 0;
+}
+.popover.right .arrow {
+  top: 50%;
+  left: -11px;
+  margin-top: -11px;
+  border-right-color: #999;
+  border-right-color: rgba(0, 0, 0, .25);
+  border-left-width: 0;
+}
+.popover.right .arrow:after {
+  bottom: -10px;
+  left: 1px;
+  content: " ";
+  border-right-color: #fff;
+  border-left-width: 0;
+}
+.popover.bottom .arrow {
+  top: -11px;
+  left: 50%;
+  margin-left: -11px;
+  border-top-width: 0;
+  border-bottom-color: #999;
+  border-bottom-color: rgba(0, 0, 0, .25);
+}
+.popover.bottom .arrow:after {
+  top: 1px;
+  margin-left: -10px;
+  content: " ";
+  border-top-width: 0;
+  border-bottom-color: #fff;
+}
+.popover.left .arrow {
+  top: 50%;
+  right: -11px;
+  margin-top: -11px;
+  border-right-width: 0;
+  border-left-color: #999;
+  border-left-color: rgba(0, 0, 0, .25);
+}
+.popover.left .arrow:after {
+  right: 1px;
+  bottom: -10px;
+  content: " ";
+  border-right-width: 0;
+  border-left-color: #fff;
+}
+#TAT_FC_14 .actions {
+  display: block !important;
+}
Index: /extensions/TakeATour/css/bootstrap-tour.min.css
===================================================================
--- /extensions/TakeATour/css/bootstrap-tour.min.css	(revision 27995)
+++ /extensions/TakeATour/css/bootstrap-tour.min.css	(revision 27995)
@@ -0,0 +1,19 @@
+/* ===========================================================
+# bootstrap-tour - v0.8.1
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+.tour-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1030;background-color:#000;opacity:.8}.tour-step-backdrop{position:relative;z-index:1031;background:inherit}.tour-step-background{position:absolute;z-index:1030;background:inherit;border-radius:6px}.popover[class*=tour-]{z-index:1030}.popover[class*=tour-] .popover-navigation{padding:9px 14px}.popover[class*=tour-] .popover-navigation [data-role=end]{float:right}.popover[class*=tour-] .popover-navigation [data-role=prev],.popover[class*=tour-] .popover-navigation [data-role=next],.popover[class*=tour-] .popover-navigation [data-role=end]{cursor:pointer}.popover[class*=tour-] .popover-navigation [data-role=prev].disabled,.popover[class*=tour-] .popover-navigation [data-role=next].disabled,.popover[class*=tour-] .popover-navigation [data-role=end].disabled{cursor:default}.popover[class*=tour-].orphan{position:fixed;margin-top:0}.popover[class*=tour-].orphan .arrow{display:none}
Index: /extensions/TakeATour/js/bootstrap-tour-last.js
===================================================================
--- /extensions/TakeATour/js/bootstrap-tour-last.js	(revision 27995)
+++ /extensions/TakeATour/js/bootstrap-tour-last.js	(revision 27995)
@@ -0,0 +1,694 @@
+/* ===========================================================
+# bootstrap-tour - v0.8.1
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+(function($, window) {
+  var Tour, document;
+  document = window.document;
+  Tour = (function() {
+    function Tour(options) {
+      this._options = $.extend({
+        name: "tour",
+        container: "body",
+        keyboard: true,
+        storage: window.localStorage,
+        debug: false,
+        backdrop: false,
+        redirect: true,
+        orphan: false,
+        duration: false,
+        basePath: "",
+        template: "<div class='popover'>          <div class='arrow'></div>          <h3 class='popover-title'></h3>          <div class='popover-content'></div>          <div class='popover-navigation'>            <div class='btn-group'>              <button class='btn btn-sm btn-default' data-role='prev'>&laquo; Prev</button>              <button class='btn btn-sm btn-default' data-role='next'>Next &raquo;</button>              <button class='btn btn-sm btn-default' data-role='pause-resume'                data-pause-text='Pause'                data-resume-text='Resume'              >Pause</button>            </div>            <button class='btn btn-sm btn-default' data-role='end'>End tour</button>          </div>        </div>",
+        afterSetState: function(key, value) {},
+        afterGetState: function(key, value) {},
+        afterRemoveState: function(key) {},
+        onStart: function(tour) {},
+        onEnd: function(tour) {},
+        onShow: function(tour) {},
+        onShown: function(tour) {},
+        onHide: function(tour) {},
+        onHidden: function(tour) {},
+        onNext: function(tour) {},
+        onPrev: function(tour) {},
+        onPause: function(tour, duration) {},
+        onResume: function(tour, duration) {}
+      }, options);
+      this._force = false;
+      this._inited = false;
+      this._steps = [];
+      this.backdrop = {
+        overlay: null,
+        $element: null,
+        $background: null,
+        backgroundShown: false,
+        overlayElementShown: false
+      };
+    }
+
+    Tour.prototype.setState = function(key, value) {
+      var e, keyName;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        try {
+          this._options.storage.setItem(keyName, value);
+        } catch (_error) {
+          e = _error;
+          if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
+            this.debug("LocalStorage quota exceeded. setState failed.");
+          }
+        }
+        return this._options.afterSetState(keyName, value);
+      } else {
+        if (this._state == null) {
+          this._state = {};
+        }
+        return this._state[key] = value;
+      }
+    };
+
+    Tour.prototype.removeState = function(key) {
+      var keyName;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        this._options.storage.removeItem(keyName);
+        return this._options.afterRemoveState(keyName);
+      } else {
+        if (this._state != null) {
+          return delete this._state[key];
+        }
+      }
+    };
+
+    Tour.prototype.getState = function(key) {
+      var keyName, value;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        value = this._options.storage.getItem(keyName);
+      } else {
+        if (this._state != null) {
+          value = this._state[key];
+        }
+      }
+      if (value === void 0 || value === "null") {
+        value = null;
+      }
+      this._options.afterGetState(key, value);
+      return value;
+    };
+
+    Tour.prototype.addSteps = function(steps) {
+      var step, _i, _len, _results;
+      _results = [];
+      for (_i = 0, _len = steps.length; _i < _len; _i++) {
+        step = steps[_i];
+        _results.push(this.addStep(step));
+      }
+      return _results;
+    };
+
+    Tour.prototype.addStep = function(step) {
+      return this._steps.push(step);
+    };
+
+    Tour.prototype.getStep = function(i) {
+      if (this._steps[i] != null) {
+        return $.extend({
+          id: "step-" + i,
+          path: "",
+          placement: "right",
+          title: "",
+          content: "<p></p>",
+          next: i === this._steps.length - 1 ? -1 : i + 1,
+          prev: i - 1,
+          animation: true,
+          container: this._options.container,
+          backdrop: this._options.backdrop,
+          redirect: this._options.redirect,
+          orphan: this._options.orphan,
+          duration: this._options.duration,
+          template: this._options.template,
+          onShow: this._options.onShow,
+          onShown: this._options.onShown,
+          onHide: this._options.onHide,
+          onHidden: this._options.onHidden,
+          onNext: this._options.onNext,
+          onPrev: this._options.onPrev,
+          onPause: this._options.onPause,
+          onResume: this._options.onResume
+        }, this._steps[i]);
+      }
+    };
+
+    Tour.prototype.init = function(force) {
+      var _this = this;
+      this._force = force;
+      if (this.ended()) {
+        return this._debug("Tour ended, init prevented.");
+      }
+      this.setCurrentStep();
+      this._setupMouseNavigation();
+      this._setupKeyboardNavigation();
+      this._onResize(function() {
+        return _this.showStep(_this._current);
+      });
+      if (this._current !== null) {
+        this.showStep(this._current);
+      }
+      this._inited = true;
+      return this;
+    };
+
+    Tour.prototype.start = function(force) {
+      var promise;
+      if (force == null) {
+        force = false;
+      }
+      if (!this._inited) {
+        this.init(force);
+      }
+      if (this._current === null) {
+        promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
+        return this._callOnPromiseDone(promise, this.showStep, 0);
+      }
+    };
+
+    Tour.prototype.next = function() {
+      var promise;
+      if (this.ended()) {
+        return this._debug("Tour ended, next prevented.");
+      }
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this._showNextStep);
+    };
+
+    Tour.prototype.prev = function() {
+      var promise;
+      if (this.ended()) {
+        return this._debug("Tour ended, prev prevented.");
+      }
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this._showPrevStep);
+    };
+
+    Tour.prototype.goTo = function(i) {
+      var promise;
+      if (this.ended()) {
+        return this._debug("Tour ended, goTo prevented.");
+      }
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this.showStep, i);
+    };
+
+    Tour.prototype.end = function() {
+      var endHelper, promise,
+        _this = this;
+      endHelper = function(e) {
+        $(document).off("click.tour-" + _this._options.name);
+        $(document).off("keyup.tour-" + _this._options.name);
+        $(window).off("resize.tour-" + _this._options.name);
+        _this.setState("end", "yes");
+        _this._inited = false;
+        _this._force = false;
+        _this._clearTimer();
+        if (_this._options.onEnd != null) {
+          return _this._options.onEnd(_this);
+        }
+      };
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, endHelper);
+    };
+
+    Tour.prototype.ended = function() {
+      return !this._force && !!this.getState("end");
+    };
+
+    Tour.prototype.restart = function() {
+      this.removeState("current_step");
+      this.removeState("end");
+      this.setCurrentStep(0);
+      return this.start();
+    };
+
+    Tour.prototype.pause = function() {
+      var step;
+      step = this.getStep(this._current);
+      if (!(step && step.duration)) {
+        return;
+      }
+      this._paused = true;
+      this._duration -= new Date().getTime() - this._start;
+      window.clearTimeout(this._timer);
+      this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining).");
+      if (step.onPause != null) {
+        return step.onPause(this, this._duration);
+      }
+    };
+
+    Tour.prototype.resume = function() {
+      var step,
+        _this = this;
+      step = this.getStep(this._current);
+      if (!(step && step.duration)) {
+        return;
+      }
+      this._paused = false;
+      this._start = new Date().getTime();
+      this._duration = this._duration || step.duration;
+      this._timer = window.setTimeout(function() {
+        if (_this._isLast()) {
+          return _this.next();
+        } else {
+          return _this.end();
+        }
+      }, this._duration);
+      this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration);
+      if ((step.onResume != null) && this._duration !== step.duration) {
+        return step.onResume(this, this._duration);
+      }
+    };
+
+    Tour.prototype.hideStep = function(i) {
+      var hideStepHelper, promise, step,
+        _this = this;
+      step = this.getStep(i);
+      if (!step) {
+        return;
+      }
+      this._clearTimer();
+      promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
+      hideStepHelper = function(e) {
+        var $element;
+        $element = $(step.element);
+        if (!($element.data("bs.popover") || $element.data("popover"))) {
+          $element = $("body");
+        }
+        $element.popover("destroy");
+        if (step.reflex) {
+          $element.css("cursor", "").off("click.tour-" + _this._options.name);
+        }
+        if (step.backdrop) {
+          _this._hideBackdrop();
+        }
+        if (step.onHidden != null) {
+          return step.onHidden(_this);
+        }
+      };
+      this._callOnPromiseDone(promise, hideStepHelper);
+      return promise;
+    };
+
+    Tour.prototype.showStep = function(i) {
+      var promise, showStepHelper, skipToPrevious, step,
+        _this = this;
+      step = this.getStep(i);
+      if (!step) {
+        return;
+      }
+      skipToPrevious = i < this._current;
+      promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
+      showStepHelper = function(e) {
+        var current_path, path;
+        _this.setCurrentStep(i);
+        path = $.isFunction(step.path) ? step.path.call() : _this._options.basePath + step.path;
+        current_path = [document.location.pathname, document.location.hash].join("");
+        if (_this._isRedirect(path, current_path)) {
+          _this._redirect(step, path);
+          return;
+        }
+        if (_this._isOrphan(step)) {
+          if (!step.orphan) {
+            _this._debug("Skip the orphan step " + (_this._current + 1) + ". Orphan option is false and the element doesn't exist or is hidden.");
+            if (skipToPrevious) {
+              _this._showPrevStep();
+            } else {
+              _this._showNextStep();
+            }
+            return;
+          }
+          _this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
+        }
+        if (step.backdrop) {
+          _this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
+        }
+        _this._scrollIntoView(step.element, function() {
+          if ((step.element != null) && step.backdrop) {
+            _this._showOverlayElement(step.element);
+          }
+          _this._showPopover(step, i);
+          if (step.onShown != null) {
+            step.onShown(_this);
+          }
+          return _this._debug("Step " + (_this._current + 1) + " of " + _this._steps.length);
+        });
+        if (step.duration) {
+          return _this.resume();
+        }
+      };
+      this._callOnPromiseDone(promise, showStepHelper);
+      return promise;
+    };
+
+    Tour.prototype.getCurrentStep = function() {
+      return this._current;
+    };
+
+    Tour.prototype.setCurrentStep = function(value) {
+      if (value != null) {
+        this._current = value;
+        this.setState("current_step", value);
+      } else {
+        this._current = this.getState("current_step");
+        this._current = this._current === null ? null : parseInt(this._current, 10);
+      }
+      return this;
+    };
+
+    Tour.prototype._showNextStep = function() {
+      var promise, showNextStepHelper, step,
+        _this = this;
+      step = this.getStep(this._current);
+      showNextStepHelper = function(e) {
+        return _this.showStep(step.next);
+      };
+      promise = this._makePromise((step.onNext != null ? step.onNext(this) : void 0));
+      return this._callOnPromiseDone(promise, showNextStepHelper);
+    };
+
+    Tour.prototype._showPrevStep = function() {
+      var promise, showPrevStepHelper, step,
+        _this = this;
+      step = this.getStep(this._current);
+      showPrevStepHelper = function(e) {
+        return _this.showStep(step.prev);
+      };
+      promise = this._makePromise((step.onPrev != null ? step.onPrev(this) : void 0));
+      return this._callOnPromiseDone(promise, showPrevStepHelper);
+    };
+
+    Tour.prototype._debug = function(text) {
+      if (this._options.debug) {
+        return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
+      }
+    };
+
+    Tour.prototype._isRedirect = function(path, currentPath) {
+      return (path != null) && path !== "" && path.replace(/\?.*$/, "").replace(/\/?$/, "") !== currentPath.replace(/\/?$/, "");
+    };
+
+    Tour.prototype._redirect = function(step, path) {
+      if ($.isFunction(step.redirect)) {
+        return step.redirect.call(this, path);
+      } else if (step.redirect === true) {
+        this._debug("Redirect to " + path);
+        return document.location.href = path;
+      }
+    };
+
+    Tour.prototype._isOrphan = function(step) {
+      return (step.element == null) || !$(step.element).length || $(step.element).is(":hidden") && ($(step.element)[0].namespaceURI !== "http://www.w3.org/2000/svg");
+    };
+
+    Tour.prototype._isLast = function() {
+      return this._current < this._steps.length - 1;
+    };
+
+    Tour.prototype._showPopover = function(step, i) {
+      var $element, $navigation, $template, $tip, isOrphan, options,
+        _this = this;
+      options = $.extend({}, this._options);
+      $template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
+      $navigation = $template.find(".popover-navigation");
+      isOrphan = this._isOrphan(step);
+      if (isOrphan) {
+        step.element = "body";
+        step.placement = "top";
+        $template = $template.addClass("orphan");
+      }
+      $element = $(step.element);
+      $template.addClass("tour-" + this._options.name);
+      if (step.options) {
+        $.extend(options, step.options);
+      }
+      if (step.reflex) {
+        $element.css("cursor", "pointer").on("click.tour-" + this._options.name, function() {
+          if (_this._isLast()) {
+            return _this.next();
+          } else {
+            return _this.end();
+          }
+        });
+      }
+      if (step.prev < 0) {
+        $navigation.find("*[data-role=prev]").addClass("disabled");
+      }
+      if (step.next < 0) {
+        $navigation.find("*[data-role=next]").addClass("disabled");
+      }
+      if (!step.duration) {
+        $navigation.find("*[data-role='pause-resume']").remove();
+      }
+      step.template = $template.clone().wrap("<div>").parent().html();
+      $element.popover({
+        placement: step.placement,
+        trigger: "manual",
+        title: step.title,
+        content: step.content,
+        html: true,
+        animation: step.animation,
+        container: step.container,
+        template: step.template,
+        selector: step.element
+      }).popover("show");
+      $tip = $element.data("bs.popover") ? $element.data("bs.popover").tip() : $element.data("popover").tip();
+      $tip.attr("id", step.id);
+      this._reposition($tip, step);
+      if (isOrphan) {
+        return this._center($tip);
+      }
+    };
+
+    Tour.prototype._reposition = function($tip, step) {
+      var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
+      offsetWidth = $tip[0].offsetWidth;
+      offsetHeight = $tip[0].offsetHeight;
+      tipOffset = $tip.offset();
+      originalLeft = tipOffset.left;
+      originalTop = tipOffset.top;
+      offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
+      if (offsetBottom < 0) {
+        tipOffset.top = tipOffset.top + offsetBottom;
+      }
+      offsetRight = $("html").outerWidth() - tipOffset.left - $tip.outerWidth();
+      if (offsetRight < 0) {
+        tipOffset.left = tipOffset.left + offsetRight;
+      }
+      if (tipOffset.top < 0) {
+        tipOffset.top = 0;
+      }
+      if (tipOffset.left < 0) {
+        tipOffset.left = 0;
+      }
+      $tip.offset(tipOffset);
+      if (step.placement === "bottom" || step.placement === "top") {
+        if (originalLeft !== tipOffset.left) {
+          return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, "left");
+        }
+      } else {
+        if (originalTop !== tipOffset.top) {
+          return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top");
+        }
+      }
+    };
+
+    Tour.prototype._center = function($tip) {
+      return $tip.css("top", $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
+    };
+
+    Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
+      return $tip.find(".arrow").css(position, delta ? 50 * (1 - delta / dimension) + "%" : "");
+    };
+
+    Tour.prototype._scrollIntoView = function(element, callback) {
+      var $element, $window, counter, offsetTop, scrollTop, windowHeight,
+        _this = this;
+      $element = $(element);
+      if (!$element.length) {
+        return callback();
+      }
+      $window = $(window);
+      offsetTop = $element.offset().top;
+      windowHeight = $window.height();
+      scrollTop = Math.max(0, offsetTop - (windowHeight / 2));
+      this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + ".");
+      counter = 0;
+      return $("body,html").stop(true, true).animate({
+        scrollTop: Math.ceil(scrollTop)
+      }, function() {
+        if (++counter === 2) {
+          callback();
+          return _this._debug("Scroll into view. Animation end element offset: " + ($element.offset().top) + ". Window height: " + ($window.height()) + ".");
+        }
+      });
+    };
+
+    Tour.prototype._onResize = function(callback, timeout) {
+      return $(window).on("resize.tour-" + this._options.name, function() {
+        clearTimeout(timeout);
+        return timeout = setTimeout(callback, 100);
+      });
+    };
+
+    Tour.prototype._setupMouseNavigation = function() {
+      var _this = this;
+      _this = this;
+      $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=next]:not(.disabled)").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=next]:not(.disabled)", function(e) {
+        e.preventDefault();
+        return _this.next();
+      });
+      $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=prev]:not(.disabled)").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=prev]:not(.disabled)", function(e) {
+        e.preventDefault();
+        return _this.prev();
+      });
+      $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=end]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=end]", function(e) {
+        e.preventDefault();
+        return _this.end();
+      });
+      return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=pause-resume]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=pause-resume]", function(e) {
+        var $this;
+        e.preventDefault();
+        $this = $(this);
+        $this.text(_this._paused ? $this.data("pause-text") : $this.data("resume-text"));
+        if (_this._paused) {
+          return _this.resume();
+        } else {
+          return _this.pause();
+        }
+      });
+    };
+
+    Tour.prototype._setupKeyboardNavigation = function() {
+      var _this = this;
+      if (!this._options.keyboard) {
+        return;
+      }
+      return $(document).on("keyup.tour-" + this._options.name, function(e) {
+        if (!e.which) {
+          return;
+        }
+        switch (e.which) {
+          case 39:
+            e.preventDefault();
+            if (_this._isLast()) {
+              return _this.next();
+            } else {
+              return _this.end();
+            }
+            break;
+          case 37:
+            e.preventDefault();
+            if (_this._current > 0) {
+              return _this.prev();
+            }
+            break;
+          case 27:
+            e.preventDefault();
+            return _this.end();
+        }
+      });
+    };
+
+    Tour.prototype._makePromise = function(result) {
+      if (result && $.isFunction(result.then)) {
+        return result;
+      } else {
+        return null;
+      }
+    };
+
+    Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
+      var _this = this;
+      if (promise) {
+        return promise.then(function(e) {
+          return cb.call(_this, arg);
+        });
+      } else {
+        return cb.call(this, arg);
+      }
+    };
+
+    Tour.prototype._showBackdrop = function(element) {
+      if (this.backdrop.backgroundShown) {
+        return;
+      }
+      this.backdrop = $("<div/>", {
+        "class": "tour-backdrop"
+      });
+      this.backdrop.backgroundShown = true;
+      return $("body").append(this.backdrop);
+    };
+
+    Tour.prototype._hideBackdrop = function() {
+      this._hideOverlayElement();
+      return this._hideBackground();
+    };
+
+    Tour.prototype._hideBackground = function() {
+      this.backdrop.remove();
+      this.backdrop.overlay = null;
+      return this.backdrop.backgroundShown = false;
+    };
+
+    Tour.prototype._showOverlayElement = function(element) {
+      var $background, $element, offset;
+      if (this.backdrop.overlayElementShown) {
+        return;
+      }
+      this.backdrop.overlayElementShown = true;
+      $element = $(element);
+      $background = $("<div/>");
+      offset = $element.offset();
+      offset.top = offset.top;
+      offset.left = offset.left;
+      $background.width($element.innerWidth()).height($element.innerHeight()).addClass("tour-step-background").offset(offset);
+      $element.addClass("tour-step-backdrop");
+      $("body").append($background);
+      this.backdrop.$element = $element;
+      return this.backdrop.$background = $background;
+    };
+
+    Tour.prototype._hideOverlayElement = function() {
+      if (!this.backdrop.overlayElementShown) {
+        return;
+      }
+      this.backdrop.$element.removeClass("tour-step-backdrop");
+      this.backdrop.$background.remove();
+      this.backdrop.$element = null;
+      this.backdrop.$background = null;
+      return this.backdrop.overlayElementShown = false;
+    };
+
+    Tour.prototype._clearTimer = function() {
+      window.clearTimeout(this._timer);
+      this._timer = null;
+      return this._duration = null;
+    };
+
+    return Tour;
+
+  })();
+  return window.Tour = Tour;
+})(jQuery, window);
Index: /extensions/TakeATour/js/bootstrap-tour-standalone.min.js
===================================================================
--- /extensions/TakeATour/js/bootstrap-tour-standalone.min.js	(revision 27995)
+++ /extensions/TakeATour/js/bootstrap-tour-standalone.min.js	(revision 27995)
@@ -0,0 +1,19 @@
+/* ===========================================================
+# bootstrap-tour - v0.9.0
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
++function(a){"use strict";var b=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};b.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1},b.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},b.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},b.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show),void 0):c.show()},b.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type);return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide),void 0):c.hide()},b.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){if(this.$element.trigger(b),b.isDefaultPrevented())return;var c=this,d=this.tip();this.setContent(),this.options.animation&&d.addClass("fade");var e="function"==typeof this.options.placement?this.options.placement.call(this,d[0],this.$element[0]):this.options.placement,f=/\s?auto?\s?/i,g=f.test(e);g&&(e=e.replace(f,"")||"top"),d.detach().css({top:0,left:0,display:"block"}).addClass(e),this.options.container?d.appendTo(this.options.container):d.insertAfter(this.$element);var h=this.getPosition(),i=d[0].offsetWidth,j=d[0].offsetHeight;if(g){var k=this.$element.parent(),l=e,m=document.documentElement.scrollTop||document.body.scrollTop,n="body"==this.options.container?window.innerWidth:k.outerWidth(),o="body"==this.options.container?window.innerHeight:k.outerHeight(),p="body"==this.options.container?0:k.offset().left;e="bottom"==e&&h.top+h.height+j-m>o?"top":"top"==e&&h.top-m-j<0?"bottom":"right"==e&&h.right+i>n?"left":"left"==e&&h.left-i<p?"right":e,d.removeClass(l).addClass(e)}var q=this.getCalculatedOffset(e,h,i,j);this.applyPlacement(q,e),this.hoverState=null;var r=function(){c.$element.trigger("shown.bs."+c.type)};a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,r).emulateTransitionEnd(150):r()}},b.prototype.applyPlacement=function(b,c){var d,e=this.tip(),f=e[0].offsetWidth,g=e[0].offsetHeight,h=parseInt(e.css("margin-top"),10),i=parseInt(e.css("margin-left"),10);isNaN(h)&&(h=0),isNaN(i)&&(i=0),b.top=b.top+h,b.left=b.left+i,a.offset.setOffset(e[0],a.extend({using:function(a){e.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),e.addClass("in");var j=e[0].offsetWidth,k=e[0].offsetHeight;if("top"==c&&k!=g&&(d=!0,b.top=b.top+g-k),/bottom|top/.test(c)){var l=0;b.left<0&&(l=-2*b.left,b.left=0,e.offset(b),j=e[0].offsetWidth,k=e[0].offsetHeight),this.replaceArrow(l-f+j,j,"left")}else this.replaceArrow(k-g,k,"top");d&&e.offset(b)},b.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},b.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach(),c.$element.trigger("hidden.bs."+c.type)}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one(a.support.transition.end,b).emulateTransitionEnd(150):b(),this.hoverState=null,this)},b.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},b.prototype.hasContent=function(){return this.getTitle()},b.prototype.getPosition=function(){var b=this.$element[0];return a.extend({},"function"==typeof b.getBoundingClientRect?b.getBoundingClientRect():{width:b.offsetWidth,height:b.offsetHeight},this.$element.offset())},b.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},b.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},b.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},b.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},b.prototype.enable=function(){this.enabled=!0},b.prototype.disable=function(){this.enabled=!1},b.prototype.toggleEnabled=function(){this.enabled=!this.enabled},b.prototype.toggle=function(b){var c=b?a(b.currentTarget)[this.type](this.getDelegateOptions()).data("bs."+this.type):this;c.tip().hasClass("in")?c.leave(c):c.enter(c)},b.prototype.destroy=function(){clearTimeout(this.timeout),this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var c=a.fn.tooltip;a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof c&&c;(e||"destroy"!=c)&&(e||d.data("bs.tooltip",e=new b(this,f)),"string"==typeof c&&e[c]())})},a.fn.tooltip.Constructor=b,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=c,this}}(jQuery),+function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");b.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),b.prototype.constructor=b,b.prototype.getDefaults=function(){return b.DEFAULTS},b.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content")[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},b.prototype.hasContent=function(){return this.getTitle()||this.getContent()},b.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},b.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},b.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var c=a.fn.popover;a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof c&&c;(e||"destroy"!=c)&&(e||d.data("bs.popover",e=new b(this,f)),"string"==typeof c&&e[c]())})},a.fn.popover.Constructor=b,a.fn.popover.noConflict=function(){return a.fn.popover=c,this}}(jQuery),function(a,b){var c,d;return d=b.document,c=function(){function c(c){this._options=a.extend({name:"tour",steps:[],container:"body",keyboard:!0,storage:b.localStorage,debug:!1,backdrop:!1,redirect:!0,orphan:!1,duration:!1,basePath:"",template:"<div class='popover'>          <div class='arrow'></div>          <h3 class='popover-title'></h3>          <div class='popover-content'></div>          <div class='popover-navigation'>            <div class='btn-group'>              <button class='btn btn-sm btn-default' data-role='prev'>&laquo; Prev</button>              <button class='btn btn-sm btn-default' data-role='next'>Next &raquo;</button>              <button class='btn btn-sm btn-default' data-role='pause-resume' data-pause-text='Pause' data-resume-text='Resume'>Pause</button>            </div>            <button class='btn btn-sm btn-default' data-role='end'>End tour</button>          </div>        </div>",afterSetState:function(){},afterGetState:function(){},afterRemoveState:function(){},onStart:function(){},onEnd:function(){},onShow:function(){},onShown:function(){},onHide:function(){},onHidden:function(){},onNext:function(){},onPrev:function(){},onPause:function(){},onResume:function(){}},c),this._force=!1,this._inited=!1,this.backdrop={overlay:null,$element:null,$background:null,backgroundShown:!1,overlayElementShown:!1}}return c.prototype.addSteps=function(a){var b,c,d;for(c=0,d=a.length;d>c;c++)b=a[c],this.addStep(b);return this},c.prototype.addStep=function(a){return this._options.steps.push(a),this},c.prototype.getStep=function(b){return null!=this._options.steps[b]?a.extend({id:"step-"+b,path:"",placement:"right",title:"",content:"<p></p>",next:b===this._options.steps.length-1?-1:b+1,prev:b-1,animation:!0,container:this._options.container,backdrop:this._options.backdrop,redirect:this._options.redirect,orphan:this._options.orphan,duration:this._options.duration,template:this._options.template,onShow:this._options.onShow,onShown:this._options.onShown,onHide:this._options.onHide,onHidden:this._options.onHidden,onNext:this._options.onNext,onPrev:this._options.onPrev,onPause:this._options.onPause,onResume:this._options.onResume},this._options.steps[b]):void 0},c.prototype.init=function(a){var b=this;return this._force=a,this.ended()?(this._debug("Tour ended, init prevented."),this):(this.setCurrentStep(),this._initMouseNavigation(),this._initKeyboardNavigation(),this._onResize(function(){return b.showStep(b._current)}),null!==this._current&&this.showStep(this._current),this._inited=!0,this)},c.prototype.start=function(a){var b;return null==a&&(a=!1),this._inited||this.init(a),null===this._current&&(b=this._makePromise(null!=this._options.onStart?this._options.onStart(this):void 0),this._callOnPromiseDone(b,this.showStep,0)),this},c.prototype.next=function(){var a;return a=this.hideStep(this._current),this._callOnPromiseDone(a,this._showNextStep)},c.prototype.prev=function(){var a;return a=this.hideStep(this._current),this._callOnPromiseDone(a,this._showPrevStep)},c.prototype.goTo=function(a){var b;return b=this.hideStep(this._current),this._callOnPromiseDone(b,this.showStep,a)},c.prototype.end=function(){var c,e,f=this;return c=function(){return a(d).off("click.tour-"+f._options.name),a(d).off("keyup.tour-"+f._options.name),a(b).off("resize.tour-"+f._options.name),f._setState("end","yes"),f._inited=!1,f._force=!1,f._clearTimer(),null!=f._options.onEnd?f._options.onEnd(f):void 0},e=this.hideStep(this._current),this._callOnPromiseDone(e,c)},c.prototype.ended=function(){return!this._force&&!!this._getState("end")},c.prototype.restart=function(){return this._removeState("current_step"),this._removeState("end"),this.setCurrentStep(0),this.start()},c.prototype.pause=function(){var a;return a=this.getStep(this._current),a&&a.duration?(this._paused=!0,this._duration-=(new Date).getTime()-this._start,b.clearTimeout(this._timer),this._debug("Paused/Stopped step "+(this._current+1)+" timer ("+this._duration+" remaining)."),null!=a.onPause?a.onPause(this,this._duration):void 0):this},c.prototype.resume=function(){var a,c=this;return a=this.getStep(this._current),a&&a.duration?(this._paused=!1,this._start=(new Date).getTime(),this._duration=this._duration||a.duration,this._timer=b.setTimeout(function(){return c._isLast()?c.next():c.end()},this._duration),this._debug("Started step "+(this._current+1)+" timer with duration "+this._duration),null!=a.onResume&&this._duration!==a.duration?a.onResume(this,this._duration):void 0):this},c.prototype.hideStep=function(b){var c,d,e,f=this;return(e=this.getStep(b))?(this._clearTimer(),d=this._makePromise(null!=e.onHide?e.onHide(this,b):void 0),c=function(){var b;return b=a(e.element),b.data("bs.popover")||b.data("popover")||(b=a("body")),b.popover("destroy"),e.reflex&&b.css("cursor","").off("click.tour-"+f._options.name),e.backdrop&&f._hideBackdrop(),null!=e.onHidden?e.onHidden(f):void 0},this._callOnPromiseDone(d,c),d):void 0},c.prototype.showStep=function(a){var b,c,e,f,g=this;return this.ended()?(this._debug("Tour ended, showStep prevented."),this):(f=this.getStep(a))?(e=a<this._current,b=this._makePromise(null!=f.onShow?f.onShow(this,a):void 0),c=function(){var b,c;if(g.setCurrentStep(a),c=function(){switch(toString.call(f.path)){case"[object Function]":return f.path();case"[object String]":return this._options.basePath+f.path;default:return f.path}}.call(g),b=[d.location.pathname,d.location.hash].join(""),g._isRedirect(c,b))return g._redirect(f,c),void 0;if(g._isOrphan(f)){if(!f.orphan)return g._debug("Skip the orphan step "+(g._current+1)+". Orphan option is false and the element doesn't exist or is hidden."),e?g._showPrevStep():g._showNextStep(),void 0;g._debug("Show the orphan step "+(g._current+1)+". Orphans option is true.")}return f.backdrop&&g._showBackdrop(g._isOrphan(f)?void 0:f.element),g._scrollIntoView(f.element,function(){return null!=f.element&&f.backdrop&&g._showOverlayElement(f.element),g._showPopover(f,a),null!=f.onShown&&f.onShown(g),g._debug("Step "+(g._current+1)+" of "+g._options.steps.length)}),f.duration?g.resume():void 0},this._callOnPromiseDone(b,c),b):void 0},c.prototype.getCurrentStep=function(){return this._current},c.prototype.setCurrentStep=function(a){return null!=a?(this._current=a,this._setState("current_step",a)):(this._current=this._getState("current_step"),this._current=null===this._current?null:parseInt(this._current,10)),this},c.prototype._setState=function(a,b){var c,d;if(this._options.storage){d=""+this._options.name+"_"+a;try{this._options.storage.setItem(d,b)}catch(e){c=e,c.code===DOMException.QUOTA_EXCEEDED_ERR&&this.debug("LocalStorage quota exceeded. State storage failed.")}return this._options.afterSetState(d,b)}return null==this._state&&(this._state={}),this._state[a]=b},c.prototype._removeState=function(a){var b;return this._options.storage?(b=""+this._options.name+"_"+a,this._options.storage.removeItem(b),this._options.afterRemoveState(b)):null!=this._state?delete this._state[a]:void 0},c.prototype._getState=function(a){var b,c;return this._options.storage?(b=""+this._options.name+"_"+a,c=this._options.storage.getItem(b)):null!=this._state&&(c=this._state[a]),(void 0===c||"null"===c)&&(c=null),this._options.afterGetState(a,c),c},c.prototype._showNextStep=function(){var a,b,c,d=this;return c=this.getStep(this._current),b=function(){return d.showStep(c.next)},a=this._makePromise(null!=c.onNext?c.onNext(this):void 0),this._callOnPromiseDone(a,b)},c.prototype._showPrevStep=function(){var a,b,c,d=this;return c=this.getStep(this._current),b=function(){return d.showStep(c.prev)},a=this._makePromise(null!=c.onPrev?c.onPrev(this):void 0),this._callOnPromiseDone(a,b)},c.prototype._debug=function(a){return this._options.debug?b.console.log("Bootstrap Tour '"+this._options.name+"' | "+a):void 0},c.prototype._isRedirect=function(a,b){return null!=a&&""!==a&&("[object RegExp]"===toString.call(a)&&!a.test(b)||"[object String]"===toString.call(a)&&a.replace(/\?.*$/,"").replace(/\/?$/,"")!==b.replace(/\/?$/,""))},c.prototype._redirect=function(b,c){return a.isFunction(b.redirect)?b.redirect.call(this,c):b.redirect===!0?(this._debug("Redirect to "+c),d.location.href=c):void 0},c.prototype._isOrphan=function(b){return null==b.element||!a(b.element).length||a(b.element).is(":hidden")&&"http://www.w3.org/2000/svg"!==a(b.element)[0].namespaceURI},c.prototype._isLast=function(){return this._current<this._options.steps.length-1},c.prototype._showPopover=function(b,c){var d,e,f,g,h,i,j=this;return i=a.extend({},this._options),f=a.isFunction(b.template)?a(b.template(c,b)):a(b.template),e=f.find(".popover-navigation"),h=this._isOrphan(b),h&&(b.element="body",b.placement="top",f=f.addClass("orphan")),d=a(b.element),f.addClass("tour-"+this._options.name+" tour-"+this._options.name+"-"+c),b.options&&a.extend(i,b.options),b.reflex&&d.css("cursor","pointer").on("click.tour-"+this._options.name,function(){return j._isLast()?j.next():j.end()}),b.prev<0&&e.find("[data-role='prev']").addClass("disabled"),b.next<0&&e.find("[data-role='next']").addClass("disabled"),b.duration||e.find("[data-role='pause-resume']").remove(),b.template=f.clone().wrap("<div>").parent().html(),d.popover({placement:b.placement,trigger:"manual",title:b.title,content:b.content,html:!0,animation:b.animation,container:b.container,template:b.template,selector:b.element}).popover("show"),g=d.data("bs.popover")?d.data("bs.popover").tip():d.data("popover").tip(),g.attr("id",b.id),this._reposition(g,b),h?this._center(g):void 0},c.prototype._reposition=function(b,c){var e,f,g,h,i,j,k;if(h=b[0].offsetWidth,f=b[0].offsetHeight,k=b.offset(),i=k.left,j=k.top,e=a(d).outerHeight()-k.top-b.outerHeight(),0>e&&(k.top=k.top+e),g=a("html").outerWidth()-k.left-b.outerWidth(),0>g&&(k.left=k.left+g),k.top<0&&(k.top=0),k.left<0&&(k.left=0),b.offset(k),"bottom"===c.placement||"top"===c.placement){if(i!==k.left)return this._replaceArrow(b,2*(k.left-i),h,"left")}else if(j!==k.top)return this._replaceArrow(b,2*(k.top-j),f,"top")},c.prototype._center=function(c){return c.css("top",a(b).outerHeight()/2-c.outerHeight()/2)},c.prototype._replaceArrow=function(a,b,c,d){return a.find(".arrow").css(d,b?50*(1-b/c)+"%":"")},c.prototype._scrollIntoView=function(c,d){var e,f,g,h,i,j,k=this;return e=a(c),e.length?(f=a(b),h=e.offset().top,j=f.height(),i=Math.max(0,h-j/2),this._debug("Scroll into view. ScrollTop: "+i+". Element offset: "+h+". Window height: "+j+"."),g=0,a("body,html").stop(!0,!0).animate({scrollTop:Math.ceil(i)},function(){return 2===++g?(d(),k._debug("Scroll into view. Animation end element offset: "+e.offset().top+". Window height: "+f.height()+".")):void 0})):d()},c.prototype._onResize=function(c,d){return a(b).on("resize.tour-"+this._options.name,function(){return clearTimeout(d),d=setTimeout(c,100)})},c.prototype._initMouseNavigation=function(){var b=this;return b=this,a(d).off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='prev']:not(.disabled)").off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='next']:not(.disabled)").off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='end']").off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='pause-resume']").on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='next']:not(.disabled)",function(a){return a.preventDefault(),b.next()}).on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='prev']:not(.disabled)",function(a){return a.preventDefault(),b.prev()}).on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='end']",function(a){return a.preventDefault(),b.end()}).on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role='pause-resume']",function(c){var d;return c.preventDefault(),d=a(this),d.text(b._paused?d.data("pause-text"):d.data("resume-text")),b._paused?b.resume():b.pause()})},c.prototype._initKeyboardNavigation=function(){var b=this;if(this._options.keyboard)return a(d).on("keyup.tour-"+this._options.name,function(a){if(a.which)switch(a.which){case 39:return a.preventDefault(),b._isLast()?b.next():b.end();case 37:if(a.preventDefault(),b._current>0)return b.prev();break;case 27:return a.preventDefault(),b.end()}})},c.prototype._makePromise=function(b){return b&&a.isFunction(b.then)?b:null},c.prototype._callOnPromiseDone=function(a,b,c){var d=this;return a?a.then(function(){return b.call(d,c)}):b.call(this,c)},c.prototype._showBackdrop=function(){return this.backdrop.backgroundShown?void 0:(this.backdrop=a("<div/>",{"class":"tour-backdrop"}),this.backdrop.backgroundShown=!0,a("body").append(this.backdrop))},c.prototype._hideBackdrop=function(){return this._hideOverlayElement(),this._hideBackground()},c.prototype._hideBackground=function(){return this.backdrop.remove(),this.backdrop.overlay=null,this.backdrop.backgroundShown=!1},c.prototype._showOverlayElement=function(b){var c,d,e;return d=a(b),d&&0!==d.length&&!this.backdrop.overlayElementShown?(this.backdrop.overlayElementShown=!0,c=a("<div/>"),e=d.offset(),e.top=e.top,e.left=e.left,c.width(d.innerWidth()).height(d.innerHeight()).addClass("tour-step-background").offset(e),d.addClass("tour-step-backdrop"),a("body").append(c),this.backdrop.$element=d,this.backdrop.$background=c):void 0},c.prototype._hideOverlayElement=function(){return this.backdrop.overlayElementShown?(this.backdrop.$element.removeClass("tour-step-backdrop"),this.backdrop.$background.remove(),this.backdrop.$element=null,this.backdrop.$background=null,this.backdrop.overlayElementShown=!1):void 0},c.prototype._clearTimer=function(){return b.clearTimeout(this._timer),this._timer=null,this._duration=null},c}(),b.Tour=c}(jQuery,window);
Index: /extensions/TakeATour/js/bootstrap-tour.js
===================================================================
--- /extensions/TakeATour/js/bootstrap-tour.js	(revision 27995)
+++ /extensions/TakeATour/js/bootstrap-tour.js	(revision 27995)
@@ -0,0 +1,694 @@
+/* ===========================================================
+# bootstrap-tour - v0.8.1
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+(function($, window) {
+  var Tour, document;
+  document = window.document;
+  Tour = (function() {
+    function Tour(options) {
+      this._options = $.extend({
+        name: "tour",
+        container: "body",
+        keyboard: true,
+        storage: window.localStorage,
+        debug: false,
+        backdrop: false,
+        redirect: true,
+        orphan: false,
+        duration: false,
+        basePath: "",
+        template: "<div class='popover'>          <div class='arrow'></div>          <h3 class='popover-title'></h3>          <div class='popover-content'></div>          <div class='popover-navigation'>            <div class='btn-group'>              <button class='btn btn-sm btn-default' data-role='prev'>&laquo; Prev</button>              <button class='btn btn-sm btn-default' data-role='next'>Next &raquo;</button>              <button class='btn btn-sm btn-default' data-role='pause-resume'                data-pause-text='Pause'                data-resume-text='Resume'              >Pause</button>            </div>            <button class='btn btn-sm btn-default' data-role='end'>End tour</button>          </div>        </div>",
+        afterSetState: function(key, value) {},
+        afterGetState: function(key, value) {},
+        afterRemoveState: function(key) {},
+        onStart: function(tour) {},
+        onEnd: function(tour) {},
+        onShow: function(tour) {},
+        onShown: function(tour) {},
+        onHide: function(tour) {},
+        onHidden: function(tour) {},
+        onNext: function(tour) {},
+        onPrev: function(tour) {},
+        onPause: function(tour, duration) {},
+        onResume: function(tour, duration) {}
+      }, options);
+      this._force = false;
+      this._inited = false;
+      this._steps = [];
+      this.backdrop = {
+        overlay: null,
+        $element: null,
+        $background: null,
+        backgroundShown: false,
+        overlayElementShown: false
+      };
+    }
+
+    Tour.prototype.setState = function(key, value) {
+      var e, keyName;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        try {
+          this._options.storage.setItem(keyName, value);
+        } catch (_error) {
+          e = _error;
+          if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
+            this.debug("LocalStorage quota exceeded. setState failed.");
+          }
+        }
+        return this._options.afterSetState(keyName, value);
+      } else {
+        if (this._state == null) {
+          this._state = {};
+        }
+        return this._state[key] = value;
+      }
+    };
+
+    Tour.prototype.removeState = function(key) {
+      var keyName;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        this._options.storage.removeItem(keyName);
+        return this._options.afterRemoveState(keyName);
+      } else {
+        if (this._state != null) {
+          return delete this._state[key];
+        }
+      }
+    };
+
+    Tour.prototype.getState = function(key) {
+      var keyName, value;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        value = this._options.storage.getItem(keyName);
+      } else {
+        if (this._state != null) {
+          value = this._state[key];
+        }
+      }
+      if (value === void 0 || value === "null") {
+        value = null;
+      }
+      this._options.afterGetState(key, value);
+      return value;
+    };
+
+    Tour.prototype.addSteps = function(steps) {
+      var step, _i, _len, _results;
+      _results = [];
+      for (_i = 0, _len = steps.length; _i < _len; _i++) {
+        step = steps[_i];
+        _results.push(this.addStep(step));
+      }
+      return _results;
+    };
+
+    Tour.prototype.addStep = function(step) {
+      return this._steps.push(step);
+    };
+
+    Tour.prototype.getStep = function(i) {
+      if (this._steps[i] != null) {
+        return $.extend({
+          id: "step-" + i,
+          path: "",
+          placement: "right",
+          title: "",
+          content: "<p></p>",
+          next: i === this._steps.length - 1 ? -1 : i + 1,
+          prev: i - 1,
+          animation: true,
+          container: this._options.container,
+          backdrop: this._options.backdrop,
+          redirect: this._options.redirect,
+          orphan: this._options.orphan,
+          duration: this._options.duration,
+          template: this._options.template,
+          onShow: this._options.onShow,
+          onShown: this._options.onShown,
+          onHide: this._options.onHide,
+          onHidden: this._options.onHidden,
+          onNext: this._options.onNext,
+          onPrev: this._options.onPrev,
+          onPause: this._options.onPause,
+          onResume: this._options.onResume
+        }, this._steps[i]);
+      }
+    };
+
+    Tour.prototype.init = function(force) {
+      var _this = this;
+      this._force = force;
+      if (this.ended()) {
+        return this._debug("Tour ended, init prevented.");
+      }
+      this.setCurrentStep();
+      this._setupMouseNavigation();
+      this._setupKeyboardNavigation();
+      this._onResize(function() {
+        return _this.showStep(_this._current);
+      });
+      if (this._current !== null) {
+        this.showStep(this._current);
+      }
+      this._inited = true;
+      return this;
+    };
+
+    Tour.prototype.start = function(force) {
+      var promise;
+      if (force == null) {
+        force = false;
+      }
+      if (!this._inited) {
+        this.init(force);
+      }
+      if (this._current === null) {
+        promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
+        return this._callOnPromiseDone(promise, this.showStep, 0);
+      }
+    };
+
+    Tour.prototype.next = function() {
+      var promise;
+      if (this.ended()) {
+        return this._debug("Tour ended, next prevented.");
+      }
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this._showNextStep);
+    };
+
+    Tour.prototype.prev = function() {
+      var promise;
+      if (this.ended()) {
+        return this._debug("Tour ended, prev prevented.");
+      }
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this._showPrevStep);
+    };
+
+    Tour.prototype.goTo = function(i) {
+      var promise;
+      if (this.ended()) {
+        return this._debug("Tour ended, goTo prevented.");
+      }
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this.showStep, i);
+    };
+
+    Tour.prototype.end = function() {
+      var endHelper, promise,
+        _this = this;
+      endHelper = function(e) {
+        $(document).off("click.tour-" + _this._options.name);
+        $(document).off("keyup.tour-" + _this._options.name);
+        $(window).off("resize.tour-" + _this._options.name);
+        _this.setState("end", "yes");
+        _this._inited = false;
+        _this._force = false;
+        _this._clearTimer();
+        if (_this._options.onEnd != null) {
+          return _this._options.onEnd(_this);
+        }
+      };
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, endHelper);
+    };
+
+    Tour.prototype.ended = function() {
+      return !this._force && !!this.getState("end");
+    };
+
+    Tour.prototype.restart = function() {
+      this.removeState("current_step");
+      this.removeState("end");
+      this.setCurrentStep(0);
+      return this.start();
+    };
+
+    Tour.prototype.pause = function() {
+      var step;
+      step = this.getStep(this._current);
+      if (!(step && step.duration)) {
+        return;
+      }
+      this._paused = true;
+      this._duration -= new Date().getTime() - this._start;
+      window.clearTimeout(this._timer);
+      this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining).");
+      if (step.onPause != null) {
+        return step.onPause(this, this._duration);
+      }
+    };
+
+    Tour.prototype.resume = function() {
+      var step,
+        _this = this;
+      step = this.getStep(this._current);
+      if (!(step && step.duration)) {
+        return;
+      }
+      this._paused = false;
+      this._start = new Date().getTime();
+      this._duration = this._duration || step.duration;
+      this._timer = window.setTimeout(function() {
+        if (_this._isLast()) {
+          return _this.next();
+        } else {
+          return _this.end();
+        }
+      }, this._duration);
+      this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration);
+      if ((step.onResume != null) && this._duration !== step.duration) {
+        return step.onResume(this, this._duration);
+      }
+    };
+
+    Tour.prototype.hideStep = function(i) {
+      var hideStepHelper, promise, step,
+        _this = this;
+      step = this.getStep(i);
+      if (!step) {
+        return;
+      }
+      this._clearTimer();
+      promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
+      hideStepHelper = function(e) {
+        var $element;
+        $element = $(step.element);
+        if (!($element.data("bs.popover") || $element.data("popover"))) {
+          $element = $("body");
+        }
+        $element.popover("destroy");
+        if (step.reflex) {
+          $element.css("cursor", "").off("click.tour-" + _this._options.name);
+        }
+        if (step.backdrop) {
+          _this._hideBackdrop();
+        }
+        if (step.onHidden != null) {
+          return step.onHidden(_this);
+        }
+      };
+      this._callOnPromiseDone(promise, hideStepHelper);
+      return promise;
+    };
+
+    Tour.prototype.showStep = function(i) {
+      var promise, showStepHelper, skipToPrevious, step,
+        _this = this;
+      step = this.getStep(i);
+      if (!step) {
+        return;
+      }
+      skipToPrevious = i < this._current;
+      promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
+      showStepHelper = function(e) {
+        var current_path, path;
+        _this.setCurrentStep(i);
+        path = $.isFunction(step.path) ? step.path.call() : _this._options.basePath + step.path;
+        current_path = [document.location.pathname, document.location.hash].join("");
+        if (_this._isRedirect(path, current_path)) {
+          _this._redirect(step, path);
+          return;
+        }
+        if (_this._isOrphan(step)) {
+          if (!step.orphan) {
+            _this._debug("Skip the orphan step " + (_this._current + 1) + ". Orphan option is false and the element doesn't exist or is hidden.");
+            if (skipToPrevious) {
+              _this._showPrevStep();
+            } else {
+              _this._showNextStep();
+            }
+            return;
+          }
+          _this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
+        }
+        if (step.backdrop) {
+          _this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
+        }
+        _this._scrollIntoView(step.element, function() {
+          if ((step.element != null) && step.backdrop) {
+            _this._showOverlayElement(step.element);
+          }
+          _this._showPopover(step, i);
+          if (step.onShown != null) {
+            step.onShown(_this);
+          }
+          return _this._debug("Step " + (_this._current + 1) + " of " + _this._steps.length);
+        });
+        if (step.duration) {
+          return _this.resume();
+        }
+      };
+      this._callOnPromiseDone(promise, showStepHelper);
+      return promise;
+    };
+
+    Tour.prototype.getCurrentStep = function() {
+      return this._current;
+    };
+
+    Tour.prototype.setCurrentStep = function(value) {
+      if (value != null) {
+        this._current = value;
+        this.setState("current_step", value);
+      } else {
+        this._current = this.getState("current_step");
+        this._current = this._current === null ? null : parseInt(this._current, 10);
+      }
+      return this;
+    };
+
+    Tour.prototype._showNextStep = function() {
+      var promise, showNextStepHelper, step,
+        _this = this;
+      step = this.getStep(this._current);
+      showNextStepHelper = function(e) {
+        return _this.showStep(step.next);
+      };
+      promise = this._makePromise((step.onNext != null ? step.onNext(this) : void 0));
+      return this._callOnPromiseDone(promise, showNextStepHelper);
+    };
+
+    Tour.prototype._showPrevStep = function() {
+      var promise, showPrevStepHelper, step,
+        _this = this;
+      step = this.getStep(this._current);
+      showPrevStepHelper = function(e) {
+        return _this.showStep(step.prev);
+      };
+      promise = this._makePromise((step.onPrev != null ? step.onPrev(this) : void 0));
+      return this._callOnPromiseDone(promise, showPrevStepHelper);
+    };
+
+    Tour.prototype._debug = function(text) {
+      if (this._options.debug) {
+        return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
+      }
+    };
+
+    Tour.prototype._isRedirect = function(path, currentPath) {
+      return (path != null) && path !== "" && path.replace(/\?.*$/, "").replace(/\/?$/, "") !== currentPath.replace(/\/?$/, "");
+    };
+
+    Tour.prototype._redirect = function(step, path) {
+      if ($.isFunction(step.redirect)) {
+        return step.redirect.call(this, path);
+      } else if (step.redirect === true) {
+        this._debug("Redirect to " + path);
+        return document.location.href = path;
+      }
+    };
+
+    Tour.prototype._isOrphan = function(step) {
+      return (step.element == null) || !$(step.element).length || $(step.element).is(":hidden") && ($(step.element)[0].namespaceURI !== "http://www.w3.org/2000/svg");
+    };
+
+    Tour.prototype._isLast = function() {
+      return this._current < this._steps.length - 1;
+    };
+
+    Tour.prototype._showPopover = function(step, i) {
+      var $element, $navigation, $template, $tip, isOrphan, options,
+        _this = this;
+      options = $.extend({}, this._options);
+      $template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
+      $navigation = $template.find(".popover-navigation");
+      isOrphan = this._isOrphan(step);
+      if (isOrphan) {
+        step.element = "body";
+        step.placement = "top";
+        $template = $template.addClass("orphan");
+      }
+      $element = $(step.element);
+      $template.addClass("tour-" + this._options.name);
+      if (step.options) {
+        $.extend(options, step.options);
+      }
+      if (step.reflex) {
+        $element.css("cursor", "pointer").on("click.tour-" + this._options.name, function() {
+          if (_this._isLast()) {
+            return _this.next();
+          } else {
+            return _this.end();
+          }
+        });
+      }
+      if (step.prev < 0) {
+        $navigation.find("*[data-role=prev]").addClass("disabled");
+      }
+      if (step.next < 0) {
+        $navigation.find("*[data-role=next]").addClass("disabled");
+      }
+      if (!step.duration) {
+        $navigation.find("*[data-role='pause-resume']").remove();
+      }
+      step.template = $template.clone().wrap("<div>").parent().html();
+      $element.popover({
+        placement: step.placement,
+        trigger: "manual",
+        title: step.title,
+        content: step.content,
+        html: true,
+        animation: step.animation,
+        container: step.container,
+        template: step.template,
+        selector: step.element
+      }).popover("show");
+      $tip = $element.data("bs.popover") ? $element.data("bs.popover").tip() : $element.data("popover").tip();
+      $tip.attr("id", step.id);
+      this._reposition($tip, step);
+      if (isOrphan) {
+        return this._center($tip);
+      }
+    };
+
+    Tour.prototype._reposition = function($tip, step) {
+      var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
+      offsetWidth = $tip[0].offsetWidth;
+      offsetHeight = $tip[0].offsetHeight;
+      tipOffset = $tip.offset();
+      originalLeft = tipOffset.left;
+      originalTop = tipOffset.top;
+      offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
+      if (offsetBottom < 0) {
+        tipOffset.top = tipOffset.top + offsetBottom;
+      }
+      offsetRight = $("html").outerWidth() - tipOffset.left - $tip.outerWidth();
+      if (offsetRight < 0) {
+        tipOffset.left = tipOffset.left + offsetRight;
+      }
+      if (tipOffset.top < 0) {
+        tipOffset.top = 0;
+      }
+      if (tipOffset.left < 0) {
+        tipOffset.left = 0;
+      }
+      $tip.offset(tipOffset);
+      if (step.placement === "bottom" || step.placement === "top") {
+        if (originalLeft !== tipOffset.left) {
+          return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, "left");
+        }
+      } else {
+        if (originalTop !== tipOffset.top) {
+          return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top");
+        }
+      }
+    };
+
+    Tour.prototype._center = function($tip) {
+      return $tip.css("top", $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
+    };
+
+    Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
+      return $tip.find(".arrow").css(position, delta ? 50 * (1 - delta / dimension) + "%" : "");
+    };
+
+    Tour.prototype._scrollIntoView = function(element, callback) {
+      var $element, $window, counter, offsetTop, scrollTop, windowHeight,
+        _this = this;
+      $element = $(element);
+      if (!$element.length) {
+        return callback();
+      }
+      $window = $(window);
+      offsetTop = $element.offset().top;
+      windowHeight = $window.height();
+      scrollTop = Math.max(0, offsetTop - (windowHeight / 2));
+      this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + ".");
+      counter = 0;
+      return $("body,html").stop(true, true).animate({
+        scrollTop: Math.ceil(scrollTop)
+      }, function() {
+        if (++counter === 2) {
+          callback();
+          return _this._debug("Scroll into view. Animation end element offset: " + ($element.offset().top) + ". Window height: " + ($window.height()) + ".");
+        }
+      });
+    };
+
+    Tour.prototype._onResize = function(callback, timeout) {
+      return $(window).on("resize.tour-" + this._options.name, function() {
+        clearTimeout(timeout);
+        return timeout = setTimeout(callback, 100);
+      });
+    };
+
+    Tour.prototype._setupMouseNavigation = function() {
+      var _this = this;
+      _this = this;
+      $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=next]:not(.disabled)").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=next]:not(.disabled)", function(e) {
+        e.preventDefault();
+        return _this.next();
+      });
+      $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=prev]:not(.disabled)").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=prev]:not(.disabled)", function(e) {
+        e.preventDefault();
+        return _this.prev();
+      });
+      $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=end]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=end]", function(e) {
+        e.preventDefault();
+        return _this.end();
+      });
+      return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=pause-resume]").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role=pause-resume]", function(e) {
+        var $this;
+        e.preventDefault();
+        $this = $(this);
+        $this.text(_this._paused ? $this.data("pause-text") : $this.data("resume-text"));
+        if (_this._paused) {
+          return _this.resume();
+        } else {
+          return _this.pause();
+        }
+      });
+    };
+
+    Tour.prototype._setupKeyboardNavigation = function() {
+      var _this = this;
+      if (!this._options.keyboard) {
+        return;
+      }
+      return $(document).on("keyup.tour-" + this._options.name, function(e) {
+        if (!e.which) {
+          return;
+        }
+        switch (e.which) {
+          case 39:
+            e.preventDefault();
+            if (_this._isLast()) {
+              return _this.next();
+            } else {
+              return _this.end();
+            }
+            break;
+          case 37:
+            e.preventDefault();
+            if (_this._current > 0) {
+              return _this.prev();
+            }
+            break;
+          case 27:
+            e.preventDefault();
+            return _this.end();
+        }
+      });
+    };
+
+    Tour.prototype._makePromise = function(result) {
+      if (result && $.isFunction(result.then)) {
+        return result;
+      } else {
+        return null;
+      }
+    };
+
+    Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
+      var _this = this;
+      if (promise) {
+        return promise.then(function(e) {
+          return cb.call(_this, arg);
+        });
+      } else {
+        return cb.call(this, arg);
+      }
+    };
+
+    Tour.prototype._showBackdrop = function(element) {
+      if (this.backdrop.backgroundShown) {
+        return;
+      }
+      this.backdrop = $("<div/>", {
+        "class": "tour-backdrop"
+      });
+      this.backdrop.backgroundShown = true;
+      return $("body").append(this.backdrop);
+    };
+
+    Tour.prototype._hideBackdrop = function() {
+      this._hideOverlayElement();
+      return this._hideBackground();
+    };
+
+    Tour.prototype._hideBackground = function() {
+      this.backdrop.remove();
+      this.backdrop.overlay = null;
+      return this.backdrop.backgroundShown = false;
+    };
+
+    Tour.prototype._showOverlayElement = function(element) {
+      var $background, $element, offset;
+      if (this.backdrop.overlayElementShown) {
+        return;
+      }
+      this.backdrop.overlayElementShown = true;
+      $element = $(element);
+      $background = $("<div/>");
+      offset = $element.offset();
+      offset.top = offset.top;
+      offset.left = offset.left;
+      $background.width($element.innerWidth()).height($element.innerHeight()).addClass("tour-step-background").offset(offset);
+      $element.addClass("tour-step-backdrop");
+      $("body").append($background);
+      this.backdrop.$element = $element;
+      return this.backdrop.$background = $background;
+    };
+
+    Tour.prototype._hideOverlayElement = function() {
+      if (!this.backdrop.overlayElementShown) {
+        return;
+      }
+      this.backdrop.$element.removeClass("tour-step-backdrop");
+      this.backdrop.$background.remove();
+      this.backdrop.$element = null;
+      this.backdrop.$background = null;
+      return this.backdrop.overlayElementShown = false;
+    };
+
+    Tour.prototype._clearTimer = function() {
+      window.clearTimeout(this._timer);
+      this._timer = null;
+      return this._duration = null;
+    };
+
+    return Tour;
+
+  })();
+  return window.Tour = Tour;
+})(jQuery, window);
Index: /extensions/TakeATour/js/bootstrap-tour.min.js
===================================================================
--- /extensions/TakeATour/js/bootstrap-tour.min.js	(revision 27995)
+++ /extensions/TakeATour/js/bootstrap-tour.min.js	(revision 27995)
@@ -0,0 +1,19 @@
+/* ===========================================================
+# bootstrap-tour - v0.8.1
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+!function(a,b){var c,d;return d=b.document,c=function(){function c(c){this._options=a.extend({name:"tour",container:"body",keyboard:!0,storage:b.localStorage,debug:!1,backdrop:!1,redirect:!0,orphan:!1,duration:!1,basePath:"",template:"<div class='popover'>          <div class='arrow'></div>          <h3 class='popover-title'></h3>          <div class='popover-content'></div>          <div class='popover-navigation'>            <div class='btn-group'>              <button class='btn btn-sm btn-default' data-role='prev'>&laquo; Prev</button>              <button class='btn btn-sm btn-default' data-role='next'>Next &raquo;</button>              <button class='btn btn-sm btn-default' data-role='pause-resume'                data-pause-text='Pause'                data-resume-text='Resume'              >Pause</button>            </div>            <button class='btn btn-sm btn-default' data-role='end'>End tour</button>          </div>        </div>",afterSetState:function(){},afterGetState:function(){},afterRemoveState:function(){},onStart:function(){},onEnd:function(){},onShow:function(){},onShown:function(){},onHide:function(){},onHidden:function(){},onNext:function(){},onPrev:function(){},onPause:function(){},onResume:function(){}},c),this._force=!1,this._inited=!1,this._steps=[],this.backdrop={overlay:null,$element:null,$background:null,backgroundShown:!1,overlayElementShown:!1}}return c.prototype.setState=function(a,b){var c,d;if(this._options.storage){d=""+this._options.name+"_"+a;try{this._options.storage.setItem(d,b)}catch(e){c=e,c.code===DOMException.QUOTA_EXCEEDED_ERR&&this.debug("LocalStorage quota exceeded. setState failed.")}return this._options.afterSetState(d,b)}return null==this._state&&(this._state={}),this._state[a]=b},c.prototype.removeState=function(a){var b;return this._options.storage?(b=""+this._options.name+"_"+a,this._options.storage.removeItem(b),this._options.afterRemoveState(b)):null!=this._state?delete this._state[a]:void 0},c.prototype.getState=function(a){var b,c;return this._options.storage?(b=""+this._options.name+"_"+a,c=this._options.storage.getItem(b)):null!=this._state&&(c=this._state[a]),(void 0===c||"null"===c)&&(c=null),this._options.afterGetState(a,c),c},c.prototype.addSteps=function(a){var b,c,d,e;for(e=[],c=0,d=a.length;d>c;c++)b=a[c],e.push(this.addStep(b));return e},c.prototype.addStep=function(a){return this._steps.push(a)},c.prototype.getStep=function(b){return null!=this._steps[b]?a.extend({id:"step-"+b,path:"",placement:"right",title:"",content:"<p></p>",next:b===this._steps.length-1?-1:b+1,prev:b-1,animation:!0,container:this._options.container,backdrop:this._options.backdrop,redirect:this._options.redirect,orphan:this._options.orphan,duration:this._options.duration,template:this._options.template,onShow:this._options.onShow,onShown:this._options.onShown,onHide:this._options.onHide,onHidden:this._options.onHidden,onNext:this._options.onNext,onPrev:this._options.onPrev,onPause:this._options.onPause,onResume:this._options.onResume},this._steps[b]):void 0},c.prototype.init=function(a){var b=this;return this._force=a,this.ended()?this._debug("Tour ended, init prevented."):(this.setCurrentStep(),this._setupMouseNavigation(),this._setupKeyboardNavigation(),this._onResize(function(){return b.showStep(b._current)}),null!==this._current&&this.showStep(this._current),this._inited=!0,this)},c.prototype.start=function(a){var b;return null==a&&(a=!1),this._inited||this.init(a),null===this._current?(b=this._makePromise(null!=this._options.onStart?this._options.onStart(this):void 0),this._callOnPromiseDone(b,this.showStep,0)):void 0},c.prototype.next=function(){var a;return this.ended()?this._debug("Tour ended, next prevented."):(a=this.hideStep(this._current),this._callOnPromiseDone(a,this._showNextStep))},c.prototype.prev=function(){var a;return this.ended()?this._debug("Tour ended, prev prevented."):(a=this.hideStep(this._current),this._callOnPromiseDone(a,this._showPrevStep))},c.prototype.goTo=function(a){var b;return this.ended()?this._debug("Tour ended, goTo prevented."):(b=this.hideStep(this._current),this._callOnPromiseDone(b,this.showStep,a))},c.prototype.end=function(){var c,e,f=this;return c=function(){return a(d).off("click.tour-"+f._options.name),a(d).off("keyup.tour-"+f._options.name),a(b).off("resize.tour-"+f._options.name),f.setState("end","yes"),f._inited=!1,f._force=!1,f._clearTimer(),null!=f._options.onEnd?f._options.onEnd(f):void 0},e=this.hideStep(this._current),this._callOnPromiseDone(e,c)},c.prototype.ended=function(){return!this._force&&!!this.getState("end")},c.prototype.restart=function(){return this.removeState("current_step"),this.removeState("end"),this.setCurrentStep(0),this.start()},c.prototype.pause=function(){var a;return a=this.getStep(this._current),a&&a.duration?(this._paused=!0,this._duration-=(new Date).getTime()-this._start,b.clearTimeout(this._timer),this._debug("Paused/Stopped step "+(this._current+1)+" timer ("+this._duration+" remaining)."),null!=a.onPause?a.onPause(this,this._duration):void 0):void 0},c.prototype.resume=function(){var a,c=this;return a=this.getStep(this._current),a&&a.duration?(this._paused=!1,this._start=(new Date).getTime(),this._duration=this._duration||a.duration,this._timer=b.setTimeout(function(){return c._isLast()?c.next():c.end()},this._duration),this._debug("Started step "+(this._current+1)+" timer with duration "+this._duration),null!=a.onResume&&this._duration!==a.duration?a.onResume(this,this._duration):void 0):void 0},c.prototype.hideStep=function(b){var c,d,e,f=this;return(e=this.getStep(b))?(this._clearTimer(),d=this._makePromise(null!=e.onHide?e.onHide(this,b):void 0),c=function(){var b;return b=a(e.element),b.data("bs.popover")||b.data("popover")||(b=a("body")),b.popover("destroy"),e.reflex&&b.css("cursor","").off("click.tour-"+f._options.name),e.backdrop&&f._hideBackdrop(),null!=e.onHidden?e.onHidden(f):void 0},this._callOnPromiseDone(d,c),d):void 0},c.prototype.showStep=function(b){var c,e,f,g,h=this;return(g=this.getStep(b))?(f=b<this._current,c=this._makePromise(null!=g.onShow?g.onShow(this,b):void 0),e=function(){var c,e;if(h.setCurrentStep(b),e=a.isFunction(g.path)?g.path.call():h._options.basePath+g.path,c=[d.location.pathname,d.location.hash].join(""),h._isRedirect(e,c))return h._redirect(g,e),void 0;if(h._isOrphan(g)){if(!g.orphan)return h._debug("Skip the orphan step "+(h._current+1)+". Orphan option is false and the element doesn't exist or is hidden."),f?h._showPrevStep():h._showNextStep(),void 0;h._debug("Show the orphan step "+(h._current+1)+". Orphans option is true.")}return g.backdrop&&h._showBackdrop(h._isOrphan(g)?void 0:g.element),h._scrollIntoView(g.element,function(){return null!=g.element&&g.backdrop&&h._showOverlayElement(g.element),h._showPopover(g,b),null!=g.onShown&&g.onShown(h),h._debug("Step "+(h._current+1)+" of "+h._steps.length)}),g.duration?h.resume():void 0},this._callOnPromiseDone(c,e),c):void 0},c.prototype.getCurrentStep=function(){return this._current},c.prototype.setCurrentStep=function(a){return null!=a?(this._current=a,this.setState("current_step",a)):(this._current=this.getState("current_step"),this._current=null===this._current?null:parseInt(this._current,10)),this},c.prototype._showNextStep=function(){var a,b,c,d=this;return c=this.getStep(this._current),b=function(){return d.showStep(c.next)},a=this._makePromise(null!=c.onNext?c.onNext(this):void 0),this._callOnPromiseDone(a,b)},c.prototype._showPrevStep=function(){var a,b,c,d=this;return c=this.getStep(this._current),b=function(){return d.showStep(c.prev)},a=this._makePromise(null!=c.onPrev?c.onPrev(this):void 0),this._callOnPromiseDone(a,b)},c.prototype._debug=function(a){return this._options.debug?b.console.log("Bootstrap Tour '"+this._options.name+"' | "+a):void 0},c.prototype._isRedirect=function(a,b){return null!=a&&""!==a&&a.replace(/\?.*$/,"").replace(/\/?$/,"")!==b.replace(/\/?$/,"")},c.prototype._redirect=function(b,c){return a.isFunction(b.redirect)?b.redirect.call(this,c):b.redirect===!0?(this._debug("Redirect to "+c),d.location.href=c):void 0},c.prototype._isOrphan=function(b){return null==b.element||!a(b.element).length||a(b.element).is(":hidden")&&"http://www.w3.org/2000/svg"!==a(b.element)[0].namespaceURI},c.prototype._isLast=function(){return this._current<this._steps.length-1},c.prototype._showPopover=function(b,c){var d,e,f,g,h,i,j=this;return i=a.extend({},this._options),f=a.isFunction(b.template)?a(b.template(c,b)):a(b.template),e=f.find(".popover-navigation"),h=this._isOrphan(b),h&&(b.element="body",b.placement="top",f=f.addClass("orphan")),d=a(b.element),f.addClass("tour-"+this._options.name),b.options&&a.extend(i,b.options),b.reflex&&d.css("cursor","pointer").on("click.tour-"+this._options.name,function(){return j._isLast()?j.next():j.end()}),b.prev<0&&e.find("*[data-role=prev]").addClass("disabled"),b.next<0&&e.find("*[data-role=next]").addClass("disabled"),b.duration||e.find("*[data-role='pause-resume']").remove(),b.template=f.clone().wrap("<div>").parent().html(),d.popover({placement:b.placement,trigger:"manual",title:b.title,content:b.content,html:!0,animation:b.animation,container:b.container,template:b.template,selector:b.element}).popover("show"),g=d.data("bs.popover")?d.data("bs.popover").tip():d.data("popover").tip(),g.attr("id",b.id),this._reposition(g,b),h?this._center(g):void 0},c.prototype._reposition=function(b,c){var e,f,g,h,i,j,k;if(h=b[0].offsetWidth,f=b[0].offsetHeight,k=b.offset(),i=k.left,j=k.top,e=a(d).outerHeight()-k.top-b.outerHeight(),0>e&&(k.top=k.top+e),g=a("html").outerWidth()-k.left-b.outerWidth(),0>g&&(k.left=k.left+g),k.top<0&&(k.top=0),k.left<0&&(k.left=0),b.offset(k),"bottom"===c.placement||"top"===c.placement){if(i!==k.left)return this._replaceArrow(b,2*(k.left-i),h,"left")}else if(j!==k.top)return this._replaceArrow(b,2*(k.top-j),f,"top")},c.prototype._center=function(c){return c.css("top",a(b).outerHeight()/2-c.outerHeight()/2)},c.prototype._replaceArrow=function(a,b,c,d){return a.find(".arrow").css(d,b?50*(1-b/c)+"%":"")},c.prototype._scrollIntoView=function(c,d){var e,f,g,h,i,j,k=this;return e=a(c),e.length?(f=a(b),h=e.offset().top,j=f.height(),i=Math.max(0,h-j/2),this._debug("Scroll into view. ScrollTop: "+i+". Element offset: "+h+". Window height: "+j+"."),g=0,a("body,html").stop(!0,!0).animate({scrollTop:Math.ceil(i)},function(){return 2===++g?(d(),k._debug("Scroll into view. Animation end element offset: "+e.offset().top+". Window height: "+f.height()+".")):void 0})):d()},c.prototype._onResize=function(c,d){return a(b).on("resize.tour-"+this._options.name,function(){return clearTimeout(d),d=setTimeout(c,100)})},c.prototype._setupMouseNavigation=function(){var b=this;return b=this,a(d).off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role=next]:not(.disabled)").on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role=next]:not(.disabled)",function(a){return a.preventDefault(),b.next()}),a(d).off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role=prev]:not(.disabled)").on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role=prev]:not(.disabled)",function(a){return a.preventDefault(),b.prev()}),a(d).off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role=end]").on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role=end]",function(a){return a.preventDefault(),b.end()}),a(d).off("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role=pause-resume]").on("click.tour-"+this._options.name,".popover.tour-"+this._options.name+" *[data-role=pause-resume]",function(c){var d;return c.preventDefault(),d=a(this),d.text(b._paused?d.data("pause-text"):d.data("resume-text")),b._paused?b.resume():b.pause()})},c.prototype._setupKeyboardNavigation=function(){var b=this;if(this._options.keyboard)return a(d).on("keyup.tour-"+this._options.name,function(a){if(a.which)switch(a.which){case 39:return a.preventDefault(),b._isLast()?b.next():b.end();case 37:if(a.preventDefault(),b._current>0)return b.prev();break;case 27:return a.preventDefault(),b.end()}})},c.prototype._makePromise=function(b){return b&&a.isFunction(b.then)?b:null},c.prototype._callOnPromiseDone=function(a,b,c){var d=this;return a?a.then(function(){return b.call(d,c)}):b.call(this,c)},c.prototype._showBackdrop=function(){return this.backdrop.backgroundShown?void 0:(this.backdrop=a("<div/>",{"class":"tour-backdrop"}),this.backdrop.backgroundShown=!0,a("body").append(this.backdrop))},c.prototype._hideBackdrop=function(){return this._hideOverlayElement(),this._hideBackground()},c.prototype._hideBackground=function(){return this.backdrop.remove(),this.backdrop.overlay=null,this.backdrop.backgroundShown=!1},c.prototype._showOverlayElement=function(b){var c,d,e;if(!this.backdrop.overlayElementShown)return this.backdrop.overlayElementShown=!0,d=a(b),c=a("<div/>"),e=d.offset(),e.top=e.top,e.left=e.left,c.width(d.innerWidth()).height(d.innerHeight()).addClass("tour-step-background").offset(e),d.addClass("tour-step-backdrop"),a("body").append(c),this.backdrop.$element=d,this.backdrop.$background=c},c.prototype._hideOverlayElement=function(){return this.backdrop.overlayElementShown?(this.backdrop.$element.removeClass("tour-step-backdrop"),this.backdrop.$background.remove(),this.backdrop.$element=null,this.backdrop.$background=null,this.backdrop.overlayElementShown=!1):void 0},c.prototype._clearTimer=function(){return b.clearTimeout(this._timer),this._timer=null,this._duration=null},c}(),b.Tour=c}(jQuery,window);
Index: /extensions/TakeATour/js/bootstrap.js
===================================================================
--- /extensions/TakeATour/js/bootstrap.js	(revision 27995)
+++ /extensions/TakeATour/js/bootstrap.js	(revision 27995)
@@ -0,0 +1,1999 @@
+/**
+* bootstrap.js v3.0.0 by @fat and @mdo
+* Copyright 2013 Twitter Inc.
+* http://www.apache.org/licenses/LICENSE-2.0
+*/
+if (!jQuery) { throw new Error("Bootstrap requires jQuery") }
+
+/* ========================================================================
+ * Bootstrap: transition.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#transitions
+ * ========================================================================
+ * Copyright 2013 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
+  // ============================================================
+
+  function transitionEnd() {
+    var el = document.createElement('bootstrap')
+
+    var transEndEventNames = {
+      'WebkitTransition' : 'webkitTransitionEnd'
+    , 'MozTransition'    : 'transitionend'
+    , 'OTransition'      : 'oTransitionEnd otransitionend'
+    , 'transition'       : 'transitionend'
+    }
+
+    for (var name in transEndEventNames) {
+      if (el.style[name] !== undefined) {
+        return { end: transEndEventNames[name] }
+      }
+    }
+  }
+
+  // http://blog.alexmaccaw.com/css-transitions
+  $.fn.emulateTransitionEnd = function (duration) {
+    var called = false, $el = this
+    $(this).one($.support.transition.end, function () { called = true })
+    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
+    setTimeout(callback, duration)
+    return this
+  }
+
+  $(function () {
+    $.support.transition = transitionEnd()
+  })
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: alert.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#alerts
+ * ========================================================================
+ * Copyright 2013 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // ALERT CLASS DEFINITION
+  // ======================
+
+  var dismiss = '[data-dismiss="alert"]'
+  var Alert   = function (el) {
+    $(el).on('click', dismiss, this.close)
+  }
+
+  Alert.prototype.close = function (e) {
+    var $this    = $(this)
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
+    }
+
+    var $parent = $(selector)
+
+    if (e) e.preventDefault()
+
+    if (!$parent.length) {
+      $parent = $this.hasClass('alert') ? $this : $this.parent()
+    }
+
+    $parent.trigger(e = $.Event('close.bs.alert'))
+
+    if (e.isDefaultPrevented()) return
+
+    $parent.removeClass('in')
+
+    function removeElement() {
+      $parent.trigger('closed.bs.alert').remove()
+    }
+
+    $.support.transition && $parent.hasClass('fade') ?
+      $parent
+        .one($.support.transition.end, removeElement)
+        .emulateTransitionEnd(150) :
+      removeElement()
+  }
+
+
+  // ALERT PLUGIN DEFINITION
+  // =======================
+
+  var old = $.fn.alert
+
+  $.fn.alert = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.alert')
+
+      if (!data) $this.data('bs.alert', (data = new Alert(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  $.fn.alert.Constructor = Alert
+
+
+  // ALERT NO CONFLICT
+  // =================
+
+  $.fn.alert.noConflict = function () {
+    $.fn.alert = old
+    return this
+  }
+
+
+  // ALERT DATA-API
+  // ==============
+
+  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: button.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#buttons
+ * ========================================================================
+ * Copyright 2013 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // BUTTON PUBLIC CLASS DEFINITION
+  // ==============================
+
+  var Button = function (element, options) {
+    this.$element = $(element)
+    this.options  = $.extend({}, Button.DEFAULTS, options)
+  }
+
+  Button.DEFAULTS = {
+    loadingText: 'loading...'
+  }
+
+  Button.prototype.setState = function (state) {
+    var d    = 'disabled'
+    var $el  = this.$element
+    var val  = $el.is('input') ? 'val' : 'html'
+    var data = $el.data()
+
+    state = state + 'Text'
+
+    if (!data.resetText) $el.data('resetText', $el[val]())
+
+    $el[val](data[state] || this.options[state])
+
+    // push to event loop to allow forms to submit
+    setTimeout(function () {
+      state == 'loadingText' ?
+        $el.addClass(d).attr(d, d) :
+        $el.removeClass(d).removeAttr(d);
+    }, 0)
+  }
+
+  Button.prototype.toggle = function () {
+    var $parent = this.$element.closest('[data-toggle="buttons"]')
+
+    if ($parent.length) {
+      var $input = this.$element.find('input')
+        .prop('checked', !this.$element.hasClass('active'))
+        .trigger('change')
+      if ($input.prop('type') === 'radio') $parent.find('.active').removeClass('active')
+    }
+
+    this.$element.toggleClass('active')
+  }
+
+
+  // BUTTON PLUGIN DEFINITION
+  // ========================
+
+  var old = $.fn.button
+
+  $.fn.button = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.button')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.button', (data = new Button(this, options)))
+
+      if (option == 'toggle') data.toggle()
+      else if (option) data.setState(option)
+    })
+  }
+
+  $.fn.button.Constructor = Button
+
+
+  // BUTTON NO CONFLICT
+  // ==================
+
+  $.fn.button.noConflict = function () {
+    $.fn.button = old
+    return this
+  }
+
+
+  // BUTTON DATA-API
+  // ===============
+
+  $(document).on('click.bs.button.data-api', '[data-toggle^=button]', function (e) {
+    var $btn = $(e.target)
+    if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')
+    $btn.button('toggle')
+    e.preventDefault()
+  })
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: carousel.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#carousel
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // CAROUSEL CLASS DEFINITION
+  // =========================
+
+  var Carousel = function (element, options) {
+    this.$element    = $(element)
+    this.$indicators = this.$element.find('.carousel-indicators')
+    this.options     = options
+    this.paused      =
+    this.sliding     =
+    this.interval    =
+    this.$active     =
+    this.$items      = null
+
+    this.options.pause == 'hover' && this.$element
+      .on('mouseenter', $.proxy(this.pause, this))
+      .on('mouseleave', $.proxy(this.cycle, this))
+  }
+
+  Carousel.DEFAULTS = {
+    interval: 5000
+  , pause: 'hover'
+  , wrap: true
+  }
+
+  Carousel.prototype.cycle =  function (e) {
+    e || (this.paused = false)
+
+    this.interval && clearInterval(this.interval)
+
+    this.options.interval
+      && !this.paused
+      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
+
+    return this
+  }
+
+  Carousel.prototype.getActiveIndex = function () {
+    this.$active = this.$element.find('.item.active')
+    this.$items  = this.$active.parent().children()
+
+    return this.$items.index(this.$active)
+  }
+
+  Carousel.prototype.to = function (pos) {
+    var that        = this
+    var activeIndex = this.getActiveIndex()
+
+    if (pos > (this.$items.length - 1) || pos < 0) return
+
+    if (this.sliding)       return this.$element.one('slid', function () { that.to(pos) })
+    if (activeIndex == pos) return this.pause().cycle()
+
+    return this.slide(pos > activeIndex ? 'next' : 'prev', $(this.$items[pos]))
+  }
+
+  Carousel.prototype.pause = function (e) {
+    e || (this.paused = true)
+
+    if (this.$element.find('.next, .prev').length && $.support.transition.end) {
+      this.$element.trigger($.support.transition.end)
+      this.cycle(true)
+    }
+
+    this.interval = clearInterval(this.interval)
+
+    return this
+  }
+
+  Carousel.prototype.next = function () {
+    if (this.sliding) return
+    return this.slide('next')
+  }
+
+  Carousel.prototype.prev = function () {
+    if (this.sliding) return
+    return this.slide('prev')
+  }
+
+  Carousel.prototype.slide = function (type, next) {
+    var $active   = this.$element.find('.item.active')
+    var $next     = next || $active[type]()
+    var isCycling = this.interval
+    var direction = type == 'next' ? 'left' : 'right'
+    var fallback  = type == 'next' ? 'first' : 'last'
+    var that      = this
+
+    if (!$next.length) {
+      if (!this.options.wrap) return
+      $next = this.$element.find('.item')[fallback]()
+    }
+
+    this.sliding = true
+
+    isCycling && this.pause()
+
+    var e = $.Event('slide.bs.carousel', { relatedTarget: $next[0], direction: direction })
+
+    if ($next.hasClass('active')) return
+
+    if (this.$indicators.length) {
+      this.$indicators.find('.active').removeClass('active')
+      this.$element.one('slid', function () {
+        var $nextIndicator = $(that.$indicators.children()[that.getActiveIndex()])
+        $nextIndicator && $nextIndicator.addClass('active')
+      })
+    }
+
+    if ($.support.transition && this.$element.hasClass('slide')) {
+      this.$element.trigger(e)
+      if (e.isDefaultPrevented()) return
+      $next.addClass(type)
+      $next[0].offsetWidth // force reflow
+      $active.addClass(direction)
+      $next.addClass(direction)
+      $active
+        .one($.support.transition.end, function () {
+          $next.removeClass([type, direction].join(' ')).addClass('active')
+          $active.removeClass(['active', direction].join(' '))
+          that.sliding = false
+          setTimeout(function () { that.$element.trigger('slid') }, 0)
+        })
+        .emulateTransitionEnd(600)
+    } else {
+      this.$element.trigger(e)
+      if (e.isDefaultPrevented()) return
+      $active.removeClass('active')
+      $next.addClass('active')
+      this.sliding = false
+      this.$element.trigger('slid')
+    }
+
+    isCycling && this.cycle()
+
+    return this
+  }
+
+
+  // CAROUSEL PLUGIN DEFINITION
+  // ==========================
+
+  var old = $.fn.carousel
+
+  $.fn.carousel = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.carousel')
+      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
+      var action  = typeof option == 'string' ? option : options.slide
+
+      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
+      if (typeof option == 'number') data.to(option)
+      else if (action) data[action]()
+      else if (options.interval) data.pause().cycle()
+    })
+  }
+
+  $.fn.carousel.Constructor = Carousel
+
+
+  // CAROUSEL NO CONFLICT
+  // ====================
+
+  $.fn.carousel.noConflict = function () {
+    $.fn.carousel = old
+    return this
+  }
+
+
+  // CAROUSEL DATA-API
+  // =================
+
+  $(document).on('click.bs.carousel.data-api', '[data-slide], [data-slide-to]', function (e) {
+    var $this   = $(this), href
+    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+    var options = $.extend({}, $target.data(), $this.data())
+    var slideIndex = $this.attr('data-slide-to')
+    if (slideIndex) options.interval = false
+
+    $target.carousel(options)
+
+    if (slideIndex = $this.attr('data-slide-to')) {
+      $target.data('bs.carousel').to(slideIndex)
+    }
+
+    e.preventDefault()
+  })
+
+  $(window).on('load', function () {
+    $('[data-ride="carousel"]').each(function () {
+      var $carousel = $(this)
+      $carousel.carousel($carousel.data())
+    })
+  })
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: collapse.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#collapse
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // COLLAPSE PUBLIC CLASS DEFINITION
+  // ================================
+
+  var Collapse = function (element, options) {
+    this.$element      = $(element)
+    this.options       = $.extend({}, Collapse.DEFAULTS, options)
+    this.transitioning = null
+
+    if (this.options.parent) this.$parent = $(this.options.parent)
+    if (this.options.toggle) this.toggle()
+  }
+
+  Collapse.DEFAULTS = {
+    toggle: true
+  }
+
+  Collapse.prototype.dimension = function () {
+    var hasWidth = this.$element.hasClass('width')
+    return hasWidth ? 'width' : 'height'
+  }
+
+  Collapse.prototype.show = function () {
+    if (this.transitioning || this.$element.hasClass('in')) return
+
+    var startEvent = $.Event('show.bs.collapse')
+    this.$element.trigger(startEvent)
+    if (startEvent.isDefaultPrevented()) return
+
+    var actives = this.$parent && this.$parent.find('> .panel > .in')
+
+    if (actives && actives.length) {
+      var hasData = actives.data('bs.collapse')
+      if (hasData && hasData.transitioning) return
+      actives.collapse('hide')
+      hasData || actives.data('bs.collapse', null)
+    }
+
+    var dimension = this.dimension()
+
+    this.$element
+      .removeClass('collapse')
+      .addClass('collapsing')
+      [dimension](0)
+
+    this.transitioning = 1
+
+    var complete = function () {
+      this.$element
+        .removeClass('collapsing')
+        .addClass('in')
+        [dimension]('auto')
+      this.transitioning = 0
+      this.$element.trigger('shown.bs.collapse')
+    }
+
+    if (!$.support.transition) return complete.call(this)
+
+    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
+
+    this.$element
+      .one($.support.transition.end, $.proxy(complete, this))
+      .emulateTransitionEnd(350)
+      [dimension](this.$element[0][scrollSize])
+  }
+
+  Collapse.prototype.hide = function () {
+    if (this.transitioning || !this.$element.hasClass('in')) return
+
+    var startEvent = $.Event('hide.bs.collapse')
+    this.$element.trigger(startEvent)
+    if (startEvent.isDefaultPrevented()) return
+
+    var dimension = this.dimension()
+
+    this.$element
+      [dimension](this.$element[dimension]())
+      [0].offsetHeight
+
+    this.$element
+      .addClass('collapsing')
+      .removeClass('collapse')
+      .removeClass('in')
+
+    this.transitioning = 1
+
+    var complete = function () {
+      this.transitioning = 0
+      this.$element
+        .trigger('hidden.bs.collapse')
+        .removeClass('collapsing')
+        .addClass('collapse')
+    }
+
+    if (!$.support.transition) return complete.call(this)
+
+    this.$element
+      [dimension](0)
+      .one($.support.transition.end, $.proxy(complete, this))
+      .emulateTransitionEnd(350)
+  }
+
+  Collapse.prototype.toggle = function () {
+    this[this.$element.hasClass('in') ? 'hide' : 'show']()
+  }
+
+
+  // COLLAPSE PLUGIN DEFINITION
+  // ==========================
+
+  var old = $.fn.collapse
+
+  $.fn.collapse = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.collapse')
+      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.collapse.Constructor = Collapse
+
+
+  // COLLAPSE NO CONFLICT
+  // ====================
+
+  $.fn.collapse.noConflict = function () {
+    $.fn.collapse = old
+    return this
+  }
+
+
+  // COLLAPSE DATA-API
+  // =================
+
+  $(document).on('click.bs.collapse.data-api', '[data-toggle=collapse]', function (e) {
+    var $this   = $(this), href
+    var target  = $this.attr('data-target')
+        || e.preventDefault()
+        || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
+    var $target = $(target)
+    var data    = $target.data('bs.collapse')
+    var option  = data ? 'toggle' : $this.data()
+    var parent  = $this.attr('data-parent')
+    var $parent = parent && $(parent)
+
+    if (!data || !data.transitioning) {
+      if ($parent) $parent.find('[data-toggle=collapse][data-parent="' + parent + '"]').not($this).addClass('collapsed')
+      $this[$target.hasClass('in') ? 'addClass' : 'removeClass']('collapsed')
+    }
+
+    $target.collapse(option)
+  })
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: dropdown.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#dropdowns
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // DROPDOWN CLASS DEFINITION
+  // =========================
+
+  var backdrop = '.dropdown-backdrop'
+  var toggle   = '[data-toggle=dropdown]'
+  var Dropdown = function (element) {
+    var $el = $(element).on('click.bs.dropdown', this.toggle)
+  }
+
+  Dropdown.prototype.toggle = function (e) {
+    var $this = $(this)
+
+    if ($this.is('.disabled, :disabled')) return
+
+    var $parent  = getParent($this)
+    var isActive = $parent.hasClass('open')
+
+    clearMenus()
+
+    if (!isActive) {
+      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
+        // if mobile we we use a backdrop because click events don't delegate
+        $('<div class="dropdown-backdrop"/>').insertAfter($(this)).on('click', clearMenus)
+      }
+
+      $parent.trigger(e = $.Event('show.bs.dropdown'))
+
+      if (e.isDefaultPrevented()) return
+
+      $parent
+        .toggleClass('open')
+        .trigger('shown.bs.dropdown')
+
+      $this.focus()
+    }
+
+    return false
+  }
+
+  Dropdown.prototype.keydown = function (e) {
+    if (!/(38|40|27)/.test(e.keyCode)) return
+
+    var $this = $(this)
+
+    e.preventDefault()
+    e.stopPropagation()
+
+    if ($this.is('.disabled, :disabled')) return
+
+    var $parent  = getParent($this)
+    var isActive = $parent.hasClass('open')
+
+    if (!isActive || (isActive && e.keyCode == 27)) {
+      if (e.which == 27) $parent.find(toggle).focus()
+      return $this.click()
+    }
+
+    var $items = $('[role=menu] li:not(.divider):visible a', $parent)
+
+    if (!$items.length) return
+
+    var index = $items.index($items.filter(':focus'))
+
+    if (e.keyCode == 38 && index > 0)                 index--                        // up
+    if (e.keyCode == 40 && index < $items.length - 1) index++                        // down
+    if (!~index)                                      index=0
+
+    $items.eq(index).focus()
+  }
+
+  function clearMenus() {
+    $(backdrop).remove()
+    $(toggle).each(function (e) {
+      var $parent = getParent($(this))
+      if (!$parent.hasClass('open')) return
+      $parent.trigger(e = $.Event('hide.bs.dropdown'))
+      if (e.isDefaultPrevented()) return
+      $parent.removeClass('open').trigger('hidden.bs.dropdown')
+    })
+  }
+
+  function getParent($this) {
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && /#/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+    }
+
+    var $parent = selector && $(selector)
+
+    return $parent && $parent.length ? $parent : $this.parent()
+  }
+
+
+  // DROPDOWN PLUGIN DEFINITION
+  // ==========================
+
+  var old = $.fn.dropdown
+
+  $.fn.dropdown = function (option) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('dropdown')
+
+      if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+      if (typeof option == 'string') data[option].call($this)
+    })
+  }
+
+  $.fn.dropdown.Constructor = Dropdown
+
+
+  // DROPDOWN NO CONFLICT
+  // ====================
+
+  $.fn.dropdown.noConflict = function () {
+    $.fn.dropdown = old
+    return this
+  }
+
+
+  // APPLY TO STANDARD DROPDOWN ELEMENTS
+  // ===================================
+
+  $(document)
+    .on('click.bs.dropdown.data-api', clearMenus)
+    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
+    .on('click.bs.dropdown.data-api'  , toggle, Dropdown.prototype.toggle)
+    .on('keydown.bs.dropdown.data-api', toggle + ', [role=menu]' , Dropdown.prototype.keydown)
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: modal.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#modals
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // MODAL CLASS DEFINITION
+  // ======================
+
+  var Modal = function (element, options) {
+    this.options   = options
+    this.$element  = $(element)
+    this.$backdrop =
+    this.isShown   = null
+
+    if (this.options.remote) this.$element.load(this.options.remote)
+  }
+
+  Modal.DEFAULTS = {
+      backdrop: true
+    , keyboard: true
+    , show: true
+  }
+
+  Modal.prototype.toggle = function (_relatedTarget) {
+    return this[!this.isShown ? 'show' : 'hide'](_relatedTarget)
+  }
+
+  Modal.prototype.show = function (_relatedTarget) {
+    var that = this
+    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
+
+    this.$element.trigger(e)
+
+    if (this.isShown || e.isDefaultPrevented()) return
+
+    this.isShown = true
+
+    this.escape()
+
+    this.$element.on('click.dismiss.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
+
+    this.backdrop(function () {
+      var transition = $.support.transition && that.$element.hasClass('fade')
+
+      if (!that.$element.parent().length) {
+        that.$element.appendTo(document.body) // don't move modals dom position
+      }
+
+      that.$element.show()
+
+      if (transition) {
+        that.$element[0].offsetWidth // force reflow
+      }
+
+      that.$element
+        .addClass('in')
+        .attr('aria-hidden', false)
+
+      that.enforceFocus()
+
+      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
+
+      transition ?
+        that.$element.find('.modal-dialog') // wait for modal to slide in
+          .one($.support.transition.end, function () {
+            that.$element.focus().trigger(e)
+          })
+          .emulateTransitionEnd(300) :
+        that.$element.focus().trigger(e)
+    })
+  }
+
+  Modal.prototype.hide = function (e) {
+    if (e) e.preventDefault()
+
+    e = $.Event('hide.bs.modal')
+
+    this.$element.trigger(e)
+
+    if (!this.isShown || e.isDefaultPrevented()) return
+
+    this.isShown = false
+
+    this.escape()
+
+    $(document).off('focusin.bs.modal')
+
+    this.$element
+      .removeClass('in')
+      .attr('aria-hidden', true)
+      .off('click.dismiss.modal')
+
+    $.support.transition && this.$element.hasClass('fade') ?
+      this.$element
+        .one($.support.transition.end, $.proxy(this.hideModal, this))
+        .emulateTransitionEnd(300) :
+      this.hideModal()
+  }
+
+  Modal.prototype.enforceFocus = function () {
+    $(document)
+      .off('focusin.bs.modal') // guard against infinite focus loop
+      .on('focusin.bs.modal', $.proxy(function (e) {
+        if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {
+          this.$element.focus()
+        }
+      }, this))
+  }
+
+  Modal.prototype.escape = function () {
+    if (this.isShown && this.options.keyboard) {
+      this.$element.on('keyup.dismiss.bs.modal', $.proxy(function (e) {
+        e.which == 27 && this.hide()
+      }, this))
+    } else if (!this.isShown) {
+      this.$element.off('keyup.dismiss.bs.modal')
+    }
+  }
+
+  Modal.prototype.hideModal = function () {
+    var that = this
+    this.$element.hide()
+    this.backdrop(function () {
+      that.removeBackdrop()
+      that.$element.trigger('hidden.bs.modal')
+    })
+  }
+
+  Modal.prototype.removeBackdrop = function () {
+    this.$backdrop && this.$backdrop.remove()
+    this.$backdrop = null
+  }
+
+  Modal.prototype.backdrop = function (callback) {
+    var that    = this
+    var animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+    if (this.isShown && this.options.backdrop) {
+      var doAnimate = $.support.transition && animate
+
+      this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+        .appendTo(document.body)
+
+      this.$element.on('click.dismiss.modal', $.proxy(function (e) {
+        if (e.target !== e.currentTarget) return
+        this.options.backdrop == 'static'
+          ? this.$element[0].focus.call(this.$element[0])
+          : this.hide.call(this)
+      }, this))
+
+      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+      this.$backdrop.addClass('in')
+
+      if (!callback) return
+
+      doAnimate ?
+        this.$backdrop
+          .one($.support.transition.end, callback)
+          .emulateTransitionEnd(150) :
+        callback()
+
+    } else if (!this.isShown && this.$backdrop) {
+      this.$backdrop.removeClass('in')
+
+      $.support.transition && this.$element.hasClass('fade')?
+        this.$backdrop
+          .one($.support.transition.end, callback)
+          .emulateTransitionEnd(150) :
+        callback()
+
+    } else if (callback) {
+      callback()
+    }
+  }
+
+
+  // MODAL PLUGIN DEFINITION
+  // =======================
+
+  var old = $.fn.modal
+
+  $.fn.modal = function (option, _relatedTarget) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.modal')
+      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
+
+      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
+      if (typeof option == 'string') data[option](_relatedTarget)
+      else if (options.show) data.show(_relatedTarget)
+    })
+  }
+
+  $.fn.modal.Constructor = Modal
+
+
+  // MODAL NO CONFLICT
+  // =================
+
+  $.fn.modal.noConflict = function () {
+    $.fn.modal = old
+    return this
+  }
+
+
+  // MODAL DATA-API
+  // ==============
+
+  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
+    var $this   = $(this)
+    var href    = $this.attr('href')
+    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7
+    var option  = $target.data('modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
+
+    e.preventDefault()
+
+    $target
+      .modal(option, this)
+      .one('hide', function () {
+        $this.is(':visible') && $this.focus()
+      })
+  })
+
+  $(document)
+    .on('show.bs.modal',  '.modal', function () { $(document.body).addClass('modal-open') })
+    .on('hidden.bs.modal', '.modal', function () { $(document.body).removeClass('modal-open') })
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // TOOLTIP PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Tooltip = function (element, options) {
+    this.type       =
+    this.options    =
+    this.enabled    =
+    this.timeout    =
+    this.hoverState =
+    this.$element   = null
+
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.DEFAULTS = {
+    animation: true
+  , placement: 'top'
+  , selector: false
+  , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
+  , trigger: 'hover focus'
+  , title: ''
+  , delay: 0
+  , html: false
+  , container: false
+  }
+
+  Tooltip.prototype.init = function (type, element, options) {
+    this.enabled  = true
+    this.type     = type
+    this.$element = $(element)
+    this.options  = this.getOptions(options)
+
+    var triggers = this.options.trigger.split(' ')
+
+    for (var i = triggers.length; i--;) {
+      var trigger = triggers[i]
+
+      if (trigger == 'click') {
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+      } else if (trigger != 'manual') {
+        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focus'
+        var eventOut = trigger == 'hover' ? 'mouseleave' : 'blur'
+
+        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+      }
+    }
+
+    this.options.selector ?
+      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+      this.fixTitle()
+  }
+
+  Tooltip.prototype.getDefaults = function () {
+    return Tooltip.DEFAULTS
+  }
+
+  Tooltip.prototype.getOptions = function (options) {
+    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+    if (options.delay && typeof options.delay == 'number') {
+      options.delay = {
+        show: options.delay
+      , hide: options.delay
+      }
+    }
+
+    return options
+  }
+
+  Tooltip.prototype.getDelegateOptions = function () {
+    var options  = {}
+    var defaults = this.getDefaults()
+
+    this._options && $.each(this._options, function (key, value) {
+      if (defaults[key] != value) options[key] = value
+    })
+
+    return options
+  }
+
+  Tooltip.prototype.enter = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'in'
+
+    if (!self.options.delay || !self.options.delay.show) return self.show()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'in') self.show()
+    }, self.options.delay.show)
+  }
+
+  Tooltip.prototype.leave = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'out'
+
+    if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'out') self.hide()
+    }, self.options.delay.hide)
+  }
+
+  Tooltip.prototype.show = function () {
+    var e = $.Event('show.bs.'+ this.type)
+
+    if (this.hasContent() && this.enabled) {
+      this.$element.trigger(e)
+
+      if (e.isDefaultPrevented()) return
+
+      var $tip = this.tip()
+
+      this.setContent()
+
+      if (this.options.animation) $tip.addClass('fade')
+
+      var placement = typeof this.options.placement == 'function' ?
+        this.options.placement.call(this, $tip[0], this.$element[0]) :
+        this.options.placement
+
+      var autoToken = /\s?auto?\s?/i
+      var autoPlace = autoToken.test(placement)
+      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+      $tip
+        .detach()
+        .css({ top: 0, left: 0, display: 'block' })
+        .addClass(placement)
+
+      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+      var pos          = this.getPosition()
+      var actualWidth  = $tip[0].offsetWidth
+      var actualHeight = $tip[0].offsetHeight
+
+      if (autoPlace) {
+        var $parent = this.$element.parent()
+
+        var orgPlacement = placement
+        var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
+        var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
+        var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+        var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
+
+        placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
+                    placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
+                    placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
+                    placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
+                    placement
+
+        $tip
+          .removeClass(orgPlacement)
+          .addClass(placement)
+      }
+
+      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+      this.applyPlacement(calculatedOffset, placement)
+      this.$element.trigger('shown.bs.' + this.type)
+    }
+  }
+
+  Tooltip.prototype.applyPlacement = function(offset, placement) {
+    var replace
+    var $tip   = this.tip()
+    var width  = $tip[0].offsetWidth
+    var height = $tip[0].offsetHeight
+
+    // manually read margins because getBoundingClientRect includes difference
+    var marginTop = parseInt($tip.css('margin-top'), 10)
+    var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+    // we must check for NaN for ie 8/9
+    if (isNaN(marginTop))  marginTop  = 0
+    if (isNaN(marginLeft)) marginLeft = 0
+
+    offset.top  = offset.top  + marginTop
+    offset.left = offset.left + marginLeft
+
+    $tip
+      .offset(offset)
+      .addClass('in')
+
+    // check to see if placing tip in new offset caused the tip to resize itself
+    var actualWidth  = $tip[0].offsetWidth
+    var actualHeight = $tip[0].offsetHeight
+
+    if (placement == 'top' && actualHeight != height) {
+      replace = true
+      offset.top = offset.top + height - actualHeight
+    }
+
+    if (/bottom|top/.test(placement)) {
+      var delta = 0
+
+      if (offset.left < 0) {
+        delta       = offset.left * -2
+        offset.left = 0
+
+        $tip.offset(offset)
+
+        actualWidth  = $tip[0].offsetWidth
+        actualHeight = $tip[0].offsetHeight
+      }
+
+      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+    } else {
+      this.replaceArrow(actualHeight - height, actualHeight, 'top')
+    }
+
+    if (replace) $tip.offset(offset)
+  }
+
+  Tooltip.prototype.replaceArrow = function(delta, dimension, position) {
+    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + "%") : '')
+  }
+
+  Tooltip.prototype.setContent = function () {
+    var $tip  = this.tip()
+    var title = this.getTitle()
+
+    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+    $tip.removeClass('fade in top bottom left right')
+  }
+
+  Tooltip.prototype.hide = function () {
+    var that = this
+    var $tip = this.tip()
+    var e    = $.Event('hide.bs.' + this.type)
+
+    function complete() {
+      if (that.hoverState != 'in') $tip.detach()
+    }
+
+    this.$element.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    $tip.removeClass('in')
+
+    $.support.transition && this.$tip.hasClass('fade') ?
+      $tip
+        .one($.support.transition.end, complete)
+        .emulateTransitionEnd(150) :
+      complete()
+
+    this.$element.trigger('hidden.bs.' + this.type)
+
+    return this
+  }
+
+  Tooltip.prototype.fixTitle = function () {
+    var $e = this.$element
+    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+    }
+  }
+
+  Tooltip.prototype.hasContent = function () {
+    return this.getTitle()
+  }
+
+  Tooltip.prototype.getPosition = function () {
+    var el = this.$element[0]
+    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+      width: el.offsetWidth
+    , height: el.offsetHeight
+    }, this.$element.offset())
+  }
+
+  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
+  }
+
+  Tooltip.prototype.getTitle = function () {
+    var title
+    var $e = this.$element
+    var o  = this.options
+
+    title = $e.attr('data-original-title')
+      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
+
+    return title
+  }
+
+  Tooltip.prototype.tip = function () {
+    return this.$tip = this.$tip || $(this.options.template)
+  }
+
+  Tooltip.prototype.arrow = function () {
+    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+  }
+
+  Tooltip.prototype.validate = function () {
+    if (!this.$element[0].parentNode) {
+      this.hide()
+      this.$element = null
+      this.options  = null
+    }
+  }
+
+  Tooltip.prototype.enable = function () {
+    this.enabled = true
+  }
+
+  Tooltip.prototype.disable = function () {
+    this.enabled = false
+  }
+
+  Tooltip.prototype.toggleEnabled = function () {
+    this.enabled = !this.enabled
+  }
+
+  Tooltip.prototype.toggle = function (e) {
+    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+  }
+
+  Tooltip.prototype.destroy = function () {
+    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+  }
+
+
+  // TOOLTIP PLUGIN DEFINITION
+  // =========================
+
+  var old = $.fn.tooltip
+
+  $.fn.tooltip = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.tooltip')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.tooltip.Constructor = Tooltip
+
+
+  // TOOLTIP NO CONFLICT
+  // ===================
+
+  $.fn.tooltip.noConflict = function () {
+    $.fn.tooltip = old
+    return this
+  }
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#popovers
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // POPOVER PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Popover = function (element, options) {
+    this.init('popover', element, options)
+  }
+
+  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+  Popover.DEFAULTS = $.extend({} , $.fn.tooltip.Constructor.DEFAULTS, {
+    placement: 'right'
+  , trigger: 'click'
+  , content: ''
+  , template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+  })
+
+
+  // NOTE: POPOVER EXTENDS tooltip.js
+  // ================================
+
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+  Popover.prototype.constructor = Popover
+
+  Popover.prototype.getDefaults = function () {
+    return Popover.DEFAULTS
+  }
+
+  Popover.prototype.setContent = function () {
+    var $tip    = this.tip()
+    var title   = this.getTitle()
+    var content = this.getContent()
+
+    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+    $tip.find('.popover-content')[this.options.html ? 'html' : 'text'](content)
+
+    $tip.removeClass('fade top bottom left right in')
+
+    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+    // this manually by checking the contents.
+    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+  }
+
+  Popover.prototype.hasContent = function () {
+    return this.getTitle() || this.getContent()
+  }
+
+  Popover.prototype.getContent = function () {
+    var $e = this.$element
+    var o  = this.options
+
+    return $e.attr('data-content')
+      || (typeof o.content == 'function' ?
+            o.content.call($e[0]) :
+            o.content)
+  }
+
+  Popover.prototype.arrow = function () {
+    return this.$arrow = this.$arrow || this.tip().find('.arrow')
+  }
+
+  Popover.prototype.tip = function () {
+    if (!this.$tip) this.$tip = $(this.options.template)
+    return this.$tip
+  }
+
+
+  // POPOVER PLUGIN DEFINITION
+  // =========================
+
+  var old = $.fn.popover
+
+  $.fn.popover = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.popover')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.popover.Constructor = Popover
+
+
+  // POPOVER NO CONFLICT
+  // ===================
+
+  $.fn.popover.noConflict = function () {
+    $.fn.popover = old
+    return this
+  }
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: scrollspy.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#scrollspy
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // SCROLLSPY CLASS DEFINITION
+  // ==========================
+
+  function ScrollSpy(element, options) {
+    var href
+    var process  = $.proxy(this.process, this)
+
+    this.$element       = $(element).is('body') ? $(window) : $(element)
+    this.$body          = $('body')
+    this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
+    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
+    this.selector       = (this.options.target
+      || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+      || '') + ' .nav li > a'
+    this.offsets        = $([])
+    this.targets        = $([])
+    this.activeTarget   = null
+
+    this.refresh()
+    this.process()
+  }
+
+  ScrollSpy.DEFAULTS = {
+    offset: 10
+  }
+
+  ScrollSpy.prototype.refresh = function () {
+    var offsetMethod = this.$element[0] == window ? 'offset' : 'position'
+
+    this.offsets = $([])
+    this.targets = $([])
+
+    var self     = this
+    var $targets = this.$body
+      .find(this.selector)
+      .map(function () {
+        var $el   = $(this)
+        var href  = $el.data('target') || $el.attr('href')
+        var $href = /^#\w/.test(href) && $(href)
+
+        return ($href
+          && $href.length
+          && [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
+      })
+      .sort(function (a, b) { return a[0] - b[0] })
+      .each(function () {
+        self.offsets.push(this[0])
+        self.targets.push(this[1])
+      })
+  }
+
+  ScrollSpy.prototype.process = function () {
+    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
+    var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
+    var maxScroll    = scrollHeight - this.$scrollElement.height()
+    var offsets      = this.offsets
+    var targets      = this.targets
+    var activeTarget = this.activeTarget
+    var i
+
+    if (scrollTop >= maxScroll) {
+      return activeTarget != (i = targets.last()[0]) && this.activate(i)
+    }
+
+    for (i = offsets.length; i--;) {
+      activeTarget != targets[i]
+        && scrollTop >= offsets[i]
+        && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+        && this.activate( targets[i] )
+    }
+  }
+
+  ScrollSpy.prototype.activate = function (target) {
+    this.activeTarget = target
+
+    $(this.selector)
+      .parents('.active')
+      .removeClass('active')
+
+    var selector = this.selector
+      + '[data-target="' + target + '"],'
+      + this.selector + '[href="' + target + '"]'
+
+    var active = $(selector)
+      .parents('li')
+      .addClass('active')
+
+    if (active.parent('.dropdown-menu').length)  {
+      active = active
+        .closest('li.dropdown')
+        .addClass('active')
+    }
+
+    active.trigger('activate')
+  }
+
+
+  // SCROLLSPY PLUGIN DEFINITION
+  // ===========================
+
+  var old = $.fn.scrollspy
+
+  $.fn.scrollspy = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.scrollspy')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.scrollspy.Constructor = ScrollSpy
+
+
+  // SCROLLSPY NO CONFLICT
+  // =====================
+
+  $.fn.scrollspy.noConflict = function () {
+    $.fn.scrollspy = old
+    return this
+  }
+
+
+  // SCROLLSPY DATA-API
+  // ==================
+
+  $(window).on('load', function () {
+    $('[data-spy="scroll"]').each(function () {
+      var $spy = $(this)
+      $spy.scrollspy($spy.data())
+    })
+  })
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: tab.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#tabs
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // TAB CLASS DEFINITION
+  // ====================
+
+  var Tab = function (element) {
+    this.element = $(element)
+  }
+
+  Tab.prototype.show = function () {
+    var $this    = this.element
+    var $ul      = $this.closest('ul:not(.dropdown-menu)')
+    var selector = $this.attr('data-target')
+
+    if (!selector) {
+      selector = $this.attr('href')
+      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+    }
+
+    if ($this.parent('li').hasClass('active')) return
+
+    var previous = $ul.find('.active:last a')[0]
+    var e        = $.Event('show.bs.tab', {
+      relatedTarget: previous
+    })
+
+    $this.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    var $target = $(selector)
+
+    this.activate($this.parent('li'), $ul)
+    this.activate($target, $target.parent(), function () {
+      $this.trigger({
+        type: 'shown.bs.tab'
+      , relatedTarget: previous
+      })
+    })
+  }
+
+  Tab.prototype.activate = function (element, container, callback) {
+    var $active    = container.find('> .active')
+    var transition = callback
+      && $.support.transition
+      && $active.hasClass('fade')
+
+    function next() {
+      $active
+        .removeClass('active')
+        .find('> .dropdown-menu > .active')
+        .removeClass('active')
+
+      element.addClass('active')
+
+      if (transition) {
+        element[0].offsetWidth // reflow for transition
+        element.addClass('in')
+      } else {
+        element.removeClass('fade')
+      }
+
+      if (element.parent('.dropdown-menu')) {
+        element.closest('li.dropdown').addClass('active')
+      }
+
+      callback && callback()
+    }
+
+    transition ?
+      $active
+        .one($.support.transition.end, next)
+        .emulateTransitionEnd(150) :
+      next()
+
+    $active.removeClass('in')
+  }
+
+
+  // TAB PLUGIN DEFINITION
+  // =====================
+
+  var old = $.fn.tab
+
+  $.fn.tab = function ( option ) {
+    return this.each(function () {
+      var $this = $(this)
+      var data  = $this.data('bs.tab')
+
+      if (!data) $this.data('bs.tab', (data = new Tab(this)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.tab.Constructor = Tab
+
+
+  // TAB NO CONFLICT
+  // ===============
+
+  $.fn.tab.noConflict = function () {
+    $.fn.tab = old
+    return this
+  }
+
+
+  // TAB DATA-API
+  // ============
+
+  $(document).on('click.bs.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+    e.preventDefault()
+    $(this).tab('show')
+  })
+
+}(window.jQuery);
+
+/* ========================================================================
+ * Bootstrap: affix.js v3.0.0
+ * http://twbs.github.com/bootstrap/javascript.html#affix
+ * ========================================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ======================================================================== */
+
+
++function ($) { "use strict";
+
+  // AFFIX CLASS DEFINITION
+  // ======================
+
+  var Affix = function (element, options) {
+    this.options = $.extend({}, Affix.DEFAULTS, options)
+    this.$window = $(window)
+      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
+      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
+
+    this.$element = $(element)
+    this.affixed  =
+    this.unpin    = null
+
+    this.checkPosition()
+  }
+
+  Affix.RESET = 'affix affix-top affix-bottom'
+
+  Affix.DEFAULTS = {
+    offset: 0
+  }
+
+  Affix.prototype.checkPositionWithEventLoop = function () {
+    setTimeout($.proxy(this.checkPosition, this), 1)
+  }
+
+  Affix.prototype.checkPosition = function () {
+    if (!this.$element.is(':visible')) return
+
+    var scrollHeight = $(document).height()
+    var scrollTop    = this.$window.scrollTop()
+    var position     = this.$element.offset()
+    var offset       = this.options.offset
+    var offsetTop    = offset.top
+    var offsetBottom = offset.bottom
+
+    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
+    if (typeof offsetTop == 'function')    offsetTop    = offset.top()
+    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom()
+
+    var affix = this.unpin   != null && (scrollTop + this.unpin <= position.top) ? false :
+                offsetBottom != null && (position.top + this.$element.height() >= scrollHeight - offsetBottom) ? 'bottom' :
+                offsetTop    != null && (scrollTop <= offsetTop) ? 'top' : false
+
+    if (this.affixed === affix) return
+    if (this.unpin) this.$element.css('top', '')
+
+    this.affixed = affix
+    this.unpin   = affix == 'bottom' ? position.top - scrollTop : null
+
+    this.$element.removeClass(Affix.RESET).addClass('affix' + (affix ? '-' + affix : ''))
+
+    if (affix == 'bottom') {
+      this.$element.offset({ top: document.body.offsetHeight - offsetBottom - this.$element.height() })
+    }
+  }
+
+
+  // AFFIX PLUGIN DEFINITION
+  // =======================
+
+  var old = $.fn.affix
+
+  $.fn.affix = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.affix')
+      var options = typeof option == 'object' && option
+
+      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.affix.Constructor = Affix
+
+
+  // AFFIX NO CONFLICT
+  // =================
+
+  $.fn.affix.noConflict = function () {
+    $.fn.affix = old
+    return this
+  }
+
+
+  // AFFIX DATA-API
+  // ==============
+
+  $(window).on('load', function () {
+    $('[data-spy="affix"]').each(function () {
+      var $spy = $(this)
+      var data = $spy.data()
+
+      data.offset = data.offset || {}
+
+      if (data.offsetBottom) data.offset.bottom = data.offsetBottom
+      if (data.offsetTop)    data.offset.top    = data.offsetTop
+
+      $spy.affix(data)
+    })
+  })
+
+}(window.jQuery);
Index: /extensions/TakeATour/js/bootstrap.popover.js
===================================================================
--- /extensions/TakeATour/js/bootstrap.popover.js	(revision 27995)
+++ /extensions/TakeATour/js/bootstrap.popover.js	(revision 27995)
@@ -0,0 +1,110 @@
+/* ========================================================================
+ * Bootstrap: popover.js v3.1.0
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // POPOVER PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Popover = function (element, options) {
+    this.init('popover', element, options)
+  }
+
+  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+    placement: 'right',
+    trigger: 'click',
+    content: '',
+    template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+  })
+
+
+  // NOTE: POPOVER EXTENDS tooltip.js
+  // ================================
+
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+  Popover.prototype.constructor = Popover
+
+  Popover.prototype.getDefaults = function () {
+    return Popover.DEFAULTS
+  }
+
+  Popover.prototype.setContent = function () {
+    var $tip    = this.tip()
+    var title   = this.getTitle()
+    var content = this.getContent()
+
+    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+    $tip.find('.popover-content')[ // we use append for html objects to maintain js events
+      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+    ](content)
+
+    $tip.removeClass('fade top bottom left right in')
+
+    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+    // this manually by checking the contents.
+    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+  }
+
+  Popover.prototype.hasContent = function () {
+    return this.getTitle() || this.getContent()
+  }
+
+  Popover.prototype.getContent = function () {
+    var $e = this.$element
+    var o  = this.options
+
+    return $e.attr('data-content')
+      || (typeof o.content == 'function' ?
+            o.content.call($e[0]) :
+            o.content)
+  }
+
+  Popover.prototype.arrow = function () {
+    return this.$arrow = this.$arrow || this.tip().find('.arrow')
+  }
+
+  Popover.prototype.tip = function () {
+    if (!this.$tip) this.$tip = $(this.options.template)
+    return this.$tip
+  }
+
+
+  // POPOVER PLUGIN DEFINITION
+  // =========================
+
+  var old = $.fn.popover
+
+  $.fn.popover = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.popover')
+      var options = typeof option == 'object' && option
+
+      if (!data && option == 'destroy') return
+      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.popover.Constructor = Popover
+
+
+  // POPOVER NO CONFLICT
+  // ===================
+
+  $.fn.popover.noConflict = function () {
+    $.fn.popover = old
+    return this
+  }
+
+}(jQuery);
Index: /extensions/TakeATour/js/bootstrap.tooltip.js
===================================================================
--- /extensions/TakeATour/js/bootstrap.tooltip.js	(revision 27995)
+++ /extensions/TakeATour/js/bootstrap.tooltip.js	(revision 27995)
@@ -0,0 +1,399 @@
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.1.0
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TOOLTIP PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Tooltip = function (element, options) {
+    this.type       =
+    this.options    =
+    this.enabled    =
+    this.timeout    =
+    this.hoverState =
+    this.$element   = null
+
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.DEFAULTS = {
+    animation: true,
+    placement: 'top',
+    selector: false,
+    template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+    trigger: 'hover focus',
+    title: '',
+    delay: 0,
+    html: false,
+    container: false
+  }
+
+  Tooltip.prototype.init = function (type, element, options) {
+    this.enabled  = true
+    this.type     = type
+    this.$element = $(element)
+    this.options  = this.getOptions(options)
+
+    var triggers = this.options.trigger.split(' ')
+
+    for (var i = triggers.length; i--;) {
+      var trigger = triggers[i]
+
+      if (trigger == 'click') {
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+      } else if (trigger != 'manual') {
+        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
+        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+      }
+    }
+
+    this.options.selector ?
+      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+      this.fixTitle()
+  }
+
+  Tooltip.prototype.getDefaults = function () {
+    return Tooltip.DEFAULTS
+  }
+
+  Tooltip.prototype.getOptions = function (options) {
+    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+    if (options.delay && typeof options.delay == 'number') {
+      options.delay = {
+        show: options.delay,
+        hide: options.delay
+      }
+    }
+
+    return options
+  }
+
+  Tooltip.prototype.getDelegateOptions = function () {
+    var options  = {}
+    var defaults = this.getDefaults()
+
+    this._options && $.each(this._options, function (key, value) {
+      if (defaults[key] != value) options[key] = value
+    })
+
+    return options
+  }
+
+  Tooltip.prototype.enter = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'in'
+
+    if (!self.options.delay || !self.options.delay.show) return self.show()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'in') self.show()
+    }, self.options.delay.show)
+  }
+
+  Tooltip.prototype.leave = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'out'
+
+    if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'out') self.hide()
+    }, self.options.delay.hide)
+  }
+
+  Tooltip.prototype.show = function () {
+    var e = $.Event('show.bs.' + this.type)
+
+    if (this.hasContent() && this.enabled) {
+      this.$element.trigger(e)
+
+      if (e.isDefaultPrevented()) return
+      var that = this;
+
+      var $tip = this.tip()
+
+      this.setContent()
+
+      if (this.options.animation) $tip.addClass('fade')
+
+      var placement = typeof this.options.placement == 'function' ?
+        this.options.placement.call(this, $tip[0], this.$element[0]) :
+        this.options.placement
+
+      var autoToken = /\s?auto?\s?/i
+      var autoPlace = autoToken.test(placement)
+      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+      $tip
+        .detach()
+        .css({ top: 0, left: 0, display: 'block' })
+        .addClass(placement)
+
+      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+      var pos          = this.getPosition()
+      var actualWidth  = $tip[0].offsetWidth
+      var actualHeight = $tip[0].offsetHeight
+
+      if (autoPlace) {
+        var $parent = this.$element.parent()
+
+        var orgPlacement = placement
+        var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
+        var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
+        var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+        var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
+
+        placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
+                    placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
+                    placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
+                    placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
+                    placement
+
+        $tip
+          .removeClass(orgPlacement)
+          .addClass(placement)
+      }
+
+      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+      this.applyPlacement(calculatedOffset, placement)
+      this.hoverState = null
+
+      var complete = function() {
+        that.$element.trigger('shown.bs.' + that.type)
+      }
+
+      $.support.transition && this.$tip.hasClass('fade') ?
+        $tip
+          .one($.support.transition.end, complete)
+          .emulateTransitionEnd(150) :
+        complete()
+    }
+  }
+
+  Tooltip.prototype.applyPlacement = function (offset, placement) {
+    var replace
+    var $tip   = this.tip()
+    var width  = $tip[0].offsetWidth
+    var height = $tip[0].offsetHeight
+
+    // manually read margins because getBoundingClientRect includes difference
+    var marginTop = parseInt($tip.css('margin-top'), 10)
+    var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+    // we must check for NaN for ie 8/9
+    if (isNaN(marginTop))  marginTop  = 0
+    if (isNaN(marginLeft)) marginLeft = 0
+
+    offset.top  = offset.top  + marginTop
+    offset.left = offset.left + marginLeft
+
+    // $.fn.offset doesn't round pixel values
+    // so we use setOffset directly with our own function B-0
+    $.offset.setOffset($tip[0], $.extend({
+      using: function (props) {
+        $tip.css({
+          top: Math.round(props.top),
+          left: Math.round(props.left)
+        })
+      }
+    }, offset), 0)
+
+    $tip.addClass('in')
+
+    // check to see if placing tip in new offset caused the tip to resize itself
+    var actualWidth  = $tip[0].offsetWidth
+    var actualHeight = $tip[0].offsetHeight
+
+    if (placement == 'top' && actualHeight != height) {
+      replace = true
+      offset.top = offset.top + height - actualHeight
+    }
+
+    if (/bottom|top/.test(placement)) {
+      var delta = 0
+
+      if (offset.left < 0) {
+        delta       = offset.left * -2
+        offset.left = 0
+
+        $tip.offset(offset)
+
+        actualWidth  = $tip[0].offsetWidth
+        actualHeight = $tip[0].offsetHeight
+      }
+
+      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+    } else {
+      this.replaceArrow(actualHeight - height, actualHeight, 'top')
+    }
+
+    if (replace) $tip.offset(offset)
+  }
+
+  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
+    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
+  }
+
+  Tooltip.prototype.setContent = function () {
+    var $tip  = this.tip()
+    var title = this.getTitle()
+
+    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+    $tip.removeClass('fade in top bottom left right')
+  }
+
+  Tooltip.prototype.hide = function () {
+    var that = this
+    var $tip = this.tip()
+    var e    = $.Event('hide.bs.' + this.type)
+
+    function complete() {
+      if (that.hoverState != 'in') $tip.detach()
+      that.$element.trigger('hidden.bs.' + that.type)
+    }
+
+    this.$element.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    $tip.removeClass('in')
+
+    $.support.transition && this.$tip.hasClass('fade') ?
+      $tip
+        .one($.support.transition.end, complete)
+        .emulateTransitionEnd(150) :
+      complete()
+
+    this.hoverState = null
+
+    return this
+  }
+
+  Tooltip.prototype.fixTitle = function () {
+    var $e = this.$element
+    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+    }
+  }
+
+  Tooltip.prototype.hasContent = function () {
+    return this.getTitle()
+  }
+
+  Tooltip.prototype.getPosition = function () {
+    var el = this.$element[0]
+    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+      width: el.offsetWidth,
+      height: el.offsetHeight
+    }, this.$element.offset())
+  }
+
+  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
+  }
+
+  Tooltip.prototype.getTitle = function () {
+    var title
+    var $e = this.$element
+    var o  = this.options
+
+    title = $e.attr('data-original-title')
+      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
+
+    return title
+  }
+
+  Tooltip.prototype.tip = function () {
+    return this.$tip = this.$tip || $(this.options.template)
+  }
+
+  Tooltip.prototype.arrow = function () {
+    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+  }
+
+  Tooltip.prototype.validate = function () {
+    if (!this.$element[0].parentNode) {
+      this.hide()
+      this.$element = null
+      this.options  = null
+    }
+  }
+
+  Tooltip.prototype.enable = function () {
+    this.enabled = true
+  }
+
+  Tooltip.prototype.disable = function () {
+    this.enabled = false
+  }
+
+  Tooltip.prototype.toggleEnabled = function () {
+    this.enabled = !this.enabled
+  }
+
+  Tooltip.prototype.toggle = function (e) {
+    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+  }
+
+  Tooltip.prototype.destroy = function () {
+    clearTimeout(this.timeout)
+    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+  }
+
+
+  // TOOLTIP PLUGIN DEFINITION
+  // =========================
+
+  var old = $.fn.tooltip
+
+  $.fn.tooltip = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.tooltip')
+      var options = typeof option == 'object' && option
+
+      if (!data && option == 'destroy') return
+      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.tooltip.Constructor = Tooltip
+
+
+  // TOOLTIP NO CONFLICT
+  // ===================
+
+  $.fn.tooltip.noConflict = function () {
+    $.fn.tooltip = old
+    return this
+  }
+
+}(jQuery);
Index: /extensions/TakeATour/js/custom-bootstrap-tour-standalone.js
===================================================================
--- /extensions/TakeATour/js/custom-bootstrap-tour-standalone.js	(revision 27995)
+++ /extensions/TakeATour/js/custom-bootstrap-tour-standalone.js	(revision 27995)
@@ -0,0 +1,1233 @@
+/* ===========================================================
+# bootstrap-tour - v0.9.0
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.1.0
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TOOLTIP PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Tooltip = function (element, options) {
+    this.type       =
+    this.options    =
+    this.enabled    =
+    this.timeout    =
+    this.hoverState =
+    this.$element   = null
+
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.DEFAULTS = {
+    animation: true,
+    placement: 'top',
+    selector: false,
+    template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+    trigger: 'hover focus',
+    title: '',
+    delay: 0,
+    html: false,
+    container: false
+  }
+
+  Tooltip.prototype.init = function (type, element, options) {
+    this.enabled  = true
+    this.type     = type
+    this.$element = $(element)
+    this.options  = this.getOptions(options)
+
+    var triggers = this.options.trigger.split(' ')
+
+    for (var i = triggers.length; i--;) {
+      var trigger = triggers[i]
+
+      if (trigger == 'click') {
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+      } else if (trigger != 'manual') {
+        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
+        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+      }
+    }
+
+    this.options.selector ?
+      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+      this.fixTitle()
+  }
+
+  Tooltip.prototype.getDefaults = function () {
+    return Tooltip.DEFAULTS
+  }
+
+  Tooltip.prototype.getOptions = function (options) {
+    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+    if (options.delay && typeof options.delay == 'number') {
+      options.delay = {
+        show: options.delay,
+        hide: options.delay
+      }
+    }
+
+    return options
+  }
+
+  Tooltip.prototype.getDelegateOptions = function () {
+    var options  = {}
+    var defaults = this.getDefaults()
+
+    this._options && $.each(this._options, function (key, value) {
+      if (defaults[key] != value) options[key] = value
+    })
+
+    return options
+  }
+
+  Tooltip.prototype.enter = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'in'
+
+    if (!self.options.delay || !self.options.delay.show) return self.show()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'in') self.show()
+    }, self.options.delay.show)
+  }
+
+  Tooltip.prototype.leave = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'out'
+
+    if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'out') self.hide()
+    }, self.options.delay.hide)
+  }
+
+  Tooltip.prototype.show = function () {
+    var e = $.Event('show.bs.' + this.type)
+
+    if (this.hasContent() && this.enabled) {
+      this.$element.trigger(e)
+
+      if (e.isDefaultPrevented()) return
+      var that = this;
+
+      var $tip = this.tip()
+
+      this.setContent()
+
+      if (this.options.animation) $tip.addClass('fade')
+
+      var placement = typeof this.options.placement == 'function' ?
+        this.options.placement.call(this, $tip[0], this.$element[0]) :
+        this.options.placement
+
+      var autoToken = /\s?auto?\s?/i
+      var autoPlace = autoToken.test(placement)
+      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+      $tip
+        .detach()
+        .css({ top: 0, left: 0, display: 'block' })
+        .addClass(placement)
+
+      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+      var pos          = this.getPosition()
+      var actualWidth  = $tip[0].offsetWidth
+      var actualHeight = $tip[0].offsetHeight
+
+      if (autoPlace) {
+        var $parent = this.$element.parent()
+
+        var orgPlacement = placement
+        var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
+        var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
+        var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+        var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
+
+        placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
+                    placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
+                    placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
+                    placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
+                    placement
+
+        $tip
+          .removeClass(orgPlacement)
+          .addClass(placement)
+      }
+
+      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+      this.applyPlacement(calculatedOffset, placement)
+      this.hoverState = null
+
+      var complete = function() {
+        that.$element.trigger('shown.bs.' + that.type)
+      }
+
+      $.support.transition && this.$tip.hasClass('fade') ?
+        $tip
+          .one($.support.transition.end, complete)
+          .emulateTransitionEnd(150) :
+        complete()
+    }
+  }
+
+  Tooltip.prototype.applyPlacement = function (offset, placement) {
+    var replace
+    var $tip   = this.tip()
+    var width  = $tip[0].offsetWidth
+    var height = $tip[0].offsetHeight
+
+    // manually read margins because getBoundingClientRect includes difference
+    var marginTop = parseInt($tip.css('margin-top'), 10)
+    var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+    // we must check for NaN for ie 8/9
+    if (isNaN(marginTop))  marginTop  = 0
+    if (isNaN(marginLeft)) marginLeft = 0
+
+    offset.top  = offset.top  + marginTop
+    offset.left = offset.left + marginLeft
+
+    // $.fn.offset doesn't round pixel values
+    // so we use setOffset directly with our own function B-0
+    $.offset.setOffset($tip[0], $.extend({
+      using: function (props) {
+        $tip.css({
+          top: Math.round(props.top),
+          left: Math.round(props.left)
+        })
+      }
+    }, offset), 0)
+
+    $tip.addClass('in')
+
+    // check to see if placing tip in new offset caused the tip to resize itself
+    var actualWidth  = $tip[0].offsetWidth
+    var actualHeight = $tip[0].offsetHeight
+
+    if (placement == 'top' && actualHeight != height) {
+      replace = true
+      offset.top = offset.top + height - actualHeight
+    }
+
+    if (/bottom|top/.test(placement)) {
+      var delta = 0
+
+      if (offset.left < 0) {
+        delta       = offset.left * -2
+        offset.left = 0
+
+        $tip.offset(offset)
+
+        actualWidth  = $tip[0].offsetWidth
+        actualHeight = $tip[0].offsetHeight
+      }
+
+      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+    } else {
+      this.replaceArrow(actualHeight - height, actualHeight, 'top')
+    }
+
+    if (replace) $tip.offset(offset)
+  }
+
+  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
+    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
+  }
+
+  Tooltip.prototype.setContent = function () {
+    var $tip  = this.tip()
+    var title = this.getTitle()
+
+    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+    $tip.removeClass('fade in top bottom left right')
+  }
+
+  Tooltip.prototype.hide = function () {
+    var that = this
+    var $tip = this.tip()
+    var e    = $.Event('hide.bs.' + this.type)
+
+    function complete() {
+      if (that.hoverState != 'in') $tip.detach()
+      that.$element.trigger('hidden.bs.' + that.type)
+    }
+
+    this.$element.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    $tip.removeClass('in')
+
+    $.support.transition && this.$tip.hasClass('fade') ?
+      $tip
+        .one($.support.transition.end, complete)
+        .emulateTransitionEnd(150) :
+      complete()
+
+    this.hoverState = null
+
+    return this
+  }
+
+  Tooltip.prototype.fixTitle = function () {
+    var $e = this.$element
+    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+    }
+  }
+
+  Tooltip.prototype.hasContent = function () {
+    return this.getTitle()
+  }
+
+  Tooltip.prototype.getPosition = function () {
+    var el = this.$element[0]
+    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+      width: el.offsetWidth,
+      height: el.offsetHeight
+    }, this.$element.offset())
+  }
+
+  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
+  }
+
+  Tooltip.prototype.getTitle = function () {
+    var title
+    var $e = this.$element
+    var o  = this.options
+
+    title = $e.attr('data-original-title')
+      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
+
+    return title
+  }
+
+  Tooltip.prototype.tip = function () {
+    return this.$tip = this.$tip || $(this.options.template)
+  }
+
+  Tooltip.prototype.arrow = function () {
+    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+  }
+
+  Tooltip.prototype.validate = function () {
+    if (!this.$element[0].parentNode) {
+      this.hide()
+      this.$element = null
+      this.options  = null
+    }
+  }
+
+  Tooltip.prototype.enable = function () {
+    this.enabled = true
+  }
+
+  Tooltip.prototype.disable = function () {
+    this.enabled = false
+  }
+
+  Tooltip.prototype.toggleEnabled = function () {
+    this.enabled = !this.enabled
+  }
+
+  Tooltip.prototype.toggle = function (e) {
+    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+  }
+
+  Tooltip.prototype.destroy = function () {
+    clearTimeout(this.timeout)
+    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+  }
+
+
+  // TOOLTIP PLUGIN DEFINITION
+  // =========================
+
+  var old = $.fn.tooltip
+
+  $.fn.tooltip = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.tooltip')
+      var options = typeof option == 'object' && option
+
+      if (!data && option == 'destroy') return
+      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.tooltip.Constructor = Tooltip
+
+
+  // TOOLTIP NO CONFLICT
+  // ===================
+
+  $.fn.tooltip.noConflict = function () {
+    $.fn.tooltip = old
+    return this
+  }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.1.0
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // POPOVER PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Popover = function (element, options) {
+    this.init('popover', element, options)
+  }
+
+  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+    placement: 'right',
+    trigger: 'click',
+    content: '',
+    template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+  })
+
+
+  // NOTE: POPOVER EXTENDS tooltip.js
+  // ================================
+
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+  Popover.prototype.constructor = Popover
+
+  Popover.prototype.getDefaults = function () {
+    return Popover.DEFAULTS
+  }
+
+  Popover.prototype.setContent = function () {
+    var $tip    = this.tip()
+    var title   = this.getTitle()
+    var content = this.getContent()
+
+    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+    $tip.find('.popover-content')[ // we use append for html objects to maintain js events
+      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+    ](content)
+
+    $tip.removeClass('fade top bottom left right in')
+
+    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+    // this manually by checking the contents.
+    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+  }
+
+  Popover.prototype.hasContent = function () {
+    return this.getTitle() || this.getContent()
+  }
+
+  Popover.prototype.getContent = function () {
+    var $e = this.$element
+    var o  = this.options
+
+    return $e.attr('data-content')
+      || (typeof o.content == 'function' ?
+            o.content.call($e[0]) :
+            o.content)
+  }
+
+  Popover.prototype.arrow = function () {
+    return this.$arrow = this.$arrow || this.tip().find('.arrow')
+  }
+
+  Popover.prototype.tip = function () {
+    if (!this.$tip) this.$tip = $(this.options.template)
+    return this.$tip
+  }
+
+
+  // POPOVER PLUGIN DEFINITION
+  // =========================
+
+  var old = $.fn.popover
+
+  $.fn.popover = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.popover')
+      var options = typeof option == 'object' && option
+
+      if (!data && option == 'destroy') return
+      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.popover.Constructor = Popover
+
+
+  // POPOVER NO CONFLICT
+  // ===================
+
+  $.fn.popover.noConflict = function () {
+    $.fn.popover = old
+    return this
+  }
+
+}(jQuery);
+
+(function($, window) {
+  var Tour, document;
+  document = window.document;
+  Tour = (function() {
+    function Tour(options) {
+      this._options = $.extend({
+        name: "tour",
+        steps: [],
+        container: "body",
+        keyboard: true,
+        storage: window.localStorage,
+        debug: false,
+        backdrop: false,
+        redirect: true,
+        orphan: false,
+        duration: false,
+        basePath: "",
+        template: "<div class='popover'>          <div class='arrow'></div>          <h3 class='popover-title'></h3>          <div class='popover-content'></div>          <div class='popover-navigation'>            <div class='btn-group'>              <button class='btn btn-sm btn-default' data-role='prev'>&laquo; Prev</button>              <button class='btn btn-sm btn-default' data-role='next'>Next &raquo;</button>              <button class='btn btn-sm btn-default' data-role='pause-resume' data-pause-text='Pause' data-resume-text='Resume'>Pause</button>            </div>            <button class='btn btn-sm btn-default' data-role='end'>End tour</button>          </div>        </div>",
+        afterSetState: function(key, value) {},
+        afterGetState: function(key, value) {},
+        afterRemoveState: function(key) {},
+        onStart: function(tour) {},
+        onEnd: function(tour) {},
+        onShow: function(tour) {},
+        onShown: function(tour) {},
+        onHide: function(tour) {},
+        onHidden: function(tour) {},
+        onNext: function(tour) {},
+        onPrev: function(tour) {},
+        onPause: function(tour, duration) {},
+        onResume: function(tour, duration) {}
+      }, options);
+      this._force = false;
+      this._inited = false;
+      this.backdrop = {
+        overlay: null,
+        $element: null,
+        $background: null,
+        backgroundShown: false,
+        overlayElementShown: false
+      };
+      this;
+    }
+
+    Tour.prototype.addSteps = function(steps) {
+      var step, _i, _len;
+      for (_i = 0, _len = steps.length; _i < _len; _i++) {
+        step = steps[_i];
+        this.addStep(step);
+      }
+      return this;
+    };
+
+    Tour.prototype.addStep = function(step) {
+      this._options.steps.push(step);
+      return this;
+    };
+
+    Tour.prototype.getStep = function(i) {
+      if (this._options.steps[i] != null) {
+        return $.extend({
+          id: "step-" + i,
+          path: "",
+          placement: "right",
+          title: "",
+          content: "<p></p>",
+          next: i === this._options.steps.length - 1 ? -1 : i + 1,
+          prev: i - 1,
+          animation: true,
+          container: this._options.container,
+          backdrop: this._options.backdrop,
+          redirect: this._options.redirect,
+          orphan: this._options.orphan,
+          duration: this._options.duration,
+          template: this._options.template,
+          onShow: this._options.onShow,
+          onShown: this._options.onShown,
+          onHide: this._options.onHide,
+          onHidden: this._options.onHidden,
+          onNext: this._options.onNext,
+          onPrev: this._options.onPrev,
+          onPause: this._options.onPause,
+          onResume: this._options.onResume
+        }, this._options.steps[i]);
+      }
+    };
+
+    Tour.prototype.init = function(force) {
+      this._force = force;
+      if (this.ended()) {
+        this._debug("Tour ended, init prevented.");
+        return this;
+      }
+      this.setCurrentStep();
+      this._initMouseNavigation();
+      this._initKeyboardNavigation();
+      this._onResize((function(_this) {
+        return function() {
+        return _this.showStep(_this._current);
+        };
+      })(this));
+      if (this._current !== null) {
+        this.showStep(this._current);
+      }
+      this._inited = true;
+      return this;
+    };
+
+    Tour.prototype.start = function(force) {
+      var promise;
+      if (force == null) {
+        force = false;
+      }
+      if (!this._inited) {
+        this.init(force);
+      }
+      if (this._current === null) {
+        promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
+        this._callOnPromiseDone(promise, this.showStep, 0);
+      }
+      return this;
+    };
+
+    Tour.prototype.next = function() {
+      var promise;
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this._showNextStep);
+    };
+
+    Tour.prototype.prev = function() {
+      var promise;
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this._showPrevStep);
+    };
+
+    Tour.prototype.goTo = function(i) {
+      var promise;
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this.showStep, i);
+    };
+
+    Tour.prototype.end = function() {
+      var endHelper, promise;
+      endHelper = (function(_this) {
+        return function(e) {
+        $(document).off("click.tour-" + _this._options.name);
+        $(document).off("keyup.tour-" + _this._options.name);
+        $(window).off("resize.tour-" + _this._options.name);
+        _this._setState("end", "yes");
+        _this._inited = false;
+        _this._force = false;
+        _this._clearTimer();
+        if (_this._options.onEnd != null) {
+          return _this._options.onEnd(_this);
+        }
+      };
+      })(this);
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, endHelper);
+    };
+
+    Tour.prototype.ended = function() {
+      return !this._force && !!this._getState("end");
+    };
+
+    Tour.prototype.restart = function() {
+      this._removeState("current_step");
+      this._removeState("end");
+      this.setCurrentStep(0);
+      return this.start();
+    };
+
+    Tour.prototype.pause = function() {
+      var step;
+      step = this.getStep(this._current);
+      if (!(step && step.duration)) {
+        return this;
+      }
+      this._paused = true;
+      this._duration -= new Date().getTime() - this._start;
+      window.clearTimeout(this._timer);
+      this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining).");
+      if (step.onPause != null) {
+        return step.onPause(this, this._duration);
+      }
+    };
+
+    Tour.prototype.resume = function() {
+      var step;
+      step = this.getStep(this._current);
+      if (!(step && step.duration)) {
+        return this;
+      }
+      this._paused = false;
+      this._start = new Date().getTime();
+      this._duration = this._duration || step.duration;
+      this._timer = window.setTimeout((function(_this) {
+        return function() {
+        if (_this._isLast()) {
+          return _this.next();
+        } else {
+          return _this.end();
+        }
+        };
+      })(this), this._duration);
+      this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration);
+      if ((step.onResume != null) && this._duration !== step.duration) {
+        return step.onResume(this, this._duration);
+      }
+    };
+
+    Tour.prototype.hideStep = function(i) {
+      var hideStepHelper, promise, step;
+      step = this.getStep(i);
+      if (!step) {
+        return;
+      }
+      this._clearTimer();
+      promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
+      hideStepHelper = (function(_this) {
+        return function(e) {
+        var $element;
+        $element = $(step.element);
+        if (!($element.data("bs.popover") || $element.data("popover"))) {
+          $element = $("body");
+        }
+          $element.popover("destroy").removeClass("tour-" + _this._options.name + "-element tour-" + _this._options.name + "-" + i + "-element");
+        if (step.reflex) {
+          $element.css("cursor", "").off("click.tour-" + _this._options.name);
+        }
+        if (step.backdrop) {
+          _this._hideBackdrop();
+        }
+        if (step.onHidden != null) {
+          return step.onHidden(_this);
+        }
+      };
+      })(this);
+      this._callOnPromiseDone(promise, hideStepHelper);
+      return promise;
+    };
+
+    Tour.prototype.showStep = function(i) {
+      var promise, showStepHelper, skipToPrevious, step;
+      if (this.ended()) {
+        this._debug("Tour ended, showStep prevented.");
+        return this;
+      }
+      step = this.getStep(i);
+      if (!step) {
+        return;
+      }
+      skipToPrevious = i < this._current;
+      promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
+      showStepHelper = (function(_this) {
+        return function(e) {
+        var current_path, path;
+        _this.setCurrentStep(i);
+        path = (function() {
+            switch ({}.toString.call(step.path)) {
+            case "[object Function]":
+              return step.path();
+            case "[object String]":
+              return this._options.basePath + step.path;
+            default:
+              return step.path;
+          }
+        }).call(_this);
+        current_path = document.location.href;
+        if (_this._isRedirect(path, current_path)) {
+          if (toString.call(path) === "[object RegExp]") {
+            _this._redirect(step, path);
+          }
+          else {
+            path = document.location.protocol+'//'+path;
+            _this._redirect(step, path);
+          }
+          return;
+        }
+        if (_this._isOrphan(step)) {
+          if (!step.orphan) {
+            _this._debug("Skip the orphan step " + (_this._current + 1) + ". Orphan option is false and the element doesn't exist or is hidden.");
+            if (skipToPrevious) {
+              _this._showPrevStep();
+            } else {
+              _this._showNextStep();
+            }
+            return;
+          }
+          _this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
+        }
+        if (step.backdrop) {
+          _this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
+        }
+        _this._scrollIntoView(step.element, function() {
+          if ((step.element != null) && step.backdrop) {
+            _this._showOverlayElement(step.element);
+          }
+          _this._showPopover(step, i);
+          if (step.onShown != null) {
+            step.onShown(_this);
+          }
+          return _this._debug("Step " + (_this._current + 1) + " of " + _this._options.steps.length);
+        });
+        if (step.duration) {
+          return _this.resume();
+        }
+      };
+      })(this);
+      this._callOnPromiseDone(promise, showStepHelper);
+      return promise;
+    };
+
+    Tour.prototype.getCurrentStep = function() {
+      return this._current;
+    };
+
+    Tour.prototype.setCurrentStep = function(value) {
+      if (value != null) {
+        this._current = value;
+        this._setState("current_step", value);
+      } else {
+        this._current = this._getState("current_step");
+        this._current = this._current === null ? null : parseInt(this._current, 10);
+      }
+      return this;
+    };
+
+    Tour.prototype._setState = function(key, value) {
+      var e, keyName;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        try {
+          this._options.storage.setItem(keyName, value);
+        } catch (_error) {
+          e = _error;
+          if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
+            this.debug("LocalStorage quota exceeded. State storage failed.");
+          }
+        }
+        return this._options.afterSetState(keyName, value);
+      } else {
+        if (this._state == null) {
+          this._state = {};
+        }
+        return this._state[key] = value;
+      }
+    };
+
+    Tour.prototype._removeState = function(key) {
+      var keyName;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        this._options.storage.removeItem(keyName);
+        return this._options.afterRemoveState(keyName);
+      } else {
+        if (this._state != null) {
+          return delete this._state[key];
+        }
+      }
+    };
+
+    Tour.prototype._getState = function(key) {
+      var keyName, value;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        value = this._options.storage.getItem(keyName);
+      } else {
+        if (this._state != null) {
+          value = this._state[key];
+        }
+      }
+      if (value === void 0 || value === "null") {
+        value = null;
+      }
+      this._options.afterGetState(key, value);
+      return value;
+    };
+
+    Tour.prototype._showNextStep = function() {
+      var promise, showNextStepHelper, step;
+      step = this.getStep(this._current);
+      showNextStepHelper = (function(_this) {
+        return function(e) {
+        return _this.showStep(step.next);
+      };
+      })(this);
+      promise = this._makePromise(step.onNext != null ? step.onNext(this) : void 0);
+      return this._callOnPromiseDone(promise, showNextStepHelper);
+    };
+
+    Tour.prototype._showPrevStep = function() {
+      var promise, showPrevStepHelper, step;
+      step = this.getStep(this._current);
+      showPrevStepHelper = (function(_this) {
+        return function(e) {
+        return _this.showStep(step.prev);
+      };
+      })(this);
+      promise = this._makePromise(step.onPrev != null ? step.onPrev(this) : void 0);
+      return this._callOnPromiseDone(promise, showPrevStepHelper);
+    };
+
+    Tour.prototype._debug = function(text) {
+      if (this._options.debug) {
+        return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
+      }
+    };
+
+    Tour.prototype._isRedirect = function(path, currentPath) {
+      return (path != null) && path !== "" && ((toString.call(path) === "[object RegExp]" && !path.test(currentPath)) || (toString.call(path) === "[object String]" && path !== currentPath.replace("http://", "").replace("https://", "")));
+    };
+
+    Tour.prototype._redirect = function(step, path) {
+      if ($.isFunction(step.redirect)) {
+        return step.redirect.call(this, path);
+      } else if (step.redirect === true) {
+        this._debug("Redirect to " + path);
+        return document.location.href = path;
+      }
+    };
+
+    Tour.prototype._isOrphan = function(step) {
+      return (step.element == null) || !$(step.element).length || $(step.element).is(":hidden") && ($(step.element)[0].namespaceURI !== "http://www.w3.org/2000/svg");
+    };
+
+    Tour.prototype._isLast = function() {
+      return this._current < this._options.steps.length - 1;
+    };
+
+    Tour.prototype._showPopover = function(step, i) {
+      var $element, $navigation, $template, $tip, isOrphan, options;
+      options = $.extend({}, this._options);
+      $template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
+      $navigation = $template.find(".popover-navigation");
+      isOrphan = this._isOrphan(step);
+      if (isOrphan) {
+        step.element = "body";
+        step.placement = "top";
+        $template = $template.addClass("orphan");
+      }
+      $element = $(step.element);
+      $template.addClass("tour-" + this._options.name + " tour-" + this._options.name + "-" + i);
+      $element.addClass("tour-" + this._options.name + "-element tour-" + this._options.name + "-" + i + "-element");
+      if (step.options) {
+        $.extend(options, step.options);
+      }
+      if (step.reflex) {
+        $element.css("cursor", "pointer").on("click.tour-" + this._options.name, (function(_this) {
+          return function() {
+          if (_this._isLast()) {
+            return _this.next();
+          } else {
+            return _this.end();
+          }
+          };
+        })(this));
+      }
+      if (step.prev < 0) {
+        $navigation.find("[data-role='prev']").addClass("disabled");
+      }
+      if (step.next < 0) {
+        $navigation.find("[data-role='next']").addClass("disabled");
+      }
+      if (!step.duration) {
+        $navigation.find("[data-role='pause-resume']").remove();
+      }
+      step.template = $template.clone().wrap("<div>").parent().html();
+      $element.popover({
+        placement: step.placement,
+        trigger: "manual",
+        title: step.title,
+        content: step.content,
+        html: true,
+        animation: step.animation,
+        container: step.container,
+        template: step.template,
+        selector: step.element
+      }).popover("show");
+      $tip = $element.data("bs.popover") ? $element.data("bs.popover").tip() : $element.data("popover").tip();
+      $tip.attr("id", step.id);
+      this._reposition($tip, step);
+      if (isOrphan) {
+        return this._center($tip);
+      }
+    };
+
+    Tour.prototype._reposition = function($tip, step) {
+      var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
+      offsetWidth = $tip[0].offsetWidth;
+      offsetHeight = $tip[0].offsetHeight;
+      tipOffset = $tip.offset();
+      originalLeft = tipOffset.left;
+      originalTop = tipOffset.top;
+      offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
+      if (offsetBottom < 0) {
+        tipOffset.top = tipOffset.top + offsetBottom;
+      }
+      offsetRight = $("html").outerWidth() - tipOffset.left - $tip.outerWidth();
+      if (offsetRight < 0) {
+        tipOffset.left = tipOffset.left + offsetRight;
+      }
+      if (tipOffset.top < 0) {
+        tipOffset.top = 0;
+      }
+      if (tipOffset.left < 0) {
+        tipOffset.left = 0;
+      }
+      $tip.offset(tipOffset);
+      if (step.placement === "bottom" || step.placement === "top") {
+        if (originalLeft !== tipOffset.left) {
+          return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, "left");
+        }
+      } else {
+        if (originalTop !== tipOffset.top) {
+          return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top");
+        }
+      }
+    };
+
+    Tour.prototype._center = function($tip) {
+      return $tip.css("top", $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
+    };
+
+    Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
+      return $tip.find(".arrow").css(position, delta ? 50 * (1 - delta / dimension) + "%" : "");
+    };
+
+    Tour.prototype._scrollIntoView = function(element, callback) {
+      var $element, $window, counter, offsetTop, scrollTop, windowHeight;
+      $element = $(element);
+      if (!$element.length) {
+        return callback();
+      }
+      $window = $(window);
+      offsetTop = $element.offset().top;
+      windowHeight = $window.height();
+      scrollTop = Math.max(0, offsetTop - (windowHeight / 2));
+      this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + ".");
+      counter = 0;
+      return $("body,html").stop(true, true).animate({
+        scrollTop: Math.ceil(scrollTop)
+      }, (function(_this) {
+        return function() {
+        if (++counter === 2) {
+          callback();
+          return _this._debug("Scroll into view. Animation end element offset: " + ($element.offset().top) + ". Window height: " + ($window.height()) + ".");
+        }
+        };
+      })(this));
+    };
+
+    Tour.prototype._onResize = function(callback, timeout) {
+      return $(window).on("resize.tour-" + this._options.name, function() {
+        clearTimeout(timeout);
+        return timeout = setTimeout(callback, 100);
+      });
+    };
+
+    Tour.prototype._initMouseNavigation = function() {
+      var _this;
+      _this = this;
+      return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)", (function(_this) {
+        return function(e) {
+        e.preventDefault();
+        return _this.next();
+        };
+      })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)", (function(_this) {
+        return function(e) {
+        e.preventDefault();
+        return _this.prev();
+        };
+      })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']", (function(_this) {
+        return function(e) {
+        e.preventDefault();
+        return _this.end();
+        };
+      })(this)).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']", function(e) {
+        var $this;
+        e.preventDefault();
+        $this = $(this);
+        $this.text(_this._paused ? $this.data("pause-text") : $this.data("resume-text"));
+        if (_this._paused) {
+          return _this.resume();
+        } else {
+          return _this.pause();
+        }
+      });
+    };
+
+    Tour.prototype._initKeyboardNavigation = function() {
+      if (!this._options.keyboard) {
+        return;
+      }
+      return $(document).on("keyup.tour-" + this._options.name, (function(_this) {
+        return function(e) {
+        if (!e.which) {
+          return;
+        }
+        switch (e.which) {
+          case 39:
+            e.preventDefault();
+            if (_this._isLast()) {
+              return _this.next();
+            } else {
+              return _this.end();
+            }
+            break;
+          case 37:
+            e.preventDefault();
+            if (_this._current > 0) {
+              return _this.prev();
+            }
+            break;
+          case 27:
+            e.preventDefault();
+            return _this.end();
+        }
+        };
+      })(this));
+    };
+
+    Tour.prototype._makePromise = function(result) {
+      if (result && $.isFunction(result.then)) {
+        return result;
+      } else {
+        return null;
+      }
+    };
+
+    Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
+      if (promise) {
+        return promise.then((function(_this) {
+          return function(e) {
+          return cb.call(_this, arg);
+          };
+        })(this));
+      } else {
+        return cb.call(this, arg);
+      }
+    };
+
+    Tour.prototype._showBackdrop = function(element) {
+      if (this.backdrop.backgroundShown) {
+        return;
+      }
+      this.backdrop = $("<div/>", {
+        "class": "tour-backdrop"
+      });
+      this.backdrop.backgroundShown = true;
+      return $("body").append(this.backdrop);
+    };
+
+    Tour.prototype._hideBackdrop = function() {
+      this._hideOverlayElement();
+      return this._hideBackground();
+    };
+
+    Tour.prototype._hideBackground = function() {
+      this.backdrop.remove();
+      this.backdrop.overlay = null;
+      return this.backdrop.backgroundShown = false;
+    };
+
+    Tour.prototype._showOverlayElement = function(element) {
+      var $background, $element, offset;
+      $element = $(element);
+      if (!$element || $element.length === 0 || this.backdrop.overlayElementShown) {
+        return;
+      }
+      this.backdrop.overlayElementShown = true;
+      $background = $("<div/>");
+      offset = $element.offset();
+      offset.top = offset.top;
+      offset.left = offset.left;
+      $background.width($element.innerWidth()).height($element.innerHeight()).addClass("tour-step-background").offset(offset);
+      $element.addClass("tour-step-backdrop");
+      $("body").append($background);
+      this.backdrop.$element = $element;
+      return this.backdrop.$background = $background;
+    };
+
+    Tour.prototype._hideOverlayElement = function() {
+      if (!this.backdrop.overlayElementShown) {
+        return;
+      }
+      this.backdrop.$element.removeClass("tour-step-backdrop");
+      this.backdrop.$background.remove();
+      this.backdrop.$element = null;
+      this.backdrop.$background = null;
+      return this.backdrop.overlayElementShown = false;
+    };
+
+    Tour.prototype._clearTimer = function() {
+      window.clearTimeout(this._timer);
+      this._timer = null;
+      return this._duration = null;
+    };
+
+    return Tour;
+
+  })();
+  return window.Tour = Tour;
+})(jQuery, window);
Index: /extensions/TakeATour/js/custom-bootstrap-tour-standalone.min.js
===================================================================
--- /extensions/TakeATour/js/custom-bootstrap-tour-standalone.min.js	(revision 27995)
+++ /extensions/TakeATour/js/custom-bootstrap-tour-standalone.min.js	(revision 27995)
@@ -0,0 +1,1216 @@
+/* ===========================================================
+# bootstrap-tour - v0.9.0
+# http://bootstraptour.com
+# ==============================================================
+# Copyright 2012-2013 Ulrich Sossou
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+/* ========================================================================
+ * Bootstrap: tooltip.js v3.1.0
+ * http://getbootstrap.com/javascript/#tooltip
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // TOOLTIP PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Tooltip = function (element, options) {
+    this.type       =
+    this.options    =
+    this.enabled    =
+    this.timeout    =
+    this.hoverState =
+    this.$element   = null
+
+    this.init('tooltip', element, options)
+  }
+
+  Tooltip.DEFAULTS = {
+    animation: true,
+    placement: 'top',
+    selector: false,
+    template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
+    trigger: 'hover focus',
+    title: '',
+    delay: 0,
+    html: false,
+    container: false
+  }
+
+  Tooltip.prototype.init = function (type, element, options) {
+    this.enabled  = true
+    this.type     = type
+    this.$element = $(element)
+    this.options  = this.getOptions(options)
+
+    var triggers = this.options.trigger.split(' ')
+
+    for (var i = triggers.length; i--;) {
+      var trigger = triggers[i]
+
+      if (trigger == 'click') {
+        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
+      } else if (trigger != 'manual') {
+        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
+        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
+
+        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
+        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
+      }
+    }
+
+    this.options.selector ?
+      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+      this.fixTitle()
+  }
+
+  Tooltip.prototype.getDefaults = function () {
+    return Tooltip.DEFAULTS
+  }
+
+  Tooltip.prototype.getOptions = function (options) {
+    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
+
+    if (options.delay && typeof options.delay == 'number') {
+      options.delay = {
+        show: options.delay,
+        hide: options.delay
+      }
+    }
+
+    return options
+  }
+
+  Tooltip.prototype.getDelegateOptions = function () {
+    var options  = {}
+    var defaults = this.getDefaults()
+
+    this._options && $.each(this._options, function (key, value) {
+      if (defaults[key] != value) options[key] = value
+    })
+
+    return options
+  }
+
+  Tooltip.prototype.enter = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'in'
+
+    if (!self.options.delay || !self.options.delay.show) return self.show()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'in') self.show()
+    }, self.options.delay.show)
+  }
+
+  Tooltip.prototype.leave = function (obj) {
+    var self = obj instanceof this.constructor ?
+      obj : $(obj.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type)
+
+    clearTimeout(self.timeout)
+
+    self.hoverState = 'out'
+
+    if (!self.options.delay || !self.options.delay.hide) return self.hide()
+
+    self.timeout = setTimeout(function () {
+      if (self.hoverState == 'out') self.hide()
+    }, self.options.delay.hide)
+  }
+
+  Tooltip.prototype.show = function () {
+    var e = $.Event('show.bs.' + this.type)
+
+    if (this.hasContent() && this.enabled) {
+      this.$element.trigger(e)
+
+      if (e.isDefaultPrevented()) return
+      var that = this;
+
+      var $tip = this.tip()
+
+      this.setContent()
+
+      if (this.options.animation) $tip.addClass('fade')
+
+      var placement = typeof this.options.placement == 'function' ?
+        this.options.placement.call(this, $tip[0], this.$element[0]) :
+        this.options.placement
+
+      var autoToken = /\s?auto?\s?/i
+      var autoPlace = autoToken.test(placement)
+      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
+
+      $tip
+        .detach()
+        .css({ top: 0, left: 0, display: 'block' })
+        .addClass(placement)
+
+      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
+
+      var pos          = this.getPosition()
+      var actualWidth  = $tip[0].offsetWidth
+      var actualHeight = $tip[0].offsetHeight
+
+      if (autoPlace) {
+        var $parent = this.$element.parent()
+
+        var orgPlacement = placement
+        var docScroll    = document.documentElement.scrollTop || document.body.scrollTop
+        var parentWidth  = this.options.container == 'body' ? window.innerWidth  : $parent.outerWidth()
+        var parentHeight = this.options.container == 'body' ? window.innerHeight : $parent.outerHeight()
+        var parentLeft   = this.options.container == 'body' ? 0 : $parent.offset().left
+
+        placement = placement == 'bottom' && pos.top   + pos.height  + actualHeight - docScroll > parentHeight  ? 'top'    :
+                    placement == 'top'    && pos.top   - docScroll   - actualHeight < 0                         ? 'bottom' :
+                    placement == 'right'  && pos.right + actualWidth > parentWidth                              ? 'left'   :
+                    placement == 'left'   && pos.left  - actualWidth < parentLeft                               ? 'right'  :
+                    placement
+
+        $tip
+          .removeClass(orgPlacement)
+          .addClass(placement)
+      }
+
+      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
+
+      this.applyPlacement(calculatedOffset, placement)
+      this.hoverState = null
+
+      var complete = function() {
+        that.$element.trigger('shown.bs.' + that.type)
+      }
+
+      $.support.transition && this.$tip.hasClass('fade') ?
+        $tip
+          .one($.support.transition.end, complete)
+          .emulateTransitionEnd(150) :
+        complete()
+    }
+  }
+
+  Tooltip.prototype.applyPlacement = function (offset, placement) {
+    var replace
+    var $tip   = this.tip()
+    var width  = $tip[0].offsetWidth
+    var height = $tip[0].offsetHeight
+
+    // manually read margins because getBoundingClientRect includes difference
+    var marginTop = parseInt($tip.css('margin-top'), 10)
+    var marginLeft = parseInt($tip.css('margin-left'), 10)
+
+    // we must check for NaN for ie 8/9
+    if (isNaN(marginTop))  marginTop  = 0
+    if (isNaN(marginLeft)) marginLeft = 0
+
+    offset.top  = offset.top  + marginTop
+    offset.left = offset.left + marginLeft
+
+    // $.fn.offset doesn't round pixel values
+    // so we use setOffset directly with our own function B-0
+    $.offset.setOffset($tip[0], $.extend({
+      using: function (props) {
+        $tip.css({
+          top: Math.round(props.top),
+          left: Math.round(props.left)
+        })
+      }
+    }, offset), 0)
+
+    $tip.addClass('in')
+
+    // check to see if placing tip in new offset caused the tip to resize itself
+    var actualWidth  = $tip[0].offsetWidth
+    var actualHeight = $tip[0].offsetHeight
+
+    if (placement == 'top' && actualHeight != height) {
+      replace = true
+      offset.top = offset.top + height - actualHeight
+    }
+
+    if (/bottom|top/.test(placement)) {
+      var delta = 0
+
+      if (offset.left < 0) {
+        delta       = offset.left * -2
+        offset.left = 0
+
+        $tip.offset(offset)
+
+        actualWidth  = $tip[0].offsetWidth
+        actualHeight = $tip[0].offsetHeight
+      }
+
+      this.replaceArrow(delta - width + actualWidth, actualWidth, 'left')
+    } else {
+      this.replaceArrow(actualHeight - height, actualHeight, 'top')
+    }
+
+    if (replace) $tip.offset(offset)
+  }
+
+  Tooltip.prototype.replaceArrow = function (delta, dimension, position) {
+    this.arrow().css(position, delta ? (50 * (1 - delta / dimension) + '%') : '')
+  }
+
+  Tooltip.prototype.setContent = function () {
+    var $tip  = this.tip()
+    var title = this.getTitle()
+
+    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
+    $tip.removeClass('fade in top bottom left right')
+  }
+
+  Tooltip.prototype.hide = function () {
+    var that = this
+    var $tip = this.tip()
+    var e    = $.Event('hide.bs.' + this.type)
+
+    function complete() {
+      if (that.hoverState != 'in') $tip.detach()
+      that.$element.trigger('hidden.bs.' + that.type)
+    }
+
+    this.$element.trigger(e)
+
+    if (e.isDefaultPrevented()) return
+
+    $tip.removeClass('in')
+
+    $.support.transition && this.$tip.hasClass('fade') ?
+      $tip
+        .one($.support.transition.end, complete)
+        .emulateTransitionEnd(150) :
+      complete()
+
+    this.hoverState = null
+
+    return this
+  }
+
+  Tooltip.prototype.fixTitle = function () {
+    var $e = this.$element
+    if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
+    }
+  }
+
+  Tooltip.prototype.hasContent = function () {
+    return this.getTitle()
+  }
+
+  Tooltip.prototype.getPosition = function () {
+    var el = this.$element[0]
+    return $.extend({}, (typeof el.getBoundingClientRect == 'function') ? el.getBoundingClientRect() : {
+      width: el.offsetWidth,
+      height: el.offsetHeight
+    }, this.$element.offset())
+  }
+
+  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
+    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2  } :
+           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
+        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width   }
+  }
+
+  Tooltip.prototype.getTitle = function () {
+    var title
+    var $e = this.$element
+    var o  = this.options
+
+    title = $e.attr('data-original-title')
+      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
+
+    return title
+  }
+
+  Tooltip.prototype.tip = function () {
+    return this.$tip = this.$tip || $(this.options.template)
+  }
+
+  Tooltip.prototype.arrow = function () {
+    return this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')
+  }
+
+  Tooltip.prototype.validate = function () {
+    if (!this.$element[0].parentNode) {
+      this.hide()
+      this.$element = null
+      this.options  = null
+    }
+  }
+
+  Tooltip.prototype.enable = function () {
+    this.enabled = true
+  }
+
+  Tooltip.prototype.disable = function () {
+    this.enabled = false
+  }
+
+  Tooltip.prototype.toggleEnabled = function () {
+    this.enabled = !this.enabled
+  }
+
+  Tooltip.prototype.toggle = function (e) {
+    var self = e ? $(e.currentTarget)[this.type](this.getDelegateOptions()).data('bs.' + this.type) : this
+    self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
+  }
+
+  Tooltip.prototype.destroy = function () {
+    clearTimeout(this.timeout)
+    this.hide().$element.off('.' + this.type).removeData('bs.' + this.type)
+  }
+
+
+  // TOOLTIP PLUGIN DEFINITION
+  // =========================
+
+  var old = $.fn.tooltip
+
+  $.fn.tooltip = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.tooltip')
+      var options = typeof option == 'object' && option
+
+      if (!data && option == 'destroy') return
+      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.tooltip.Constructor = Tooltip
+
+
+  // TOOLTIP NO CONFLICT
+  // ===================
+
+  $.fn.tooltip.noConflict = function () {
+    $.fn.tooltip = old
+    return this
+  }
+
+}(jQuery);
+
+/* ========================================================================
+ * Bootstrap: popover.js v3.1.0
+ * http://getbootstrap.com/javascript/#popovers
+ * ========================================================================
+ * Copyright 2011-2014 Twitter, Inc.
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
+ * ======================================================================== */
+
+
++function ($) {
+  'use strict';
+
+  // POPOVER PUBLIC CLASS DEFINITION
+  // ===============================
+
+  var Popover = function (element, options) {
+    this.init('popover', element, options)
+  }
+
+  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
+
+  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
+    placement: 'right',
+    trigger: 'click',
+    content: '',
+    template: '<div class="popover"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
+  })
+
+
+  // NOTE: POPOVER EXTENDS tooltip.js
+  // ================================
+
+  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
+
+  Popover.prototype.constructor = Popover
+
+  Popover.prototype.getDefaults = function () {
+    return Popover.DEFAULTS
+  }
+
+  Popover.prototype.setContent = function () {
+    var $tip    = this.tip()
+    var title   = this.getTitle()
+    var content = this.getContent()
+
+    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
+    $tip.find('.popover-content')[ // we use append for html objects to maintain js events
+      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
+    ](content)
+
+    $tip.removeClass('fade top bottom left right in')
+
+    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
+    // this manually by checking the contents.
+    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
+  }
+
+  Popover.prototype.hasContent = function () {
+    return this.getTitle() || this.getContent()
+  }
+
+  Popover.prototype.getContent = function () {
+    var $e = this.$element
+    var o  = this.options
+
+    return $e.attr('data-content')
+      || (typeof o.content == 'function' ?
+            o.content.call($e[0]) :
+            o.content)
+  }
+
+  Popover.prototype.arrow = function () {
+    return this.$arrow = this.$arrow || this.tip().find('.arrow')
+  }
+
+  Popover.prototype.tip = function () {
+    if (!this.$tip) this.$tip = $(this.options.template)
+    return this.$tip
+  }
+
+
+  // POPOVER PLUGIN DEFINITION
+  // =========================
+
+  var old = $.fn.popover
+
+  $.fn.popover = function (option) {
+    return this.each(function () {
+      var $this   = $(this)
+      var data    = $this.data('bs.popover')
+      var options = typeof option == 'object' && option
+
+      if (!data && option == 'destroy') return
+      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
+      if (typeof option == 'string') data[option]()
+    })
+  }
+
+  $.fn.popover.Constructor = Popover
+
+
+  // POPOVER NO CONFLICT
+  // ===================
+
+  $.fn.popover.noConflict = function () {
+    $.fn.popover = old
+    return this
+  }
+
+}(jQuery);
+
+(function($, window) {
+  var Tour, document;
+  document = window.document;
+  Tour = (function() {
+    function Tour(options) {
+      this._options = $.extend({
+        name: "tour",
+        steps: [],
+        container: "body",
+        keyboard: true,
+        storage: window.localStorage,
+        debug: false,
+        backdrop: false,
+        redirect: true,
+        orphan: false,
+        duration: false,
+        basePath: "",
+        template: "<div class='popover'>          <div class='arrow'></div>          <h3 class='popover-title'></h3>          <div class='popover-content'></div>          <div class='popover-navigation'>            <div class='btn-group'>              <button class='btn btn-sm btn-default' data-role='prev'>&laquo; Prev</button>              <button class='btn btn-sm btn-default' data-role='next'>Next &raquo;</button>              <button class='btn btn-sm btn-default' data-role='pause-resume' data-pause-text='Pause' data-resume-text='Resume'>Pause</button>            </div>            <button class='btn btn-sm btn-default' data-role='end'>End tour</button>          </div>        </div>",
+        afterSetState: function(key, value) {},
+        afterGetState: function(key, value) {},
+        afterRemoveState: function(key) {},
+        onStart: function(tour) {},
+        onEnd: function(tour) {},
+        onShow: function(tour) {},
+        onShown: function(tour) {},
+        onHide: function(tour) {},
+        onHidden: function(tour) {},
+        onNext: function(tour) {},
+        onPrev: function(tour) {},
+        onPause: function(tour, duration) {},
+        onResume: function(tour, duration) {}
+      }, options);
+      this._force = false;
+      this._inited = false;
+      this.backdrop = {
+        overlay: null,
+        $element: null,
+        $background: null,
+        backgroundShown: false,
+        overlayElementShown: false
+      };
+      this;
+    }
+
+    Tour.prototype.addSteps = function(steps) {
+      var step, _i, _len;
+      for (_i = 0, _len = steps.length; _i < _len; _i++) {
+        step = steps[_i];
+        this.addStep(step);
+      }
+      return this;
+    };
+
+    Tour.prototype.addStep = function(step) {
+      this._options.steps.push(step);
+      return this;
+    };
+
+    Tour.prototype.getStep = function(i) {
+      if (this._options.steps[i] != null) {
+        return $.extend({
+          id: "step-" + i,
+          path: "",
+          placement: "right",
+          title: "",
+          content: "<p></p>",
+          next: i === this._options.steps.length - 1 ? -1 : i + 1,
+          prev: i - 1,
+          animation: true,
+          container: this._options.container,
+          backdrop: this._options.backdrop,
+          redirect: this._options.redirect,
+          orphan: this._options.orphan,
+          duration: this._options.duration,
+          template: this._options.template,
+          onShow: this._options.onShow,
+          onShown: this._options.onShown,
+          onHide: this._options.onHide,
+          onHidden: this._options.onHidden,
+          onNext: this._options.onNext,
+          onPrev: this._options.onPrev,
+          onPause: this._options.onPause,
+          onResume: this._options.onResume
+        }, this._options.steps[i]);
+      }
+    };
+
+    Tour.prototype.init = function(force) {
+      var _this = this;
+      this._force = force;
+      if (this.ended()) {
+        this._debug("Tour ended, init prevented.");
+        return this;
+      }
+      this.setCurrentStep();
+      this._initMouseNavigation();
+      this._initKeyboardNavigation();
+      this._onResize(function() {
+        return _this.showStep(_this._current);
+      });
+      if (this._current !== null) {
+        this.showStep(this._current);
+      }
+      this._inited = true;
+      return this;
+    };
+
+    Tour.prototype.start = function(force) {
+      var promise;
+      if (force == null) {
+        force = false;
+      }
+      if (!this._inited) {
+        this.init(force);
+      }
+      if (this._current === null) {
+        promise = this._makePromise(this._options.onStart != null ? this._options.onStart(this) : void 0);
+        this._callOnPromiseDone(promise, this.showStep, 0);
+      }
+      return this;
+    };
+
+    Tour.prototype.next = function() {
+      var promise;
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this._showNextStep);
+    };
+
+    Tour.prototype.prev = function() {
+      var promise;
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this._showPrevStep);
+    };
+
+    Tour.prototype.goTo = function(i) {
+      var promise;
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, this.showStep, i);
+    };
+
+    Tour.prototype.end = function() {
+      var endHelper, promise,
+        _this = this;
+      endHelper = function(e) {
+        $(document).off("click.tour-" + _this._options.name);
+        $(document).off("keyup.tour-" + _this._options.name);
+        $(window).off("resize.tour-" + _this._options.name);
+        _this._setState("end", "yes");
+        _this._inited = false;
+        _this._force = false;
+        _this._clearTimer();
+        if (_this._options.onEnd != null) {
+          return _this._options.onEnd(_this);
+        }
+      };
+      promise = this.hideStep(this._current);
+      return this._callOnPromiseDone(promise, endHelper);
+    };
+
+    Tour.prototype.ended = function() {
+      return !this._force && !!this._getState("end");
+    };
+
+    Tour.prototype.restart = function() {
+      this._removeState("current_step");
+      this._removeState("end");
+      this.setCurrentStep(0);
+      return this.start();
+    };
+
+    Tour.prototype.pause = function() {
+      var step;
+      step = this.getStep(this._current);
+      if (!(step && step.duration)) {
+        return this;
+      }
+      this._paused = true;
+      this._duration -= new Date().getTime() - this._start;
+      window.clearTimeout(this._timer);
+      this._debug("Paused/Stopped step " + (this._current + 1) + " timer (" + this._duration + " remaining).");
+      if (step.onPause != null) {
+        return step.onPause(this, this._duration);
+      }
+    };
+
+    Tour.prototype.resume = function() {
+      var step,
+        _this = this;
+      step = this.getStep(this._current);
+      if (!(step && step.duration)) {
+        return this;
+      }
+      this._paused = false;
+      this._start = new Date().getTime();
+      this._duration = this._duration || step.duration;
+      this._timer = window.setTimeout(function() {
+        if (_this._isLast()) {
+          return _this.next();
+        } else {
+          return _this.end();
+        }
+      }, this._duration);
+      this._debug("Started step " + (this._current + 1) + " timer with duration " + this._duration);
+      if ((step.onResume != null) && this._duration !== step.duration) {
+        return step.onResume(this, this._duration);
+      }
+    };
+
+    Tour.prototype.hideStep = function(i) {
+      var hideStepHelper, promise, step,
+        _this = this;
+      step = this.getStep(i);
+      if (!step) {
+        return;
+      }
+      this._clearTimer();
+      promise = this._makePromise(step.onHide != null ? step.onHide(this, i) : void 0);
+      hideStepHelper = function(e) {
+        var $element;
+        $element = $(step.element);
+        if (!($element.data("bs.popover") || $element.data("popover"))) {
+          $element = $("body");
+        }
+        $element.popover("destroy");
+        if (step.reflex) {
+          $element.css("cursor", "").off("click.tour-" + _this._options.name);
+        }
+        if (step.backdrop) {
+          _this._hideBackdrop();
+        }
+        if (step.onHidden != null) {
+          return step.onHidden(_this);
+        }
+      };
+      this._callOnPromiseDone(promise, hideStepHelper);
+      return promise;
+    };
+
+    Tour.prototype.showStep = function(i) {
+      var promise, showStepHelper, skipToPrevious, step,
+        _this = this;
+      if (this.ended()) {
+        this._debug("Tour ended, showStep prevented.");
+        return this;
+      }
+      step = this.getStep(i);
+      if (!step) {
+        return;
+      }
+      skipToPrevious = i < this._current;
+      promise = this._makePromise(step.onShow != null ? step.onShow(this, i) : void 0);
+      showStepHelper = function(e) {
+        var current_path, path;
+        _this.setCurrentStep(i);
+        path = (function() {
+          switch (toString.call(step.path)) {
+            case "[object Function]":
+              return step.path();
+            case "[object String]":
+              return this._options.basePath + step.path;
+            default:
+              return step.path;
+          }
+        }).call(_this);
+        current_path = [document.location.pathname, document.location.hash].join("?");
+        window.console.log(current_path);
+        console.log(current_path);
+        console.log("FUCK");
+        if (_this._isRedirect(path, current_path)) {
+          //_this._redirect(step, path);
+          console.log(current_path);
+          console.log(path);
+          return;
+        }
+        if (_this._isOrphan(step)) {
+          if (!step.orphan) {
+            _this._debug("Skip the orphan step " + (_this._current + 1) + ". Orphan option is false and the element doesn't exist or is hidden.");
+            if (skipToPrevious) {
+              _this._showPrevStep();
+            } else {
+              _this._showNextStep();
+            }
+            return;
+          }
+          _this._debug("Show the orphan step " + (_this._current + 1) + ". Orphans option is true.");
+        }
+        if (step.backdrop) {
+          _this._showBackdrop(!_this._isOrphan(step) ? step.element : void 0);
+        }
+        _this._scrollIntoView(step.element, function() {
+          if ((step.element != null) && step.backdrop) {
+            _this._showOverlayElement(step.element);
+          }
+          _this._showPopover(step, i);
+          if (step.onShown != null) {
+            step.onShown(_this);
+          }
+          return _this._debug("Step " + (_this._current + 1) + " of " + _this._options.steps.length);
+        });
+        if (step.duration) {
+          return _this.resume();
+        }
+      };
+      this._callOnPromiseDone(promise, showStepHelper);
+      return promise;
+    };
+
+    Tour.prototype.getCurrentStep = function() {
+      return this._current;
+    };
+
+    Tour.prototype.setCurrentStep = function(value) {
+      if (value != null) {
+        this._current = value;
+        this._setState("current_step", value);
+      } else {
+        this._current = this._getState("current_step");
+        this._current = this._current === null ? null : parseInt(this._current, 10);
+      }
+      return this;
+    };
+
+    Tour.prototype._setState = function(key, value) {
+      var e, keyName;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        try {
+          this._options.storage.setItem(keyName, value);
+        } catch (_error) {
+          e = _error;
+          if (e.code === DOMException.QUOTA_EXCEEDED_ERR) {
+            this.debug("LocalStorage quota exceeded. State storage failed.");
+          }
+        }
+        return this._options.afterSetState(keyName, value);
+      } else {
+        if (this._state == null) {
+          this._state = {};
+        }
+        return this._state[key] = value;
+      }
+    };
+
+    Tour.prototype._removeState = function(key) {
+      var keyName;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        this._options.storage.removeItem(keyName);
+        return this._options.afterRemoveState(keyName);
+      } else {
+        if (this._state != null) {
+          return delete this._state[key];
+        }
+      }
+    };
+
+    Tour.prototype._getState = function(key) {
+      var keyName, value;
+      if (this._options.storage) {
+        keyName = "" + this._options.name + "_" + key;
+        value = this._options.storage.getItem(keyName);
+      } else {
+        if (this._state != null) {
+          value = this._state[key];
+        }
+      }
+      if (value === void 0 || value === "null") {
+        value = null;
+      }
+      this._options.afterGetState(key, value);
+      return value;
+    };
+
+    Tour.prototype._showNextStep = function() {
+      var promise, showNextStepHelper, step,
+        _this = this;
+      step = this.getStep(this._current);
+      showNextStepHelper = function(e) {
+        return _this.showStep(step.next);
+      };
+      promise = this._makePromise(step.onNext != null ? step.onNext(this) : void 0);
+      return this._callOnPromiseDone(promise, showNextStepHelper);
+    };
+
+    Tour.prototype._showPrevStep = function() {
+      var promise, showPrevStepHelper, step,
+        _this = this;
+      step = this.getStep(this._current);
+      showPrevStepHelper = function(e) {
+        return _this.showStep(step.prev);
+      };
+      promise = this._makePromise(step.onPrev != null ? step.onPrev(this) : void 0);
+      return this._callOnPromiseDone(promise, showPrevStepHelper);
+    };
+
+    Tour.prototype._debug = function(text) {
+      if (this._options.debug) {
+        return window.console.log("Bootstrap Tour '" + this._options.name + "' | " + text);
+      }
+    };
+
+    Tour.prototype._isRedirect = function(path, currentPath) {
+      console.log(path.replace(/\?.*$/, "").replace(/\/?$/, ""));
+      console.log(currentPath.replace(/\/?$/, ""));
+      return (path != null) && path !== "" && ((toString.call(path) === "[object RegExp]" && !path.test(currentPath)) || (toString.call(path) === "[object String]" && path.replace(/\?.*$/, "").replace(/\/?$/, "") !== currentPath.replace(/\/?$/, "")));
+    };
+
+    Tour.prototype._redirect = function(step, path) {
+      if ($.isFunction(step.redirect)) {
+        return step.redirect.call(this, path);
+      } else if (step.redirect === true) {
+        this._debug("Redirect to " + path);
+        return document.location.href = path;
+      }
+    };
+
+    Tour.prototype._isOrphan = function(step) {
+      return (step.element == null) || !$(step.element).length || $(step.element).is(":hidden") && ($(step.element)[0].namespaceURI !== "http://www.w3.org/2000/svg");
+    };
+
+    Tour.prototype._isLast = function() {
+      return this._current < this._options.steps.length - 1;
+    };
+
+    Tour.prototype._showPopover = function(step, i) {
+      var $element, $navigation, $template, $tip, isOrphan, options,
+        _this = this;
+      options = $.extend({}, this._options);
+      $template = $.isFunction(step.template) ? $(step.template(i, step)) : $(step.template);
+      $navigation = $template.find(".popover-navigation");
+      isOrphan = this._isOrphan(step);
+      if (isOrphan) {
+        step.element = "body";
+        step.placement = "top";
+        $template = $template.addClass("orphan");
+      }
+      $element = $(step.element);
+      $template.addClass("tour-" + this._options.name + " tour-" + this._options.name + "-" + i);
+      if (step.options) {
+        $.extend(options, step.options);
+      }
+      if (step.reflex) {
+        $element.css("cursor", "pointer").on("click.tour-" + this._options.name, function() {
+          if (_this._isLast()) {
+            return _this.next();
+          } else {
+            return _this.end();
+          }
+        });
+      }
+      if (step.prev < 0) {
+        $navigation.find("[data-role='prev']").addClass("disabled");
+      }
+      if (step.next < 0) {
+        $navigation.find("[data-role='next']").addClass("disabled");
+      }
+      if (!step.duration) {
+        $navigation.find("[data-role='pause-resume']").remove();
+      }
+      step.template = $template.clone().wrap("<div>").parent().html();
+      $element.popover({
+        placement: step.placement,
+        trigger: "manual",
+        title: step.title,
+        content: step.content,
+        html: true,
+        animation: step.animation,
+        container: step.container,
+        template: step.template,
+        selector: step.element
+      }).popover("show");
+      $tip = $element.data("bs.popover") ? $element.data("bs.popover").tip() : $element.data("popover").tip();
+      $tip.attr("id", step.id);
+      this._reposition($tip, step);
+      if (isOrphan) {
+        return this._center($tip);
+      }
+    };
+
+    Tour.prototype._reposition = function($tip, step) {
+      var offsetBottom, offsetHeight, offsetRight, offsetWidth, originalLeft, originalTop, tipOffset;
+      offsetWidth = $tip[0].offsetWidth;
+      offsetHeight = $tip[0].offsetHeight;
+      tipOffset = $tip.offset();
+      originalLeft = tipOffset.left;
+      originalTop = tipOffset.top;
+      offsetBottom = $(document).outerHeight() - tipOffset.top - $tip.outerHeight();
+      if (offsetBottom < 0) {
+        tipOffset.top = tipOffset.top + offsetBottom;
+      }
+      offsetRight = $("html").outerWidth() - tipOffset.left - $tip.outerWidth();
+      if (offsetRight < 0) {
+        tipOffset.left = tipOffset.left + offsetRight;
+      }
+      if (tipOffset.top < 0) {
+        tipOffset.top = 0;
+      }
+      if (tipOffset.left < 0) {
+        tipOffset.left = 0;
+      }
+      $tip.offset(tipOffset);
+      if (step.placement === "bottom" || step.placement === "top") {
+        if (originalLeft !== tipOffset.left) {
+          return this._replaceArrow($tip, (tipOffset.left - originalLeft) * 2, offsetWidth, "left");
+        }
+      } else {
+        if (originalTop !== tipOffset.top) {
+          return this._replaceArrow($tip, (tipOffset.top - originalTop) * 2, offsetHeight, "top");
+        }
+      }
+    };
+
+    Tour.prototype._center = function($tip) {
+      return $tip.css("top", $(window).outerHeight() / 2 - $tip.outerHeight() / 2);
+    };
+
+    Tour.prototype._replaceArrow = function($tip, delta, dimension, position) {
+      return $tip.find(".arrow").css(position, delta ? 50 * (1 - delta / dimension) + "%" : "");
+    };
+
+    Tour.prototype._scrollIntoView = function(element, callback) {
+      var $element, $window, counter, offsetTop, scrollTop, windowHeight,
+        _this = this;
+      $element = $(element);
+      if (!$element.length) {
+        return callback();
+      }
+      $window = $(window);
+      offsetTop = $element.offset().top;
+      windowHeight = $window.height();
+      scrollTop = Math.max(0, offsetTop - (windowHeight / 2));
+      this._debug("Scroll into view. ScrollTop: " + scrollTop + ". Element offset: " + offsetTop + ". Window height: " + windowHeight + ".");
+      counter = 0;
+      return $("body,html").stop(true, true).animate({
+        scrollTop: Math.ceil(scrollTop)
+      }, function() {
+        if (++counter === 2) {
+          callback();
+          return _this._debug("Scroll into view. Animation end element offset: " + ($element.offset().top) + ". Window height: " + ($window.height()) + ".");
+        }
+      });
+    };
+
+    Tour.prototype._onResize = function(callback, timeout) {
+      return $(window).on("resize.tour-" + this._options.name, function() {
+        clearTimeout(timeout);
+        return timeout = setTimeout(callback, 100);
+      });
+    };
+
+    Tour.prototype._initMouseNavigation = function() {
+      var _this = this;
+      _this = this;
+      return $(document).off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']").off("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']").on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='next']:not(.disabled)", function(e) {
+        e.preventDefault();
+        return _this.next();
+      }).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='prev']:not(.disabled)", function(e) {
+        e.preventDefault();
+        return _this.prev();
+      }).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='end']", function(e) {
+        e.preventDefault();
+        return _this.end();
+      }).on("click.tour-" + this._options.name, ".popover.tour-" + this._options.name + " *[data-role='pause-resume']", function(e) {
+        var $this;
+        e.preventDefault();
+        $this = $(this);
+        $this.text(_this._paused ? $this.data("pause-text") : $this.data("resume-text"));
+        if (_this._paused) {
+          return _this.resume();
+        } else {
+          return _this.pause();
+        }
+      });
+    };
+
+    Tour.prototype._initKeyboardNavigation = function() {
+      var _this = this;
+      if (!this._options.keyboard) {
+        return;
+      }
+      return $(document).on("keyup.tour-" + this._options.name, function(e) {
+        if (!e.which) {
+          return;
+        }
+        switch (e.which) {
+          case 39:
+            e.preventDefault();
+            if (_this._isLast()) {
+              return _this.next();
+            } else {
+              return _this.end();
+            }
+            break;
+          case 37:
+            e.preventDefault();
+            if (_this._current > 0) {
+              return _this.prev();
+            }
+            break;
+          case 27:
+            e.preventDefault();
+            return _this.end();
+        }
+      });
+    };
+
+    Tour.prototype._makePromise = function(result) {
+      if (result && $.isFunction(result.then)) {
+        return result;
+      } else {
+        return null;
+      }
+    };
+
+    Tour.prototype._callOnPromiseDone = function(promise, cb, arg) {
+      var _this = this;
+      if (promise) {
+        return promise.then(function(e) {
+          return cb.call(_this, arg);
+        });
+      } else {
+        return cb.call(this, arg);
+      }
+    };
+
+    Tour.prototype._showBackdrop = function(element) {
+      if (this.backdrop.backgroundShown) {
+        return;
+      }
+      this.backdrop = $("<div/>", {
+        "class": "tour-backdrop"
+      });
+      this.backdrop.backgroundShown = true;
+      return $("body").append(this.backdrop);
+    };
+
+    Tour.prototype._hideBackdrop = function() {
+      this._hideOverlayElement();
+      return this._hideBackground();
+    };
+
+    Tour.prototype._hideBackground = function() {
+      this.backdrop.remove();
+      this.backdrop.overlay = null;
+      return this.backdrop.backgroundShown = false;
+    };
+
+    Tour.prototype._showOverlayElement = function(element) {
+      var $background, $element, offset;
+      $element = $(element);
+      if (!$element || $element.length === 0 || this.backdrop.overlayElementShown) {
+        return;
+      }
+      this.backdrop.overlayElementShown = true;
+      $background = $("<div/>");
+      offset = $element.offset();
+      offset.top = offset.top;
+      offset.left = offset.left;
+      $background.width($element.innerWidth()).height($element.innerHeight()).addClass("tour-step-background").offset(offset);
+      $element.addClass("tour-step-backdrop");
+      $("body").append($background);
+      this.backdrop.$element = $element;
+      return this.backdrop.$background = $background;
+    };
+
+    Tour.prototype._hideOverlayElement = function() {
+      if (!this.backdrop.overlayElementShown) {
+        return;
+      }
+      this.backdrop.$element.removeClass("tour-step-backdrop");
+      this.backdrop.$background.remove();
+      this.backdrop.$element = null;
+      this.backdrop.$background = null;
+      return this.backdrop.overlayElementShown = false;
+    };
+
+    Tour.prototype._clearTimer = function() {
+      window.clearTimeout(this._timer);
+      this._timer = null;
+      return this._duration = null;
+    };
+
+    return Tour;
+
+  })();
+  return window.Tour = Tour;
+})(jQuery, window);
Index: /extensions/TakeATour/language/en_UK/description.txt
===================================================================
--- /extensions/TakeATour/language/en_UK/description.txt	(revision 27995)
+++ /extensions/TakeATour/language/en_UK/description.txt	(revision 27995)
@@ -0,0 +1,1 @@
+Apprenez à utiliser votre Piwigo, avec ce plugin qui vous prendra par la main à travers ses 'visites' à thèmes
Index: /extensions/TakeATour/language/en_UK/index.php
===================================================================
--- /extensions/TakeATour/language/en_UK/index.php	(revision 27995)
+++ /extensions/TakeATour/language/en_UK/index.php	(revision 27995)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/TakeATour/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/TakeATour/language/en_UK/plugin.lang.php	(revision 27995)
+++ /extensions/TakeATour/language/en_UK/plugin.lang.php	(revision 27995)
@@ -0,0 +1,19 @@
+<?php
+$lang['First Contact'] = 'Premier contact';
+$lang['Launch the Tour'] = 'Commencez la visite';
+$lang[''] = '';
+$lang['Welcome in your Piwigo gallery'] = 'Bienvenue dans votre galerie Piwigo';
+$lang['Step_1 Let\'s start by adding pictures'] = 'Bonjour, à travers ce guide, vous allez comprendre comment utiliser votre galerie et avoir un aperçu des fonctionnalités offertes';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+?>
Index: /extensions/TakeATour/language/fr_FR/description.txt
===================================================================
--- /extensions/TakeATour/language/fr_FR/description.txt	(revision 27995)
+++ /extensions/TakeATour/language/fr_FR/description.txt	(revision 27995)
@@ -0,0 +1,1 @@
+Apprenez à utiliser votre Piwigo, avec ce plugin qui vous prendra par la main à travers ses 'visites' à thèmes
Index: /extensions/TakeATour/language/fr_FR/index.php
===================================================================
--- /extensions/TakeATour/language/fr_FR/index.php	(revision 27995)
+++ /extensions/TakeATour/language/fr_FR/index.php	(revision 27995)
@@ -0,0 +1,33 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | PhpWebGallery - a PHP based picture gallery                           |
+// | Copyright (C) 2002-2003 Pierrick LE GALL - pierrick@phpwebgallery.net |
+// | Copyright (C) 2003-2007 PhpWebGallery Team - http://phpwebgallery.net |
+// +-----------------------------------------------------------------------+
+// | file          : $Id: index.php 1912 2007-03-16 06:30:07Z rub $
+// | last update   : $Date: 2007-03-16 07:30:07 +0100 (ven, 16 mar 2007) $
+// | last modifier : $Author: rub $
+// | revision      : $Revision: 1912 $
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify  |
+// | it under the terms of the GNU General Public License as published by  |
+// | the Free Software Foundation                                          |
+// |                                                                       |
+// | This program is distributed in the hope that it will be useful, but   |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
+// | General Public License for more details.                              |
+// |                                                                       |
+// | You should have received a copy of the GNU General Public License     |
+// | along with this program; if not, write to the Free Software           |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA.                                                                  |
+// +-----------------------------------------------------------------------+
+
+// Recursive call
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/TakeATour/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/TakeATour/language/fr_FR/plugin.lang.php	(revision 27995)
+++ /extensions/TakeATour/language/fr_FR/plugin.lang.php	(revision 27995)
@@ -0,0 +1,19 @@
+<?php
+$lang['First Contact'] = 'Premier contact';
+$lang['Launch the Tour'] = 'Commencez la visite';
+$lang[''] = '';
+$lang['Welcome in your Piwigo gallery'] = 'Bienvenue dans votre galerie Piwigo';
+$lang['Step_1 Let\'s start by adding pictures'] = 'Bonjour, à travers ce guide, vous allez comprendre comment utiliser votre galerie et avoir un aperçu des fonctionnalités offertes';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+$lang[''] = '';
+?>
Index: /extensions/TakeATour/main.inc.php
===================================================================
--- /extensions/TakeATour/main.inc.php	(revision 27995)
+++ /extensions/TakeATour/main.inc.php	(revision 27995)
@@ -0,0 +1,135 @@
+<?php
+/*
+Plugin Name: Take A Tour of Your Piwigo
+Version: 1.0
+Description: Plugin Personnel
+Plugin URI: http://piwigo.org
+Author:Piwigo Team
+Author URI:
+*/
+if (!defined('PHPWG_ROOT_PATH'))
+{
+  die('Hacking attempt!');
+}
+
+$avalaible_tour = array('first_contact', 'privacy', 'picture_protection');
+
+if ( isset($_POST['submited_tour']) and in_array($_POST['submited_tour'], $avalaible_tour) and defined('IN_ADMIN') and IN_ADMIN )
+{
+  pwg_set_session_var('tour_to_launch', $_POST['submited_tour']);
+  global $TAT_restart;
+  $TAT_restart=true;
+}
+elseif ( isset($_GET['tour_ended']) and in_array($_GET['tour_ended'], $avalaible_tour) and defined('IN_ADMIN') and IN_ADMIN )
+{
+  pwg_unset_session_var('tour_to_launch');
+}
+
+if ( pwg_get_session_var('tour_to_launch') and defined('IN_ADMIN') and IN_ADMIN )
+{
+  add_event_handler('init', 'TAT_add_js_css');
+}
+function TAT_add_js_css()
+{
+  global $template, $TAT_restart;
+  $tour_to_launch=pwg_get_session_var('tour_to_launch');
+  load_language('plugin.lang', PHPWG_PLUGINS_PATH .'TakeATour/');
+  $template->set_filename('TAT_js_css', PHPWG_PLUGINS_PATH.'TakeATour/tpl/js_css.tpl');
+  $template->parse('TAT_js_css');//http://piwigo.org/forum/viewtopic.php?id=23248
+  if (isset($TAT_restart) and $TAT_restart)
+  {
+    $TAT_restart=false;
+    $template->assign('TAT_restart',true);
+  }
+  $tat_path=str_replace(basename($_SERVER['SCRIPT_NAME']),'', $_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME']);
+  //$tat_path=$_SERVER['HTTP_HOST'] . $_SERVER['SCRIPT_NAME'];
+  $template->assign('TAT_path', $tat_path);
+  $template->set_filename('TAT_tour_tpl', PHPWG_PLUGINS_PATH.'TakeATour/tpl/'.$tour_to_launch.'.tpl');
+  $template->parse('TAT_tour_tpl');
+  unset($tour_to_launch);
+}
+
+if ( defined('IN_ADMIN') and IN_ADMIN )
+{
+/* first contact */
+add_event_handler('loc_end_element_set_global', 'TAT_FC_14');
+add_event_handler('loc_end_picture_modify', 'TAT_FC_16');
+add_event_handler('loc_end_picture_modify', 'TAT_FC_17');
+add_event_handler('loc_end_cat_modify', 'TAT_FC_23');
+add_event_handler('loc_end_themes_installed', 'TAT_FC_35');
+}
+
+function TAT_FC_14() {
+  global $template;
+  $template->set_prefilter('batch_manager_global', 'TAT_FC_14_prefilter');
+}
+function TAT_FC_14_prefilter ($content, &$smarty) {
+  $search = '<span class="wrap2';
+  $replacement = '{counter print=false assign=TAT_FC_14}<span {if $TAT_FC_14==1}id="TAT_FC_14"{/if} class="wrap2';
+  return str_replace($search, $replacement, $content);
+}
+function TAT_FC_16() {
+  global $template;
+  $template->set_prefilter('picture_modify', 'TAT_FC_16_prefilter');
+}
+function TAT_FC_16_prefilter ($content, &$smarty) {
+  $search = '<strong>{\'Linked albums\'|@translate}</strong>';
+  $replacement = '<span id="TAT_FC_16"><strong>{\'Linked albums\'|@translate}</strong></span>';
+  return str_replace($search, $replacement, $content);
+}
+function TAT_FC_17() {
+  global $template;
+  $template->set_prefilter('picture_modify', 'TAT_FC_17_prefilter');
+}
+function TAT_FC_17_prefilter ($content, &$smarty) {
+  $search = '<strong>{\'Representation of albums\'|@translate}</strong>';
+  $replacement = '<span id="TAT_FC_17"><strong>{\'Representation of albums\'|@translate}</strong></span>';
+  return str_replace($search, $replacement, $content);
+}
+function TAT_FC_23() {
+  global $template;
+  $template->set_prefilter('album_properties', 'TAT_FC_23_prefilter');
+}
+function TAT_FC_23_prefilter ($content, &$smarty) {
+  $search = '<strong>{\'Lock\'|@translate}</strong>';
+  $replacement = '<span id="TAT_FC_23"><strong>{\'Lock\'|@translate}</strong></span>';
+  return str_replace($search, $replacement, $content);
+}
+function TAT_FC_35() {
+  global $template;
+  $template->set_prefilter('themes', 'TAT_FC_35_prefilter');
+}
+function TAT_FC_35_prefilter ($content, &$smarty) {
+  $search = '<a href="{$set_default_baseurl}{$theme.ID}" class="tiptip"';
+  $replacement = '{counter print=false assign=TAT_FC_35}<a href="{$set_default_baseurl}{$theme.ID}" class="tiptip" {if $TAT_FC_35==1}id="TAT_FC_35"{/if}';
+  return str_replace($search, $replacement, $content);
+}
+
+/*
+add_event_handler('init', 'TAT_add_js_css');
+function TAT_add_js_css()
+{
+  $avalaible_tour = array('first_contact', 'privacy', 'picture_protection');
+
+  if ( isset($_POST['submited_tour']) and in_array($_POST['submited_tour'], $avalaible_tour) and defined('IN_ADMIN') and IN_ADMIN )
+  {
+    $tour_to_launch = $_POST['submited_tour'];
+  }
+  global $template;
+  load_language('plugin.lang', PHPWG_PLUGINS_PATH .'TakeATour/');
+  $template->set_filename('TAT_js_css', PHPWG_PLUGINS_PATH.'TakeATour/tpl/js_css.tpl');
+  $template->parse('TAT_js_css');//http://piwigo.org/forum/viewtopic.php?id=23248
+  $template->set_filename('TAT_tour_tpl', PHPWG_PLUGINS_PATH.'TakeATour/tpl/'.$tour_to_launch.'.tpl');
+  $template->parse('TAT_tour_tpl');
+}*/
+add_event_handler('get_admin_plugin_menu_links', 'TAT_admin_menu' );
+function TAT_admin_menu($menu)
+{
+  array_push($menu, array(
+    'NAME' => 'Take a Tour',
+    'URL' => get_root_url().'admin.php?page=plugin-TakeATour'
+    )
+  );
+  return $menu;
+}
+?>
Index: /extensions/TakeATour/tpl/admin.tpl
===================================================================
--- /extensions/TakeATour/tpl/admin.tpl	(revision 27995)
+++ /extensions/TakeATour/tpl/admin.tpl	(revision 27995)
@@ -0,0 +1,13 @@
+<div class="titrePage">
+  <h2>{'iconset_configpage'|@translate}</h2>
+</div>
+<div id="themesContent">
+  <fieldset>
+    <legend>{'First Contact'|@translate}</legend>
+    <form action="{$F_ACTION}" method="post">
+      <input type="hidden" name="submited_tour" value="first_contact">
+      <input type="submit" name="button2" id="button2" value="{'Launch the Tour'|@translate}" style=" width:100%" />
+    </form>
+  </fieldset>
+</div>
+<!-- themesContent --> 
Index: /extensions/TakeATour/tpl/first_contact.tpl
===================================================================
--- /extensions/TakeATour/tpl/first_contact.tpl	(revision 27995)
+++ /extensions/TakeATour/tpl/first_contact.tpl	(revision 27995)
@@ -0,0 +1,325 @@
+{footer_script require='jquery.bootstrap-tour'}{literal}
+// Instance the tour
+var tour = new Tour({
+  name: "first_contact",
+  orphan: true,
+  onEnd: function (tour) {window.location = "admin.php?page=plugin-TakeATour&tour_ended=first_contact";},
+});
+{/literal}{if $TAT_restart}tour.restart();{/if}{literal}
+// Add your steps. Not too many, you don't really want to get your users sleepy
+tour.addSteps([
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php",
+    title: "{/literal}{'Welcome in your Piwigo gallery'|@translate}{literal}",
+    content: "{/literal}{'Let\'s start by adding pictures'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php",
+    placement: "right",
+    element: ".icon-plus-circled",
+    reflex:true,
+    content: "{/literal}{'The link is here. Click Next to continue'|@translate}{literal}",
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=photos_add",
+    placement: "bottom",
+    element: ".selected_tab",
+    title: "{/literal}{'Add Photo Page'|@translate}{literal}",
+    content: "{/literal}{'First tab to add photos from your browser, other tabs to add from a software, mobile or FTP'|@translate}{literal}",
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=photos_add",
+    placement: "left",
+    element: "#albumSelection",
+    title: "{/literal}{'Lets add photo!'|@translate}{literal}",
+    content: "{/literal}{'First choose an album; create one if there is no album yet.'|@translate}{literal}"
+  },
+  {//5
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=photos_add",
+    placement: "top",
+    element: "#uploadify",
+    content: "{/literal}{'Then click the button to select photos to send from your computer'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=photos_add/,
+    redirect:function (tour) {tour.goTo(4);},
+    placement: "left",
+    element: "#fileQueue",
+    title: "{/literal}{''|@translate}{literal}",
+    content: "{/literal}{'You see that photos are being listed. Add at least 2 pictures and when you\'re ready click the button Start Upload'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=photos_add/,
+    redirect:function (tour) {tour.goTo(4);},
+    placement: "top",
+    element: "#photosAddContent legend",
+    content: "{/literal}{'Here a summary of your uploaded pictures. See that Piwigo has generated itself the thumbnails. You can know add more photos with the link at the bottom, edit the properties of a picture by cliking on it, or click to manage all the uploaded pictures in the Batch Manager...'|@translate}{literal}",
+    onPrev:function (tour) {tour.goTo(4);}
+  },
+  {
+    path: /admin\.php\?page=photos_add/,
+    redirect:function (tour) {tour.goTo(4);},
+    placement: "bottom",
+    element: "#batchLink",
+    reflex:true,
+    content: "{/literal}{'Let\'s edit them! Click on the link. If you don\'t see it click Prev to add at least 2 photos.'|@translate}{literal}",
+    onPrev:function (tour) {tour.goTo(4);}
+  },
+  {
+    path: /admin\.php\?page=(photos_add|batch_manager&filter=prefilter-last_import|prefilter-caddie)/,
+    redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+    placement: "top",
+    element: "",
+    title: "{/literal}{'The Batch Manager'|@translate}{literal}",
+    content: "{/literal}{'You are know in the Batch Manager, where you can batch edit multiple pictures. Here the Caddy is set as a filter because we comes from the upload result page.'|@translate}{literal}"
+  },
+  {//10
+    path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+    redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+    placement: "right",
+    element: ".icon-flag",
+    content: "{/literal}{'Here is the link to directly access to your caddy: that/s a tool for administrators to easily add pictures to a set in order to edit them in the Batch Manager. You can add photos to the caddy from the public picture page when logged as an admin, or using the action \"Add to caddy\" on the Batch Manager'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+    redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+    placement: "left",
+    element: "#checkActions",
+    title: "{/literal}{'How to edit a photos'|@translate}{literal}",
+    content: "{/literal}{'So you can select from here one or more photos'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+    redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+    placement: "top",
+    element: "#action",
+    content: "{/literal}{'then edit them using and action. But for instance, you can\'t -for now- batch edit descriptions since they are mostly unique'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+    redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+    placement: "bottom",
+    element: "#tabsheet .normal_tab",
+    content: "{/literal}{'You can edit descriptions and more from the batch manager in unit mode. But for now, let\'s stay in the global mode'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=batch_manager&filter=(prefilter-caddie|prefilter-last_import)/,
+    redirect:function (tour) {window.location = "admin.php?page=batch_manager&filter=prefilter-last_import";},
+    placement: "top",
+    element: "#TAT_FC_14",
+    reflex:true,
+    content: "{/literal}{'We will see now the edition page of one picture. That page is reachable from here but also from the public picture page when logged as an administrator. Click on Edit or go next'|@translate}{literal}",
+    onNext:function (tour) {window.location = "admin.php?page=photo-1";}
+  },
+  {//15
+    path: /admin\.php\?page=photo-/,
+    redirect:function (tour) {window.location = "admin.php?page=photo-1";},
+    placement: "bottom",
+    element: ".selected_tab",
+    title: "{/literal}{'The edition page of a picture'|@translate}{literal}",
+    content: "{/literal}{'On that page you can edit all the properties of a photo, for instance...'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=photo-/,
+    redirect:function (tour) {window.location = "admin.php?page=photo-1";},
+    placement: "top",
+    element: "#TAT_FC_16",
+    content: "{/literal}{'here to add or remove the photo from albums. The link is virtual, no photos will be physcally moved ever.'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=photo-/,
+    redirect:function (tour) {window.location = "admin.php?page=photo-1";},
+    placement: "top",
+    element: "#TAT_FC_17",
+    content: "{/literal}{'and here to set the photo as a picture representative of an album. So you can set as a representative of a public album, a photo in a private album, which is ideal to set custom thumbnails for albums but the user won\'t see those pictures inside those albums. Like setting a portrait of someone as representative, for an album which contains photos of nature; it would be weird to see that photo of the man/woman among trees or animals.'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=photo-/,
+    redirect:function (tour) {window.location = "admin.php?page=photo-1";},
+    placement: "top",
+    title: "{/literal}{'Manage albums'|@translate}{literal}",
+    content: "{/literal}{'That previous example was just a small overview of tricks and how powerfull Piwigo is. So I\'ve told about private albums, but how can we manage albums? Click On album->Manage or hit Next'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=cat_list",
+    placement: "left",
+    element: "#content",
+    title: "{/literal}{'Manage Albums'|@translate}{literal}",
+    content: "{/literal}{'Here are listed all the \'top\' albums, the ones at the root of your gallery. If you see an album with a dashed backgroung, it\'s an real physical album from a FTP synchro, which can\'t be moved or deleted from here. The others albums are called virtual albums.'|@translate}{literal}",
+    onPrev: function (tour) {window.location = "admin.php?page=photo-1";},
+
+  },
+  {//20
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=cat_list",
+    placement: "top",
+    element: "#categoryOrdering",
+    title: "{/literal}{'Manage Albums'|@translate}{literal}",
+    content: "{/literal}{'When your mouse is hover a album, links and information appear. When you drag and drop an album -a rounded block-, you will change its position and then you can save or cancel your manual order.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=cat_list",
+    placement: "left",
+    element: "#tabsheet:first-child",
+    title: "{/literal}{'Other Tabs'|@translate}{literal}",
+    content: "{/literal}{'The next tab is a page where you can move any virtual album.<br>The permalink tab is to set a particular url for an album, for tecnhical reasons like to set a specific template or for just sending cool customized links.<br>But let\'s edit an album: click on Edit of a album'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=album-/,
+    redirect:function (tour) {window.location = "admin.php?page=album-1";},
+    placement: "top",
+    element: ".selected_tab",
+    title: "{/literal}{'Album Edition Page'|@translate}{literal}",
+    content: "{/literal}{'Like for a picture, here you can edit the properties of an album'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=album-/,
+    redirect:function (tour) {window.location = "admin.php?page=album-1";},
+    placement: "top",
+    element: "#TAT_FC_23",
+    content: "{/literal}{'Locking a album means only administrators will be able to see that album: it\'s usually used when an admin is managing the properties of an album or don\'t want to publish the album immediatly'|@translate}{literal}"
+  },
+  {
+    path: /admin\.php\?page=album-/,
+    redirect:function (tour) {window.location = "admin.php?page=album-1";},
+    placement: "bottom",
+    element: ".tabsheet",
+    content: "{/literal}{'Certainly, one of the most important page in the permission page of an album. Click on the permission tab or click next'|@translate}{literal}"
+  },
+  {//25
+    path: /admin\.php\?page=album-[0-9]+-permissions/,
+    redirect:function (tour) {window.location = "admin.php?page=album-1-permissions";},
+    placement: "left",
+    element: "#content",
+    title: "{/literal}{'Album Permission'|@translate}{literal}",
+    content: "{/literal}{'As you can read in the Help of your Piwigo -link at the top right-, album permissions are set by groups and users. You can directly set private/public multiple albums using the Administration » Albums » Properties page.'|@translate}{literal}"
+  },
+  {
+    placement: "top",
+    element: "#selectStatus",
+    content: "{/literal}{'Here you can set the current album as private, then grant access to users and groups. By default, permissions are not recursive for sub albums, but upper-albums will be granted with the same permission in order to let the granted users browse to the album.'|@translate}{literal}"
+  },
+  {
+    placement: "top",
+    element: "#selectStatus",
+    content: "{/literal}{'Important fact: the webmasters and administrators are not omniscient when browsing the public part, but they can access to every album and photos on the admin part.'|@translate}{literal}"
+  },
+  {
+    placement: "top",
+    element: "",
+    title: "{/literal}{'Configuration'|@translate}{literal}",
+    content: "{/literal}{'Now we will look at the options available to set Piwigo working your way. Click on Configuration->Options or just hit Next.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+    placement: "top",
+    element: "",
+    title: "{/literal}{'Configuration->Options->General'|@translate}{literal}",
+    content: "{/literal}{'Here, on that first page, you will set the essential and basic configuration of your gallery.'|@translate}{literal}"
+  },
+  {//30
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+    placement: "right",
+    element: "#gallery_title",
+    content: "{/literal}{'Let\'s start by changing the tittle'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+    placement: "right",
+    element: "#page_banner",
+    content: "{/literal}{'Then the banner, which will be displayed on top of every pages. As you can see, HTML tags are allowed here. You can also use the %gallery_title% tag to display the tittle you just typed above.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+    reflex: true,
+    placement: "top",
+    element: ".formButtons input",
+    content: "{/literal}{'Now save you changes'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=configuration",
+    placement: "top",
+    title: "{/literal}{'Guest settings'|@translate}{literal}",
+    content: "{/literal}{'Just a final word about the options, the \'Guest settings\' page is to set the preferences of unregistered visitors. Each time Piwigo refers to \'guest\' that means unregistered visitors.<br>Let\'s continue about Configuration: click on Configuration->Themes or just hit Next.'|@translate}{literal}",
+    onPrev:function (tour) {tour.goTo(30);}
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=themes",
+    placement: "top",
+    element: "",
+    title: "{/literal}{'Themes'|@translate}{literal}",
+    content: "{/literal}{'Themes are one of the three way to customize your Piwigo, with Plugins and Templates. Themes installed are listed here.<br>More than one theme can be enabled: users can change their theme by choosing one among the one enabled here, if the option \'Allow user customization\' is checked on the Option page.'|@translate}{literal}"
+  },
+  {//35
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=themes",
+    placement: "top",
+    element: "#TAT_FC_35",
+    title: "{/literal}{'Themes'|@translate}{literal}",
+    content: "{/literal}{'Themes can also be set as Default, which means that\'s the theme for unregistred visitors (guests, you remember?) and any new registred user will be have this theme. But for any previously registred users, the theme won\'t change until you do it from the User Management page or you disable their theme: be carefull, you might disturb your users by changing their whole display.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=themes",
+    placement: "top",
+    element: "",
+    title: "{/literal}{'Themes'|@translate}{literal}",
+    content: "{/literal}{'Themes have a system of dependency: that\'s why some theme can\'t be deleted (a parent theme can\'t be deleted if a child theme is enabled) or others can\'t be enabled (a child theme need its parent theme). For instance, when you put you\'re mouse over a Delete link, if the theme can\'t be deleted, a information bubble will explain you why.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=themes",
+    placement: "right",
+    element: ".tabsheet",
+    title: "{/literal}{'Themes'|@translate}{literal}",
+    content: "{/literal}{'To install new themes, you can directly download them from the tab \'Add a theme\'. Only the themes marked as compatible with your version of Piwigo are showed.<br>Let\'s discover the plugins now! Click on Plugin->Manage'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=plugins",
+    placement: "left",
+    element: "",
+    title: "{/literal}{'Plugins'|@translate}{literal}",
+    content: "{/literal}{'Plugins are very easy ways to customize your Piwigo. They can do almost anything you can imagine from small text addition to complete features, like the Community plugin which allows non admistrators users to upload without entering to the administration part.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=plugins",
+    placement: "left",
+    element: "#content",
+    title: "{/literal}{'Plugins'|@translate}{literal}",
+    content: "{/literal}{'On that first page, are listed the installed plugins. At the top, are listed the plugins activated, which are currently running. At the bottom, the plugins which are installed in the /plugins folder, but disabled. Deleting a plugin means that any trace of the plugin will be removed (files, options etc). For most of the plugins, disabling will keep the data registered by the plugins.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=plugins",
+    placement: "bottom",
+    element: "#TakeATour",
+    content: "{/literal}{'Here it\'s me! Don\'t disable me now, but you can see you can Disable or Restore an activated plugin.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=plugins",
+    placement: "right",
+    element: ".tabsheet",
+    content: "{/literal}{'You can see on the last tab all the plugins available for your version of Piwigo. Hundred of plugins are there!'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=languages",
+    title: "{/literal}{'Languages'|@translate}{literal}",
+    content: "{/literal}{'Piwigo is multilingual. By default, the language displayed by Piwigo change according to the language of the browser of the visitor. If the language of the visitor is not availble, the language set by default is used.'|@translate}{literal}"
+  },
+  {
+    path: "{/literal}{$TAT_path}{literal}admin.php?page=plugin-TakeATour",
+    placement: "top",
+    element: "",
+    title: "{/literal}{'It\'s been a great time'|@translate}{literal}",
+    content: "{/literal}{'This tour was quite long, but we only have seen a small part of how powerfull Piwigo is. Everything has a end, this overview is finished.<br>You can discover much deeper the features of Piwigo by taking an other tour or reading our documentation, on the piwigo.org website'|@translate}{literal}"
+  }
+]);
+
+// Initialize the tour
+tour.init();
+
+// Start the tour
+tour.start();
+
+jQuery( "input[class='submit']" ).click(function() {
+  if (tour.getCurrentStep()==5)
+  {
+    tour.goTo(6);
+  }
+});
+{/literal}{/footer_script}
Index: /extensions/TakeATour/tpl/js_css.tpl
===================================================================
--- /extensions/TakeATour/tpl/js_css.tpl	(revision 27995)
+++ /extensions/TakeATour/tpl/js_css.tpl	(revision 27995)
@@ -0,0 +1,6 @@
+{*combine_script id='jquery.bootstrap.tooltip' load='header' require='jquery' path='plugins/TakeATour/js/bootstrap.tooltip.js'}
+{combine_script id='jquery.bootstrap.popover' load='header' require='jquery.bootstrap.tooltip' path='plugins/TakeATour/js/bootstrap.popover.js'}
+{combine_script id='jquery.bootstrap' load='header' require='jquery' path='plugins/TakeATour/js/bootstrap.js'*}
+{combine_script id='jquery.bootstrap-tour' load='header' require='jquery' path='plugins/TakeATour/js/custom-bootstrap-tour-standalone.js'}
+{combine_css path="plugins/TakeATour/css/bootstrap-essential.css"}
+{combine_css path="plugins/TakeATour/css/bootstrap-tour.min.css"}
