五月21号是什么星座| 雷人是什么意思| 发烧咳嗽吃什么药| 36周岁属什么| 小孩肚子痛挂什么科| hay什么意思| 今年春节是什么时候| 下眼袋浮肿是什么原因| 塔丝隆是什么面料| 腹部b超可以检查什么| 10月16日出生的是什么星座| pm2.5是什么| 蕴是什么意思| 生理期什么意思| cto是什么职位| 澍在人名中读什么| 梦见蛇咬别人是什么意思| 吃知柏地黄丸有什么副作用| 如鱼得水是什么意思| 低压偏高是什么原因| jbp什么意思| 环比是什么意思| 睡觉为什么要枕枕头| 生气胸口疼是什么原因| 狗狗为什么喜欢舔人| emoji是什么意思| 陶土色是什么颜色| 未什么意思| 微恶风寒是什么意思| 什么叫玄学| 月经来头疼是什么原因引起的| 反流性食管炎能吃什么水果| 10月份是什么星座| 尿多吃什么药| 头大脸大适合什么发型| 荨麻疹是什么原因引起| 腹泻吃什么好| 七月十九是什么星座| 搭桥香是什么意思| 齐天大圣是什么级别| 石决明是什么| ldl是什么意思| 金句是什么意思| 肾病到什么程度腿会肿| 腱鞘炎是什么原因引起的| 肋骨骨折吃什么食物好得快| 一月十二号是什么星座| 素质教育是什么| 羊肉汤放什么调料| 梦见父母是什么意思| 端午是什么时候| 办理暂住证需要什么材料| 小别胜新婚什么意思| 螳螂捕蝉黄雀在后是什么生肖| 钠尿肽高是什么原因| 澳门什么时候回归| 吃龟苓膏有什么好处| 梦到车被撞了什么预兆| 口酸吃什么药效果好| 一厢情愿什么意思| 国窖1573是什么香型| 左边后背疼是什么原因| 手指甲紫色是什么原因| 拉肚子吃什么食物好得快| 牙刷什么样的刷毛最好| 转氨酶高挂什么科| 骑马野战指什么生肖| 仄怎么读什么意思| 簇新是什么意思| 白血球低是什么原因| 生理盐水敷脸有什么作用| 两个克念什么| twins什么意思| 金银满堂是什么生肖| 后脑勺疼什么原因| 过继是什么意思| 走路带风是什么意思| 身体多病戴什么首饰| 沙棘有什么作用| 多梦睡眠质量不好是什么原因| 茶寿为什么是108岁| 1948属什么生肖| 我适合什么发型| 落枕挂什么科| 越描越黑是什么意思| 小粉是什么粉| 兔子怕什么| 梦见黑色的蛇是什么意思| 蚰蜒吃什么| 盗汗遗精是什么意思| 看是什么意思| 三合是什么意思| 猪笼入水是什么意思| 肌酐高吃什么食物好| 早上起床吐痰带血是什么原因| 白头翁是什么生肖| 血压低是什么症状| 总手是什么意思| 牙龈发炎是什么原因引起的| 血小板减少是什么原因造成的| 吃完晚饭就犯困是什么原因| 皮疹是什么症状| 螺旋体感染是什么意思| 堃是什么意思| 什么是躯体化症状表现| 史密斯夫妇是什么意思| 小孩吃牛肉有什么好处| 盆腔炎是什么症状| wmf是什么牌子| 三界牌是什么| 爸爸的爸爸叫什么儿歌| romantic什么意思| 血蛋白低会有什么影响| 不走寻常路是什么意思| 吃什么东西补脑| hook是什么意思| 经常手麻是什么原因引起的| 黄的什么| 黄疸严重会造成什么后果| 头疼喝什么药| 脾胃虚弱吃什么药最好| 骇人听闻是什么意思| 儿童鼻窦炎吃什么药| 血象高会导致什么后果| 血小板为什么会高| 血糖高什么水果可以吃| 一唱一和是什么生肖| 梦见滑雪是什么意思| 什么的水洼| 脉搏快是什么原因| 右乳导管扩张什么意思| 无花果什么味道| 是什么符号| 理数是什么意思| 3个火念什么| 心肌供血不足吃什么药| 急性扁桃体化脓是什么原因引起的| soeasy是什么意思| 股票举牌什么意思| 鲤鱼旗的含义是什么| 一月六日是什么星座| 西洋参有什么作用和功效| 合胞病毒吃什么药| 肤如凝脂是什么意思| 生姜能治什么病| 应届毕业生是什么意思| 广州有什么小吃特产| 角瓜是什么瓜| 什么水果是发物| 十二生肖排第七是什么生肖| 高什么亮什么| 督邮相当于现在什么官| 背后长痘痘什么原因| 淘宝预售是什么意思| 丸吞是什么意思| 病毒性结膜炎用什么眼药水| 白羊座后面是什么星座| 系带断裂有什么影响吗| 2006属狗的五行缺什么| 女人心肌缺血吃什么药| sku图是什么意思| 黄褐斑内调吃什么中药| 肝上火有什么症状| 画地为牢是什么意思| 压寨夫人是什么意思| 节律是什么意思| 铁蛋白高吃什么药能降下来| 梦见自己生二胎是什么意思| 牙龈萎缩是什么原因| 肌酐高有什么危害| 人中浅的女人代表什么| 被猫抓了有什么症状| 为什么医生很少开阿斯美| 笔触是什么意思| 食是代表什么生肖| 超现实主义是什么意思| 女人喜欢黑色代表什么| 拔牙后吃什么食物最好| 严重失眠挂什么科| 雄鱼是什么鱼| 什么是超标电动车| hdr是什么拍照功能| 阳虚和阴虚有什么区别| naco是什么牌子| 什么食物含硒| 尿频尿量少是什么原因| psa检查是什么意思| 大爱是什么意思| 潜血是什么意思| 羊胡子疮用什么药膏| 益生菌的食物是什么| 应酬是什么意思| 开理疗店需要什么证件| 一什么眉毛| 90年是什么命| 锌是什么颜色| 什么时候不能喷芸苔素| 落拓是什么意思| 屈髋是什么姿势| 订盟是什么意思| 父亲节什么时候| 焦虑症是什么原因引起的| 怀孕吃叶酸片有什么用| 上海有什么烟| 皮肤经常痒是什么原因| 三个毛念什么字| 甲状腺弥漫性改变是什么意思| 什么是有氧运动包括哪些| 今年什么时间进伏| 什么叫个人修养| 喉咙痛用什么药好得快| 幽门螺杆菌是什么| 坎宅是什么意思| 眼睛疼吃什么药效果最好| 什么是高压氧| 巨蟹座是什么象| 大是大非是什么意思| 香菜什么时候种最合适| 血脂高可以吃什么水果| 星期六打喷嚏代表什么| 土笋冻是什么虫子| 戒指戴无名指是什么意思| 卵泡是什么意思| 孕妇可以喝什么汤| 嗓子挂什么科| 甘胆酸偏高是什么原因| 爱是什么排比句| 狗上皮过敏是什么意思| 倒霉是什么意思| 吃什么补维生素| 泌尿科主要看什么病| 迷茫什么意思| 梦见自己丢钱了什么征兆| 处女座是什么| 骨盐量偏低是什么意思| marlboro是什么烟| 泰安有什么大学| 产检建档需要什么资料| 肺结节是什么引起的| 体检吃早餐有什么影响| zoom 是什么意思| 头伏饺子二伏面三伏吃什么| 市政协主席是什么级别| 心脏早博吃什么药好| 卵子排出体外是什么样子| 女性肝囊肿要注意什么| rst是什么意思| 腰间盘突出吃什么药好| 头皮痒用什么洗发水效果好| 5.20什么星座| 子宫肌瘤吃什么药好| 头痛吃什么药效果好| 药学是什么| 妇科检查bv是什么意思| 什么是共产主义社会| 血压低是什么原因| 血液病是什么| 财多身弱什么意思| 脑梗三项是检查什么| 卤牛肉用什么部位| 导管是什么意思| 心超是检查什么的| 阔以是什么意思| 贴士是什么意思| 百度Jump to content

河北省要求加大无偿献血宣传力度 完善采血设施

From mediawiki.org
MediaWiki extensions
百度 ”清华大学政治经济学研究中心主任蔡继明代表表示,在新业态下,有关劳动者保护的相关法律法规滞后了。

Individual projects will often find it useful to extend the built-in wiki markup with additional capabilities, whether simple string processing, or full-blown information retrieval. Tag extensions allow users to create new custom tags that do just that. For example, one might use a tag extension to introduce a simple ‎<donation /> tag, which injects a donation form into the page. Extensions, including parser functions and hooks, are the most effective way to change or enhance the functionality of MediaWiki. You should always check before you start work on an extension to make sure someone else hasn't done exactly what you are trying to do.

A simple tag extension consists of a callback function, which is hooked to the parser so that, when the parser runs, it will find and replace all instances of a specific tag, calling the corresponding callback function to render the actual HTML.

Example

In extension.json , set up the hooks:

...
  "Hooks": {
       "ParserFirstCallInit": "ExampleExtensionHooks"
   },
   "HookHandlers": {
       "ExampleExtensionHooks": {
           "class": "MediaWiki\\Extension\\ExampleExtension\\Hooks"
       }
   }
...

And add the hook into a PHP file

<?php
namespace MediaWiki\Extension\ExampleExtension;

class ExampleExtension implements ParserFirstCallInitHook {
	// Register any render callbacks with the parser
	public function onParserFirstCallInit( $parser ) {
		// When the parser sees the <sample> tag, it executes renderTagSample (see below)
		$parser->setHook( 'sample', [ $this, 'renderTagSample' ] );
	}

	// Render <sample>
	public function renderTagSample( $input, array $args, Parser $parser, PPFrame $frame ) {
		// Nothing exciting here, just escape the user-provided input and throw it back out again (as example)
		return htmlspecialchars( $input );
	}
}

This example registers a callback function for the ‎<sample> tag. When a user adds this tag to a page like this: <sample arg1="xxx" arg2="xxx">...input...</sample>, the parser will call the renderTagSample() function, passing in four arguments:

$input
Input between the ‎<sample> and ‎</sample> tags, or null if the tag is "closed", i.e. ‎<sample />
$args
Tag arguments, which are entered like HTML tag attributes; this is an associative array indexed by attribute name.
$parser
The parent parser (a Parser object); more advanced extensions use this to obtain the contextual Title, parse wiki text, expand braces, register link relationships and dependencies, etc.
$frame
The parent frame (a PPFrame object). This is used together with $parser to provide the parser with more complete information on the context in which the extension was called.

For a more elaborate example, see Tag extension example


Attributes

Let's look at another example:

<?php

$wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit';

function onParserFirstCallInit( Parser $parser ) {
	$parser->setHook( 'sample', 'wfSampleRender' );
}

function wfSampleRender( $input, array $args, Parser $parser, PPFrame $frame ) {
	$attr = [];    
	// This time, make a list of attributes and their values, and dump them, along with the user input
	foreach( $args as $name => $value ) {
		$attr[] = '<strong>' . htmlspecialchars( $name ) . '</strong> = ' . htmlspecialchars( $value );
	}
	return implode( '<br />', $attr ) . "\n\n" . htmlspecialchars( $input );

/**
 * The following lines can be used to get the variable values directly:
 * $to = $args['to'] ;
 * $email = $args['email'] ;
 */
}

This example dumps the attributes passed to the tag, along with their values. It's quite evident that this allows for flexible specification of new, custom tags. You might, for example, define a tag extension that allows a user to inject a contact form on their user page, using something like <emailform to="User" email="user@foo.com" />.

There is a veritable plethora of tag extensions available for MediaWiki, some of which are listed on this site; others can be found via a quick web search. While a number of these are quite specialised for their use case, there are a great deal of well-loved and well-used extensions providing varying degrees of functionality.

Conventions

See Manual:Developing extensions for the general layout and setup of an extension.

Publishing your extensions

  1. Create a new page on this wiki named Extension:<extension_name> with information on your extension, how to install it, and screenshots of it in use. A convenient template has been created to hold this information called Template:Extension . See the template page for more information. You should also add as much detail as possible to the body of the page, and it is wise to check back fairly regularly to respond to user questions on the associated talk page. Also, make sure the page belongs to Category:Extensions .
  2. Extensions that create new hooks within the extension code should register them in the extension hook category.
  3. Notify the mediawiki-l mailing list.

See also publishing your extension.

FAQ

Security concerns

You'll notice above that the input in the examples above is escaped using htmlspecialchars() before being returned. It is vital that all user input is treated in this manner before echoing it back to the clients, to avoid introducing vectors for arbitrary HTML injection, which can lead to cross-site scripting vulnerabilities.

Loading modules

The right way to add modules for your extension is to attach them to the ParserOutput rather than to $wgOut. The module list will then be automatically taken from the ParserOutput object and added to $wgOut even when the page rendering is pre-cached. If you are directly adding the modules to $wgOut they might not be cached in the parser output.

function myCoolHook( $text, array $params, Parser $parser, PPFrame $frame ) {
	// ... do stuff ...
	$parser->getOutput()->addModules( 'ext.mycoolext' );
	$parser->getOutput()->addModuleStyles( 'ext.mycoolext.styles' );
	// ... do more stuff ...
}

Timing and extensions

If you change the code for an extension, all pages that use the extension will, theoretically, immediately reflect the results of new code. Technically speaking, this means your code is executed each and every time a page containing the extension is rendered.

In practice, this is often not the case, due to page caching - either by the MediaWiki software, the browser or by an intermediary proxy or firewall.

To bypass MediaWiki's parser cache and ensure a new version of the page is generated, click on edit, replace "action=edit" in the URL shown in the address bar of your browser by "action=purge" and submit the new URL. The page and all templates it references will be regenerated, ignoring all cached data. The purge action is needed if the main page itself is not modified, but the way it must be rendered has changed (the extension was modified, or only a referenced template was modified).

If this is not sufficient to get you a fresh copy of the page, you can normally bypass intermediary caches by adding '&rand=somerandomtext' to the end of the above URL. Make sure 'somerandomtext' is different every time.

How do I disable caching for pages using my extension?

Since MediaWiki 1.5, the parser is passed as the third parameter to an extension. This parser can be used to invalidate the parser cache like this:

function wfSampleSomeHookFunction( $text, array $args, Parser $parser, PPFrame $frame ) {
	$parser->getOutput()->updateCacheExpiry(0);
	// ...
}

Regenerating the page when another page is edited

Maybe you don't want to disable caching entirely, you just want the page to be regenerated whenever another page is edited, similar to the way that template transclusions are handled. This can be done using the parser object that is passed to your hook function and calling the addTemplate.


Fine grained adjustment of caching behavior

You can use fine grained caching for your extension by using cache keys to differentiate between different versions of your extension output. While rendering you can add cache keys for every feature by adding an addExtraKey method to your hook function, e.g.:

function wfSampleSomeHookFunction( $text, array $args, Parser $parser, PPFrame $frame ) {
	$userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
	$setting1= (int)$userOptionsLookup->getOption( $parser->getUserIdentity(), 'setting1' );
	$parser->getOptions()->optionUsed( 'setting1' );
	$setting2= (int)$userOptionsLookup->getOption( $parser->getUserIdentity(), 'setting2' );
	$parser->getOptions()->optionUsed( 'setting2' );
	...
}

However, modifying $parser->getOptions() during parse means that the extra option keys aren't included when trying to get a cached page, only when rendering a page to go into cache, so you can use the PageRenderingHash hook to set extra options. PageRenderingHash is run both when putting a page into cache, and getting it out, so its important to only add new keys to the hash if they're not already there. e.g:

$wgHooks['PageRenderingHash'][] = 'wfMyExtOnPageRenderingHash';

function wfMyExtOnPageRenderingHash( &$confstr, $user, $optionsUsed ) {
	$userOptionsLookup = MediaWikiServices::getInstance()->getUserOptionsLookup();
	if ( in_array( 'setting1', $optionsUsed ) ) {
		$confstr .= "!setting1=" . $userOptionsLookup->getOption( $user, 'setting1' );
	}
	if ( in_array( 'setting2', $optionsUsed ) ) {
		$confstr .= "!setting2=" . $userOptionsLookup->getOption( $user, 'setting2' );
	}
}

Some important notes on this:

  • Using "!setting1=$value" instead of just "!$value" in the confstr ensures that the parser cache does not become messed up if different extensions are installed or their load order changes. ! is used a separator for different rendering options
  • Some people use $parser->getOptions()->addExtraKey() instead of $parser->getOptions()->optionUsed(). Be warned that addExtraKey does not tell the parser cache that the extra key is in use, and thus can easily result in breaking the cache if you are not careful.

How do I render wikitext in my extension?

Since version 1.16

MediaWiki version:
1.16

Parser hook functions are passed a reference to the parser object and a frame object; these should be used to parse wikitext.

function wfSampleWonderfulHook( $text, array $args, Parser $parser, PPFrame $frame ) {
	$output = $parser->recursiveTagParse( $text, $frame );
	return '<div class="wonderful">' . $output . '</div>';
}

Parser::recursiveTagParse() has been around since version 1.8. Its advantages include simplicity (it takes just one argument and returns a string) and the fact that it parses extension tags in $text, so you can nest extension tags.

The second parameter to recursiveTagParse, $frame, is an optional argument introduced in MW 1.16 alpha (r55682).

  • If $frame is provided (using the value of $frame passed to your extension), then any template parameters in $text will be expanded. In other words, content such as {{{1}}} will be recognized and converted into the appropriate value.
  • If $frame is not provided (e.g., $parser->recursiveTagParse( $text )), or if $frame is set to false, then template parameters will not be expanded; {{{1}}} will not be altered. Although this unlikely to be the desired behavior, this was the only option available before MW 1.16.

However, one step of parsing that is still skipped for tags, even when using recursiveTagParse, is Parser::preSaveTransform. preSaveTransform is the first step of parsing, responsible for making permanent changes to the about-to-be saved wikitext, such as:

  • Converting signatures (~~~, ~~~~, ~~~~~)
  • Expanding link labels, also known as the pipe-trick (e.g., changing [[Help:Contents|]] into [[Help:Contents|Contents]]). Without this step, shorthand links such as [[Help:Contents|]] are considered to be invalid, and are left in their wikitext form when parsed.
  • Expanding {{subst:}} templates.

The original call to preSaveTransform intentionally skips such conversions within all extension tags. If you need pre save transform to be done, you should consider using a parser function instead. All tag extensions can also be called as a parser function using {{#tag:tagname|input|attribute_name=value}} which will have pre save transform applied.

How can I pass XML-style parameters in my extension tag?

Since version 1.5

Since MediaWiki 1.5, XML-style parameters (tag attributes) are supported. The parameters are passed as the second parameter to the hook function, as an associative array. The value strings have already had HTML character entities decoded for you, so if you emit them back to HTML, don't forget to use htmlspecialchars( $codeToEncode, ENT_QUOTES ), to avoid the risk of HTML injection.

How can I avoid modification of my extension's HTML output?

The return value of a tag extension is considered almost parsed text, which means its not treated as pure html, but still modified slightly. There are two main things that are done to the output of a tag extension (Along with a couple other minor things):

  • Replace strip markers. Strip markers are certain items which are inserted at various stages of processing wikitext to act as a marker to re-insert removed content at a later time. This is not something extensions usually need to worry about.
  • Parser::doBlockLevels which turns *'s into lists, and turns any line starting with a leading space into a ‎<pre> among other things. This can sometimes be an issue in some extensions.

Tag extensions also support returning an array instead of just a string (Much like parser functions) in order to change how the return value is interpreted. The 0th value of the array must be the HTML. The "markerType" key can be set to nowiki in order to stop further parsing. Doing something like return [ $html, 'markerType' => 'nowiki' ]; would ensure that the $html value is not further modified and treated as just plain html.

How do I get my extension to show up on Special:Version?

See Manual:Extension registration and register your extension accordingly.

Retrieving the tag name inside of the callback

Suppose you have several tags ‎<foo> and ‎<bar> that share the same callback, and inside the callback function, you want to obtain the name of the tag that invoked the callback.

$wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit';

# ...

public function onParserFirstCallInit( Parser $parser ) {
	$parser->setHook( 'foo', 'sharedFunctionality' );
	$parser->setHook( 'bar', 'sharedFunctionality' );
}

# ...

public function sharedFunctionality( $input, array $args, Parser $parser, PPFrame $frame ) {
	// How to distinguish between 'foo' and 'bar' calls?
}

The short answer is: the tag name (foo or bar) is not present in any of the callback's arguments. But you can work around this by dynamically constructing a separate callback for each tag:

$wgHooks['ParserFirstCallInit'][] = 'onParserFirstCallInit';

# ...

public function onParserFirstCallInit( Parser $parser ) {
	// For each tag name
	foreach ( [ 'foo', 'bar' ] as $tagName ) {
		// Dynamically create a callback function
		$callback = function( $input, $args, $parser, $frame ) use ( $tagName ) {
			// The callback invokes the shared function.
			// Notice we now pass the tag name as a parameter.
			return sharedFunctionality( $input, $args, $parser, $frame, $tagName );
		};
		// Assign the callback to the tag
		$parser->setHook( $tagName, $callback );
	}
}

# ...

public function sharedFunctionality( $input, array $args, Parser $parser, PPFrame $frame, $tagName) {
	// Now we can retrieve the tag name and perform custom actions for that tag
	switch ( $tagName ) {
		//...
	}
}

Toolbar buttons

Extension:WikiEditor provides an editing toolbar, allowing users to add tags into their editor by simply clicking a button. If you want a toolbar button for your new tag, create a file named something like toolbar-button.js in your extension's resources folder. The file should look like this:

var customizeToolbar = function () {
    $('#wpTextbox1').wikiEditor('addToToolbar', {
        section: 'main',
        group: 'format',
        tools: {
            "ExtensionName": { // replace with the name of your extension
                label: 'TagName', // replace with the label that should appear when hoving the button
                type: 'button',
                icon: "extensions/ExtensionName/images/button-image.svg", // path to the image that should go on the button
                action: {
                    type: 'encapsulate',
                    options: {
                        pre: "<tagName>", // tags that get inserted when the button is clicked
                        post: "</tagName>"
                    }
                }
            }
        }
    });
};

/* Check if view is in edit mode and that the required modules are available. Then, customize the toolbar … */
if ( [ 'edit', 'submit' ].indexOf( mw.config.get( 'wgAction' ) ) !== -1 ) {
    mw.loader.using( 'user.options' ).then( function () {
        // This can be the string "0" if the user disabled the preference ([[phab:T54542#555387]])
        if ( mw.user.options.get( 'usebetatoolbar' ) == 1 ) {
            $.when(
                mw.loader.using( 'ext.wikiEditor' ), $.ready
            ).then( customizeToolbar );
        }
    } );
}

Further details about customizing this file can be found here. Once you've created the file, you need to register it with ResourceLoader so it will be delivered to visitors; this is done by editing your extension.json:

"Hooks": {
    "BeforePageDisplay": "ExtensionName::onBeforePageDisplay"
}
"ResourceModules": {
    "ext.ExtensionName": {
        "scripts": ["toolbarButton.js"]
    }
}

Then, in your PHP file:

public static function onBeforePageDisplay( OutputPage $out ) {
    $out->addModules( [ 'ext.ExtensionName' ] );
}

See also

返场是什么意思 免疫十一项都检查什么 龚自珍是什么朝代的 阴虱用什么药物 什么人不能喝绿豆汤
氨气对人体有什么危害 肚子胀气吃什么药好 什么情况下挂疼痛科 疖肿是什么意思 牙龈萎缩用什么牙膏
st股票是什么意思 胰岛素针头4mm和5mm有什么区别 什么是地中海饮食 跑步胸口疼什么原因 胆气不足吃什么中成药
什么是回南天 孩子注意力不集中是什么原因 cool什么意思中文 润肠通便吃什么药 蝙蝠飞到家里是什么预兆
南方有什么水果hcv9jop2ns9r.cn 同房出血是什么原因zsyouku.com 镇长属于什么级别creativexi.com 一品诰命夫人是什么意思hcv8jop3ns6r.cn 看见乌鸦有什么预兆hcv8jop0ns0r.cn
尿急尿频吃什么药hcv7jop4ns6r.cn 龟代表什么生肖hcv7jop5ns4r.cn 八月底什么星座cl108k.com 山东登州府现在叫什么hcv9jop6ns9r.cn 霉菌性阴道炎有什么症状hcv8jop3ns6r.cn
血管堵塞吃什么药hcv8jop6ns1r.cn 后入什么意思weuuu.com 破损是什么意思hcv8jop4ns3r.cn 头皮挂什么科hcv8jop2ns4r.cn 梦见偷别人东西是什么意思hcv9jop7ns3r.cn
什么是理想hcv8jop4ns8r.cn 狗是什么属性hcv8jop9ns0r.cn 属鼠女和什么属相最配beikeqingting.com 洗手指征是什么hcv7jop9ns7r.cn 什么叫低级别上皮内瘤变hcv7jop5ns4r.cn
百度 技术支持:蜘蛛池 www.kelongchi.com