答案:
<a href=”http://mp.weixin.qq.com/mp/redirect?url=[url地址]#wechat_redirect" download>下载</a>
npm config set msvs_version 2012
或者
npm install <module> –msvs_version=2012
]]>
答案很简单:
cd -
/**!
@author zhaoxianlie(http://www.baidufe.com)
*/
var WeixinApi = (function () {
“use strict”;
/**
@p-config {Function} all(resp) 无论成功失败都会执行的回调
*/
function weixinShareTimeline(data, callbacks) {
callbacks = callbacks || {};
var shareTimeline = function (theData) {
WeixinJSBridge.invoke('shareTimeline', { "appid":theData.appId ? theData.appId : '', "img_url":theData.imgUrl, "link":theData.link, "desc":theData.title, "title":theData.desc, // 注意这里要分享出去的内容是desc "img_width":"640", "img_height":"640"}, function (resp) { switch (resp.err_msg) { // share_timeline:cancel 用户取消 case 'share_timeline:cancel': callbacks.cancel && callbacks.cancel(resp); break; // share_timeline:confirm 发送成功 case 'share_timeline:confirm': case 'share_timeline:ok': callbacks.confirm && callbacks.confirm(resp); break; // share_timeline:fail 发送失败 case 'share_timeline:fail': default: callbacks.fail && callbacks.fail(resp); break; } // 无论成功失败都会执行的回调 callbacks.all && callbacks.all(resp);});
};
WeixinJSBridge.on(‘menu:share:timeline’, function (argv) {
if (callbacks.async && callbacks.ready) { window["_wx_loadedCb_"] = callbacks.dataLoaded || new Function(); if(window["_wx_loadedCb_"].toString().indexOf("_wx_loadedCb_") > 0) { window["_wx_loadedCb_"] = new Function(); } callbacks.dataLoaded = function (newData) { window["_wx_loadedCb_"](newData); shareTimeline(newData); }; // 然后就绪 callbacks.ready && callbacks.ready(argv);} else { // 就绪状态 callbacks.ready && callbacks.ready(argv); shareTimeline(data);}
});
}
/**
@p-config {Function} all(resp) 无论成功失败都会执行的回调
*/
function weixinSendAppMessage(data, callbacks) {
callbacks = callbacks || {};
var sendAppMessage = function (theData) {
WeixinJSBridge.invoke('sendAppMessage', { "appid":theData.appId ? theData.appId : '', "img_url":theData.imgUrl, "link":theData.link, "desc":theData.desc, "title":theData.title, "img_width":"640", "img_height":"640"}, function (resp) { switch (resp.err_msg) { // send_app_msg:cancel 用户取消 case 'send_app_msg:cancel': callbacks.cancel && callbacks.cancel(resp); break; // send_app_msg:confirm 发送成功 case 'send_app_msg:confirm': case 'send_app_msg:ok': callbacks.confirm && callbacks.confirm(resp); break; // send_app_msg:fail 发送失败 case 'send_app_msg:fail': default: callbacks.fail && callbacks.fail(resp); break; } // 无论成功失败都会执行的回调 callbacks.all && callbacks.all(resp);});
};
WeixinJSBridge.on(‘menu:share:appmessage’, function (argv) {
if (callbacks.async && callbacks.ready) { window["_wx_loadedCb_"] = callbacks.dataLoaded || new Function(); if(window["_wx_loadedCb_"].toString().indexOf("_wx_loadedCb_") > 0) { window["_wx_loadedCb_"] = new Function(); } callbacks.dataLoaded = function (newData) { window["_wx_loadedCb_"](newData); sendAppMessage(newData); }; // 然后就绪 callbacks.ready && callbacks.ready(argv);} else { // 就绪状态 callbacks.ready && callbacks.ready(argv); sendAppMessage(data);}
});
}
/**
@p-config {Function} all(resp) 无论成功失败都会执行的回调
*/
function weixinShareWeibo(data, callbacks) {
callbacks = callbacks || {};
var shareWeibo = function (theData) {
WeixinJSBridge.invoke('shareWeibo', { "content":theData.desc, "url":theData.link}, function (resp) { switch (resp.err_msg) { // share_weibo:cancel 用户取消 case 'share_weibo:cancel': callbacks.cancel && callbacks.cancel(resp); break; // share_weibo:confirm 发送成功 case 'share_weibo:confirm': case 'share_weibo:ok': callbacks.confirm && callbacks.confirm(resp); break; // share_weibo:fail 发送失败 case 'share_weibo:fail': default: callbacks.fail && callbacks.fail(resp); break; } // 无论成功失败都会执行的回调 callbacks.all && callbacks.all(resp);});
};
WeixinJSBridge.on(‘menu:share:weibo’, function (argv) {
if (callbacks.async && callbacks.ready) { window["_wx_loadedCb_"] = callbacks.dataLoaded || new Function(); if(window["_wx_loadedCb_"].toString().indexOf("_wx_loadedCb_") > 0) { window["_wx_loadedCb_"] = new Function(); } callbacks.dataLoaded = function (newData) { window["_wx_loadedCb_"](newData); shareWeibo(newData); }; // 然后就绪 callbacks.ready && callbacks.ready(argv);} else { // 就绪状态 callbacks.ready && callbacks.ready(argv); shareWeibo(data);}
});
}
/**
@p-config {Function} all(resp,shareTo) 无论成功失败都会执行的回调
*/
function weixinGeneralShare(data, callbacks) {
callbacks = callbacks || {};
var generalShare = function (general,theData) {
// 如果是分享到朋友圈,则需要把title和desc交换一下if(general.shareTo == 'timeline') { var title = theData.title; theData.title = theData.desc || title; theData.desc = title;}// 分享出去general.generalShare({ "appid":theData.appId ? theData.appId : '', "img_url":theData.imgUrl, "link":theData.link, "desc":theData.desc, "title":theData.title, "img_width":"640", "img_height":"640"}, function (resp) { switch (resp.err_msg) { // general_share:cancel 用户取消 case 'general_share:cancel': callbacks.cancel && callbacks.cancel(resp ,general.shareTo); break; // general_share:confirm 发送成功 case 'general_share:confirm': case 'general_share:ok': callbacks.confirm && callbacks.confirm(resp ,general.shareTo); break; // general_share:fail 发送失败 case 'general_share:fail': default: callbacks.fail && callbacks.fail(resp ,general.shareTo); break; } // 无论成功失败都会执行的回调 callbacks.all && callbacks.all(resp ,general.shareTo);});
};
WeixinJSBridge.on(‘menu:general:share’, function (general) {
if (callbacks.async && callbacks.ready) { window["_wx_loadedCb_"] = callbacks.dataLoaded || new Function(); if(window["_wx_loadedCb_"].toString().indexOf("_wx_loadedCb_") > 0) { window["_wx_loadedCb_"] = new Function(); } callbacks.dataLoaded = function (newData) { window["_wx_loadedCb_"](newData); generalShare(general,newData); }; // 然后就绪 callbacks.ready && callbacks.ready(general,general.shareTo);} else { // 就绪状态 callbacks.ready && callbacks.ready(general,general.shareTo); generalShare(general,data);}
});
}
/**
@p-config {Function} confirm(resp) 成功
*/
function addContact(appWeixinId,callbacks){
callbacks = callbacks || {};
WeixinJSBridge.invoke(“addContact”, {
webtype: "1",username: appWeixinId
}, function (resp) {
var success = !resp.err_msg || "add_contact:ok" == resp.err_msg || "add_contact:added" == resp.err_msg;if(success) { callbacks.success && callbacks.success(resp);}else{ callbacks.fail && callbacks.fail(resp);}
})
}
/**
@param {Array} srcList 图片地址列表
*/
function imagePreview(curSrc,srcList) {
if(!curSrc || !srcList || srcList.length == 0) {
return;
}
WeixinJSBridge.invoke(‘imagePreview’, {
'current' : curSrc,'urls' : srcList
});
}
/**
显示网页右上角的按钮
*/
function showOptionMenu() {
WeixinJSBridge.call(‘showOptionMenu’);
}
/**
隐藏网页右上角的按钮
*/
function hideOptionMenu() {
WeixinJSBridge.call(‘hideOptionMenu’);
}
/**
显示底部工具栏
*/
function showToolbar() {
WeixinJSBridge.call(‘showToolbar’);
}
/**
隐藏底部工具栏
*/
function hideToolbar() {
WeixinJSBridge.call(‘hideToolbar’);
}
/**
@param callback
*/
function getNetworkType(callback) {
if (callback && typeof callback == ‘function’) {
WeixinJSBridge.invoke('getNetworkType', {}, function (e) { // 在这里拿到e.err_msg,这里面就包含了所有的网络类型 callback(e.err_msg);});
}
}
/**
关闭当前微信公众平台页面
*/
function closeWindow() {
WeixinJSBridge.call(“closeWindow”);
}
/**
@param readyCallback
*/
function wxJsBridgeReady(readyCallback) {
if (readyCallback && typeof readyCallback == ‘function’) {
var Api = this;var wxReadyFunc = function () { readyCallback(Api);};if (typeof window.WeixinJSBridge == "undefined"){ if (document.addEventListener) { document.addEventListener('WeixinJSBridgeReady', wxReadyFunc, false); } else if (document.attachEvent) { document.attachEvent('WeixinJSBridgeReady', wxReadyFunc); document.attachEvent('onWeixinJSBridgeReady', wxReadyFunc); }}else{ wxReadyFunc();}
}
}
/**
判断当前网页是否在微信内置浏览器中打开
*/
function openInWeixin(){
return /MicroMessenger/i.test(navigator.userAgent);
}
/*
打开扫描二维码
*/
function scanQRCode () {
WeixinJSBridge.invoke(“scanQRCode”);
}
return {
version :”2.2”,
ready :wxJsBridgeReady,
shareToTimeline :weixinShareTimeline,
shareToWeibo :weixinShareWeibo,
shareToFriend :weixinSendAppMessage,
generalShare :weixinGeneralShare,
addContact :addContact,
showOptionMenu :showOptionMenu,
hideOptionMenu :hideOptionMenu,
showToolbar :showToolbar,
hideToolbar :hideToolbar,
getNetworkType :getNetworkType,
imagePreview :imagePreview,
closeWindow :closeWindow,
openInWeixin :openInWeixin,
scanQRCode :scanQRCode
};
})();
#rpm –ivh vsftpd-2.0.5-10.el5.i386.rpm 安装rpm程序包
#service vsftpd start =/etc/init.d/vsftpd start 启动vsftpd服务
#service vsftpd stop =/etc/init.d/vsftpd stop 停止vsftpd服务
#service vsftpd restart =/etc/init.d/vsftpd restart 重启vsftpd服务
#service vsftpd status =/etc/init.d/vsftpd status 检查vsftpd服务状态
Vsftpd的配置文件:
/etc/vsftpd/vsftpd.conf
主配置文件
/usr/sbin/vsftpd
Vsftpd的主程序
/etc/rc.d/init.d/vsftpd
启动脚本
/etc/pam.d/vsftpd
PAM认证文件(此文件中file=/etc/vsftpd/ftpusers字段,指明阻止访问的用户来自/etc/vsftpd/ftpusers文件中的用户)
/etc/vsftpd/ftpusers
禁止使用vsftpd的用户列表文件。记录不允许访问FTP服务器的用户名单,管理员可以把一些对系统安全有威胁的用户账号记录在此文件中,以免用户从FTP登录后获得大于上传下载操作的权利,而对系统造成损坏。(注意:linux-4中此文件在/etc/目录下)
/etc/vsftpd/user_list
禁止或允许使用vsftpd的用户列表文件。这个文件中指定的用户缺省情况(即在/etc/vsftpd/vsftpd.conf中设置userlist_deny=YES)下也不能访问FTP服务器,在设置了userlist_deny=NO时,仅允许user_list中指定的用户访问FTP服务器。(注意:linux-4中此文件在/etc/目录下)
/var/ftp
匿名用户主目录;本地用户主目录为:/home/用户主目录,即登录后进入自己家目录
/var/ftp/pub
匿名用户的下载目录,此目录需赋权根chmod 1777 pub(1为特殊权限,使上载后无法删除)
/etc/logrotate.d/vsftpd.log
Vsftpd的日志文件
vsftpd的主配置文件/etc/vsftpd/vsftpd.conf说明(修改前先备份):
anonymous_enable=YES (是否允许匿名登录FTP服务器,默认设置为YES允许,即用户可使用用户名ftp或anonymous进行ftp登录,口令为用户的E-mail地址。如不允许匿名访问去掉前面#并设置为NO)
local_enable=YES (是否允许本地用户(即linux系统中的用户帐号)登录FTP服务器,默认设置为YES允许,本地用户登录后会进入用户主目录,而匿名用户登录后进入匿名用户的下载目录/var/ftp/pub;若只允许匿名用户访问,前面加上#,可阻止本地用户访问FTP服务器。)
write_enable=YES (是否允许本地用户对FTP服务器文件具有写权限,默认设置为YES允许)
#local_umask=022 (或其它值,设置本地用户的文件掩码为缺省022,也可根据个人喜好将其设置为其他值,默认值为077)
#anon_upload_enable=YES (是否允许匿名用户上传文件,须将write_enable=YES,默认设置为YES允许)
#anon_mkdir_write_enable=YES (是否允许匿名用户创建新文件夹,默认设置为YES允许)
#dirmessage_enable=YES (是否激活目录欢迎信息功能,当用户用CMD 模式首次访问服务器上某个目录时,FTP服务器将显示欢迎信息,默认情况下,欢迎信息是通过该目录下的.message文件获得的,此文件保存自定义的欢迎信息,由用户自己建立)
xferlog_enable=YES (默认值为NO如果启用此选项,系统将会维护记录服务器上传和下载情况的日志文件,默认情况该日志文件为/var/log/vsftpd.log,也可以通过下面的xferlog_file选项对其进行设定。)
connect_from_port_20=YES (设定FTP服务器将启用FTP数据端口的连接请求,ftp-data数据传输,21为连接控制端口)
#chown_uploads=YES(设定是否允许改变上传文件的属主,与下面一个设定项配合使用)
#chown_username=whoever (设置想要改变的上传文件的属主,如果需要,则输入一个系统用户名,例如可以把上传的文件都改成root属主。whoever:任何人)
#xferlog_file=/var/log/vsftpd.log(设定系统维护记录FTP服务器上传和下载情况的日志文件,/var/log/vsftpd.log是默认的,也可以另设其它)
#xferlog_std_format=YES(如果启用此选项,传输日志文件将以标准xferlog的格式书写,该格式的日志文件默认为/var/log/xferlog,也可以通过xferlog_file选项对其进行设定,默认值为NO)
#dual_log_enable(如果添加并启用此选项,将生成两个相似的日志文件,默认在/var/log/xferlog和/var/log/vsftpd.log目录下。前者是wu_ftpd类型的传输日志,可以利用标准日志工具对其进行分析;后者是vsftpd类型的日志)
#syslog_enable(如果添加并启用此选项,则原本应该输出到/var/log/vsftpd.log中的日志,将输出到系统日志中)
#idle_session_timeout=600 (设置数据传输中断间隔时间,此语句表示空闲的用户会话中断时间为600秒,即当数据传输结束后,用户连接FTP服务器的时间不应超过600秒,可以根据实际情况对该值进行修改)
#data_connection_timeout=120 (设置数据连接超时时间,该语句表示数据连接超时时间为120秒,可根据实际情况对其个修改)
#nopriv_user=ftpsecure (运行vsftpd需要的非特权系统用户,缺省是nobody)
#async_abor_enable=YES(如果FTP client会下达“async ABOR”这个指令时,这个设定才需要启用,而一般此设定并不安全,所以通常将其取消)
#ascii_upload_enable=YES (大多数FTP服务器都选择用ASCII方式传输数据,将#去掉就能实现用ASCII方式上传和下载文件)
#ascii_download_enable=YES (将#去掉就能实现用ASCII方式下载文件)
#ftpd_banner=Welcome to blah FTP service. (将#去掉可设置登录FTP服务器时显示的欢迎信息,可以修改=后的欢迎信息内容。另外如在需要设置更改目录欢迎信息的目录下创建名为.message的文件,并写入欢迎信息保存后,在进入到此目录会显示自定义欢迎信息)
#deny_email_enable=YES(可将某些特殊的email address抵挡住。如果以anonymous登录服务器时,会要求输入密码,也就是您的email address,如果很讨厌某些email address,就可以使用此设定来取消他的登录权限,但必须与下面的设置项配合)
#banned_email_file=/etc/vsftpd/banned_emails(当上面的deny_email_enable=YES时,可以利用这个设定项来规定那个email address不可登录vsftpd服务器,此文件需用户自己创建,一行一个email address即可!)
#chroot_list_enable=YES(设置为NO时,用户登录FTP服务器后具有访问自己目录以外的其他文件的权限,设置为YES时,用户被锁定在自己的home目录中,vsftpd将在下面chroot_list_file选项值的位置寻找chroot_list文件,此文件需用户建立,再将需锁定在自己home目录的用户列入其中,每行一个用户)
#chroot_list_file=/etc/vsftpd/chroot_list(此文件需自己建立,被列入此文件的用户,在登录后将不能切换到自己目录以外的其他目录,由FTP服务器自动地chrooted到用户自己的home目录下,使得chroot_list文件中的用户不能随意转到其他用户的FTP home目录下,从而有利于FTP服务器的安全管理和隐私保护)
#ls_recurse_enable=YES(是否允许递归查询,大型站点的FTP服务器启用此项可以方便远程用户查询)
listen=YES(如果设置为YES,则vsftpd将以独立模式运行,由vsftpd自己监听和处理连接请求)
#listen_ipv6=YES(设定是否支持IPV6)
#pam_service_name=vsftpd(设置PAM外挂模块提供的认证服务所使用的配置文件名,即/etc/pam.d/vsftpd文件,此文件中file=/etc/vsftpd/ftpusers字段,说明了PAM模块能抵挡的帐号内容来自文件/etc/vsftpd/ftpusers中)
#userlist_enable=YES/NO(此选项默认值为NO ,此时ftpusers文件中的用户禁止登录FTP服务器;若此项设为YES,则user_list文件中的用户允许登录 FTP服务器,而如果同时设置了userlist_deny=YES,则user_list文件中的用户将不允许登录FTP服务器,甚至连输入密码提示信息都没有,直接被FTP服务器拒绝)
#userlist_deny=YES/NO(此项默认为YES,设置是否阻扯user_list文件中的用户登录FTP服务器)
tcp_wrappers=YES (表明服务器使用tcp_wrappers作为主机访问控制方式,tcp_wrappers可以实现linux系统中网络服务的基于主机地址的访问控制,在/etc目录中的hosts.allow和hosts.deny两个文件用于设置tcp_wrappers的访问控制,前者设置允许访问记录,后者设置拒绝访问记录。例如想限制某些主机对FTP服务器192.168.57.2的匿名访问,编缉/etc/hosts.allow文件,如在下面增加两行命令:vsftpd:192.168.57.1:DENY 和vsftpd:192.168.57.9:DENY表明限制IP为192.168.57.1/192.168.57.9主机访问IP为192.168.57.2的FTP服务器,此时FTP服务器虽可以PING通,但无法连接)
在FTP服务器的管理中无论对本地用户还是匿名用户,对于FTP服务器资源的使用都需要进行控控制,避免由于负担过大造成FTP服务器运行异常,可以添加以下配置项对FTP客户机使用FTP服务器资源进行控制:
max_client设置项用于设置FTP服务器所允许的最大客户端连接数,值为0时表示不限制。例如max_client=100表示FTP服务器的所有客户端最大连接数不超过100个。
max_per_ip设置项用于设置对于同一IP地址允许的最大客户端连接数,值为0时表示不限制。例如max_per_ip=5表示同一IP地址的FTP客户机与FTP服务器建立的最大连接数不超过5个。
local_max_rate设置项用于设置本地用户的最大传输速率,单位为B/s,值为0时表示不限制。例如local_max_rate=500000表示FTP服务器的本地用户最大传输速率设置为500KB/s.
ano n_max_rate设置项用于设置匿名用户的最大传输速率,单位为B/s,值为0表示不限制。例如ano_max_rate=200000,表示FTP服务器的匿名用户最大传输速率设置为200KB/s.
vsftpd.user_list文件需要与vsftpd.conf文件中的配置项结合来实现对于vsftpd.user_list文件中指定用户账号的访问控制:
(1)设置禁止登录的用户账号
当vsftpd.conf配置文件中包括以下设置时,vsftpd.user_list文件中的用户账号被禁止进行FTP登录:
userlist_enable=YES
userlist_deny=YES
userlist_enable设置项设置使用vsftpd.user_list文件,userlist_deny设置为YES表示vsftpd.user_list文件用于设置禁止的用户账号。
(2)设置只允许登录的用户账号
当vsftpd.conf配置文件中包括以下设置时,只有vsftpd.user_list文件中的用户账号能够进行FTP登录:
userlist_enable=YES
userlist_deny=NO
userlist_enable设置项设置使用vsftpd.user_list文件,userlist _deny设置为NO表示vsftpd.usre_list文件用于设置只允许登录的用户账号,文件中未包括的用户账号被禁止FTP登录。
userlist_deny和userlist_enable选项限制用户登录FTP服务器(使用userlist_deny选项和user_list文件一起能有效阻止root,apache,www等系统用户登录FTP服务器,从而保证FTP服务器的分级安全性):
Userlist_enable=YES
Ftpusers中用户允许访问
User_list中用户允许访问
Userlist_enable=NO
Ftpusers中用户禁止访问
User_list中用户允许访问
Userlist_deny=YES
Ftpusers中用户禁止访问(登录时可以看到密码输入提示,但仍无法访问)
user_list 中用户禁止访问
Userlist_deny=NO
ftpusers中用户禁止访问
user_list中用户允许访问
Userlist_enable=YES 并且
Userlist_deny=YES
Ftpusers中用户禁止访问
User_list中用户禁止访问(登录时不会出现密码提示,直接被服务器拒绝)
Userlist_enable=YES 并且
Userlist_deny=NO
Ftpusers中用户禁止访问
User_list中用户允许访问
配置FTP服务器的虚拟用户
在vsftpd服务器中支持匿名用户,本地用户,和虚拟用户3类用户账号,用途及区别如下:
匿名用户是名为anonymous或ftp的FTP用户,匿名FTP用户登录后将FTP服务器中的/var/ftp作为FTP根目录。匿名用户通常用于提供公共文件的下载,如架设公共软件下载的FTP服务器,所有人都可以使用匿名用户进行软件下载。
本地用户账号是FTP服务器中的系统用户账号,使用FTP本地用户账号登录FTP服务器后,登录目录为本地用户的宿主目录。本地FTP用户账号通常和Web服务器一起提供虚拟主机服务,作为网页虚拟主机更新网页的途径。
虚拟用户账号是为了保证FTP服务器的安全性,由vsftpd服务器提供的非系统用户账号。虚拟用户FTP登录后将把指定的目录作为FTP根目录。虚拟用户与本地用户具有类似的功能,由于虚拟用户相对安全,因此正逐步替代本地用户账号。
由于虚拟用户账号具有较高的安全性,可以替代本地用户账号使用,下面是vsftpd虚拟用户账号设置的几个步骤:
以设置miket 和 john 两个虚拟用户帐号为例来配置vsftpd服务器
(1)建立虚拟用户口令库文件
建立虚拟用户的口令文件,文件中奇数行设置虚拟用户的用户名,偶数行设置用户的口令。例如,使用vi编辑器建立名为logins.txt的用户口令库文件,在文件中设置用户mike的口令为pwabcd,用户john 的口令是pw1234:
#vi logins.txt
mike (奇数行设置虚拟用户名)
pwabcd (偶数行设置用户口令)
john
pw1234
:wq(保存退出)
(2)生成vsftpd 的认证文件
使用db_load 命令生成认证文件。“-f”命令选项设置的值是虚拟用户的口令库文件,即上面创建的logins.txt。命令的参数设置为需要生成的认证文件名如 vsftpd_login.db,该文件放置在目录/etc/vsftpd/下:
#db_load -T -t hash –f logins.txt /etc/vsftpd_login.db (生成认证文件)
#file /etc/vsftpd/vsftpd_login.db (查看文件类型)
/etc/vsftpd/vsftpd_login.db:Berkeley DB (Hash,version 8 , native byte-order)
生成的认证文件的权限应设置为只对root用户可读可写,即600:
#chmod 600 /etc/vsftpd/vsftpd_login.db
(3)建立虚拟用户所需的PAM配置文件
在/etc/pam.d目录下建立vsftpd虚拟用户身份认证所需的PAM配置文件,名称是vsftpd.vu,内容为:
#cat /etc/pam.d/vsftpd.vu
auth required /lib/security/pam_userdb.so db=/etc/vsftpd/vsftpd_login
account required /lib/security/pam_userdb.so db=/etc/vsftpd/vsftpd_login
(4)建立虚拟用户及要访问的目录并设置相应的权限
建立vsftpd虚拟用户所需的系统用户账号,账号名为virtual,指定用户的宿主目录是/home/ftpsite,设置宿主目录的权限为700:
#useradd -d /home/ftpsite virtual
#chmod 700 /home/ftpsite/
这样vsftpd服务器中的所有虚拟用户账号登录后都将在/home/ftpsite目录中
(5)设置vsftpd.conf主配置文件
在对vsftpd.conf配置文件进行修改之前,应先将原有的文件进行备份,以便出现配置错误时可进行恢复:
#cd /etc/vsftpd
#cp vsftpd.conf vsftpd.conf.bak
在vsftpd.conf配置文件中添加虚拟用户的配置项,内容为:
guest_enable=YES
guest_username=virtual
pam_service_name=vsftpd.vu
(6)重新启动vsftpd服务程序
在对vsftpd.conf配置文件进行了任何修改后都需要重新启动vsftpd服务,以便配置生效:
#service vsftpd restart
(7)测试vsftpd中的虚拟用户账号:mike 或 john
在测试前可以先在/home/ftpsite目录中建立测试文件,用于测试时进行下载,并设置该文件的属主和属组为virtual
#touch /home/ftpsite/afile
#chown virtual.virtual /home/ftpsite/afile
使用ftp命令登录vsftpd服务器,并使用已配置的虚拟用户帐号mike进行登录
#ftp localhost
name (localhost:root):mike
password:
ftp>get afile
在完成虚拟用户的FTP登录后,可使用get命令下载测试文件,测试文件会保存到用户的当前目录中。
(8)对不同的虚拟用户设置不同的权限
vsftpd服务器中的虚拟用户可以灵活的针对不同的用户账号设置不同的用户权限,配置的步骤如下:
1.设置主配置文件
在vsftpd.conf配置文件中添加user_config_dir配置项,并设置用户配置文件的保存目录
user_config_dir=/etc/vsftpd_user_conf
在上面的配置实例中,设置在/etc/vsftpd_user_conf目录中保存虚拟用户的配置文件
2.建立用户配置文件目录
使用mkdir命令建立虚拟用户配置文件的保存目录
#mkdir /etc/vsftpd_user_conf
3.为虚拟用户建立单独的配置文件
在/etc/vsftpd_user_conf/目录中可以为每个虚拟用户建立独立的配置文件,配置文件名称和用户名相同。例如,为用户mike建立配置文件mike ,并将anon_world_readable_only设置为NO,表示用户具有浏览和下载的权限
#cat /etc/vsftpd_user_conf/mike
anon_world_readable_only=NO
为用户john建立配置文件john,并设置该用户具有浏览,下载,上传,改名,删除文件,建立和删除的权限。
#cat john
anon_world_readable_only=NO –表示用户可以浏览FTP目录和下载文件
anon_upload_enable=YES –表示用户可以上传文件
anon_mkdir_write_enable=YES –表示用户具有建立和删除目录的权利
anon_other_write_enable=YES –表示用户具有文件改名和删除文件的权限
通过对以上配置项的组合设置,vsftpd可以为每个虚拟用户配置不同的FTP权限,用户配置文件中没有的配置项将按照vsftpd.conf配置文件中的内容设置。
vsftpd服务器的其它主要设置:
1.最大传输速率设置:
设置匿名用户的最大传输率为20Kbps,修改/etc/vsftpd/vsftpd.conf添加语句:anon_max_rate=20000
设置本地帐号最大传输率为1Mbps,修改/etc/vsftpd/vsftpd.conf添加语句:local_max_rate=1000000
2.服务器最大并发数和用户最大线程数设置:
例如设置服务器允许的最大并发数为99,而每个用户同一时段的最大并发线程数为5,修改/etc/vsftpd/vsftpd.conf添加两行语句:max_clients=99 和 max_per_ip=5
3.修改默认端口:
默认FTP服务器端口号是21,出于安全目的,有时需修改默认端口号,修改/etc/vsftpd/vsftpd.conf
添加语句(例):listen_port=4449 该语句指定了修改后FTP服务器的端口号,应尽量大于4000,修改后访问
#ftp 192.168.57.2 4449(需加上正确的端口号了,否则不能正常连接)
4.设置用户组,增强FTP服务器安全性:
举例:
#mkdir –p /home/try 递归创建新目录
#groupadd try 新建组
#useradd –g try –d /home/try try1 新建用户try1并指定家目录和属组
#useradd –g try –d /home/try try2 新建用户try2并指定家目录和属组
#useradd –g try –d /home/try try3 新建用户try3并指定家目录和属组
#passwd try1 为新用户设密码
#passwd try2 为新用户设密码
#passwd try3 为新用户设密码
#chown try1 /home/try 设置目录属主为用户try1
#chown .try /home/try 设置目录属组为组try
#chmod 750 /home/try 设置目录访问权限try1为读,写,执行;try2,try3为读,执行
由于本地用户登录FTP服务器后进入自己主目录,而try1,try2 try3对主目录/home/try分配的权限不同,所以通过FTP访问的权限也不同,try1访问权限为:上传,下载,建目录 ;try2ty3访问权限为下载,浏览,不能建目录和上传。实现了群组中用户不同访问级别,加强了对FTP服务器的分级安全管理。
5.常见的vsftpd日志解决方案如下:
xferlog_enable=YES (表明FTP服务器记录上传下载的情况)
xferlog_std_format=YES (表明将记录的上传下载情况写在xferlog_file所指定的文件中,即xferlog_file选项指定的/var/log/xferlog文件中)
xferlog_file=/var/log/xferlog
dual_log_enable=YES (表明启用了双份日志,在用xferlog文件记录服务器上传下载情况的同时,vsftpd_log_file所指定的文件,即/var/log/vsftpd.log也将用来记录服务器的传输情况)
vsftpd_log_file=/var/log/vsftpd.log
vsftpdr的两个日志文件分析如下:
/var/log/xferlog 记录内容举例
Thu Sep 6 09:07:48 2007 7 192.168.57.1 4323279 /home/student/phpMyadmin-2.11.0-all-languages.tar.gz b – i r student ftp 0 * c
/var/log/vsftpd.log 记录内容举例
Tue Sep 11 14:59:03 2007 [pid 3460] CONNECT: Client “127.0.0.1”
Tue Sep 11 14:59:24 2007 [pid 3459] [ftp] OK LOGIN;Client “127.0.0.1” ,anon password ”?”
/var/log/xferlog日志文件中数据的分析和参数说明
记录数据 参数名称 参数说明
Thu Sep 6 09:07:48 2007 当前时间 当前服务器本地时间,格式为:
DDD MMM dd hh:mm:ss YYY
7 传输时间 传送文件所用时间,单位为秒
192.168.57.1 远程主机名称/IP 远程主机名称/IP
4323279 文件大小 传送文件的大小,单位为byte
/home/student/phpMyadmin-
2.11.0-all-languages.tar.gz 文件名 传输文件名,包括路径
b 传输类型 传输方式的类型,包括两种:
a以ASCII传输 b以二进制文件传输
– 特殊处理标志 特殊处理的标志位,可能的值包括:
_ 不做任何特殊处理
C 文件是压缩格式
U 文件是非压缩格式
T 文件是tar格式
i 传输方向 文件传输方向,包括两种:
o 从FTP服务器向客户端传输
i 从客户端向FTP服务器传输
r 访问模式 用户访问模式,包括:
a 匿名用户
g 来宾用户
r 真实用户,即系统中的用户
student 用户名 用户名称
ftp 服务名 所使用的服务名称,一般为FTP
0 认证方式 认证方式,包括:
0 无
1 RFC931认证
FTP命令 功能 FTP命令 功能
ls
显示服务器上的目录 ls [remote-dir][local-file] 显示远程目录remote-dir,并存入本地文件local-file
get remote-file [local-file]
从服务器下载指定文件到客户端 mget remote-files 下载多个远程文件(mget命令允许用通配符下载多个文件)
put local-file [remote-file]
从客户端上传指定文件到服务器 mput local-file 将多个文件上传至远程主机(mput命令允许用通配符上传多个文件)
open
连接FTP服务器 mdelete [remote-file] 删除远程主机文件
close
中断与远程服务器的ftp会话(与open对应) mkdir dir-name 在远程主机中创建目录
open host[port]
建立指定的ftp服务器连接,可指定连接端口 newer file-name 如果远程主机中file-name的修改时间比本地硬盘同名文件的时间更近,则重传该文件
cd directory
改变服务器的工作目录 rename [from][to] 更改远程主机的文件名
lcd directory
在客户端上(本地)改变工作目录 pwd 显示远程主机的当前工作目录
bye
退出FTP命令状态 quit 同bye,退出ftp会话
ascii
设置文件传输方式为ASCII模式 reget remote-file [local-file] 类似于get,但若local-file存在,则从上次传输中断处续传
binary
设置文件传输方式为二进制模式 rhelp [cmd-name] 请求获得远程主机的帮助
![cmd [args]]
在本地主机中交互shell后退回到ftp环境,如:!ls *.zip rstatus [file-name] 若未指定文件名,则显示远程主机的状态,否则显示文件状态
accout [password]
提供登录远程系统成功后访问系统资源所需的密码 hash 每传输1024字节,显示一个hash符号(#)
append local-file [remote-file]
将本地文件追加到远程系统主机,若未指定远程系统文件名,则使用本地文件名 restart marker 从指定的标志marker处,重新开始get或put,如restart 130
bye
退出ftp会话过程 rmdir dir-name 删除远程主机目录
case
在使用mget命令时,将远程主机文件名中的大写转为小写字母 size file-name 显示远程主机文件大小,如:
size idle 7200
cd remote-dir
进入远程主机目录 status 显示当前ftp状态
cdup
进入远程主机目录的父目录 system 显示远程主机的操作系统
delete remote-file
删除远程主机文件 user user-name [password][account] 向远程主机表明自己的身份,需要密码时,必须输入密码,如:user anonymous my@email
dir [remote-dir][local-file]
显示远程主机目录,并将结果存入本地文件 help [cmd] 显示ftp内部命令cmd的帮助信息,如help get
FTP数字代码的意义110 重新启动标记应答。
120 服务在多久时间内ready。
125 数据链路端口开启,准备传送。
150 文件状态正常,开启数据连接端口。
200 命令执行成功。
202 命令执行失败。
211 系统状态或是系统求助响应。
212 目录的状态。
213 文件的状态。
214 求助的讯息。
215 名称系统类型。
220 新的联机服务ready。
221 服务的控制连接端口关闭,可以注销。
225 数据连结开启,但无传输动作。
226 关闭数据连接端口,请求的文件操作成功。
227 进入passive mode。
230 使用者登入。
250 请求的文件操作完成。
257 显示目前的路径名称。
331 用户名称正确,需要密码。
332 登入时需要账号信息。
350 请求的操作需要进一部的命令。
421 无法提供服务,关闭控制连结。
425 无法开启数据链路。
426 关闭联机,终止传输。
450 请求的操作未执行。
451 命令终止:有本地的错误。
452 未执行命令:磁盘空间不足。
500 格式错误,无法识别命令。
501 参数语法错误。
502 命令执行失败。
503 命令顺序错误。
504 命令所接的参数不正确。
530 未登入。 532 储存文件需要账户登入。 550 未执行请求的操作。 551 请求的命令终止,类型未知。
552 请求的文件终止,储存位溢出。 553 未执行请求的的命令,名称不正确。
摘录一些选项
BEGIN:VCARD
FN:姓
N:名
NICKNAME:小名
TITLE:职位
ORG:公司(部门)
TEL;CELL:手机
LOGO:http://www.baidu.com/img/bd_logo.png
PHOTO:http://www.baidu.com/img/bd_logo.png
TEL;WORK:电话
TEL;WORK;FAX:传真
ADR;WORK:地址
URL:网址
EMAIL;WORK:邮箱
NOTE:备注
END:VCARD
var aCity = {
11: “北京”,
12: “天津”,
13: “河北”,
14: “山西”,
15: “内蒙古”,
21: “辽宁”,
22: “吉林”,
23: “黑龙江”,
31: “上海”,
32: “江苏”,
33: “浙江”,
34: “
安徽”,
35: “福建”,
36: “江西”,
37: “山东”,
41: “河南”,
42: “湖北”,
43: “湖南”,
44: “广东”,
45: “广西”,
46: “海南”,
50: “重庆”,
51: “四川”,
52: “贵州”,
53: “云南”,
54: “西藏”,
61: “陕西”,
62: “甘肃”,
63: “青海”,
64: “宁夏”,
65: “新疆”,
71: “台湾”,
81: “香港”,
82: “澳门”,
91: “国外”
}
function cidInfo(sId) { var iSum = 0 var info = "" if (!/^\d{17}(\d|x)$/i.test(sId)) return false; sId = sId.replace(/x$/i, "a"); if (aCity[parseInt(sId.substr(0, 2))] == null) return "Error:非法地区"; sBirthday = sId.substr(6, 4) + "-" + Number(sId.substr(10, 2)) + "-" + Number(sId.substr(12, 2)); var d = new Date(sBirthday.replace(/-/g, "/")) if (sBirthday != (d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate())) return "Error:非法生日"; for (var i = 17; i >= 0; i--) iSum += (Math.pow(2, i) % 11) * parseInt(sId.charAt(17 - i), 11) if (iSum % 11 != 1) return "Error:非法证号"; return aCity[parseInt(sId.substr(0, 2))] + "," + sBirthday + "," + (sId.substr(16, 1) % 2 ? "男" : "女")}</pre>
]]>
文本修改键,只适用于命令模式
光标移动键,命令模式下控制光标移动。
退出命令,除了ZZ命令外,都以”:”开始,用[Enter]结束命令行。
搜索命令
alter table user_movement_log
Add column GatewayId int not null default 0 AFTER Regionid
(在哪个字段后面添加)
删除字段:
alter table user_movement_log
drop column Gatewayid
调整字段顺序:
ALTER TABLE user_movement_log
CHANGE GatewayId
GatewayId
int not null default 0 AFTER RegionID
//主键
alter table tabelname add new_field_id int(5) unsigned default 0 not null auto_increment ,add primary key (new_field_id);
//增加一个新列
alter table t2 add d timestamp;
alter table infos add ex tinyint not null default ‘0’;
//删除列
alter table t2 drop column c;
//重命名列
alter table t1 change a b integer;
//改变列的类型
alter table t1 change b b bigint not null;
alter table infos change list list tinyint not null default ‘0’;
//重命名表
alter table t1 rename t2;
加索引
mysql> alter table tablename change depno depno int(5) not null;
mysql> alter table tablename add index 索引名 (字段名1[,字段名2 …]);
mysql> alter table tablename add index emp_name (name);
加主关键字的索引
mysql> alter table tablename add primary key(id);
加唯一限制条件的索引
mysql> alter table tablename add unique emp_name2(cardnumber);
删除某个索引
mysql>alter table tablename drop index emp_name;
修改表:
增加字段:
mysql> ALTER TABLE table_name ADD field_name field_type;
修改原字段名称及类型:
mysql> ALTER TABLE table_name CHANGE old_field_name new_field_name field_type;
删除字段:
mysql> ALTER TABLE table_name DROP field_name;
]]>HTML 版:
<meta http-equiv=”Cache-Control” content=”no-cache, no-store, must-revalidate” />
<meta http-equiv=”Pragma” content=”no-cache” />
<meta http-equiv=”Expires” content=”0” />
header(‘Cache-Control: no-cache, no-store, must-revalidate’); // HTTP 1.1.
header(‘Pragma: no-cache’); // HTTP 1.0.
header(‘Expires: 0’); // Proxies.
response.setHeader(“Cache-Control”, “no-cache, no-store, must-revalidate”); // HTTP 1.1.
response.setHeader(“Pragma”, “no-cache”); // HTTP 1.0.
response.setDateHeader(“Expires”, 0); // Proxies.
Response.AppendHeader(“Cache-Control”, “no-cache, no-store, must-revalidate”); // HTTP 1.1.
Response.AppendHeader(“Pragma”, “no-cache”); // HTTP 1.0.
Response.AppendHeader(“Expires”, “0”); // Proxies.
Response.addHeader “Cache-Control”, “no-cache, no-store, must-revalidate” ‘ HTTP 1.1.
Response.addHeader “Pragma”, “no-cache” ‘ HTTP 1.0.
Response.addHeader “Expires”, “0” ‘ Proxies.
response.headers[“Cache-Control”] = “no-cache, no-store, must-revalidate” // HTTP 1.1.
response.headers[“Pragma”] = “no-cache” // HTTP 1.0.
response.headers[“Expires”] = “0” // Proxies.
responseWriter.Header().Set(“Cache-Control”, “no-cache, no-store, must-revalidate”) // HTTP 1.1.
responseWriter.Header().Set(“Pragma”, “no-cache”) // HTTP 1.0.
responseWriter.Header().Set(“Expires”, “0”) // Proxies
<IfModule mod_headers.c>
Header set Cache-Control “no-cache, no-store, must-revalidate”
Header set Pragma “no-cache”
Header set Expires 0
</IfModule>
语句 | 语法 |
---|---|
AND / OR | SELECT column_name(s) FROM table_name WHERE condition AND|OR condition |
ALTER TABLE (add column) | ALTER TABLE table_name ADD column_name datatype |
ALTER TABLE (drop column) | ALTER TABLE table_name DROP COLUMN column_name |
AS (alias for column) | SELECT column_name AS column_alias FROM table_name |
AS (alias for table) | SELECT column_name FROM table_name AS table_alias |
BETWEEN | SELECT column_name(s) FROM table_name WHERE column_name BETWEEN value1 AND value2 |
CREATE DATABASE | CREATE DATABASE database_name |
CREATE INDEX | CREATE INDEX index_name ON table_name (column_name) |
CREATE TABLE | CREATE TABLE table_name ( column_name1 data_type, column_name2 data_type, ……. ) |
CREATE UNIQUE INDEX | CREATE UNIQUE INDEX index_name ON table_name (column_name) |
CREATE VIEW | CREATE VIEW view_name AS SELECT column_name(s) FROM table_name WHERE condition |
DELETE FROM | DELETE FROM table_name (Note: Deletes the entire table!!)_or_ DELETE FROM table_name WHERE condition |
DROP DATABASE | DROP DATABASE database_name |
DROP INDEX | DROP INDEX table_name.index_name |
DROP TABLE | DROP TABLE table_name |
GROUP BY | SELECT column_name1,SUM(column_name2) FROM table_name GROUP BY column_name1 |
HAVING | SELECT column_name1,SUM(column_name2) FROM table_name GROUP BY column_name1 HAVING SUM(column_name2) condition value |
IN | SELECT column_name(s) FROM table_name WHERE column_name IN (value1,value2,..) |
INSERT INTO | INSERT INTO table_name VALUES (value1, value2,….)_or_ INSERT INTO table_name (column_name1, column_name2,…) VALUES (value1, value2,….) |
LIKE | SELECT column_name(s) FROM table_name WHERE column_name LIKE pattern |
ORDER BY | SELECT column_name(s) FROM table_name ORDER BY column_name [ASC|DESC] |
SELECT | SELECT column_name(s) FROM table_name |
SELECT | SELECT FROM table_name |
SELECT DISTINCT | SELECT DISTINCT column_name(s) FROM table_name |
SELECT INTO (used to create backup copies of tables) | SELECT * INTO new_table_name FROM original_table_name_or_ SELECT column_name(s) INTO new_table_name FROM original_table_name |
TRUNCATE TABLE (deletes only the data inside the table) | TRUNCATE TABLE table_name |
UPDATE | UPDATE table_name SET column_name=new_value [, column_name=new_value] WHERE column_name=some_value |
WHERE | SELECT column_name(s) FROM table_name WHERE condition |
我们可以利用MySQL中SELECT支持的一个子句——LIMIT——来完成这项功能。
LIMIT可以实现top N查询,也可以实现M至N(某一段)的记录查询,具体语法如下:
SELECT * FROM MYTABLE
ORDER BY AFIELD
LIMIT offset, recnum
其中offset为从第几条(M+1)记录开始,recnum为返回的记录条数。例:
select * from mytable
order by afield
limit 2, 5
常见算法是js实现汇总
/去重/
<script>
function delRepeat(arr){
var newArray=new Array();
var len=arr.length;
for(var i=0;i<len;i++){
for(var j=i+1;j<len;j++) { if(arr[i]==arr[j]) { ++i; } }newArray.push(arr[i]);
}
return newArray;
}
var arr=new Array(“red”,”red”,”1”,”5”,”2”);
alert(delRepeat(arr));
</script>
/二分法/
又称为折半查找算法,但是有缺陷就是要求数字是预先排序好的
<script>
function binary(items,value){
var startIndex=0,
stopIndex=items.length-1,midlleIndex=(startIndex+stopIndex)>>>1;while(items[middleIndex]!=value && startIndex<stopIndex){ if(items[middleIndex]>value){ stopIndex=middleIndex-1; }else{ startIndex=middleIndex+1; } middleIndex=(startIndex+stopIndex)>>>1;}return items[middleIndex]!=value ? false:true;
}
</script>
/十六进制颜色值的随机生成/
function randomColor(){
var arrHex=[“0”,”2”,”3”,”4”,”5”,”6”,”7”,”8”,”9”,”a”,”b”,”c”,”d”],
strHex="#",index;for(var i=0;i<6;i++){ index=Math.round(Math.random()*15); strHex+=arrHex[index];}
return strHex;
}
/一个求字符串长度的方法/
function GetBytes(str){
var len=str.length,
bytes=len;
for(var i=0;i<len;i++){
if(str.CharCodeAt>255){
bytes++;
}
}
return bytes;
}
/插入排序/
所谓的插入排序,就是将序列中的第一个元素看成一个有序的子序列,然后不段向后比较交换比较交换。
———————————华丽丽的分割线————————————-
function insertSort(arr){
var key;
for(var j = 1; j < arr.length ; j++){
//排好序的 var i = j - 1; key = arr[j]; while(i >= 0 && arr[i] > key){ arr[i + 1] = arr[i]; i --; }arr[i + 1] = key;
}
return arr;
}
/希尔排序/
希尔排序,也称递减增量排序算法具体描述:http://zh.wikipedia.org/zh/%E5%B8%8C%E5%B0%94%E6%8E%92%E5%BA%8F
其实说到底也是插入排序的变种
function shellSort(array){
var stepArr = [1750, 701, 301, 132, 57, 23, 10, 4, 1]; // reverse()在维基上看到这个最优的步长较小数组 var i = 0; var stepArrLength = stepArr.length; var len = array.length; var len2 = parseInt(len/2); for(;i < stepArrLength; i++){ if(stepArr[i] > len2){ continue; } stepSort(stepArr[i]); } // 排序一个步长 function stepSort(step){ //console.log(step) 使用的步长统计 var i = 0, j = 0, f, tem, key; var stepLen = len%step > 0 ? parseInt(len/step) + 1 : len/step; for(;i < step; i++){// 依次循环列 for(j=1;/*j < stepLen && */step * j + i < len; j++){//依次循环每列的每行 tem = f = step * j + i; key = array[f]; while((tem-=step) >= 0){// 依次向上查找 if(array[tem] > key){ array[tem+step] = array[tem]; }else{ break; } } array[tem + step ] = key; } } } return array;
}
/快速排序/
其实说到底快速排序算法就系对冒泡排序的一种改进,采用的就是算法理论中的分治递归的思想,说得明白点,它的做法就是:通过一趟排序将待排序的纪录分割成两部分,其中一部分的纪录值比另外一部分的纪录值要小,就可以继续分别对这两部分纪录进行排序;不段的递归实施上面两个操作,从而实现纪录值的排序。
这么说可能不是很清晰,直接上代码:
<script>
function sort(arr){
return quickSort(arr,0,arr.length-1);
function quickSort(arr,l,r){
if(l<r){ var mid=arr[parseInt((l+r)/2)],i=l-1,j=r+1; while(true){ //大的放到右边,小的放到左边, i与j均为游标 while(arr[++i]<mid); while(arr[--j]>mid); if(i>=j)break;//判断条件 var temp = arr[i]; arr[i]=arr[j]; arr[j]=temp; } quickSort(arr,l,i-1); quickSort(arr,j+1,r); }return arr;
}
}
function main(){
var list=new Array(49,38,65,97,76,13,27);
document.write(sort(list).valueOf());
}
main();
</script>
原理图:
/冒泡法/
function bullSort(array){
var temp;
for(var i=0;i<array.length;i++){
for(var j=array.length-1;j>i;j–){
if(array[j]<array[j-1]){ temp = array[j]; array[j]=array[j-1]; array[j-1]=temp;}
}
}
return array;
}
/js递归实现方案/
递归函数是在一个函数通过调用自身的情况下去解决的:
方式如下:
function factorial(num){
if(num<=1){return 1;
}else{
return num*factorial(num-1);
}
}
但是这在js里面可能会出现错误:
var anotherFactorial = factorial;
factorial=null;
alert(anoterFactorial(4));
因为在调用anoterFactorial时内部的factorial已经不存在了。
解决方法是通过arguments.callee来解决。
如下:
function factorial(num){
if(num<=1){
return 1;
}else{
return num*arguments.callee(num-1);
}
var anotherFactorial = factorial;
factorial = null;
alert(anotherFactorial(4));
}
成功!!!!
/js模拟多线程/
<html><head><title>emu – 用command模式模拟多线程</title></head><body>
<SCRIPT LANGUAGE=”JavaScript”>
<!–
if (Array.prototype.shift==null)
Array.prototype.shift = function (){
var rs = this[0];for (var i=1;i<this.length;i++) this[i-1]=this[i]this.length=this.length-1return rs;
}
if (Array.prototype.push==null)
Array.prototype.push = function (){
for (var i=0;i<arguments.length;i++) this[this.length]=arguments[i];return this.length;
}
var commandList = [];
var nAction = 0;//控制每次运行多少个动作
var functionConstructor = function(){}.constructor;
function executeCommands(){
for (var i=0;i<nAction;i++) if (commandList.length>0){ var command = commandList.shift(); if (command.constructor == functionConstructor) if (command.scheduleTime == null || new Date()-command.scheduleTime>0) command(); else commandList.push(command); }
}
function startNewTask(){
var resultTemp = document.getElementById("sampleResult").cloneNode(true);with (resultTemp){id="";style.display="block";style.color=(Math.floor(Math.random()* (1<<23)).toString(16)+"00000").substring(0,6);}document.body.insertBefore(resultTemp,document.body.lastChild);commandList.push(function(){simThread(resultTemp,1);});nAction++;
}
function simThread(temp,n){
if (temp.stop) n--;else temp.innerHTML = temp.innerHTML - (-n);if (n<1000) commandList.push(function(){simThread(temp,++n)});else{ var command = function(){document.body.removeChild(temp);;nAction--;}; command.scheduleTime = new Date()-(-2000); commandList.push(command);}
}
window.onload = function(){setInterval(“executeCommands()”,1);}
//–>
</SCRIPT>
<button onClick=”startNewTask()”>开始新线程</button>
<BR><BR>
<div id=sampleResult onMouseOver=”this.stop=true” onMouseOut=”this.stop=false” >0</div>
</body>
</html>
/选择法排序/
选择法主要有三种:
《1》简单的选择排序:简单的前后交互。
/简单选择法排序/
其实基本的思想就是从待排序的数组中选择最小或者最大的,放在起始位置,然后从剩下的数组中选择最小或者最大的排在这公司数的后面。
http://zh.wikipedia.org/wiki/%E9%80%89%E6%8B%A9%E6%8E%92%E5%BA%8F
function selectionSort(data)
{
var i, j, min, temp , count=data.length;for(i = 0; i < count - 1; i++) { /* find the minimum */ min = i; for (j = i+1; j < count; j++) { if (data[j] < data[min]) { min = j;} } /* swap data[i] and data[min] */ temp = data[i]; data[i] = data[min]; data[min] = temp;}
return data;
}
《2》树型排序:又称锦标赛排序,首先对n个元素进行两两比较,然后在其中[n/2]个较小者再进行两两比较如此重复直至选出最小的关键字的纪录为止。(可用完全二差树表示)。缺点:辅助空间需求过大,和“最大值”进行多余比较
《3》堆排序:(不适用于纪录数较少的文件)
堆排序算法的过程如下:
1)得到当前序列的最小(大)的元素
2)把这个元素和最后一个元素进行交换,这样当前的最小(大)的元素就放在了序列的最后,而原先的最后一个元素放到了序列的最前面
3)的交换可能会破坏堆序列的性质(注意此时的序列是除去已经放在最后面的元素),因此需要对序列进行调整,使之满足于上面堆的性质.
重复上面的过程,直到序列调整完毕为止.
js实现:
<script>
/**
堆排序
@param items 数组
@return 排序后的数组
*/
function heapSort(items)
{
items = array2heap(items); //将数组转化为堆
for(var i = items.length - 1; i >= 0; i–)
{
items = swap(items, 0, i); //将根和位置i的数据交换(用于将最大值放在最后面)items = moveDown(items, 0, i - 1); //数据交换后恢复堆的属性
}
return items;
}
/**
将数组转换为堆
@param items 数组
@return 堆
*/
function array2heap(items)
{
for(var i = Math.ceil(items.length / 2) - 1; i >= 0; i–)
{
items = moveDown(items, i, items.length - 1); //转换为堆属性
}
return items;
}
/**
转换为堆
@param items 数组
@param first 第一个元素
@param last 最后一个元素
@return 堆
*/
function moveDown(items, first, last)
{
var largest = 2 * first + 1;
while(largest <= last)
{
if(largest < last && items[largest] < items[largest + 1]){ largest++;}if(items[first] < items[largest]){ items = swap(items, first, largest); // 交换数据 first = largest; //往下移 largest = 2 * first + 1;}else{ largest = last + 1; //跳出循环}
}
return items;
}
/**
交换数据
@param items 数组
@param index1 索引1
@param index2 索引2
@return 数据交换后的数组
*/
function swap(items, index1, index2)
{
var tmp = items[index1];
items[index1] = items[index2];
items[index2] = tmp;
return items;
}
var a = [345,44,6,454,10,154,3,12,11,4,78,9,0,47,88,9453,4,65,1,5];
document.write(heapSort(a));
</script>
所谓归并就是将两个或者两个以上的有序表合成一个新的有序表。
递归形式的算法在形式上较为简洁但实用性较差,与快速排序和堆排序相比,归并排序的最大特点是,它是一种稳定的排序方法。
js实现归并:
<script>
function MemeryArray(Arr,n, Brr, m)
{ var i, j, k;
var Crr=new Array(); i = j = k = 0;while (i < n && j < m){ if (Arr[i] < Brr[j]) Crr[k++] = Arr[i++]; else Crr[k++] = Brr[j++];}while (i < n) Crr[k++] = Arr[i++];while (j < m) Crr[k++] = Brr[j++];
return Crr;
}
var Arr=new Array(45,36,89,75,65);
var Brr=new Array(48,76,59,49,25);
alert(MemeryArray(Arr , Arr.length , Brr , Brr.length));
</script>
归并排序:
<script>
//将有二个有序数列a[first…mid]和a[mid…last]合并。
function mergearray(Arr,first,mid,last,tempArr)
{
var i = first, j = mid + 1;var m = mid, n = last;var k = 0;while (i <= m && j <= n){ if (Arr[i] < Arr[j]) tempArr[k++] = Arr[i++]; else tempArr[k++] = Arr[j++];}while (i <= m) tempArr[k++] = Arr[i++];while (j <= n) tempArr[k++] = Arr[j++];for (i = 0; i < k; i++) Arr[first + i] = tempArr[i];
}
function mergesort(Arr,first,last)
{
var tempArr=new Array();if (first < last){ var mid = (first + last)>>>1; mergesort(Arr, first, mid, tempArr); //左边有序 mergesort(Arr, mid + 1, last, tempArr); //右边有序 mergearray(Arr, first, mid, last, tempArr); //再将二个有序数列合并}
return Arr;
}
var Arr=new Array(1,65,45,98,56,78);
alert(mergesort(Arr,0,Arr.length-1));
</script>
/比较两个字符串的相似性-Levenshtein算法简介/
问题与描述:
近似字符串匹配问题
说明:设给定样本,对于任意文本串,样本P在文本T中的K-近似匹配(K-approximate match)是指P在T中包含最多K个差异的匹配,这里的差别指:
(1)修改:P与T中对应的字符不同
(2)删除:T中含有一个未出现在P中的字符
(3)插入:T中不包含出现在P中的一个字符
(也就是编辑距离问题)
例如:
T: a p r o x i o m a l l y
P: a p p r o x i m a t l y
经过 1:插入 2:删除 3:修改
那么 就是一个3-近似问题
事实上,两个字符串可能有不得出不同的差别数量,所以K-近似匹配要求:
(1)差别数最多为K个
(2)差别数为所有匹配方式下最少的称为编辑距离
(字符串T到P最少的差别数称为T和P的编辑距离)
试验要求:
(1)利用动态规划方法给出两个字符串编辑距离的算法
(2)分析复杂度
(3)考虑其它方法
Levenshtein Distance 来文史特距离
goodzzp
LD也叫edit distance,它用来表示2个字符串的相似度,不同于Hamming Distance,它可以用来比较2个长度不同的字符串。LD定义为需要最少多少步基本操作才能让2个字符串相等,基本操作包含3个:
1,插入;
2,删除;
3,替换;
比如,kiteen和sitting之间的距离可以这么计算:
1,kitten – > sitten, 替换k为s;
2,sitten – > sittin, 替换e为i;
3,sittin – > sitting, 增加g;
所以,其LD为3;
计算LD的算法表示为:
int LevenshteinDistance(char str1[1..lenStr1], char str2[1..lenStr2])
// d is a table with lenStr1+1 rows and lenStr2+1 columns
declare int d[0..lenStr1, 0..lenStr2]
// i and j are used to iterate over str1 and str2
declare int i, j, cost
for i from 0 to lenStr1
d[i, 0] := i
for j from 0 to lenStr2
d[0, j] := j
for i from 1 to lenStr1
for j from 1 to lenStr2
if str1[i] = str2[j] then cost := 0
else cost := 1
d[i, j] := minimum(
d[i-1, j ] + 1, // deletion
d[i , j-1] + 1, // insertion
d[i-1, j-1] + cost // substitution
)
return d[lenStr1, lenStr2];
这个算法其实就是一个矩阵的计算:
k i t t e n
0 1 2 3 4 5 6
s 1 1 2 3 4 5 6
i 2 2 1 2 3 4 5
t 3 3 2 1 2 3 4
t 4 4 3 2 1 2 3
i 5 5 4 3 2 2 3
n 6 6 5 4 3 3 2
g 7 7 6 5 4 4 3
首先给定第一行和第一列,然后,每个值d[i,j]这样计算:d[i,j] = min(d[i-1,j]+ 1,d[i,j-1] +1,d[i-1,j-1]+(str1[i] == str2[j]?0:1));
最后一行,最后一列的那个值就是LD的结果。
LD(str1,str2) <= max(str1.len,str2.len);
有人提出了Levenshtein automaton(Levenshtein自动机)来计算和某个字符串距离小于某个值的集合。这样能够加快近似字符串的计算过程。见文献:Klaus U. Schulz, Stoyan Mihov, Fast String Correction with Levenshtein-Automata. International Journal of Document Analysis and Recognition, 5(1):67–85, 2002.
A Guided Tour to Approximate String Matching GONZALO NAVARRO
这篇文章里面对这个方面(字符串相似)进行了很多描述。其中,包含了动态规划法计算Edit distance的方法。
js实现:
<script>
//求两个字符串的相似度,返回差别字符数,Levenshtein Distance算法实现
function Levenshtein_Distance(s,t){
var n=s.length;// length of s
var m=t.length;// length of t
var d=[];// matrix
var i;// iterates through s
var j;// iterates through t
var s_i;// ith character of s
var t_j;// jth character of t
var cost;// cost
// Step 1
if (n == 0) return m;
if (m == 0) return n;
// Step 2
for (i = 0; i <= n; i++) {
d[i]=[];
d[i][0] = i;
}
for (j = 0; j <= m; j++) {
d[0][j] = j;
}
// Step 3
for (i = 1; i <= n; i++) {
s_i = s.charAt (i - 1);
// Step 4
for (j = 1; j <= m; j++) {
t_j = t.charAt (j - 1);
// Step 5
if (s_i == t_j) {
cost = 0;
}else{
cost = 1;
}
// Step 6
d[i][j] = Minimum (d[i-1][j]+1, d[i][j-1]+1, d[i-1][j-1] + cost);
}
}
// Step 7
return d[n][m];
}
//求两个字符串的相似度,返回相似度百分比
function Levenshtein_Distance_Percent(s,t){
var l=s.length>t.length?s.length:t.length;
var d=Levenshtein_Distance(s,t);
return (1-d/l).toFixed(4);
}
//求三个数字中的最小值
function Minimum(a,b,c){
return a<b?(a<c?a:c):(b<c?b:c);
}
</script>
#设置http
npm config set proxy http://xxx.com:8080
#设置https
npm config set https-proxy https://xxx.com:8080
#如果没有https代理 改变npm仓库的地址 registry
npm config set registry “http://registry.npmjs.org/"
//汉字转化成 实体
function ascii(str) {
return str.replace(/[^\u0000-\u00FF]/g, function($0) {
return escape($0).replace(/(%u)(\w{4})/gi, “\&#x$2;”)
});
}
// 汉字转化成 unicode
function unicode(str) {
return str.replace(/[^\u0000-\u00FF]/g, function($0) {
return escape($0).replace(/(%u)(\w{4})/gi, “\u$2”)
});
}
// unicode 转 汉字
function reconvert(str) {
str = str.replace(/(\u)(\w{4})/gi, function($0) {
return (String.fromCharCode(parseInt((escape($0).replace(/(%5Cu)(\w{4})/g, “$2”)), 16)));
});
str = str.replace(/(&#x)(\w{4});/gi, function($0) {
return String.fromCharCode(parseInt(escape($0).replace(/(%26%23x)(\w{4})(%3B)/g, “$2”), 16));
});
return str;
}
如题 如何实现呢,废话不多讲 直接上代码!
[code]
<style>
dt {position: absolute;} //就是这句话
</style>
<dl>
<dt>标题</dt>
<dd>实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的实得分实得分是的</dd>
</dl>
代码虽简单,里面用到的 知识还是比较全面的,可以做一个考题。
]]>
一个段落是由一个或多个连续的行构成,段落间靠一个或以上视觉上的空行划分。一般的段落不应该用空格或制表符缩进。
这是一个段落。它有两个句子。这是另一个段落。它也有 两个句子。
![Foo](http://www.baidu.com/aaa.png)
在文本中输入的换行会从最终生成的结果中删除,浏览器会根据可用空间自动换行。如果想强迫换行,可以在行尾插入至少两个空格。
*强调* **或者** _强调_ _(示例:斜体)_
**加重强调** **或者** __加重强调__ **(示例:粗体)**
***特别强调*** **或者** ___特别强调___ _**(示例:粗斜体)**_
要在Markdown中插入代码,你有两种选择。 一种是把代码用反引号(`)(键盘上Esc键下面的键)包起,例如:
夹杂着`一些代码`的文字内容,又或者以制表符或至少四个空格缩进的行,例如:
第一行代码 第二行代码 第三行代码后面一种用法会让Markdown保留所有的空白字符——而与之相反,一般情况下,Markdown会删除所有换行和空格,打乱原有的缩进和排版。### 列表
* 无序(没有编号的)列表中的一项 * 一个子项,要以一个制表符或者4个空格缩进 * 无序列表中的另一个项
1\. 有序(排好序,有编号的)列表中的一项 - 有序列表中的另一个项
可以在标题内容前输入特定数量的井号(‘#’)来实现对应级别的HTML样式的标题(HTML提供六级标题)。例如:
# 一级标题
#### 四级标题一级和二级标题还有一种写法:
一级标题===================二级标题--------------------
如果你真的想在Markdown中插入换行标签<br/>,你可以在行尾输入两个或以上的空格,然后回车。 这样插入换行十分麻烦,但是“每个换行都转换为<br/>”在 Markdown中并不合适,所以只在你确定你需要时手动添加。
引用只需要在被引用的内容段落开头加上右尖括号(‘>’)即可。你可以选择只在开头加一个。也可以在每行前面都加一个,效果是一样的。
> 这一整段的内容都会作为一个HTML的引用元素。引用元素是会自动优化排版的(reflowable,可回流)。你可以任意地将引用的内容包含进来,然后所有这些都会被解析成为单独一个引用元素。上述内容会转换成以下HTML内容:
<blockquote><p>这一整段的内容都会作为一个HTML的引用元素。引用元素是会自动优化排版的(reflowable,可回流)。你可以任意地将引用的内容包含进来,然后所有这些都会被解析成为单独一个引用元素。</p></blockquote>
> 这是一个引用。这是第一行这是第二行。>> 这是一个嵌套的引用。这是第一行。这是第二行> > 外层引用的第三行。前面需要一个视觉上的空行表示内层嵌套的结束,空行前面的('>')可以有可以没有。
链接可以在行内插入:
[链接文字](链接地址)例子: [Markdown]([http://zh.wikipedia.com/wiki/Markdown](http://zh.wikipedia.com/wiki/Markdown))另一种选择是,链接地址可以放在段落后面的脚注,前面放上链接引用标签区分。举例说,先在内容行内插入以下内容:
[链接文字][链接引用标签]然后在段落的后面(或者文档的结尾)放上以下内容,就可以生成一个链接:
[链接引用标签]: 链接地址 "链接标题"
要生成水平分割线,可以在单独一行里输入3个或以上的短横线、星号或者下划线实现。短横线和星号之间可以输入任意空格。以下每一行都产生一条水平分割线。
* * *********- - ----------------------------------------]]>
Markdown同时还是一个由Gruber编写的Perl脚本:Markdown.pl。它把用markdown语法编写的内容转换成有效的、结构良好的XHTML或HTML内容,并将左尖括号(‘<’)和&号替换成它们各自的字符实体引用。它可以用作单独的脚本,Blosxom和Movable Type的插件又或者BBEdit的文本过滤器.[1]
Markdown也已经被其他人用Perl和别的编程语言重新实现,其中一个Perl模块 “模块 (程序设计)”)放在了CPAN(Text::Markdown)上。它基于一个BSD风格的许可证分发并可以作为几个内容管理系统的插件。
]]>Object.prototype.getElementsByClass = function (searchClass, tag) {
var returnArray = [];
tag = tag || ‘*’;
var els = this.getElementsByTagName(tag);
var pattern = new RegExp(‘(^|\s)’+searchClass+’(\s|$)’);
for (var i = 0; i < els.length; i++) {
if ( pattern.test(els[i].className) ) {
returnArray.push(els[i]);
}
}
return returnArray;
}