Calculates the position of the fisrt/last step (with fix for Safari in RTL mode) to make the position and scroll calculations running (see comment on getRTLFactor for RTL behavior)
495031
function(oRoadMap, bLast){
		var iScrollWidth = oRoadMap.$("steparea").get(0).scrollWidth;
		if (sap.ui.getCore().getConfiguration().getRTL() && Device.browser.webkit) {
			return bLast ? 0 : ( -1) * iScrollWidth;
		}
		return bLast ? iScrollWidth : 0;
	}
1205052
function iterate( rtl, breakOnFalse ) {
		var range = this.range;

		// Return null if we have reached the end.
		if ( this._.end )
			return null;

		// This is the first call. Initialize it.
		if ( !this._.start ) {
			this._.start = 1;

			// A collapsed range must return null at first call.
			if ( range.collapsed ) {
				this.end();
				return null;
			}

			// Move outside of text node edges.
			range.optimize();
		}

		var node,
			startCt = range.startContainer,
			endCt = range.endContainer,
			startOffset = range.startOffset,
			endOffset = range.endOffset,
			guard,
			userGuard = this.guard,
			type = this.type,
			getSourceNodeFn = ( rtl ? 'getPreviousSourceNode' : 'getNextSourceNode' );

		// Create the LTR guard function, if necessary.
		if ( !rtl && !this._.guardLTR ) {
			// The node that stops walker from moving up.
			var limitLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt : endCt.getParent();

			// The node that stops the walker from going to next.
			var blockerLTR = endCt.type == CKEDITOR.NODE_ELEMENT ? endCt.getChild( endOffset ) : endCt.getNext();

			this._.guardLTR = function( node, movingOut ) {
				return ( ( !movingOut || !limitLTR.equals( node ) ) && ( !blockerLTR || !node.equals( blockerLTR ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) );
			};
		}

		// Create the RTL guard function, if necessary.
		if ( rtl && !this._.guardRTL ) {
			// The node that stops walker from moving up.
			var limitRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startCt : startCt.getParent();

			// The node that stops the walker from going to next.
			var blockerRTL = startCt.type == CKEDITOR.NODE_ELEMENT ? startOffset ? startCt.getChild( startOffset - 1 ) : null : startCt.getPrevious();

			this._.guardRTL = function( node, movingOut ) {
				return ( ( !movingOut || !limitRTL.equals( node ) ) && ( !blockerRTL || !node.equals( blockerRTL ) ) && ( node.type != CKEDITOR.NODE_ELEMENT || !movingOut || !node.equals( range.root ) ) );
			};
		}

		// Define which guard function to use.
		var stopGuard = rtl ? this._.guardRTL : this._.guardLTR;

		// Make the user defined guard function participate in the process,
		// otherwise simply use the boundary guard.
		if ( userGuard ) {
			guard = function( node, movingOut ) {
				if ( stopGuard( node, movingOut ) === false )
					return false;

				return userGuard( node, movingOut );
			};
		} else {
			guard = stopGuard;
		}

		if ( this.current )
			node = this.current[ getSourceNodeFn ]( false, type, guard );
		else {
			// Get the first node to be returned.
			if ( rtl ) {
				node = endCt;

				if ( node.type == CKEDITOR.NODE_ELEMENT ) {
					if ( endOffset > 0 )
						node = node.getChild( endOffset - 1 );
					else
						node = ( guard( node, true ) === false ) ? null : node.getPreviousSourceNode( true, type, guard );
				}
			} else {
				node = startCt;

				if ( node.type == CKEDITOR.NODE_ELEMENT ) {
					if ( !( node = node.getChild( startOffset ) ) )
						node = ( guard( startCt, true ) === false ) ? null : startCt.getNextSourceNode( true, type, guard );
				}
			}

			if ( node && guard( node ) === false )
				node = null;
		}

		while ( node && !this._.end ) {
			this.current = node;

			if ( !this.evaluator || this.evaluator( node ) !== false ) {
				if ( !breakOnFalse )
					return node;
			} else if ( breakOnFalse && this.evaluator ) {
				return false;
			}

			node = node[ getSourceNodeFn ]( false, type, guard );
		}

		this.end();
		return this.current = null;
	}
629566
def calculate_positions(positions):
    """"""
    current_position = {'data-x': 0,
                        'data-y': 0,
                        'data-z': 0,
                        'data-rotate-x': 0,
                        'data-rotate-y': 0,
                        'data-rotate-z': 0,
                        'data-scale': 1,
                        }

    positer = iter(positions)
    position = next(positer)
    _update_position(current_position, position)

    while True:

        if 'path' in position:
            # Start of a new path!
            path = position['path']
            # Follow the path specification
            first_point = _pos_to_cord(current_position)

            # Paths that end in Z or z are closed.
            closed_path = path.strip()[-1].upper() == 'Z'
            path = parse_path(path)

            # Find out how many positions should be calculated:
            count = 1
            last = False
            deferred_positions = []
            while True:
                try:
                    position = next(positer)
                    deferred_positions.append(position)
                except StopIteration:
                    last = True  # This path goes to the end
                    break
                if not position.get('is_path') or 'path' in position:
                    # The end of the path, or the start of a new one
                    break
                count += 1

            if count < 2:
                raise AssertionError("The path specification is only used for "
                                     "one slide, which makes it pointless.")

            if closed_path:
                # This path closes in on itself. Skip the last part, so that
                # the first and last step doesn't overlap.
                endcount = count + 1
            else:
                endcount = count

            multiplier = (endcount * DEFAULT_MOVEMENT) / path.length()
            offset = path.point(0)

            path_iter = iter(deferred_positions)
            for x in range(count):

                point = path.point(x / (endcount - 1))
                point = ((point - offset) * multiplier) + first_point

                current_position.update(_coord_to_pos(point))

                rotation = _path_angle(path, x / (endcount - 1))
                current_position['data-rotate-z'] = rotation
                yield current_position.copy()
                try:
                    position = next(path_iter)
                except StopIteration:
                    last = True
                    break
                _update_position(current_position, position)

            if last:
                break

            continue

        yield current_position.copy()
        try:
            position = next(positer)
        except StopIteration:
            break
        _update_position(current_position, position)
1048949
def from_top_left(from_window=nil, f=nil)
      if from_window.is_a?(Hash)
        f = from_window
        from_window = nil
      end
      f ||= {}
      from_window ||= target.screen || NSScreen.mainScreen
      _calculate_frame(f, from: from_window, relative_to: { x: :min, y: :max })
    end
549074
function step ({tick}) {
  setFBO({ framebuffer: FIELDS[0] }, () => {
    regl.clear({ color: [0, 0, 0, 1] })
    splatMouse()
    splatVerts({
      vertexState: VERTEX_STATE[(tick + 1) % 2]
    })
  })
  for (let i = 0; i < 2 * BLUR_PASSES; ++i) {
    blurPass({
      dest: FIELDS[(i + 1) % 2],
      src: FIELDS[i % 2],
      axis: (i % 2)
    })
  }
  gradPass({
    dest: FIELDS[1],
    src: FIELDS[0]
  })
  applySpringForces({
    dest: VERTEX_STATE[(tick + 1) % 2],
    src: VERTEX_STATE[tick % 2]
  })
  integrateVerts({
    dest: VERTEX_STATE[tick % 2],
    src: VERTEX_STATE[(tick + 1) % 2],
    field: FIELDS[1]
  })
}
263698
function (position, callback) {
      var pixelOffset = this._calcOffsetFromPosition(position);
      var closestIndex = this._getClosestIndex(pixelOffset);
      var nextValue = this._trimAlignValue(this._calcValue(pixelOffset));

      var value = this.state.value.slice(); // Clone this.state.value since we'll modify it temporarily
      value[closestIndex] = nextValue;

      // Prevents the slider from shrinking below `props.minDistance`
      for (var i = 0; i < value.length - 1; i += 1) {
        if (value[i + 1] - value[i] < this.props.minDistance) return;
      }

      this.setState({value: value}, callback.bind(this, closestIndex));
    }
220582
function (renderer, layer, rect) {
            var tile;

            // get top-left and bottom-right tile position
            var startTile = this.pixelToTileCoords(
                rect.pos.x,
                rect.pos.y,
                me.pool.pull("me.Vector2d")
            );

            // Compensate for the layer position
            startTile.sub(layer.pos);

            // get top-left and bottom-right tile position
            var startPos = this.tileToPixelCoords(
                startTile.x + layer.pos.x,
                startTile.y + layer.pos.y,
                me.pool.pull("me.Vector2d")
            );

            var rowTile = startTile.clone();
            var rowPos = startPos.clone();

           /* Determine in which half of the tile the top-left corner of the area we
            * need to draw is. If we're in the upper half, we need to start one row
            * up due to those tiles being visible as well. How we go up one row
            * depends on whether we're in the left or right half of the tile.
            */
            var inUpperHalf = rect.pos.y - startPos.y < this.sideoffsety;
            var inLeftHalf = rect.pos.x - startPos.x < this.sideoffsetx;

            if (inUpperHalf) {
                startTile.y--;
            }
            if (inLeftHalf) {
                startTile.x--;
            }

            var endX = layer.cols;
            var endY = layer.rows;

            if (this.staggerX) {
                //ensure we are in the valid tile range
                startTile.x = Math.max(0, startTile.x);
                startTile.y = Math.max(0, startTile.y);

                startPos = this.tileToPixelCoords(
                    startTile.x + layer.pos.x,
                    startTile.y + layer.pos.y
                );

                var staggeredRow = this.doStaggerX(startTile.x + layer.pos.x);

                // main drawing loop
                for (; startPos.y < rect.bottom && startTile.y < endY; ) {
                    rowTile.setV(startTile);
                    rowPos.setV(startPos);

                    for (; rowPos.x < rect.right && rowTile.x < endX; rowTile.x+=2) {
                        tile = layer.layerData[rowTile.x][rowTile.y];
                        if (tile) {
                            // draw the tile
                            tile.tileset.drawTile(renderer, rowPos.x, rowPos.y, tile);
                        }
                        rowPos.x += this.tilewidth + this.sidelengthx;
                    }

                    if (staggeredRow) {
                        startTile.x -= 1;
                        startTile.y += 1;
                        startPos.x -= this.columnwidth;
                        staggeredRow = false;
                    } else {
                        startTile.x += 1;
                        startPos.x += this.columnwidth;
                        staggeredRow = true;
                    }

                    startPos.y += this.rowheight;
                }
                me.pool.push(rowTile);
                me.pool.push(rowPos);

            } else {
                //ensure we are in the valid tile range
                startTile.x = Math.max(0, startTile.x);
                startTile.y = Math.max(0, startTile.y);

                startPos = this.tileToPixelCoords(
                    startTile.x + layer.pos.x,
                    startTile.y + layer.pos.y
                );

                // Odd row shifting is applied in the rendering loop, so un-apply it here
                if (this.doStaggerY(startTile.y)) {
                    startPos.x -= this.columnwidth;
                }

                // main drawing loop
                for (; startPos.y < rect.bottom && startTile.y < endY; startTile.y++) {
                    rowTile.setV(startTile);
                    rowPos.setV(startPos);

                    if (this.doStaggerY(startTile.y)) {
                        rowPos.x += this.columnwidth;
                    }

                    for (; rowPos.x < rect.right && rowTile.x < endX; rowTile.x++) {
                        tile = layer.layerData[rowTile.x][rowTile.y];
                        if (tile) {
                            // draw the tile
                            tile.tileset.drawTile(renderer, rowPos.x, rowPos.y, tile);
                        }
                        rowPos.x += this.tilewidth + this.sidelengthx;
                    }
                    startPos.y += this.rowheight;
                }
                me.pool.push(rowTile);
                me.pool.push(rowPos);
            }

            me.pool.push(startTile);
            me.pool.push(startPos);
        }
199909
function(e) {
      if (this.isVirtual) {
        var itemHeight = this.itemHeight;

        // TODO: This would be inaccurate if we are windowed
        var totalItems = this.listEl.children.length;

        // Grab the total height of the list
        var scrollHeight = e.target.scrollHeight;

        // Get the viewport height
        var viewportHeight = this.el.parentNode.offsetHeight;

        // scrollTop is the current scroll position
        var scrollTop = e.scrollTop;

        // High water is the pixel position of the first element to include (everything before
        // that will be removed)
        var highWater = Math.max(0, e.scrollTop + this.virtualRemoveThreshold);

        // Low water is the pixel position of the last element to include (everything after
        // that will be removed)
        var lowWater = Math.min(scrollHeight, Math.abs(e.scrollTop) + viewportHeight + this.virtualAddThreshold);

        // Compute how many items per viewport size can show
        var itemsPerViewport = Math.floor((lowWater - highWater) / itemHeight);

        // Get the first and last elements in the list based on how many can fit
        // between the pixel range of lowWater and highWater
        var first = parseInt(Math.abs(highWater / itemHeight), 10);
        var last = parseInt(Math.abs(lowWater / itemHeight), 10);

        // Get the items we need to remove
        this._virtualItemsToRemove = Array.prototype.slice.call(this.listEl.children, 0, first);

        // Grab the nodes we will be showing
        var nodes = Array.prototype.slice.call(this.listEl.children, first, first + itemsPerViewport);

        this.renderViewport && this.renderViewport(highWater, lowWater, first, last);
      }
    }
665500
protected void calculateTabPosition()
	{
		boolean isHorizontal = tabPosition == ComponentPosition.TOP || tabPosition == ComponentPosition.BOTTOM;
		UITab lastTab = null;

		for (UITab tab : listTabs.keySet())
		{
			if (isHorizontal)
			{
				IPosition p = lastTab != null ? Position.rightOf(this, lastTab, spacing) : Position.of(offset, 0);
				tab.setPosition(p);
			}
			else
			{
				IPosition p = lastTab != null ? Position.below(this, lastTab, spacing) : Position.of(0, offset);
				tab.setPosition(p);
			}
			lastTab = tab;
		}
	}
838790
function calculateScrollBarSize(){ //this should happen after the floating table has been positioned
        if($scrollContainer.length){
          if(opts.support && opts.support.perfectScrollbar && $scrollContainer.data().perfectScrollbar){
            scrollbarOffset = {horizontal:0, vertical:0};
          } else {
            if($scrollContainer.css('overflow-x') == 'scroll'){
              scrollbarOffset.horizontal = scrollbarWidth;
            } else {
              var sw = $scrollContainer.width(), tw = tableWidth($table, $fthCells);
              var offsetv = sh < th ? scrollbarWidth : 0;
              scrollbarOffset.horizontal = sw - offsetv < tw ? scrollbarWidth : 0;
            }
            if($scrollContainer.css('overflow-y') == 'scroll'){
              scrollbarOffset.vertical = scrollbarWidth;
            } else {
              var sh = $scrollContainer.height(), th = $table.height();
              var offseth = sw < tw ? scrollbarWidth : 0;
              scrollbarOffset.vertical = sh - offseth < th ? scrollbarWidth : 0;
            }
          }
        }
      }
72363
function(finalCoord) {

        var t = this.thumb,
            self = this,
            nextCoord = null,
            tmpX, tmpY;

        if (t._isRegion) {
            nextCoord = this._getNextX(this.curCoord, finalCoord);
            tmpX = (nextCoord !== null) ? nextCoord[0] : this.curCoord[0];
            nextCoord = this._getNextY(this.curCoord, finalCoord);
            tmpY = (nextCoord !== null) ? nextCoord[1] : this.curCoord[1];

            nextCoord = tmpX !== this.curCoord[0] || tmpY !== this.curCoord[1] ?
                [ tmpX, tmpY ] : null;
        } else if (t._isHoriz) {
            nextCoord = this._getNextX(this.curCoord, finalCoord);
        } else {
            nextCoord = this._getNextY(this.curCoord, finalCoord);
        }


        if (nextCoord) {

            // cache the position
            this.curCoord = nextCoord;

            // move to the next coord
            this.thumb.alignElWithMouse(t.getEl(), nextCoord[0] + this.thumbCenterPoint.x, nextCoord[1] + this.thumbCenterPoint.y);
            
            // check if we are in the final position, if not make a recursive call
            if (!(nextCoord[0] == finalCoord[0] && nextCoord[1] == finalCoord[1])) {
                setTimeout(function() { self.moveOneTick(finalCoord); }, 
                        this.tickPause);
            } else {
                this.unlock();
                if (!this._mouseDown) {
                    this.endMove();
                }
            }
        } else {
            this.unlock();
            if (!this._mouseDown) {
                this.endMove();
            }
        }
    }
748244
function (elm, rels) {
        var viewPortRect = DomUtils.getViewPort();

        for (var i = 0; i < rels.length; i++) {
          var pos = calculateRelativePosition(this, elm, rels[i]);

          if (this.state.get('fixed')) {
            if (pos.x > 0 && pos.x + pos.w < viewPortRect.w && pos.y > 0 && pos.y + pos.h < viewPortRect.h) {
              return rels[i];
            }
          } else {
            if (pos.x > viewPortRect.x && pos.x + pos.w < viewPortRect.w + viewPortRect.x &&
              pos.y > viewPortRect.y && pos.y + pos.h < viewPortRect.h + viewPortRect.y) {
              return rels[i];
            }
          }
        }

        return rels[0];
      }
1168092
def _update(self, frame_no):
        """"""
        # Check for any fatal errors from the background thread and quit if we hit anything.
        if self._oops:
            raise RuntimeError(self._oops)

        # Calculate new positions for animated movement.
        self._move_to_desired_location()

        # Re-draw the tiles - if we have any suitable ones downloaded.
        count = 0
        x_offset = self._convert_longitude(self._longitude)
        y_offset = self._convert_latitude(self._latitude)
        if self._tiles:
            # Clear the area first.
            bg = 253 if self._screen.unicode_aware and self._screen.colours >= 256 else 0
            for y in range(self._screen.height):
                self._screen.print_at("." * self._screen.width, 0, y, colour=bg, bg=bg)

            # Now draw all the available tiles.
            count = self._draw_tiles(x_offset, y_offset, bg)

        # Just a few pointers on what the user should do...
        if count == 0:
            self._screen.centre(" Loading - please wait... ", self._screen.height // 2, 1)

        self._screen.centre("Press '?' for help.", 0, 1)
        if _KEY == "":
            footer = "Using local cached data - go to https://www.mapbox.com/ and get a free key."
        else:
            footer = u"Zoom: {} Location: {:.6}, {:.6} Maps: © Mapbox, © OpenStreetMap".format(
                self._zoom, self._longitude, self._latitude)
        self._screen.centre(footer, self._screen.height - 1, 1)

        return count
1127048
function position(element) {
	let elemOffset = offset(element);
	let offsetParentBCR = {top: 0, left: 0};
	let offsetParentEl = parentOffsetEl(element);
	if (offsetParentEl !== document) {
		offsetParentBCR = offset(offsetParentEl);
		offsetParentBCR.top += offsetParentEl.clientTop - offsetParentEl.scrollTop;
		offsetParentBCR.left += offsetParentEl.clientLeft - offsetParentEl.scrollLeft;
	}

	return {
		width: Math.round(isNumber(elemOffset.width) ? elemOffset.width : element.offsetWidth),
		height: Math.round(isNumber(elemOffset.height) ? elemOffset.height : element.offsetHeight),
		top: Math.round(elemOffset.top - offsetParentBCR.top),
		left: Math.round(elemOffset.left - offsetParentBCR.left)
	};
}
629429
function () {
            var /** @type {?} */ tickSize = this._tickIntervalPercent * 100;
            var /** @type {?} */ backgroundSize = this.vertical ? "2px " + tickSize + "%" : tickSize + "% 2px";
            var /** @type {?} */ axis = this.vertical ? 'Y' : 'X';
            // Depending on the direction we pushed the ticks container, push the ticks the opposite
            // direction to re-center them but clip off the end edge. In RTL languages we need to flip the
            // ticks 180 degrees so we're really cutting off the end edge abd not the start.
            var /** @type {?} */ sign = !this.vertical && this._direction == 'rtl' ? '-' : '';
            var /** @type {?} */ rotate = !this.vertical && this._direction == 'rtl' ? ' rotate(180deg)' : '';
            var /** @type {?} */ styles = {
                'backgroundSize': backgroundSize,
                // Without translateZ ticks sometimes jitter as the slider moves on Chrome & Firefox.
                'transform': "translateZ(0) translate" + axis + "(" + sign + tickSize / 2 + "%)" + rotate
            };
            if (this._isMinValue && this._thumbGap) {
                var /** @type {?} */ side = this.vertical ?
                    (this._invertAxis ? 'Bottom' : 'Top') :
                    (this._invertAxis ? 'Right' : 'Left');
                styles["padding" + side] = this._thumbGap + "px";
            }
            return styles;
        }
227432
function calculate() {
      var move = this.move,
          length = this.length;
      var steps = move.steps,
          direction = move.direction;


      var countableSteps = isNumber(toInt(steps)) && toInt(steps) !== 0;

      switch (direction) {
        case '>':
          if (steps === '>') {
            Glide.index = length;
          } else if (this.isEnd()) {
            if (!(Glide.isType('slider') && !Glide.settings.rewind)) {
              this._o = true;

              Glide.index = 0;
            }
          } else if (countableSteps) {
            Glide.index += Math.min(length - Glide.index, -toInt(steps));
          } else {
            Glide.index++;
          }
          break;

        case '<':
          if (steps === '<') {
            Glide.index = 0;
          } else if (this.isStart()) {
            if (!(Glide.isType('slider') && !Glide.settings.rewind)) {
              this._o = true;

              Glide.index = length;
            }
          } else if (countableSteps) {
            Glide.index -= Math.min(Glide.index, toInt(steps));
          } else {
            Glide.index--;
          }
          break;

        case '=':
          Glide.index = steps;
          break;

        default:
          warn('Invalid direction pattern [' + direction + steps + '] has been used');
          break;
      }
    }
100360
private function calculateRealLocation()
    {
        if ($this->have_recalculated) {
            return;
        }

        $this->have_recalculated = true;

        $this->selection_start = $this->file_start;
        $this->selection_end = $this->file_end + 1;

        $project_analyzer = Internal\Analyzer\ProjectAnalyzer::getInstance();

        $codebase = $project_analyzer->getCodebase();

        $file_contents = $codebase->getFileContents($this->file_path);

        $file_length = strlen($file_contents);

        $search_limit = $this->single_line ? $this->selection_start : $this->selection_end;

        if ($search_limit <= $file_length) {
            $preview_end = strpos(
                $file_contents,
                "\n",
                $search_limit
            );
        } else {
            $preview_end = false;
        }

        // if the string didn't contain a newline
        if ($preview_end === false) {
            $preview_end = $this->selection_end;
        }

        $this->preview_end = $preview_end;

        if ($this->docblock_line_number &&
            $this->docblock_start_line_number &&
            $this->preview_start < $this->selection_start
        ) {
            $preview_lines = explode(
                "\n",
                substr(
                    $file_contents,
                    $this->preview_start,
                    $this->selection_start - $this->preview_start - 1
                )
            );

            $preview_offset = 0;

            $comment_line_offset = $this->docblock_line_number - $this->docblock_start_line_number;

            for ($i = 0; $i < $comment_line_offset; ++$i) {
                $preview_offset += strlen($preview_lines[$i]) + 1;
            }

            if (!isset($preview_lines[$i])) {
                throw new \Exception('Should have offset');
            }

            $key_line = $preview_lines[$i];

            $indentation = (int)strpos($key_line, '@');

            $key_line = trim(preg_replace('@\**/\s*@', '', substr($key_line, $indentation)));

            $this->selection_start = $preview_offset + $indentation + $this->preview_start;
            $this->selection_end = $this->selection_start + strlen($key_line);
        }

        if ($this->regex_type !== null) {
            switch ($this->regex_type) {
                case self::VAR_TYPE:
                    $regex = '/@(psalm-)?var[ \t]+' . CommentAnalyzer::TYPE_REGEX . '/';
                    $match_offset = 2;
                    break;

                case self::FUNCTION_RETURN_TYPE:
                    $regex = '/\\:\s+(\\??\s*[A-Za-z0-9_\\\\\[\]]+)/';
                    $match_offset = 1;
                    break;

                case self::FUNCTION_PARAM_TYPE:
                    $regex = '/^(\\??\s*[A-Za-z0-9_\\\\\[\]]+)\s/';
                    $match_offset = 1;
                    break;

                case self::FUNCTION_PHPDOC_RETURN_TYPE:
                    $regex = '/@(psalm-)?return[ \t]+' . CommentAnalyzer::TYPE_REGEX . '/';
                    $match_offset = 2;
                    break;

                case self::FUNCTION_PHPDOC_METHOD:
                    $regex = '/@(psalm-)method[ \t]+.*/';
                    $match_offset = 2;
                    break;

                case self::FUNCTION_PHPDOC_PARAM_TYPE:
                    $regex = '/@(psalm-)?param[ \t]+' . CommentAnalyzer::TYPE_REGEX . '/';
                    $match_offset = 2;
                    break;

                case self::FUNCTION_PARAM_VAR:
                    $regex = '/(\$[^ ]*)/';
                    $match_offset = 1;
                    break;

                case self::CATCH_VAR:
                    $regex = '/(\$[^ ^\)]*)/';
                    $match_offset = 1;
                    break;

                default:
                    throw new \UnexpectedValueException('Unrecognised regex type ' . $this->regex_type);
            }

            $preview_snippet = substr(
                $file_contents,
                $this->selection_start,
                $this->selection_end - $this->selection_start
            );

            if ($this->text) {
                $regex = '/(' . str_replace(',', ',[ ]*', preg_quote($this->text, '/')) . ')/';
                $match_offset = 1;
            }

            if (preg_match($regex, $preview_snippet, $matches, PREG_OFFSET_CAPTURE)) {
                $this->selection_start = $this->selection_start + (int)$matches[$match_offset][1];
                $this->selection_end = $this->selection_start + strlen((string)$matches[$match_offset][0]);
            }
        }

        // reset preview start to beginning of line
        $this->preview_start = (int)strrpos(
            $file_contents,
            "\n",
            min($this->preview_start, $this->selection_start) - strlen($file_contents)
        ) + 1;

        $this->selection_start = max($this->preview_start, $this->selection_start);
        $this->selection_end = min($this->preview_end, $this->selection_end);

        if ($this->preview_end - $this->selection_end > 200) {
            $this->preview_end = (int)strrpos(
                $file_contents,
                "\n",
                $this->selection_end + 200 - strlen($file_contents)
            );

            // if the line is over 200 characters long
            if ($this->preview_end < $this->selection_end) {
                $this->preview_end = $this->selection_end + 50;
            }
        }

        $this->snippet = substr($file_contents, $this->preview_start, $this->preview_end - $this->preview_start);
        $this->text = substr($file_contents, $this->selection_start, $this->selection_end - $this->selection_start);

        // reset preview start to beginning of line
        $this->column_from = $this->selection_start -
            (int)strrpos($file_contents, "\n", $this->selection_start - strlen($file_contents));

        $newlines = substr_count($this->text, "\n");

        if ($newlines) {
            $this->column_to = $this->selection_end -
                (int)strrpos($file_contents, "\n", $this->selection_end - strlen($file_contents));
        } else {
            $this->column_to = $this->column_from + strlen($this->text);
        }

        $this->end_line_number = $this->getLineNumber() + $newlines;
    }