docs: function(event, helper) {
  			
  			var self = this,
  				finalResult,
  				// to know where to put the tooltip, we need to know on which point
  				// of the x or y axis we should center it. That coordinate is the target
  				targets = self.__targetFind(helper),
  				testResults = [];
  			
  			// make sure the tooltip is detached while we make tests on a clone
  			self.__instance._$tooltip.detach();
  			
  			// we could actually provide the original element to the Ruler and
  			// not a clone, but it just feels right to keep it out of the
  			// machinery.
  			var $clone = self.__instance._$tooltip.clone(),
  				// start position tests session
  				ruler = $.tooltipster._getRuler($clone),
  				satisfied = false,
  				animation = self.__instance.option('animation');
  			
  			// an animation class could contain properties that distort the size
  			if (animation) {
  				$clone.removeClass('tooltipster-'+ animation);
  			}
  			
  			// start evaluating scenarios
  			$.each(['window', 'document'], function(i, container) {
  				
  				var takeTest = null;
  				
  				// let the user decide to keep on testing or not
  				self.__instance._trigger({
  					container: container,
  					helper: helper,
  					satisfied: satisfied,
  					takeTest: function(bool) {
  						takeTest = bool;
  					},
  					results: testResults,
  					type: 'positionTest'
  				});
  				
  				if (	takeTest == true
  					||	(	takeTest != false
  						&&	satisfied == false
  							// skip the window scenarios if asked. If they are reintegrated by
  							// the callback of the positionTest event, they will have to be
  							// excluded using the callback of positionTested
  						&&	(container != 'window' || self.__options.viewportAware)
  					)
  				) {
  					
  					// for each allowed side
  					for (var i=0; i < self.__options.side.length; i++) {
  						
  						var distance = {
  								horizontal: 0,
  								vertical: 0
  							},
  							side = self.__options.side[i];
  						
  						if (side == 'top' || side == 'bottom') {
  							distance.vertical = self.__options.distance[side];
  						}
  						else {
  							distance.horizontal = self.__options.distance[side];
  						}
  						
  						// this may have an effect on the size of the tooltip if there are css
  						// rules for the arrow or something else
  						self.__sideChange($clone, side);
  						
  						$.each(['natural', 'constrained'], function(i, mode) {
  							
  							takeTest = null;
  							
  							// emit an event on the instance
  							self.__instance._trigger({
  								container: container,
  								event: event,
  								helper: helper,
  								mode: mode,
  								results: testResults,
  								satisfied: satisfied,
  								side: side,
  								takeTest: function(bool) {
  									takeTest = bool;
  								},
  								type: 'positionTest'
  							});
  							
  							if (	takeTest == true
  								||	(	takeTest != false
  									&&	satisfied == false
  								)
  							) {
  								
  								var testResult = {
  									container: container,
  									// we let the distance as an object here, it can make things a little easier
  									// during the user's calculations at positionTest/positionTested
  									distance: distance,
  									// whether the tooltip can fit in the size of the viewport (does not mean
  									// that we'll be able to make it initially entirely visible, see 'whole')
  									fits: null,
  									mode: mode,
  									outerSize: null,
  									side: side,
  									size: null,
  									target: targets[side],
  									// check if the origin has enough surface on screen for the tooltip to
  									// aim at it without overflowing the viewport (this is due to the thickness
  									// of the arrow represented by the minIntersection length).
  									// If not, the tooltip will have to be partly or entirely off screen in
  									// order to stay docked to the origin. This value will stay null when the
  									// container is the document, as it is not relevant
  									whole: null
  								};
  								
  								// get the size of the tooltip with or without size constraints
  								var rulerConfigured = (mode == 'natural') ?
  										ruler.free() :
  										ruler.constrain(
  											helper.geo.available[container][side].width - distance.horizontal,
  											helper.geo.available[container][side].height - distance.vertical
  										),
  									rulerResults = rulerConfigured.measure();
  								
  								testResult.size = rulerResults.size;
  								testResult.outerSize = {
  									height: rulerResults.size.height + distance.vertical,
  									width: rulerResults.size.width + distance.horizontal
  								};
  								
  								if (mode == 'natural') {
  									
  									if(		helper.geo.available[container][side].width >= testResult.outerSize.width
  										&&	helper.geo.available[container][side].height >= testResult.outerSize.height
  									) {
  										testResult.fits = true;
  									}
  									else {
  										testResult.fits = false;
  									}
  								}
  								else {
  									testResult.fits = rulerResults.fits;
  								}
  								
  								if (container == 'window') {
  									
  									if (!testResult.fits) {
  										testResult.whole = false;
  									}
  									else {
  										if (side == 'top' || side == 'bottom') {
  											
  											testResult.whole = (
  													helper.geo.origin.windowOffset.right >= self.__options.minIntersection
  												&&	helper.geo.window.size.width - helper.geo.origin.windowOffset.left >= self.__options.minIntersection
  											);
  										}
  										else {
  											testResult.whole = (
  													helper.geo.origin.windowOffset.bottom >= self.__options.minIntersection
  												&&	helper.geo.window.size.height - helper.geo.origin.windowOffset.top >= self.__options.minIntersection
  											);
  										}
  									}
  								}
  								
  								testResults.push(testResult);
  								
  								// we don't need to compute more positions if we have one fully on screen
  								if (testResult.whole) {
  									satisfied = true;
  								}
  								else {
  									// don't run the constrained test unless the natural width was greater
  									// than the available width, otherwise it's pointless as we know it
  									// wouldn't fit either
  									if (	testResult.mode == 'natural'
  										&&	(	testResult.fits
  											||	testResult.size.width <= helper.geo.available[container][side].width
  										)
  									) {
  										return false;
  									}
  								}
  							}
  						});
  					}
  				}
  			});
  			
  			// the user may eliminate the unwanted scenarios from testResults, but he's
  			// not supposed to alter them at this point. functionPosition and the
  			// position event serve that purpose.
  			self.__instance._trigger({
  				edit: function(r) {
  					testResults = r;
  				},
  				event: event,
  				helper: helper,
  				results: testResults,
  				type: 'positionTested'
  			});
  			
  			/**
  			 * Sort the scenarios to find the favorite one.
  			 * 
  			 * The favorite scenario is when we can fully display the tooltip on screen,
  			 * even if it means that the middle of the tooltip is no longer centered on
  			 * the middle of the origin (when the origin is near the edge of the screen
  			 * or even partly off screen). We want the tooltip on the preferred side,
  			 * even if it means that we have to use a constrained size rather than a
  			 * natural one (as long as it fits). When the origin is off screen at the top
  			 * the tooltip will be positioned at the bottom (if allowed), if the origin
  			 * is off screen on the right, it will be positioned on the left, etc.
  			 * If there are no scenarios where the tooltip can fit on screen, or if the
  			 * user does not want the tooltip to fit on screen (viewportAware == false),
  			 * we fall back to the scenarios relative to the document.
  			 * 
  			 * When the tooltip is bigger than the viewport in either dimension, we stop
  			 * looking at the window scenarios and consider the document scenarios only,
  			 * with the same logic to find on which side it would fit best.
  			 * 
  			 * If the tooltip cannot fit the document on any side, we force it at the
  			 * bottom, so at least the user can scroll to see it.
   			 */
  			testResults.sort(function(a, b) {
  				
  				// best if it's whole (the tooltip fits and adapts to the viewport)
  				if (a.whole && !b.whole) {
  					return -1;
  				}
  				else if (!a.whole && b.whole) {
  					return 1;
  				}
  				else if (a.whole && b.whole) {
  					
  					var ai = self.__options.side.indexOf(a.side),
  						bi = self.__options.side.indexOf(b.side);
  					
  					// use the user's sides fallback array
  					if (ai < bi) {
  						return -1;
  					}
  					else if (ai > bi) {
  						return 1;
  					}
  					else {
  						// will be used if the user forced the tests to continue
  						return a.mode == 'natural' ? -1 : 1;
  					}
  				}
  				else {
  					
  					// better if it fits
  					if (a.fits && !b.fits) {
  						return -1;
  					}
  					else if (!a.fits && b.fits) {
  						return 1;
  					}
  					else if (a.fits && b.fits) {
  						
  						var ai = self.__options.side.indexOf(a.side),
  							bi = self.__options.side.indexOf(b.side);
  						
  						// use the user's sides fallback array
  						if (ai < bi) {
  							return -1;
  						}
  						else if (ai > bi) {
  							return 1;
  						}
  						else {
  							// will be used if the user forced the tests to continue
  							return a.mode == 'natural' ? -1 : 1;
  						}
  					}
  					else {
  						
  						// if everything failed, this will give a preference to the case where
  						// the tooltip overflows the document at the bottom
  						if (	a.container == 'document'
  							&&	a.side == 'bottom'
  							&&	a.mode == 'natural'
  						) {
  							return -1;
  						}
  						else {
  							return 1;
  						}
  					}
  				}
  			});
  			
  			finalResult = testResults[0];
  			
  			
  			// now let's find the coordinates of the tooltip relatively to the window
  			finalResult.coord = {};
  			
  			switch (finalResult.side) {
  				
  				case 'left':
  				case 'right':
  					finalResult.coord.top = Math.floor(finalResult.target - finalResult.size.height / 2);
  					break;
  				
  				case 'bottom':
  				case 'top':
  					finalResult.coord.left = Math.floor(finalResult.target - finalResult.size.width / 2);
  					break;
  			}
  			
  			switch (finalResult.side) {
  				
  				case 'left':
  					finalResult.coord.left = helper.geo.origin.windowOffset.left - finalResult.outerSize.width;
  					break;
  				
  				case 'right':
  					finalResult.coord.left = helper.geo.origin.windowOffset.right + finalResult.distance.horizontal;
  					break;
  				
  				case 'top':
  					finalResult.coord.top = helper.geo.origin.windowOffset.top - finalResult.outerSize.height;
  					break;
  				
  				case 'bottom':
  					finalResult.coord.top = helper.geo.origin.windowOffset.bottom + finalResult.distance.vertical;
  					break;
  			}
  			
  			// if the tooltip can potentially be contained within the viewport dimensions
  			// and that we are asked to make it fit on screen
  			if (finalResult.container == 'window') {
  				
  				// if the tooltip overflows the viewport, we'll move it accordingly (then it will
  				// not be centered on the middle of the origin anymore). We only move horizontally
  				// for top and bottom tooltips and vice versa.
  				if (finalResult.side == 'top' || finalResult.side == 'bottom') {
  					
  					// if there is an overflow on the left
  					if (finalResult.coord.left < 0) {
  						
  						// prevent the overflow unless the origin itself gets off screen (minus the
  						// margin needed to keep the arrow pointing at the target)
  						if (helper.geo.origin.windowOffset.right - this.__options.minIntersection >= 0) {
  							finalResult.coord.left = 0;
  						}
  						else {
  							finalResult.coord.left = helper.geo.origin.windowOffset.right - this.__options.minIntersection - 1;
  						}
  					}
  					// or an overflow on the right
  					else if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {
  						
  						if (helper.geo.origin.windowOffset.left + this.__options.minIntersection <= helper.geo.window.size.width) {
  							finalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;
  						}
  						else {
  							finalResult.coord.left = helper.geo.origin.windowOffset.left + this.__options.minIntersection + 1 - finalResult.size.width;
  						}
  					}
  				}
  				else {
  					
  					// overflow at the top
  					if (finalResult.coord.top < 0) {
  						
  						if (helper.geo.origin.windowOffset.bottom - this.__options.minIntersection >= 0) {
  							finalResult.coord.top = 0;
  						}
  						else {
  							finalResult.coord.top = helper.geo.origin.windowOffset.bottom - this.__options.minIntersection - 1;
  						}
  					}
  					// or at the bottom
  					else if (finalResult.coord.top > helper.geo.window.size.height - finalResult.size.height) {
  						
  						if (helper.geo.origin.windowOffset.top + this.__options.minIntersection <= helper.geo.window.size.height) {
  							finalResult.coord.top = helper.geo.window.size.height - finalResult.size.height;
  						}
  						else {
  							finalResult.coord.top = helper.geo.origin.windowOffset.top + this.__options.minIntersection + 1 - finalResult.size.height;
  						}
  					}
  				}
  			}
  			else {
  				
  				// there might be overflow here too but it's easier to handle. If there has
  				// to be an overflow, we'll make sure it's on the right side of the screen
  				// (because the browser will extend the document size if there is an overflow
  				// on the right, but not on the left). The sort function above has already
  				// made sure that a bottom document overflow is preferred to a top overflow,
  				// so we don't have to care about it.
  				
  				// if there is an overflow on the right
  				if (finalResult.coord.left > helper.geo.window.size.width - finalResult.size.width) {
  					
  					// this may actually create on overflow on the left but we'll fix it in a sec
  					finalResult.coord.left = helper.geo.window.size.width - finalResult.size.width;
  				}
  				
  				// if there is an overflow on the left
  				if (finalResult.coord.left < 0) {
  					
  					// don't care if it overflows the right after that, we made our best
  					finalResult.coord.left = 0;
  				}
  			}
  			
  			
  			// submit the positioning proposal to the user function which may choose to change
  			// the side, size and/or the coordinates
  			
  			// first, set the rules that corresponds to the proposed side: it may change
  			// the size of the tooltip, and the custom functionPosition may want to detect the
  			// size of something before making a decision. So let's make things easier for the
  			// implementor
  			self.__sideChange($clone, finalResult.side);
  			
  			// add some variables to the helper
  			helper.tooltipClone = $clone[0];
  			helper.tooltipParent = self.__instance.option('parent').parent[0];
  			// move informative values to the helper
  			helper.mode = finalResult.mode;
  			helper.whole = finalResult.whole;
  			// add some variables to the helper for the functionPosition callback (these
  			// will also be added to the event fired by self.__instance._trigger but that's
  			// ok, we're just being consistent)
  			helper.origin = self.__instance._$origin[0];
  			helper.tooltip = self.__instance._$tooltip[0];
  			
  			// leave only the actionable values in there for functionPosition
  			delete finalResult.container;
  			delete finalResult.fits;
  			delete finalResult.mode;
  			delete finalResult.outerSize;
  			delete finalResult.whole;
  			
  			// keep only the distance on the relevant side, for clarity
  			finalResult.distance = finalResult.distance.horizontal || finalResult.distance.vertical;
  			
  			// beginners may not be comfortable with the concept of editing the object
  			//  passed by reference, so we provide an edit function and pass a clone
  			var finalResultClone = $.extend(true, {}, finalResult);
  			
  			// emit an event on the instance
  			self.__instance._trigger({
  				edit: function(result) {
  					finalResult = result;
  				},
  				event: event,
  				helper: helper,
  				position: finalResultClone,
  				type: 'position'
  			});
  			
  			if (self.__options.functionPosition) {
  				
  				var result = self.__options.functionPosition.call(self, self.__instance, helper, finalResultClone);
  				
  				if (result) finalResult = result;
  			}
  			
  			// end the positioning tests session (the user might have had a
  			// use for it during the position event, now it's over)
  			ruler.destroy();
  			
  			// compute the position of the target relatively to the tooltip root
  			// element so we can place the arrow and make the needed adjustments
  			var arrowCoord,
  				maxVal;
  			
  			if (finalResult.side == 'top' || finalResult.side == 'bottom') {
  				
  				arrowCoord = {
  					prop: 'left',
  					val: finalResult.target - finalResult.coord.left
  				};
  				maxVal = finalResult.size.width - this.__options.minIntersection;
  			}
  			else {
  				
  				arrowCoord = {
  					prop: 'top',
  					val: finalResult.target - finalResult.coord.top
  				};
  				maxVal = finalResult.size.height - this.__options.minIntersection;
  			}
  			
  			// cannot lie beyond the boundaries of the tooltip, minus the
  			// arrow margin
  			if (arrowCoord.val < this.__options.minIntersection) {
  				arrowCoord.val = this.__options.minIntersection;
  			}
  			else if (arrowCoord.val > maxVal) {
  				arrowCoord.val = maxVal;
  			}
  			
  			var originParentOffset;
  			
  			// let's convert the window-relative coordinates into coordinates relative to the
  			// future positioned parent that the tooltip will be appended to
  			if (helper.geo.origin.fixedLineage) {
  				
  				// same as windowOffset when the position is fixed
  				originParentOffset = helper.geo.origin.windowOffset;
  			}
  			else {
  				
  				// this assumes that the parent of the tooltip is located at
  				// (0, 0) in the document, typically like when the parent is
  				// <body>.
  				// If we ever allow other types of parent, .tooltipster-ruler
  				// will have to be appended to the parent to inherit css style
  				// values that affect the display of the text and such.
  				originParentOffset = {
  					left: helper.geo.origin.windowOffset.left + helper.geo.window.scroll.left,
  					top: helper.geo.origin.windowOffset.top + helper.geo.window.scroll.top
  				};
  			}
  			
  			finalResult.coord = {
  				left: originParentOffset.left + (finalResult.coord.left - helper.geo.origin.windowOffset.left),
  				top: originParentOffset.top + (finalResult.coord.top - helper.geo.origin.windowOffset.top)
  			};
  			
  			// set position values on the original tooltip element
  			
  			self.__sideChange(self.__instance._$tooltip, finalResult.side);
  			
  			if (helper.geo.origin.fixedLineage) {
  				self.__instance._$tooltip
  					.css('position', 'fixed');
  			}
  			else {
  				// CSS default
  				self.__instance._$tooltip
  					.css('position', '');
  			}
  			
  			self.__instance._$tooltip
  				.css({
  					left: finalResult.coord.left,
  					top: finalResult.coord.top,
  					// we need to set a size even if the tooltip is in its natural size
  					// because when the tooltip is positioned beyond the width of the body
  					// (which is by default the width of the window; it will happen when
  					// you scroll the window horizontally to get to the origin), its text
  					// content will otherwise break lines at each word to keep up with the
  					// body overflow strategy.
  					height: finalResult.size.height,
  					width: finalResult.size.width
  				})
  				.find('.tooltipster-arrow')
  					.css({
  						'left': '',
  						'top': ''
  					})
  					.css(arrowCoord.prop, arrowCoord.val);
  			
  			// append the tooltip HTML element to its parent
  			self.__instance._$tooltip.appendTo(self.__instance.option('parent'));
  			
  			self.__instance._trigger({
  				type: 'repositioned',
  				event: event,
  				position: finalResult
  			});
  		}