public static function truncateHTML($html, $maxLength, $trailing='...') {
		$html = trim($html);
		$printedLength = 0;
		$position = 0;
		$tags = [];

		$res = '';

		while ($printedLength < $maxLength && preg_match('{</?([a-z]+)[^>]*>|&#?[a-zA-Z0-9]+;}', $html, $match, PREG_OFFSET_CAPTURE, $position)) {
			list($tag, $tagPosition) = $match[0];

			$str = substr($html, $position, $tagPosition - $position);
			if($printedLength + strlen($str) > $maxLength) {
				$res .= (substr($str, 0, $maxLength - $printedLength));
				$printedLength = $maxLength;
				break;
			}

			$res .= ($str);
			$printedLength += strlen($str);

			if($tag[0] == '&') {
				$res .= ($tag);
				$printedLength++;
			}
			else {
				$tagName = $match[1][0];
				if($tag[1] == '/')
					$res .= ($tag);
				elseif($tag[strlen($tag) - 2] == '/' || $tagName == 'br' || $tagName == 'hr')
					$res .= ($tag);
				else {
					$res .= ($tag);
					$tags[] = $tagName;
				}
			}

			$position = $tagPosition + strlen($tag);
		}

		if($printedLength < $maxLength && $position < strlen($html))
			$res .= (substr($html, $position, $maxLength - $printedLength));

		if($position < strlen($html))
			$res .= $trailing;

		while(!empty($tags))
			$res .= sprintf('</%s>', array_pop($tags));

		return $res;
	}