原生态纯JavaScript 100大技巧大收集

原文出处:http://yonghu.blog.51cto.com/8166136/1346946

1、原生JavaScript实现字符串长度截取

function cutstr(str, len) {
    var temp;
    var icount = 0;
    var patrn = /[^\x00-\xff]/;
    var strre = "";
    for (var i = 0; i < str.length; i++) {
        if (icount < len - 1) {
            temp = str.substr(i, 1);
            if (patrn.exec(temp) == null) {
                icount = icount + 1
            } else {
                icount = icount + 2
            }
            strre += temp
        } else {
            break
        }
    }
    return strre + "..."
}

2.原生JavaScript获取域名主机

function getHost(url) {
    var host = "null";
    if(typeof url == "undefined"|| null == url) {
        url = window.location.href;
    }
    var regex = /^\w+\:\/\/([^\/]*).*/;
    var match = url.match(regex);
    if(typeof match != "undefined" && null != match) {
        host = match[1];
    }
    return host;
}

3.原生JavaScript清除空格

String.prototype.trim = function() {
    var reExtraSpace = /^\s*(.*?)\s+$/;
    return this.replace(reExtraSpace, "$1")
}

4.原生JavaScript替换全部

String.prototype.replaceAll = function(s1, s2) {
    return this.replace(new RegExp(s1, "gm"), s2)
}

5、原生JavaScript转义html标签

function HtmlEncode(text) {
    return text.replace(/&/g, '&').replace(/\"/g, '"').replace(/</g, '<').replace(/>/g, '>')
}

6、原生JavaScript还原html标签

function HtmlDecode(text) {
    return text.replace(/&/g, '&').replace(/"/g, '\"').replace(/</g, '<').replace(/>/g, '>')
}

7、原生JavaScript时间日期格式转换

Date.prototype.Format = function(formatStr) {
    var str = formatStr;
    var Week = ['日', '一', '二', '三', '四', '五', '六'];
    str = str.replace(/yyyy|YYYY/, this.getFullYear());
    str = str.replace(/yy|YY/, (this.getYear() % 100) > 9 ? (this.getYear() % 100).toString() : '0' + (this.getYear() % 100));
    str = str.replace(/MM/, (this.getMonth() + 1) > 9 ? (this.getMonth() + 1).toString() : '0' + (this.getMonth() + 1));
    str = str.replace(/M/g, (this.getMonth() + 1));
    str = str.replace(/w|W/g, Week[this.getDay()]);
    str = str.replace(/dd|DD/, this.getDate() > 9 ? this.getDate().toString() : '0' + this.getDate());
    str = str.replace(/d|D/g, this.getDate());
    str = str.replace(/hh|HH/, this.getHours() > 9 ? this.getHours().toString() : '0' + this.getHours());
    str = str.replace(/h|H/g, this.getHours());
    str = str.replace(/mm/, this.getMinutes() > 9 ? this.getMinutes().toString() : '0' + this.getMinutes());
    str = str.replace(/m/g, this.getMinutes());
    str = str.replace(/ss|SS/, this.getSeconds() > 9 ? this.getSeconds().toString() : '0' + this.getSeconds());
    str = str.replace(/s|S/g, this.getSeconds());
    return str
}

8、原生JavaScript判断是否为数字类型

function isDigit(value) {
    var patrn = /^[0-9]*$/;
    if (patrn.exec(value) == null || value == "") {
        return false
    } else {
        return true
    }
}

9、原生JavaScript设置cookie值

function setCookie(name, value, Hours) {
    var d = new Date();
    var offset = 8;
    var utc = d.getTime() + (d.getTimezoneOffset() * 60000);
    var nd = utc + (3600000 * offset);
    var exp = new Date(nd);
    exp.setTime(exp.getTime() + Hours * 60 * 60 * 1000);
    document.cookie = name + "=" + escape(value) + ";path=/;expires=" + exp.toGMTString() + ";domain=360doc.com;"
}

10、原生JavaScript获取cookie值

function getCookie(name) {
    var arr = document.cookie.match(new RegExp("(^| )" + name + "=([^;]*)(;|$)"));
    if (arr != null) return unescape(arr[2]);
    return null
}

11、原生JavaScript加入收藏夹

function AddFavorite(sURL, sTitle) {
    try {
        window.external.addFavorite(sURL, sTitle)
    } catch(e) {
        try {
            window.sidebar.addPanel(sTitle, sURL, "")
        } catch(e) {
            alert("加入收藏失败,请使用Ctrl+D进行添加")
        }
    }
}

12、原生JavaScript设为首页

function setHomepage() {
    if (document.all) {
        document.body.style.behavior = 'url(#default#homepage)';
        document.body.setHomePage('http://www.jq-school.com')
    } else if (window.sidebar) {
        if (window.netscape) {
            try {
                netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect")
            } catch(e) {
                alert("该操作被浏览器拒绝,如果想启用该功能,请在地址栏内输入 about:config,然后将项 signed.applets.codebase_principal_support 值该为true")
            }
        }
        var prefs = Components.classes['@mozilla.org/preferences-service;1'].getService(Components.interfaces.nsIPrefBranch);
        prefs.setCharPref('browser.startup.homepage', 'http://www.jq-school.com')
    }
}

13、原生JavaScript判断IE6

var ua = navigator.userAgent.toLowerCase();
var isIE6 = ua.indexOf("msie 6") > -1;
if (isIE6) {
    try {
        document.execCommand("BackgroundImageCache", false, true)
    } catch(e) {}
}

14、原生JavaScript加载样式文件

function LoadStyle(url) {
    try {
        document.createStyleSheet(url)
    } catch(e) {
        var cssLink = document.createElement('link');
        cssLink.rel = 'stylesheet';
        cssLink.type = 'text/css';
        cssLink.href = url;
        var head = document.getElementsByTagName('head')[0];
        head.appendChild(cssLink)
    }
}

15、原生JavaScript返回脚本内容

function evalscript(s) {
	if(s.indexOf('<script') == -1) return s;
	var p = /<script[^\>]*?>([^\x00]*?)<\/script>/ig;
	var arr = [];
	while(arr = p.exec(s)) {
		var p1 = /<script[^\>]*?src=\"([^\>]*?)\"[^\>]*?(reload=\"1\")?(?:charset=\"([\w\-]+?)\")?><\/script>/i;
		var arr1 = [];
		arr1 = p1.exec(arr[0]);
		if(arr1) {
			appendscript(arr1[1], '', arr1[2], arr1[3]);
		} else {
			p1 = /<script(.*?)>([^\x00]+?)<\/script>/i;
			arr1 = p1.exec(arr[0]);
			appendscript('', arr1[2], arr1[1].indexOf('reload=') != -1);
		}
	}
	return s;
}

16、原生JavaScript清除脚本内容

function stripscript(s) {
	return s.replace(/<script.*?>.*?<\/script>/ig, '');
}

17、原生JavaScript动态加载脚本文件

function appendscript(src, text, reload, charset) {
	var id = hash(src + text);
	if(!reload && in_array(id, evalscripts)) return;
	if(reload && $(id)) {
		$(id).parentNode.removeChild($(id));
	}

	evalscripts.push(id);
	var scriptNode = document.createElement("script");
	scriptNode.type = "text/javascript";
	scriptNode.id = id;
	scriptNode.charset = charset ? charset : (BROWSER.firefox ? document.characterSet : document.charset);
	try {
		if(src) {
			scriptNode.src=\'#\'"  = false;
			scriptNode.onload = function () {
				scriptNode. = true;
				JSLOADED[src] = 1;
			};
			scriptNode.onreadystatechange = function () {
				if((scriptNode.readyState == 'loaded' || scriptNode.readyState == 'complete') && !scriptNode. {
					scriptNode. = true;
					JSLOADED[src] = 1;
				}
			};
		} else if(text){
			scriptNode.text = text;
		}
		document.getElementsByTagName('head')[0].appendChild(scriptNode);
	} catch(e) {}
}

18、原生JavaScript返回按ID检索的元素对象

function $(id) {
	return !id ? null : document.getElementById(id);
}

19、原生JavaScript返回浏览器版本内容

function browserVersion(types) {
	var other = 1;
	for(i in types) {
		var v = types[i] ? types[i] : i;
		if(USERAGENT.indexOf(v) != -1) {
			var re = new RegExp(v + '(\\/|\\s)([\\d\\.]+)', 'ig');
			var matches = re.exec(USERAGENT);
			var ver = matches != null ? matches[2] : 0;
			other = ver !== 0 && v != 'mozilla' ? 0 : other;
		}else {
			var ver = 0;
		}
		eval('BROWSER.' + i + '= ver');
	}
	BROWSER.other = other;
}

20、原生JavaScript元素显示的通用方法

function $(id) {
	return !id ? null : document.getElementById(id);
}
function display(id) {
	var obj = $(id);
	if(obj.style.visibility) {
		obj.style.visibility = obj.style.visibility == 'visible' ? 'hidden' : 'visible';
	} else {
		obj.style.display = obj.style.display == '' ? 'none' : '';
	}
}

21、原生JavaScript中有insertBefore方法,可惜却没有insertAfter方法?用如下函数实现

function insertAfter(newChild,refChild){ 
	var parElem=refChild.parentNode; 
	if(parElem.lastChild==refChild){ 
		refChild.appendChild(newChild); 
	}else{ 
		parElem.insertBefore(newChild,refChild.nextSibling); 
	} 
}

22、原生JavaScript中兼容浏览器绑定元素事件

function addEventSamp(obj,evt,fn){ 
	if (obj.addEventListener) { 
		obj.addEventListener(evt, fn, false); 
	}else if(obj.attachEvent){ 
		obj.attachEvent('on'+evt,fn); 
	} 
}

23、原生JavaScript光标停在文字的后面,文本框获得焦点时调用

function focusLast(){ 
	var e = event.srcElement; 
	var r =e.createTextRange(); 
	r.moveStart('character',e.value.length); 
	r.collapse(true); 
	r.select(); 
}

24、原生JavaScript检验URL链接是否有效

function getUrlState(URL){ 
	var xmlhttp = new ActiveXObject("microsoft.xmlhttp"); 
	xmlhttp.Open("GET",URL, false);  
	try{  
		xmlhttp.Send(); 
	}catch(e){
	}finally{ 
		var result = xmlhttp.responseText; 
		if(result){ 
			if(xmlhttp.Status==200){ 
				return(true); 
			}else{ 
				return(false); 
			} 
		}else{ 
			return(false); 
		} 
	} 
}

25、原生JavaScript格式化CSS样式代码

function formatCss(s){//格式化代码
	s = s.replace(/\s*([\{\}\:\;\,])\s*/g, "$1");
	s = s.replace(/;\s*;/g, ";"); //清除连续分号
	s = s.replace(/\,[\s\.\#\d]*{/g, "{");
	s = s.replace(/([^\s])\{([^\s])/g, "$1 {\n\t$2");
	s = s.replace(/([^\s])\}([^\n]*)/g, "$1\n}\n$2");
	s = s.replace(/([^\s]);([^\s\}])/g, "$1;\n\t$2");
	return s;
}

26、原生JavaScript压缩CSS样式代码

function yasuoCss (s) {//压缩代码
	s = s.replace(/\/\*(.|\n)*?\*\//g, ""); //删除注释
	s = s.replace(/\s*([\{\}\:\;\,])\s*/g, "$1");
	s = s.replace(/\,[\s\.\#\d]*\{/g, "{"); //容错处理
	s = s.replace(/;\s*;/g, ";"); //清除连续分号
	s = s.match(/^\s*(\S+(\s+\S+)*)\s*$/); //去掉首尾空白
	return (s == null) ? "" : s[1];
}

27、原生JavaScript获取当前路径

var currentPageUrl = "";
if (typeof this.href === "undefined") {
    currentPageUrl = document.location.toString().toLowerCase();
}
else {
    currentPageUrl = this.href.toString().toLowerCase();
}

28、原生JavaScriptIP转成整型

function _ip2int(ip){
    var num = 0;
    ip = ip.split(".");
    num = Number(ip[0]) * 256 * 256 * 256 + Number(ip[1]) * 256 * 256 + Number(ip[2]) * 256 + Number(ip[3]);
    num = num >>> 0;
    return num;
}

29、原生JavaScript整型解析为IP地址

function _int2iP(num){
    var str;
    var tt = new Array();
    tt[0] = (num >>> 24) >>> 0;
    tt[1] = ((num << 8) >>> 24) >>> 0;
    tt[2] = (num << 16) >>> 24;
    tt[3] = (num << 24) >>> 24;
    str = String(tt[0]) + "." + String(tt[1]) + "." + String(tt[2]) + "." + String(tt[3]);
    return str;
}

30、原生JavaScript实现checkbox全选与全不选

function checkAll() {
	var selectall = document.getElementById("selectall");
	var allbox = document.getElementsByName("allbox");
	if (selectall.checked) {
		for (var i = 0; i < allbox.length; i++) {
			allbox[i].checked = true;
		}
	} else {
		for (var i = 0; i < allbox.length; i++) {
			allbox[i].checked = false;
		}
	}
}

31、原生JavaScript判断是否移动设备

function isMobile(){
	if (typeof this._isMobile === 'boolean'){
		return this._isMobile;
	}
	var screenWidth = this.getScreenWidth();
	var fixViewPortsExperiment = rendererModel.runningExperiments.FixViewport || rendererModel.runningExperiments.fixviewport;
	var fixViewPortsExperimentRunning = fixViewPortsExperiment && (fixViewPortsExperiment.toLowerCase() === "new");
	if(!fixViewPortsExperiment){
		if(!this.isAppleMobileDevice()){
			screenWidth = screenWidth/window.devicePixelRatio;
		}
	}
	var isMobileScreenSize = screenWidth < 600;
	var isMobileUserAgent = false;
	this._isMobile = isMobileScreenSize && this.isTouchScreen();
	return this._isMobile;
}

32、原生JavaScript判断是否移动设备访问

function isMobileUserAgent(){
	return (/iphone|ipod|android.*mobile|windows.*phone|blackberry.*mobile/i.test(window.navigator.userAgent.toLowerCase()));
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

win7下结合wamp server和mod_wsgi搭配webpy开发开发环境

因为经常写wordpress项目,所以我的电脑上少不了wamp这样的php集成开发环境。但是今天我却是想使用我的wamp安装一个mod_wsgi.so 开发一个webpy的应用,所以就有了这一篇文章。

首先说一下我电脑上的wamp和python环境,关于如何安装python请google之。
我把python和wamp都安装在D盘,所以在D盘会看到了这么一个路径

D:/wamp/www
先在下面创建一个webpy应用的文件夹
我就把它叫webpy
并在webpy下创建一个static文件夹用来存放静态文件,如css js这些。

接下来先安装mod_wsgi模块,先到这里下载相应的模块文件。(https://code.google.com/p/modwsgi/wiki/DownloadTheSoftware?tm=2)
因为我的python环境是2.7,所以我就下载相应版本的mod_wsgi.so文件,下载后的文件名很长,改吧,直接改为mod_wsgi.so,然后放入D:\wamp\bin\apache\Apache2.2.17\modules中,再打开D:/wamp/alias文件夹,并为我们的webpy项目创建一个文件叫webpy.conf的配置文件。
写入下面的内容

#指定项目路径
WSGIScriptAlias /appname D:/wamp/www/webpy/
#指定静态文件路径
Alias /appname/static D:/wamp/www/webpy/static/
AddType text/html .py
<Directory D:/wamp/www/webpy>
Order deny,allow
Allow from all
</Directory>

现在重启一下wamp,如果能正常启动,恭喜了,证明你的mod_wsgi已经成功安装到wamp中,并且能成功加载。

每一次学习一个新的东西,我总喜欢写一个经典的hello world程序的,那么我们就直接复制webpy官网上的例子吧,

在D:/wamp/www/webpy下创建code.py文件

把下面的代码放进去

import web

urls = (
    '/.*', 'hello',
      )

class hello:
    def GET(self):
        return "Hello, world."

application = web.application(urls, globals()).wsgifunc()

接着访问一下http://127.0.0.1/appname/code.py/hello

看看是否能够成功看到hello world!

wordpress风格的hook和filter的php类

使用wordpress很久,很喜欢wordpress的hook和filter!最近想做一些商城的系统和erp整合,我第一时间想到的就是使用wordpress一样的类,商城网站有特定地方使用各种hook埋下钩子,触发各种事件,让商城系统和erp进行数据交互。DRY是一个很好的习惯,所以我在github上找到了一个不错的类
大家看我使用的代码:

<?php
include_once('php-hooks.php');
$hooks->add_action('header_action','testing');
$hooks->add_action('header_action','echo_this_in_header');

function echo_this_in_header(){
   echo 'this came from a hooked function';
}

echo '<div id="extra_header">';
$hooks->do_action('header_action');
echo '</div>';

function testing(){
	echo '<br><h2>hello world</h2><br>';
}

非常的简单明了!

记录ubuntu mod_wsgi部署django环境

好一番折腾,终于在ubuntu上部署好了一个django的环境,现在想想php的各种集成环境,python的php的这一点上也会让无数想学python的人望而生畏!挡下了不少的想深入学习这个语言的人啊!

我是在youtube上下了一个视看着一个一个字母敲出来的,

在linux上使用mod_wsgi做的环境,如何安装就不说了,ubuntu中安装mod_wsgi很方便。

部署django的环境也只要做两个文件,一个是apache的虚拟主机配置文件
我这里命名为firstweb.conf,保存于/ect/apache2/sites-available/文件夹下

<VirtualHost *:80>
WSGIScriptAlias / /var/www/firstweb/firstweb.wsgi

ServerName firstweb.com
Alias /static /var/www/firstweb/static
<Directory /var/www/firstweb/>
	Order allow,deny
	Allow from all
</Directory>
</VirtualHost>

创建文件后还要在终端在操作两步

sudo a2ensite firstweb.conf
sudo service apache2 reload

再在创建的django项目下创建一个firstweb.wsgi文件

import os 
import sys 
sys.path = ['/var/www/firstweb'] + sys.path
os.environ['DJANGO_SETTINGS_MODULE'] = 'firstweb.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

再之后就是修改/etc/hosts文件,本地解析域名

python字符串内置方法

在这一篇文章中, 我将告诉你如何使用python字符串的内置方法。

让我们首先创建一个字符变量,让其值为“Hello World”,

string = “Hello World”

我们可以使用下面的内置方法去操纵字符串。

string.upper() #get all-letters in uppercase
让所有字母大写
string.lower() #get all-letters in lowercase
让所有字母小写
string.capitalize() #capitalize the first letter
首字母大写
string.title() #capitalze the first letter of words
每个单词首字母大写
string.swapcase() #converts uppercase and lowercase
大小写转换
string.strip() #remove all white spaces
清除所有空字符
string.lstrip() #removes whitespace from left
清除左边空字符
string.rstrip() #removes whitespace from right
清除右边空字符
string.split() #splitting words
拆分单词
string.split(‘,’) #split words by comma
使用“,”拆分单词
string.count(‘l’) #count how many times l is in the string
计算字符l在整个字符串中出现次数
string.find(‘Wo’) #find the word Wo in the string
在字符串中查找Wo单词
string.index(“Wo”) #find the letters Wo in the string
查找字符串中饮食Wo字节
“:”.join(string) #add a : between every char
每个字节间添加“:”
” “.join(string) #add a whitespace between every char
每个字节间添加空白间隔
len(string) #find the length of the string
计算字符串长度
string.replace(‘World’, ‘Tomorrow’) #replace string World with Tomorrow
字符替换

原文链接:http://www.pythonforbeginners.com/python-strings/strings-built-in-methods/

python中清除html标签

python的string处理能力和php有一点不同,比如要清除一段文字中的html标签,php中就有直接的内置函数,而python则没有,google之后得到以下代码:

class MLStripper(HTMLParser):
    def __init__(self):
        self.reset()
        self.fed = []
    def handle_data(self, d):
        self.fed.append(d)
    def get_data(self):
        return ''.join(self.fed)

def strip_tags(html):
    s = MLStripper()
    s.feed(html)
    return s.get_data()

使用strip_tags()函数就可以把string中的html标签去掉!

wordpress菜单名称重命名

wordpress系统源于一个blog平台,慢慢地发展到今天的这样一个功能强大的cms系统!尽管如此,但是wordpress默认情况下文章页英文叫post, page,有时候,我们开发的时候,也许并不想要这个菜单还是显示着post,和page,也许你想要显示为其它的名称,比如“产品”,”联系人”亦或是其它的名称!当然我们可以自己写一个post type,移除原来的文章类型,新建的的内容类型可以自己命名,但是其实我们还有一个更好的方法对原来系统的内容类型菜单名称进行重命名:

看下面的一个国外的高手的代码:

<?php 
function change_post_menu_label() {
    global $menu;
    global $submenu;
    $menu[5][0] = 'Contacts';
    $submenu['edit.php'][5][0] = 'Contacts';
    $submenu['edit.php'][10][0] = 'Add Contacts';
    $submenu['edit.php'][15][0] = 'Status'; // Change name for categories
    $submenu['edit.php'][16][0] = 'Labels'; // Change name for tags
    echo '';
}

function change_post_object_label() {
        global $wp_post_types;
        $labels = &$wp_post_types['post']->labels;
        $labels->name = 'Contacts';
        $labels->singular_name = 'Contact';
        $labels->add_new = 'Add Contact';
        $labels->add_new_item = 'Add Contact';
        $labels->edit_item = 'Edit Contacts';
        $labels->new_item = 'Contact';
        $labels->view_item = 'View Contact';
        $labels->search_items = 'Search Contacts';
        $labels->not_found = 'No Contacts found';
        $labels->not_found_in_trash = 'No Contacts found in Trash';
    }
    add_action( 'init', 'change_post_object_label' );
    add_action( 'admin_menu', 'change_post_menu_label' );
To change the menu order, go with this:

// CUSTOMIZE ADMIN MENU ORDER
   function custom_menu_order($menu_ord) {
       if (!$menu_ord) return true;
       return array(
        'index.php', // this represents the dashboard link
        'edit.php', //the posts tab
        'upload.php', // the media manager
        'edit.php?post_type=page', //the posts tab
    );
   }
   add_filter('custom_menu_order', 'custom_menu_order');
   add_filter('menu_order', 'custom_menu_order');
?>

这一个代码中就是把原来的文章post的菜单名“post”更改为Contact了!

参考资料:http://wordpress.stackexchange.com/questions/9211/changing-admin-menu-labels

wordpress和飞信的整合插件

无意间在这个博客上看到有一个在“企鹅”工作的人写了这个飞信类,看着挺好的,测试也可用,就打算做成插件整合么wordpress上了!
现在是一个测试版本!还没有做好更多的事件通知功能!也没有做好自定义信息内容!

安装好插件后,到设置页面下面输入你的飞信帐号及密码!
如下图:

 

设置好帐号后,当你的wordpress博客发生如下情况的时候,就会自动地发布一条信息到你设置的手机帐号上!

用户注册
xmlrpc发布文章
评论发布
链接添加
主题切换
删除用户
密码重置
资料更新
分类添加
文章添加
页面添加

各种吐槽、支持抑或建议,请留言!

可以点击这里下载wp-fetion

php IXR_Library试用笔记

xml_rpc无疑是一个很有用的功能,最近因为在做一个wordpress多博客管理中心,以管理那些发布过的文章,所以深入了解了一下wordpress的xmlrpc api。

wordpress中的xml_rpc是使用一个开源类IXR_Library

根据上面的介绍我做了一个测试,很简单,却演示了xml_rpc数据传输的过程。

下载php本地开发环境wampserver。 在php中打开xmlrpc模块。

之后在wamp目录下创建服务端文件server.php 并写入代码:

require_once('IXR_Library.php');
function getTime($args) {
    return date('H:i:s');
}

function add($args) {
    return $args[0] + $args[1];
}

function addArray($array) {
    $total = 0;
    foreach ($array as $number) {
        $total += $number;
    }
    return implode(' + ', $array).' = '.$total;
}
/*创建xmlrpc服务,并将xml_rpc方法名指定函数*/
$server = new IXR_Server(array(
    'test.getTime' => 'getTime',
    'test.add' => 'add',
    'test.addArray' => 'addArray'
));

再创建客户端文件 client.php文件:

$client = new IXR_Client('http://localhost/xmlrpc/server.php');
if (!$client->query('test.add',15,14)) {
   die('An error occurred - '.$client->getErrorCode().":".$client->getErrorMessage());
}
print $client->getResponse();

这里使用发送一个xml请求,服务端文件接收到请求,并执行add函数。返回结果。

IXR类中还有很更高级的应该,比如客户端的IXR_ClientMulticall 多个请求同时发送执行。 服务端的自省功能IXR_IntrospectionServer