public function parseNext( $text, WikiObjectModelCollection $parentObj, $offset = 0 ) {
		$lastLF = ( $offset == 0 || $text { $offset - 1 } == "\n" );
		$text = substr( $text, $offset );
		if ( !$lastLF ) return null;

		$r = preg_match( '/^(={1,6})/', $text, $m );
		if ( $r ) {
			$text1 = substr( $text, strlen( $m[0] ) );
			$s = explode( "\n", $text1, 2 );
			$r = preg_match( '/(={1,})\s*$/', $s[0], $m1, PREG_OFFSET_CAPTURE );

			if ( $r ) {
				$len = strlen( $m[0] ) + strlen( $s[0] ) + 1/* \n */;
				$level = strlen( $m[1] ) < strlen( $m1[1][0] ) ? strlen( $m[1] ) : strlen( $m1[1][0] );

				$obj = new WOMSectionModel( trim(
					substr( WOMSectionParser::$heading, 0, strlen( $m[1] ) - $level ) .
						substr( $s[0], 0, $m1[1][1] + strlen( $m1[1][0] ) - $level ) ),
					$level );

				while ( $parentObj != null &&
					( $parentObj->getTypeID() == WOM_TYPE_SECTION ) &&
					( $parentObj->getLevel() >= $obj->getLevel() ) ) {
						$parentObj = $parentObj->getParent();
				}
				$obj->setParent( $parentObj );

				return array( 'len' => $len, 'obj' => $obj );
			}
		}

		return null;
	}
	private function parseAsk ( $text, WikiObjectModelCollection $parentObj ) {
		if ( !defined( 'SMW_VERSION' ) ) return null;

		if ( trim( strtolower( $parentObj->getFunctionKey() ) ) != 'ask' ) return null;

		if ( count ( $parentObj->getObjects() ) == 0 ) {
			return array( 'len' => 0, 'obj' => new WOMQuerystringModel() );
		}

		if ( defined( 'SMW_AGGREGATION_VERSION' ) ) {
			$r = preg_match( '/^(\s*\?([^>=|}]+)(?:\>([^=|}]*))?(?:=([^|}]*))?)(\||\}|$)/', $text, $m );
			if ( !$r ) return null;
			return array(
				'len' => strlen( $m[5] == '|' ? $m[0] : $m[1] ),
				'obj' => new WOMQueryPrintoutModel( trim( $m[2] ), trim( $m[4] ), trim( $m[3] ) ) );
		} else {
			$r = preg_match( '/^(\s*\?([^=|}]+)(?:=([^|}]*))?)(\||\}|$)/', $text, $m );
			if ( !$r ) return null;
			return array(
				'len' => strlen( $m[4] == '|' ? $m[0] : $m[1] ),
				'obj' => new WOMQueryPrintoutModel( trim( $m[2] ), trim( $m[3] ) ) );
		}
	}
	public function getWikiText() {
		return ( $this->isLastLF() ? '' : "\n" ) .
			$this->m_header . parent::getWikiText();
	}
	private static function removeSubWOMIds( WikiObjectModelCollection $parent ) {
		foreach ( $parent->getObjects() as $wobj ) {
			$wobj->setObjectID( '' );
			if ( $wobj instanceof WikiObjectModelCollection ) {
				self::removeSubWOMIds( $wobj );
			}
		}
	}
	public function getWikiText() {
		return "{{{$this->m_name}\n|" . parent::getWikiText() . "}}";
	}
	public function getInnerWikiText() {
		return parent::getWikiText();
	}
	public function getContent() {
		return parent::getWikiText();
	}
	public function __construct() {
		parent::__construct( WOM_TYPE_SENTENCE );
	}
	public function __construct() {
		parent::__construct( WOM_TYPE_PARAM_VALUE );
	}
	private static function parseSentences( WikiObjectModelCollection $wom ) {
		global $wgOMSentenceObjectTypes;
		$in_sentence = false;
		$new_objs = array();
		$sentenceObj = null;
		foreach ( $wom->getObjects() as $id => $obj ) {
			if ( in_array( $obj->getTypeID(), $wgOMSentenceObjectTypes ) ) {
				if ( !$in_sentence ) {
					$sentenceObj = new WOMSentenceModel();
					$new_objs[] = $sentenceObj;
					$in_sentence = true;
				}
				$sentenceObj->insertObject( $obj );
				// parse sentence break
				if ( $obj->getTypeID() == WOM_TYPE_TEXT ) {
					$text = $obj->getWikiText();
					$offset = 0;
					$len = strlen( $text );
					// FIXME: sentence algorithm here, for now, just think of
					// \n
					// [.?!]((['"]|'{2,6})?)<space>
					// shall think of other language, e.g., Chinese
					$r = preg_match_all( '/(\n[^\n])|(([\.!?](([\'"]|\'{2,6})?))([ \t]))/',
						$text, $ms, PREG_SET_ORDER | PREG_OFFSET_CAPTURE );
					if ( $r ) {
						foreach ( $ms as $m ) {
							if ( $m[1][1] >= 0 ) {
								$end = $m[0][1] + 1;
							} else {
								$end = $m[0][1] + strlen( $m[0][0] );
							}
							$obj->setText( substr( $text, $offset, $end - $offset ) );
							$offset = $end;
							if ( $end == $len ) break;
							$sentenceObj = new WOMSentenceModel();
							$new_objs[] = $sentenceObj;
							$obj = new WOMTextModel( substr( $text, $end ) );
							$sentenceObj->insertObject( $obj );
						}
					}
				}
			} else {
				$in_sentence = false;
				$sentenceObj = null;

				if ( $obj->getTypeID() == WOM_TYPE_HTMLTAG ) {
					// special case, html tag
				} elseif ( $obj instanceof WikiObjectModelCollection ) {
					self::parseSentences( $obj );
				}
				$new_objs[] = $obj;
			}
		}

		$wom->reset();

		foreach ( $new_objs as $obj ) {
			$wom->insertObject( $obj );
		}
	}
	public function getWikiText() {
		return "{{#{$this->m_function_key}:" .
			parent::getWikiText() .
			'}}';
	}
	public function __construct() {
		parent::__construct( WOM_TYPE_PAGE );
	}
	public function __construct() {
		parent::__construct( WOM_TYPE_NESTPROPERTYVAL );
	}
	public function getWikiText() {
		return ( $this->isLastLF() ? '' : "\n" ) .
			"{| {$this->m_style}" . parent::getWikiText() . "\n|}";
	}
	public function __construct() {
		parent::__construct( 'q_result' );
	}
	public function getValueText() {
		return parent::getWikiText();
	}
	public function getWikiText() {
		return "{$this->m_prefix}" . parent::getWikiText();
	}