Leask's profile#import "Leask.h"BlogListsGuestbook Tools Help
Thanks for visiting!
Please wait...
Sorry, the comment you entered is too long. Please shorten it.
You didn't enter anything. Please try again.
Sorry, we can't add your comment right now. Please try again later.
To add a comment, you need permission from your parent. Ask for permission
Your parent has turned off comments.
Sorry, we can't delete your comment right now. Please try again later.
You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
Complete the security check below to finish leaving your comment.
The characters you type in the security check must match the characters in the picture or audio.
Xiaoniwrote:
It's beautiful here. I like it.
May 27

I'm @ Twitter

Loading...Loading...

在Mac上通过Terminal截取网页全图 / Full Page Screenshots by Terminal On a Mac

其实很多人都知道,如果说Snow Leopard和Windows 7的图形界面是可口的点心的话,那么在*nix系统里面,命令行Shell简直就是系统的灵魂。

笔者是从事网站开发和设计的,俗称的D&D(Design and Development),经常遇到需要把制作效果汇报给上级,或者发Demo给客户的情况。然而由于Web pages脱离了Web server通常是无法完整预览的,这就需要截图了。

Mac上截图是很方便的,系统自带的截图功能就异常强大(和Windows上残废的截图功能无法类比),而且通过便利的热键就能使用。关键是Mac上的截图工具并不能截取网页的全图,也就是遇到你的网页尺寸大于你的浏览器窗口尺寸的时候,就无能为力了,难不成还要开个Photoshop来拼接?这样做很山寨,一点都不专业,而且效率相当低。于是我也尝试过使用Paparazzi和Little Snapper。说实话,这两个软件都是很优秀的,特别是华丽的Little Snapper,但是那就需要多安装一个软件了,有没有什么环保一点的办法呢?

经过一番研究,其实是有的,就是使用基于python的webkit2png,然而事实上Paparazzi和Little Snapper都是基于webkit2png项目的。
webkit2png可以在这里下载到:http://www.paulhammond.org/webkit2png/
如果你和我一样,有命令行癖,那么打开Terminal,使用CURL获取,命令如下:

curl http://www.paulhammond.org/2009/03/webkit2png-0.5/webkit2png-0.5.txt > webkit2png

于是你就得到webkit2png了。怎么用呢?
首先检查你的系统,你必须使用Mac OS X 10.2或以上系统,Safari 1.0或以上,PyObjC库1.1或以上。当然了,如果你的系统是Mac OS X 10.5 Leopard或更高版本,那么以上所有组件,你都已经安装过上了。如果不满足条件,可以升级Safari,并下载PyObjC的源代码自己编译。

webkit2png的使用很简单,Terminal执行:

python /Users/Leask/webkit2png http://www.leaskh.com/

执行效果如下:
Screen shot 2009-11-06 at 9.57.57 PM 
然后你就会发现网页已经被截图放在你的home文件夹了。

当然你还可以通过参数控制webkit2png的行为,你可以通过 --help 获得以下使用帮助:

Flora:~ Leask$ python /Users/Leask/webkit2png --help
Usage: webkit2png [options] [
http://example.net/ ...]

examples:
webkit2png
http://google.com/            # screengrab google
webkit2png -W 1000 -H 1000
http://google.com/ # bigger screengrab of google
webkit2png -T
http://google.com/         # just the thumbnail screengrab
webkit2png -TF
http://google.com/        # just thumbnail and fullsize grab
webkit2png -o foo
http://google.com/     # save images as "foo-thumb.png" etc
webkit2png -                             # screengrab urls from stdin
webkit2png -h | less                     # full documentation

Options:
  --version             show program's version number and exit
  -h, --help            show this help message and exit
  -W WIDTH, --width=WIDTH
                        initial (and minimum) width of browser (default: 800)
  -H HEIGHT, --height=HEIGHT
                        initial (and minimum) height of browser (default: 600)
  --clipwidth=WIDTH     width of clipped thumbnail (default: 200)
  --clipheight=HEIGHT   height of clipped thumbnail (default: 150)
  -s SCALE, --scale=SCALE
                        scale factor for thumbnails (default: 0.25)
  -m, --md5             use md5 hash for filename (like del.icio.us)
  -o NAME, --filename=NAME
                        save images as NAME-full.png,NAME-thumb.png etc
  -F, --fullsize        only create fullsize screenshot
  -T, --thumb           only create thumbnail sreenshot
  -C, --clipped         only create clipped thumbnail screenshot
  -d, --datestamp       include date in filename
  -D DIR, --dir=DIR     directory to place images into
  --delay=DELAY         delay between page load finishing and screenshot
  --noimages            don't load images

这里我就不一一翻译了。如果你懂一点Shell Script语言,还可以把这个命令再封装一下,例如我就把这个命令封装为:

websnap [URL]

的形式,很便利地得到截图,如输入:

websnap http://www.leaskh.com/

至于Shell Script怎么写?也不难,Unix和Linux上的Shell Script其实都大致一样,如:

#!/bin/bash
echo "Leask's WebSnap based on webkit2png"
echo ""
python /Users/Leask/webkit2png $1;
exit;

保存上面的代码片段为以websnap为名文件,注意以上的Leask为我的用户名,你还需要自己改为自己的用户名呢。放脚本的目录和脚本本身都需要有执行权限。

就先写这些吧,Enjoy。

// 如果你是Linux用户,你通常没有Webkit,那么你有Firefox就可以了,Google一下另外一个基于Mozilla Firefox的项目叫做khtml2png,和webkit2png大同小异。

自己动手清理MacBook

最近我的MacBook性能大不如前,稳定性下降,风扇噪音越来越大。
今天由于温度过高,突然断电,我可怜的写了一个多小时的数据分析告吹了,于是向公司反映,请假维修MacBook。

推测是散热风扇出毛病了,Google了MacBook的风扇价格,高得惊人,只能考虑自己修一下。
经高人(我哥)指点,找来一瓶“防锈润滑剂”,我选的叫做“WD-40”(现在买免费加送20%哦)。
其实一瓶也就10块钱,买一个原装风扇可以买几十瓶了。


大概这个样子的:

DSC00001 


动手!开始拆开:

DSC00002 


翻开上盖,尘封程度惨不忍睹,风扇基本上已经被灰尘堵住转不起来:

DSC00003 


用废旧牙刷刷干净主板,使用润滑剂对着风扇轴承处,使劲喷。
注意,润滑剂使用二氧化碳推进,喷劲十足!
喷出来会是雾状,而且有腐蚀性,最好不要沾到手,而且最理想的情况是用纸巾把屏幕也遮蔽一下,大致情况如下:

 DSC00006


来一张清洁前后的效果对比图:

DSC00004DSC00008


然后按照拆开的方法装回去,机器立刻变得安静凉爽,如果你的是MacBook,并且使用时间达到一年左右,你应该会遇到和我一样的问题(网友大量反映),建议你试试我的方法。因为较低的温度会延长你风扇和内部零件的寿命。而且用起来,也不再烫手了。

// 最后提醒大家拆机有风险,要求胆大心细。祝你好运!
// 对了,拆机的教程我是看ifixit的,一个很著名的Mac全系列拆解网站,里面的教程很详细,十分具有参考价值,网址请自行Google。

Flora_ssh-D Version 2.33 闪亮登场!

Screen shot 2009-10-29 at 10.10.21 AM

Flora_ssh-D是什么?

  1. Flora_ssh-D是一个Applescript(以app形式封装),在Mac OS上开发和运行(有计划推出针对Windows的版本);
  2. Flora_ssh-D是一个iTunes VoiveOver程序,能够像iPod shuffle那样自动报读当前正在播放的歌名和艺术家;
  3. Flora_ssh-D能够自动连接ssh -D服务器,自动创建Socks代理服务器,高速访问某些如Twitter、Facebook等国外优秀站点,并在连接断开的时候自动重连,配合ssh -D服务器使用,让Wall从此透明;
  4. Flora_ssh-D并不包含ssh -D服务器信息,如果你要使用第3条的功能,你需要自己购买ssh -D服务器,做有责任感的网民,网上行为务必符合国家法律法规
  5. Flora_ssh-D能自动更新你的Twitter状态为你正在听的歌,如:【I am listening to #Sensible by #Sun Yan-Zi in album #Leave. // Thursday, October 29, 2009 11:05:32 AM】;
  6. Flora_ssh-D能自动记录你正在听的歌到Last.fm;
  7. Flora_ssh-D能自动更新你DNS-O-MATIC上的动态IP地址为你的当前IP;
  8. Flora_ssh-D能自动判断在线状态,自动为你开启和关闭某些软件;
  9. 推荐把Flora_ssh-D设置为开机启动,只需要在开机的时候执行这一个脚本,其他的程序可以配置到脚本里面,自动根据在线状态为你自动开启和关闭;
  10. Flora_ssh-D是开源的自由软件,并已经在Google Code上创建为开源项目:http://code.google.com/p/flora-ssh-d/

Version 2.33有什么新改进?

  1. 全新的任务调度,大大缩短iTunes VoiceOver的时间延迟;
  2. 全新的配置方式,现在下载程序后无需配置就能马上执行,比较适合只需要iTunes VoiceOver功能的朋友;
  3. 优化VoiceOver功能,添加音量淡入淡出功能,听起来效果更好,和iPod shuffle上基本上没有分别了;
  4. 完善Twitter功能,自动在Twitter上发布你正在听的歌;
  5. 完善last.fm歌曲记录功能;
  6. 修正ssh -D连接的bug,让ssh -D连接更加顺畅,并在退出程序的时候自动关闭ssh –D以释放内存;
  7. 进一步减少空闲时的资源占用,让脚本更轻巧,几乎感觉不到脚本的存在;
  8. 全新的任务管理方式,运行更快,更稳定;
  9. 添加中文配置说明,方便英文不好的朋友使用。

Flora_ssh-D 2.33 能够在以下地址下载到:http://code.google.com/p/flora-ssh-d/downloads/list

 

源代码如下:

(* Flora_ssh-D Version 2.33
Open Source Project Home/开源项目主页: http://code.google.com/p/flora-ssh-d/
Code by/程序编写: 黄思夏 / Leask Huang
Blog: http://www.leaskh.com (天朝访问需翻墙)
E-mail/GTalk/MSN/QQ: i@leaskh.com *)

(* CUSTOM THESE SETTINGS BEFORE YOUR RUN THINS SCRIPT // 运行此脚本前请先配置此区域的参数
    LEAVE IT BLANK IF YOU DON'T NEED IT // 如你不需要其中某些功能请将设置留空 *)
property SSHServerName : ""
property SSHUserName : ""
property SSHPasswd : ""
property TwitterUsername : ""
property TwitterPassword : ""
property DNSUsername : ""
property DNSPassword : ""
property LastfmUsername : ""
property LastfmPassword : ""
property appStList : {}
property appQuitList : {}

(* Example/示例 // English Help // 中文帮助
property SSHServerName : "ssh.yourdomain.com"   -- ssh -D Server Address (or leave it blank)  //  ssh -D 翻墙服务器地址 (不使用ssh -D则留空)
property SSHUserName : "*******"   -- ssh -D User Name (or leave it blank)  //  ssh -D 帐号 (不使用ssh -D则留空)
property SSHPasswd : "*******"   -- ssh -D Password (or leave it blank) //  ssh -D 密码 (不使用ssh -D则留空)
property TwitterUsername : "*******"   -- Twitter User Name (or leave it blank)  //  Twitter帐号 (不使用Twitter则留空)
property TwitterPassword : "*******"   -- Twitter Password (or leave it blank)  //  Twitter密码 (不使用Twitter则留空)
property DNSUsername : "*******"   -- DNS User Name (or leave it blank)  //  DNS-O-MATIC动态IP帐号 (不使用动态IP则留空)
property DNSPassword : "*******"   -- DNS Password (or leave it blank)  //  DNS-O-MATIC动态IP密码 (不使用动态IP则留空)
property LastfmUsername : "*******"   -- last.fm User Name (or leave it blank)  // last.fm帐号 (不使用last.fm则留空)
property LastfmPassword : "*******"   -- last.fm Password (or leave it blank)  //  last.fm密码 (不使用last.fm则留空)
property appStList : {"App 1", "软件2","iChat"}   -- these apps will launch while you are online (or leave it blank)  //  填写【在线】时需【开启】的软件(不使用此功能则留空)
property appQuitList : {"App 1", "软件2","QQ"}   -- these apps will quit while you are offline (or leave it blank)  //  填写【离线】时需【关闭】的软件(不使用此功能则留空)
*)

(* ======= Variable Declaration ======= *)
global timeTry
global DNSResponse
global isOLast
global iTsCurDBID
global iTsORSoundVolume
global strSNGArtist
global strSNGName
global strSNGAlbum
global strSNGTrackNumber
global strSNGDuration
global intIdleCount

(* ======= Main Script ======= *)
on run
    set isOLast to ""
    set iTsCurDBID to ""
    set intIdleCount to 10
end run

on quit
    if isOLast is "online" then fnTwitter("I am offline now! // " & (current date), true)
    fnShellSSHEnd(true)
    fnAppQuit()
    continue quit
end quit

on idle
    if fnCheckNet() is true then
        if intIdleCount > 9 then
            fnSSHCnt()
            if isOLast is not "online" then
                fnAppStart()
                fnDNSUpdate()
                fnTwitter("I am online now! // " & (current date), true)
            end if
            set intIdleCount to 0
        end if
        fnMusic(true)
        set intIdleCount to intIdleCount + 1
        set isOLast to "online"
    else
        fnMusic(false)
        if isOLast is not "offline" then
            fnShellSSHEnd(true)
            fnAppQuit()
        end if
        set isOLast to "offline"
    end if
    return 33
end idle

(* ======= Functions ======= *)
to fnCheckNet()
    try
        do shell script "curl --connect-timeout 33 \"apple.com/favicon.ico\""
        if isOLast is not "online" then SmartSay({"Online"})
        return true
    on error
        if isOLast is not "offline" then SmartSay({"Offline"})
        return false
    end try
end fnCheckNet

to fnAppStart()
    if (count appStList) > 0 then
        SmartSay({"Start Apps"})
        try
            repeat with intSti from 1 to (count appStList)
                tell application (item intSti of appStList) to activate
            end repeat
            SmartSay({"OK"})
        on error
            SmartSay({"Failed"})
        end try
    end if
end fnAppStart

to fnAppQuit()
    if (count appQuitList) > 0 then
        SmartSay({"Quit Applications"})
        try
            repeat with intSti from 1 to count appQuitList
                tell application (item intSti of appQuitList) to quit
            end repeat
            SmartSay({"OK"})
        on error
            SmartSay({"Failed"})
        end try
    end if
end fnAppQuit

to fnSSHCnt()
    if (length of SSHServerName) > 0 and (length of SSHUserName) > 0 and (length of SSHPasswd) > 0 then
        set timeTry to 0
        repeat while fnCheckSSHD() is false
            SmartSay({"Connect SSH D"})
            if timeTry > 0 then if (button returned of (display dialog "ssh -D connection failed." & return & "" buttons {"Retry", "Ignore"})) is "Ignore" then exit repeat
            fnShellSSH()
            set timeTry to timeTry + 1
        end repeat
    end if
end fnSSHCnt

to fnCheckSSHD()
    try
        do shell script "curl --socks5 127.0.0.1:7070 --connect-timeout 33 \"apple.com/favicon.ico\""
        if timeTry > 0 then SmartSay({"OK"})
        return true
    on error
        if timeTry > 0 then SmartSay({"Failed"})
        return false
    end try
end fnCheckSSHD

to fnShellSSH()
    try
        try
            do shell script "killall Terminal"
        end try
        tell application "Terminal"
            activate
            fnShellSSHEnd(false) of me
            delay 1
            do script "nohup ssh -D 7070 " & SSHUserName & "@" & SSHServerName & " > Downloads/.Flora_ssh-D.out" in window 1
        end tell
        SmartSay({"SSH D connection request and log in request have been sent. Waiting for response from remote server."})
        tell application "Terminal"
            do script SSHPasswd in window 1
            delay 1
            quit
        end tell
    end try
end fnShellSSH

to fnShellSSHEnd(isSay)
    if (length of SSHServerName) > 0 and (length of SSHUserName) > 0 and (length of SSHPasswd) > 0 then
        if isSay is true then SmartSay({"Disconnect SSH D"})
        try
            do shell script "killall ssh"
            do shell script "killall ssh-agent"
            do shell script "rm ~/Downloads/.Flora_ssh-D.out"
        end try
    end if
end fnShellSSHEnd

to fnTwitter(strTwText, isSay)
    if (length of TwitterUsername) > 0 and (length of TwitterPassword) > 0 and (length of strTwText) > 0 then
        if (length of strTwText) > 140 then
            set strTwText to (characters 1 through 137 of strTwText as string) & "..."
        end if
        if isSay is true then SmartSay({"Update Twitter state"})
        try
            do shell script "curl --connect-timeout 33  --user " & (quoted form of (TwitterUsername & ":" & TwitterPassword)) & " --data-binary " & (quoted form of ("status=" & strTwText)) & " \"https://twitter.com/statuses/update.json\""
            if isSay is true then SmartSay({"OK"})
        on error
            if isSay is true then
                SmartSay({"Failed"})
            else
                SmartSay({"Update Twitter state failed"})
            end if
        end try
    end if
end fnTwitter

to fnDNSShell()
    try
        set DNSResponse to (do shell script "curl --connect-timeout 33 \"https://" & DNSUsername & ":" & DNSPassword & "@updates.dnsomatic.com/nic/update?&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG\"")
        if first word of DNSResponse is "good" then -- (second word of DNSResponse) is IP address
            return true
        else
            return false
        end if
    on error
        return false
    end try
end fnDNSShell

to fnDNSUpdate()
    if (length of DNSUsername) > 0 and (length of DNSPassword) > 0 then
        SmartSay({"Update dynamic IP"})
        if fnDNSShell() is true then
            SmartSay({"OK"})
        else
            SmartSay({"Failed"})
        end if
    end if
end fnDNSUpdate

to fnURLec(strToUEC)
    return do shell script "python -c 'import sys, urllib; print urllib.quote(sys.argv[1])' \"" & strToUEC & "\""
end fnURLec

to fniTunesisActive()
    tell application "System Events" to return (name of processes contains "iTunes")
end fniTunesisActive

to fuisiTunesNUD()
    if fniTunesisActive() is true then
        tell application "iTunes"
            if player state is playing then
                set iTsNewDBID to (get database ID of current track)
                if iTsNewDBID is not iTsCurDBID then
                    set strSNGArtist to (get artist of current track)
                    set strSNGName to (get name of current track)
                    set strSNGAlbum to (get album of current track)
                    set strSNGTrackNumber to (get track number of current track)
                    set strSNGDuration to (get duration of current track as integer)
                    set iTsCurDBID to iTsNewDBID
                    return true
                else
                    return false
                end if
            else
                return false
            end if
        end tell
    else
        return false
    end if
end fuisiTunesNUD

to SmartSay(strToSay)
    set isiTPing to false
    if fniTunesisActive() is true then
        tell application "iTunes" to if player state is playing then set isiTPing to true
    end if
    if isiTPing is true then
        tell application "iTunes"
            set iTsORSoundVolume to sound volume
            set timeTry to 0
            repeat while timeTry < 10
                set timeTry to timeTry + 1
                set sound volume to iTsORSoundVolume * (15 - timeTry) / 15
                delay 0.1
            end repeat
        end tell
        repeat with intSti from 1 to (count strToSay)
            say "" & (item intSti of strToSay)
            if intSti < (count strToSay) then delay 1
        end repeat
        tell application "iTunes"
            set timeTry to 10
            repeat while timeTry > 0
                set timeTry to timeTry - 1
                set sound volume to iTsORSoundVolume * (15 - timeTry) / 15
                delay 0.1
            end repeat
        end tell
    else
        say "" & strToSay
    end if
end SmartSay

to fnMusic(isOnline)
    if fuisiTunesNUD() is true then
        SmartSay({strSNGName, strSNGArtist})
        if isOnline is true then
            if (length of LastfmUsername) > 0 and (length of LastfmPassword) > 0 then
                try
                    do shell script "curl --connect-timeout 33 \"http://lastfmstats.livefrombmore.com/universalscrobbler/scrobble.php?submissionType=track" & "&username=" & LastfmUsername & "&password=" & LastfmPassword & "&artist=" & fnURLec(strSNGArtist) & "&track=" & fnURLec(strSNGName) & "&album=" & fnURLec(strSNGAlbum) & "&number=" & strSNGTrackNumber & "&duration=" & strSNGDuration & "\""
                on error
                    SmartSay({"Scrobbling Failed"})
                end try
                fnTwitter("I am listening to #" & strSNGName & " by #" & strSNGArtist & " in album #" & strSNGAlbum & ". // " & (current date), false)
            end if
        end if
    end if
end fnMusic

热烈庆祝!China GFW引用本站文章!

这两天GTalk上一下子很多朋友加我,都是询问Flora_ssh-D脚本的问题的。
我就纳闷心想我的Blog流量并没有那么大呀,后来才知道原来脚本被China GFW转载了。
转载地址是:http://www.chinagfw.org/2009/10/blog-post_1289.html
// PS:访问需要先翻墙。

感谢大家的支持,Flora_ssh-D经过周末的密集式的开发,目前已经升级到1.73了,1.73是比较成熟的版本,执行已经相当稳定和高效了。

有些人可能还不明白Flora_ssh-D能做什么,这里我有一个1.3版的屏幕录影,大家看看就明白了。
注意,录影为1.3版,不是最新的1.73版,1.73版的语音提醒已经升级了,补发这段视频是为了大家更加明白Flora_ssh-D的功能。

 
// 视频地址:http://v.youku.com/v_show/id_XMTI3ODE5NTIw.html

原计划下一步是把项目移植到X-Code,用Object-C重写的,但是由于太多朋友询问Windows是否支持这个脚本。我可能会考虑一下Flora_ssh-D在Windows上的实现。
但是由于Windows上没有如Unix上那么便利的shell,实现Flora_ssh-D的功能就需要动用更高级的开发工具了,有点小题大作了。
目前我比较想在Windows上把脚本中的iTunes VoiceOver的功能先做起来,但是Windows上开发iTunes比较困难,还没想到好的办法呢。
所以具体怎么实现,是否需要用Visual Studio写,我还在考虑中。因为周一到周五我要工作,时间也不多。
所以,Windows上怎么做,做不做,我现在还不能回答大家。

另一点就是VoiceOver使用系统的API发音,由于Mac上的语音合成API不支持中文,那么中文的歌名和艺术家就不能报读了(其实Windows上的语音引擎也一样)。
但是Apple提供给iPod使用的VoiceOver Kit是能够支持多语言的,所以iPod shuffle会说20种语言,包括中文。而Mac上的API不知道为什么就是不支持,这个问题也有待研究了。

谢谢大家支持!
提醒大家,Flora_ssh-D已经在Google Code上开源,项目地址是:http://code.google.com/p/flora-ssh-d/

/*
还有另一个值得庆祝的就是我发布的SX1_RU06_LSK_UNLOCK(用于解锁SX1的软件包)在Box.net上已经录得超过20110 times的下载量了!
但是提醒一下SX1解锁的研究已经停止很久了,我的机器也已经坏了,大家不用再找我了,不然我真的很怕上线了(太多人找)。大家Google一下就能找到我的教程,然后下载下面的包,刷进去,重启就可以了。
下载地址(天朝网民需翻墙):
http://www.box.net/shared/fvfh57d0e2
http://www.box.net/shared/hi6xl35uk0
墙内下载地址:
http://www.boxcn.net/shared/fvfh57d0e2
http://www.boxcn.net/shared/hi6xl35uk0
*/

天朝春色关我不住,一段代码让我出墙来(Flora_ssh-D 1.73隆重发布!)

Flora_ssh-D 1.73已经不单单是翻墙脚本了,目前我计划把Flora_ssh-D发展成一个自动化的助理,让你的电脑用得更舒心。

目前的功能如下:

  1. 自动检查网络状态,根据在线和离线的状态为你开启和关闭软件;
  2. 自动检查ssh -D的连接状态,如果断开了会为你自动连接,连接失败将提示自动重连,使用后墙对你来说基本上是透明的;
  3. VoiceOver语音功能,这个功能和iPod一样,你的iTunes在播放的时候能够语音提示你正在播放的歌名和艺术家名字;
  4. 语音提醒功能的改进,当需要语音提示用户操作的时候,如果你的iTunes正在播放,将自动降低你的iTunes音量,在语音提示结束后还原音量;
  5. 使用API自动将你正在收听的音乐记录到Last.fm,你已经不再需要额外的iTunes插件来记录了;
  6. 使用API自动更新你在DNS-O-MATIC上的动态IP,你不再需要其他额外的软件更新动态IP了;
  7. 新版本使用新的idle时间管理,对比上一个版本有很大的效能提升,后台的常驻几乎不占用任何资源。

Google Code上下载地址如下:http://code.google.com/p/flora-ssh-d/downloads/list (包含源代码)
// PS: 使用翻墙功能你需要先有SSH帐号,使用其他功能则不需要。

源代码如下:

(* Flora_ssh-D // Version 1.73 // Code by Leask Huang // www.leaskh.com // i@leaskh.com *)

(* ======= Variable Declaration ======= *)
global timeTry
global DNSResponse
global isOLast
global iTsCurDBID
global iTsORSoundVolume
global strSNGArtist
global strSNGName
global strSNGAlbum
global strSNGTrackNumber
global strSNGDuration

(* ======= General Settings ======= *)
(* Custom these before you run this script *)
property SSHServerName : "***.*******.com" -- Set ssh -D ServerName (or leave it blank)
property SSHUserName : "*******" -- Set UserName (or leave it blank)
property SSHPasswd : "*******" -- Set Password (or leave it blank)
property TwitterUsername : "*******" -- If you don't want to update Twitter status, leave it blank
property TwitterPassword : "*******" -- same as above
property TwitterText : "@" & TwitterUsername & " is online now! // " & (current date) -- same as above
property DNSUsername : "*******" -- Set DNS UserName (or leave it blank)
property DNSPassword : "*******" -- Set Password (or leave it blank)
property LastfmUsername : "*******" -- Set Last.fm UserName (or leave it blank)
property LastfmPassword : "*******" -- Set Password (or leave it blank)
property appStList : {"***", "***"} -- these aplications will launch while you are online (or leave it blank)
property appQuitList : {"***", "***"} -- these aplications will quit while you are offline (or leave it blank)

(* ======= Main Script ======= *)
on run
    set isOLast to ""
    set iTsCurDBID to ""
end run

on quit
    continue quit
end quit

on idle
    if fnCheckNet() is true then
        fnSSHCnt()
        if isOLast is not "online" then
            fnAppStart()
            fnDNSUpdate()
            fnTwitter()
        end if
        fnLastfm()
        set isOLast to "online"
    else
        if isOLast is not "offline" then fnAppQuit()
        set isOLast to "offline"
    end if
    return 180
end idle

(* ======= Functions ======= *)
to fnCheckNet()
    try
        do shell script "curl --connect-timeout 33 \"apple.com/favicon.ico\""
        if isOLast is not "online" then SmartSay("Online")
        return true
    on error
        if isOLast is not "offline" then SmartSay("Offline")
        return false
    end try
end fnCheckNet

to fnAppStart()
    if (count appStList) > 0 then
        SmartSay("Start Apps")
        try
            repeat with intSti from 1 to (count appStList)
                tell application (item intSti of appStList) to activate
            end repeat
            SmartSay("OK")
        on error
            SmartSay("Failed")
        end try
    end if
end fnAppStart

to fnAppQuit()
    if (count appQuitList) > 0 then
        SmartSay("Quit Applications")
        try
            repeat with intSti from 1 to count appQuitList
                tell application (item intSti of appQuitList) to quit
            end repeat
            SmartSay("OK")
        on error
            SmartSay("Failed")
        end try
    end if
end fnAppQuit

to fnSSHCnt()
    if (length of SSHServerName) > 0 and (length of SSHUserName) > 0 and (length of SSHPasswd) > 0 then
        set timeTry to 0
        repeat while fnCheckSSHD() is false
            SmartSay("Connect SSH D")
            if timeTry > 0 then if (button returned of (display dialog "ssh -D connection failed." & return & "" buttons {"Retry", "Ignore"})) is "Ignore" then exit repeat
            fnShellSSH()
            set timeTry to timeTry + 1
        end repeat
    end if
end fnSSHCnt

to fnCheckSSHD()
    try
        do shell script "curl --socks5 127.0.0.1:7070 --connect-timeout 33 \"apple.com/favicon.ico\""
        if timeTry > 0 then SmartSay("OK")
        return true
    on error
        if timeTry > 0 then SmartSay("Failed")
        return false
    end try
end fnCheckSSHD

to fnShellSSH()
    try
        tell application "Terminal"
            quit
            delay 1
            activate
            delay 1
            do script "rm ~/Downloads/.Flora_ssh-D.out" in window 1
            do script "killall ssh" in window 1
            do script "killall ssh-agent" in window 1
            do script "nohup ssh -D 7070 " & SSHUserName & "@" & SSHServerName & " > Downloads/.Flora_ssh-D.out" in window 1
        end tell
        SmartSay("SSH D connection request and log in request have been sent. Waiting for response from remote server.")
        tell application "Terminal"
            do script SSHPasswd in window 1
            delay 1
            quit
        end tell
    end try
end fnShellSSH

to fnTwitter()
    if (length of TwitterUsername) > 0 and (length of TwitterPassword) > 0 and (length of TwitterText) > 0 then
        SmartSay("Update Twitter state")
        try
            do shell script "curl --connect-timeout 33  --user " & (quoted form of (TwitterUsername & ":" & TwitterPassword)) & " --data-binary " & (quoted form of ("status=" & TwitterText)) & " \"https://twitter.com/statuses/update.json\""
            SmartSay("OK")
        on error
            SmartSay("Failed")
        end try
    end if
end fnTwitter

to fnDNSShell()
    try
        set DNSResponse to (do shell script "curl --connect-timeout 33 \"https://" & DNSUsername & ":" & DNSPassword & "@updates.dnsomatic.com/nic/update?&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG\"")
        if first word of DNSResponse is "good" then -- (second word of DNSResponse) is IP address
            return true
        else
            return false
        end if
    on error
        return false
    end try
end fnDNSShell

to fnDNSUpdate()
    if (length of DNSUsername) > 0 and (length of DNSPassword) > 0 then
        SmartSay("Update dynamic IP")
        if fnDNSShell() is true then
            SmartSay("OK")
        else
            SmartSay("Failed")
        end if
    end if
end fnDNSUpdate

to fnURLec(strToUEC)
    return do shell script "python -c 'import sys, urllib; print urllib.quote(sys.argv[1])' \"" & strToUEC & "\""
end fnURLec

to fniTunesisActive()
    tell application "System Events" to return (name of processes contains "iTunes")
end fniTunesisActive

to fuisiTunesNUD()
    if fniTunesisActive() is true then
        tell application "iTunes"
            if player state is playing then
                set iTsNewDBID to (get database ID of current track)
                if iTsNewDBID is not iTsCurDBID then
                    set strSNGArtist to (get artist of current track)
                    set strSNGName to (get name of current track)
                    set strSNGAlbum to (get album of current track)
                    set strSNGTrackNumber to (get track number of current track)
                    set strSNGDuration to (get duration of current track as integer)
                    set iTsCurDBID to iTsNewDBID
                    return true
                else
                    return false
                end if
            else
                return false
            end if
        end tell
    else
        return false
    end if
end fuisiTunesNUD

to SmartSay(strToSay)
    set isiTPing to false
    if fniTunesisActive() is true then
        tell application "iTunes" to if player state is playing then set isiTPing to true
    end if
    if isiTPing is true then
        tell application "iTunes"
            set iTsORSoundVolume to sound volume
            set sound volume to iTsORSoundVolume * 0.333
        end tell
        say "" & strToSay
        tell application "iTunes" to set sound volume to iTsORSoundVolume
    else
        say "" & strToSay
    end if
end SmartSay

to fnLastfm()
    if fuisiTunesNUD() is true then
        if (length of strSNGName) > 0 or (length of strSNGArtist) > 0 then
            tell application "iTunes"
                set iTsORSoundVolume to sound volume
                set sound volume to iTsORSoundVolume * 0.333
            end tell
            if (length of strSNGName) > 0 then
                say strSNGName
                delay 1
            end if
            if (length of strSNGArtist) > 0 then say strSNGArtist
            tell application "iTunes" to set sound volume to iTsORSoundVolume
        end if
        if (length of LastfmUsername) > 0 and (length of LastfmPassword) > 0 then
            try
                do shell script "curl --connect-timeout 33 \"http://lastfmstats.livefrombmore.com/universalscrobbler/scrobble.php?submissionType=track" & "&username=" & LastfmUsername & "&password=" & LastfmPassword & "&artist=" & fnURLec(strSNGArtist) & "&track=" & fnURLec(strSNGName) & "&album=" & fnURLec(strSNGAlbum) & "&number=" & strSNGTrackNumber & "&duration=" & strSNGDuration & "\""
            on error
                SmartSay("Scrobbling Failed")
            end try
        end if
    end if
end fnLastfm

长风破浪会有时,直挂云帆济沧海(Flora_ssh-D 1.3发布!)

Flora_ssh-D 1.3 版本发布!

  1. 本版本重新整理程序,实现模块化;
  2. 引入后台运行机制,时刻检查网络;
  3. 简化设定,功能设置只需要留空,该功能就不会执行了;
  4. 直接使用DNS-O-MATIC的API更新动态IP,不再需要额外的程序了。

不推荐升级这个版本,因为1.73版本已经开发出来了,我下一文就是发布1.73的,先发1.3是因为想保持版本的连续性。大家可以忽略。

Google Code上的下载地址为:http://code.google.com/p/flora-ssh-d/downloads/list (包含源代码)

代码如下:

(* Flora_ssh-D // Version 1.3 // Code by Leask Huang // www.leaskh.com // i@leaskh.com *)

(* ======= Variable Declaration ======= *)
global timeTry
global DNSResponse
global isOLast

(* ======= General Settings ======= *)
(* Custom these before you run this script *)

set SSHServerName to "*******" -- Set ServerName, You must set this
set SSHUserName to "*******" -- Set UserName, You must set this
set SSHPasswd to "*******" -- Set Password, You must set this
set TwitterUsername to "*******" -- If you don't want to update Twitter status, leave it blank
set TwitterPassword to "*******" -- same as above
set TwitterText to "@" & TwitterUsername & " is online now! // " & (current date) -- same as above
set DNSUsername to "*******"
set DNSPassword to "*******"
set appStList to {"Adium", "CoverSutra", "Google Notifier"} -- these aplications will launch while you are online (or leave it blank)
set appQuitList to {"CoverSutra", "Google Notifier"} -- these aplications will quit while you are offline (or leave it blank)

(* ======= Advanced Settings ======= *)
(* You don't need to change these normally *)

(* ======= Main Script ======= *)
set isOLast to ""

repeat
    delay 10000
end repeat
repeat
    if fnCheckNet() is true then
        if isOLast is not "online" then
            fnSSHCnt()
            fnAppStart()
            fnDNSUpdate()
            fnTwitter()
        end if
        set isOLast to "online"
        say "All done!"
    else
        if isOLast is not "offline" then
            fnAppQuit()
        end if
        set isOLast to "offline"
        say "All done!"
    end if
    -- delay 333
    delay 60
end repeat

(* ======= Functions ======= *)
to fnCheckNet()
    try
        do shell script "curl --connect-timeout 7 apple.com/favicon.ico"
        if isOLast is not "online" then
            say "Great! You are online."
        end if
        return true
    on error
        if isOLast is not "offline" then
            say "Opps! You are offline."
        end if
        return false
    end try
end fnCheckNet

to fnCheckSSHD()
    try
        do shell script "curl --socks5 127.0.0.1:7070 --connect-timeout 7 apple.com/favicon.ico"
        say "OK! SSH D has been successfully connected."
        return true
    on error
        if timeTry > 0 then
            say "Opps! SSH D connection failed."
        end if
        return false
    end try
end fnCheckSSHD

to fnAppStart()
    if (count appStList) > 0 then
        say "Start Applications"
        try
            repeat with intSti from 1 to (count appStList)
                tell application (item intSti of appStList)
                    activate
                end tell
            end repeat
        on error
            say "Opps! Error."
        end try
    end if
end fnAppStart

to fnAppQuit()
    if (count appQuitList) > 0 then
        say "Quit Applications"
        try
            repeat with intSti from 1 to count appQuitList
                tell application (item intSti of appQuitList)
                    quit
                end tell
            end repeat
        on error
            say "Opps! Error."
        end try
    end if
end fnAppQuit

to fnSSHCnt()
    if (length of SSHServerName) > 0 and (length of SSHUserName) > 0 and (length of SSHPasswd) > 0 then
        set timeTry to 0
        say "Create SSH D connection"
        repeat while fnCheckSSHD() is false
            if timeTry > 0 then
                if (button returned of (display dialog "Opps! ssh -D connection failed. Do you want to retry?" & return & "" buttons {"Retry", "Quit"})) is "Quit" then
                    exit repeat
                end if
            end if
            fnShellSSH()
            set timeTry to timeTry + 1
        end repeat
    end if
end fnSSHCnt

to fnShellSSH()
    try
        tell application "Terminal"
            quit
            delay 1
            activate
            delay 1
            do script "rm ~/Downloads/.Flora_ssh-D.out" in window 1
            do script "killall ssh" in window 1
            do script "killall ssh-agent" in window 1
            do script "nohup ssh -D 7070 " & SSHUserName & "@" & SSHServerName & " > Downloads/.Flora_ssh-D.out" in window 1
        end tell
        say "SSH D connection request and log in request have been sent. Waiting for response from remote server."
        tell application "Terminal"
            do script SSHPasswd in window 1
            delay 1
            quit
        end tell
    on error
        say "Opps! Error."
    end try
end fnShellSSH

to fnTwitter()
    if (length of TwitterUsername) > 0 and (length of TwitterPassword) > 0 and (length of TwitterText) > 0 then
        say "Update Twitter state"
        try
            do shell script "curl --user " & (quoted form of (TwitterUsername & ":" & TwitterPassword)) & " --data-binary " & (quoted form of ("status=" & TwitterText)) & " https://twitter.com/statuses/update.json"
            say "OK! Twitter state has been successfully updated."
        on error
            say "Opps! Error."
        end try
    end if
end fnTwitter

to fnDNSShell()
    try
        set DNSResponse to (do shell script "curl https://" & DNSUsername & ":" & DNSPassword & "@updates.dnsomatic.com/nic/update?&wildcard=NOCHG&mx=NOCHG&backmx=NOCHG")
        if first word of DNSResponse is "good" then
            return true
        else
            return false
        end if
    on error
        return false
    end try
end fnDNSShell

to fnDNSUpdate()
    if (length of DNSUsername) > 0 and (length of DNSPassword) > 0 then
        say "Update dynamic IP"
        if fnDNSShell() is true then
            say "OK! Dynamic IP has been successfully updated to " & (second word of DNSResponse)
        else
            say "Opps! Error."
        end if
    end if
end fnDNSUpdate

Mac上使用固定域名解释到动态IP的方法(类似于“花生壳”的用法)

很多人都有需要把固定域名解释到动态IP,因为很多人想在自己的电脑上提供主机服务,但是又苦于ISP提供的是动态IP而非固定IP。
怎么办呢?Windows上有“花生壳”(请自行Google),那么Mac上呢?其实Mac上也有简便的解决方案的。

实现固定域名解释到动态IP,我们需要满足两个条件:

  1. 我们首先需要一个支持实时修改IP地址映射的DNS服务器;
  2. 我们还需要一个上传本地IP地址到远程DNS服务器的客户端程序。

OK,我们来一个一个解决。

第一个问题我们可以通过D-Link Dynamic DNS解决,该服务目前免费。注册地址是:https://www.dlinkddns.com/
Screen shot 2009-10-24 at 4.32.54 PM
注册后会得到一个域名,然后你可以填上你当前的IP地址。 那么你已经能让全球的朋友通过这个域名访问你的电脑了,那么问题是如果你的IP改变了,是不是就需要重新登录这个页面填写新的IP呢?所以我们需要接着解决第二个问题。

第二个问题我们可以通过DNS-O-Matic解决,该服务目前免费。注册地址是:https://www.dnsomatic.com/
DNS-O-Matic是不提供DNS服务的,它关注的是更新各种DNS服务上的动态IP地址,DNS-O-Matic支持上面提到的D-Link Dynamic DNS,同时也支持OpenDNS。
Screen shot 2009-10-24 at 4.39.39 PM 
DNS-O-Matic的注册也同样简单,注册后你可以添加你所使用的DNS服务,如输入你的D-Link Dynamic DNS帐号、密码和域名。
为什么要引入DNS-O-Matic呢?因为DNS-O-Matic支持开放式的API,你可以通过各种形式的客户端或者脚本来更新你提交你的本地IP地址。
如以下这个Mac上的小脚本DNS-O-Matic Updater就是我们所需要的了:
http://web.me.com/zweigand/zweisoft/Software/Entries/2009/1/13_DNS-O-Matic_Updater_1.4.html
下载并填写你的DNS-O-Matic帐号就OK了,以后只需要启动这个小脚本,就能自动更新你的动态IP了哦。

使用起来,比“花生壳”还要便捷,而且一切都是免费的。
对了,最后提一下,如果你自己有一个域名,那么可以把自己的域名CNAME到你的D-Link Dynamic DNS域名,就能实现通过自己的域名,任何时候都能访问你的电脑了。

// 最后预告一下,Flora_ssh-D,也就是我的翻墙脚本的下一个版本也将直接使用DNS-O-Matic的API而不是调用DNS-O-Matic_Updater来更新动态IP了,敬请关注。

我优雅一转身,墙应声而倒。我挥一挥衣袖,不带走一片砖瓦。

Screen shot 2009-10-24 at 4.04.09 PM 

又到了周末翻墙的时间了。
使用了一段时间的ssh -D,我终于找回了做人的感觉,自由的空气如此新鲜,信息的绿洲让人神往,流连忘返。
ssh -D如此便利,速度如此流畅,让人印象深刻,但是美中不足的是每次都需要先连接,虽然上次已经分享过我写的一段脚本,实现在Mac上自动翻墙。但上次的脚本比较粗糙,仓促,于是又有了一些新的想法,目标是让翻墙更优雅、潇洒。

上次的版本是0.3,这次改动比较大我把版本设置为0.7,下面简单说一下几点改进:

  1. 自动判断在线状态,如果你还没有上网,是不会执行翻墙程序的;
  2. 自动判断翻墙结果,如果翻墙失败,程序将自动重新尝试;
  3. 自动更新动态IP,你或许在自己的电脑上使用OpenDNS,host网站,或者其他原因需要更新动态IP(近段时间我将发文谈谈Mac上动态IP的问题,请关注);
  4. 自动执行程序,如果你有一些程序,如聊天软件,邮件检查软件等需要在上网的时候开启,也可以设定;
  5. 自动退出程序,如果你有一些程序,如邮件检查程序,Last.fm等,需要在断网的时候关闭,也可以设定;
  6. 设定是否在翻墙成功的时候更新Twitter状态;
  7. 全程语音提示,告诉你程序目前正在干什么,十分Cool;

主要也就7点打改进,新的脚本还包含了错误语音提示,当过程中发生错误,将语音提醒你是什么原因发生错误。
十分建议把脚本设置为开机执行。

程序已经提交到Google Code,并开放源代码:
地址如下:
http://code.google.com/p/flora-ssh-d/
注意!访问Google Code你可能需要先翻墙。

下面贴出源代码,大家粘贴到AppleScript Editor.app里面,修改参数然后执行就可以了。
有不明白的可以邮件或者GTalk联系我,我的邮件/GTalk/MSN/QQ同为:i@leaskh.com

(* Flora_ssh-D // Version 0.7 // Code by Leask Huang // www.leaskh.com // i@leaskh.com *)

(* ======= Variable Declaration ======= *)
global YourName
global SSHServerName -- SSH Server Name
global SSHLocalPorts -- Local Port
global SSHUserName -- User Name on SSH Server
global SSHPasswd -- Password for SSH Server
global TwitterAPI -- Twitter API URL
global TwitterUsername -- Twitter User Name
global TwitterPassword -- Twitter Password
global TwitterLogin
global TwitterStatus
global JobID
global URLTestNet
global URLTestGFW
global appDNSUpdate
global appStList
global appQuitList
global isConnected
global isSSHCnt
global isUpdateTwitter
global isRunExSoft
global isQuitExSoftware
global isUpdateDNS
global isDelnohup
global strnohup
global timeTry
global isforceQuit

(* ======= General Settings ======= *)
(* You don't need to change these normally *)
set URLTestGFW to "twitter.com" -- Use this URL to check is your are Blocked by GFW
set URLTestNet to "leask.com" -- Use this URL to check if you are online
set SSHLocalPort to "7070" -- Set Socks 5 local port
set TwitterAPI to "https://twitter.com/statuses/update.json" -- Twitter API URL
-- set TwitterAPI to "http://twitter.com/statuses/update.json" -- Simple HTTP Twitter API URL (NOT Recommend)
set isDelnohup to true -- Set it as true to del SSH output informtions every time
set strnohup to "Downloads/.Flora_ssh-D.out" -- Config your SSH output file location
set isUpdateDNS to true -- Config if you want to update your dynamic IP address for OpenDNS / DLinkDDNS / DynDNS
set isUpdateTwitter to true -- Config if you want to update Twitter status every time
set isRunExSoft to true -- Config if you want to launch some aplications when you are online
set isQuitExSoftware to true -- Config if you want to quit some aplications when you are offline

(* ======= User Settings ======= *)
(* Custom these before you run this script *)
set SSHServerName to "***.*******.com" -- Set ServerName, You must set this
set SSHUserName to "*******" -- Set UserName, You must set this
set SSHPasswd to "*******" -- Set Password, You must set this
set TwitterUsername to "" -- If you don't want to update Twitter status, leave it blank
set TwitterPassword to "" -- same as above
set TwitterText to "@" & TwitterUsername & " is online now! // " & (current date) -- same as above
set appDNSUpdate to "DNS-O-Matic Updater" -- Use this application to update your dynamic IP address (or leave it blank)
set appStList to {"Adium", "CoverSutra", "Google Notifier"} -- these aplications will launch while you are online (or leave it blank)
set appQuitList to {"CoverSutra", "Google Notifier"} -- these aplications will quit while you are offline (or leave it blank)

(* ======= Main Script ======= *)
set isConnected to false
set isSSHCnt to false
set timeTry to 0
set isforceQuit to false

try
    do shell script "curl " & URLTestNet
    set isConnected to true
on error
    set isConnected to true -- false
    say "Opps! Your internet isn't ready."
    if (isQuitExSoftware is true) and ((count appQuitList) > 0) then
        repeat with intSti from 1 to count appQuitList
            tell application (item intSti of appQuitList)
                quit
            end tell
        end repeat
    end if
end try

if isConnected is true then
    repeat while isSSHCnt is false
        tell application "System Events"
            if exists process "Terminal" then
                tell application "Terminal"
                    quit
                end tell
                delay 3
                tell application "Terminal"
                    activate
                end tell
            else
                tell application "Terminal"
                    activate
                end tell
            end if
        end tell
        if (isUpdateDNS is true) and ((length of appDNSUpdate) > 0) and (timeTry is 0) then
            tell application appDNSUpdate
                activate
            end tell
        end if
        tell application "Terminal"
            if (isDelnohup is true) and (timeTry is 0) then
                do script "rm ~/" & strnohup in window 1
                delay 1
            end if
            do script "killall ssh" in window 1
            delay 1
            do script "killall ssh-agent" in window 1
            delay 1
            do script "nohup ssh -D " & SSHLocalPort & " " & SSHUserName & "@" & SSHServerName & " > " & strnohup in window 1
        end tell
        if timeTry is 0 then
            say "Hi, " & (short user name of (system info)) & ". I am your Mac. I am configuring the network for you."
            set JobID to 1
            if isUpdateDNS is true then
                say "Process " & JobID & ": Update DNS"
                set JobID to JobID + 1
            end if
        else
            set JobID to JobID + 1
            say "Process " & JobID & ": Update DNS"
            set JobID to JobID + 1
            say "Process " & JobID & ": Get ready to retry."
        end if
        tell application "Terminal"
            do script SSHPasswd in window 1
        end tell
        say "Process " & JobID & ": Create SSH D connection"
        try
            do shell script "curl --socks5 127.0.0.1:" & SSHLocalPort & " " & URLTestGFW
            say "OK! SSH D has been successfully connected."
            set isSSHCnt to true
        on error
            set isSSHCnt to false
            say "Opps! SSH D connection fail."
            if (button returned of (display dialog "Opps! ssh -D connection fail. Do you want to retry?" & return & "" buttons {"Retry", "Quit"})) is "Retry" then
                set timeTry to timeTry + 1
            else
                exit repeat
            end if
        end try
    end repeat
    if isSSHCnt is true then
        if (isUpdateTwitter is true) and ((length of TwitterUsername) > 0) and ((length of SSHPasswd) > 0) and ((length of TwitterText) > 0) then
            try
                set JobID to JobID + 1
                say "Process " & JobID & ": Update twitter state"
                set TwitterLogin to quoted form of (TwitterUsername & ":" & TwitterPassword)
                set TwitterStatus to quoted form of ("status=" & TwitterText)
                do shell script "curl --user " & TwitterLogin & " --data-binary " & TwitterStatus & " " & TwitterAPI
                say "OK! Twitter state has been successfully updated."
            on error
                say "Opps! Error while updating Twitter state."
            end try
        end if
        if (isRunExSoft is true) and ((count appStList) > 0) then
            set JobID to JobID + 1
            say "Process " & JobID & ": Start Applications"
            repeat with intSti from 1 to count appStList
                tell application (item intSti of appStList)
                    activate
                end tell
            end repeat
        end if
    end if
    tell application "Terminal"
        quit
    end tell
    if (isUpdateDNS is true) and ((length of appDNSUpdate) > 0) then
        tell application appDNSUpdate
            quit
        end tell
    end if
    say "All done! Bye!"
end if

我的第一个Adium Xtra:Snow Leopard iChat

收到来自Adium的邮件:

from    xtras@adiumxtras.com
sender-time    Sent at 8:36 PM (UTC). Current time there: 6:00 AM. ✆
to    i@leaskh.com
date    Fri, Oct 23, 2009 at 8:36 PM
subject    Your Xtra Was Approved
hide details 8:36 PM (17 hours ago)

Your Xtra, Snow Leopard iChat, was just approved:
http://adiumxtras.com/index.php?a=xtras&xtra_id=7119

意味着我的第一个Adium Xtra已经通过官方验证,发布在Adium Xtra官网上面了。

Adium相信是Mac用户都应该知道了,是一个很棒的多协议IM软件
Adium Xtra是Adium的插件架构,该架构通过很多便捷接口把Adium插件开发简化到一个惊人的地步。
只需要懂XML、CSS、Applescript等,就能开发出很好玩的Adium插件了。
这也是我近段时间放弃iChat转投Adium的其中一个原因,当然,另一个原因是Adium支持Windows Live Messenger和Facebook IM等。

好了,上图吧:

我的Snow Leopard iChat安装后,能够让你的Adium在Dock中显示和iChat 5一样的ICON,因为虽然Adium的小鸭子很可爱,但是很多Mac用户都怀念iChat图标的优雅。

喜欢的朋友去下载吧:http://adiumxtras.com/index.php?a=xtras&xtra_id=7119

这次仅仅是试验一下Adium Xtra的插件架构,在我使用Adium的过程中,我发现其实通过目前web 2.0网站的众多API,我们可以做到很多很有趣的事情,例如douban就很有趣,但是douban的机器人一直做得不怎么样。通过Adium的Xtra让douban和IM做整合,就能做出很多有趣的事儿。

等有时间吧,等我的i3机器人开发好了,我会想一下这个问题。

但是最近公司的事情也挺忙呢,不知道要等到何年何月了。

谢谢你,我很感动。

收到来自妮的鼠标垫都有一段日子了,用着挺舒服的。

如果我没有理解错,这种布好像叫做“亚麻”,我挺喜欢那种有略带粗糙的质感,有一种原始的气质。

分享一些照片给大家,同乐:

DSC00008

DSC00011

DSC00013

DSC00014

DSC00019

DSC00021

DSC00023

DSC00024

DSC00025

DSC00028

DSC00031

DSC00032

DSC03989

DSC03990

DSC03991

DSC03992

继续释放ssh -D的力量!

Screen shot 2009-10-15 at 9.09.52 PM

虽然iSSH在Mac上使用已经很便利,但是并不完美,主要是每次都需要重新加载设置才能连接,而且设置的加载也不完整。于是萌生了自己写一个链接端的念头。

程序使用Applescript编写,在Snow Leopard 10.6.1调试通过,程序前半部分通过调用终端实现ssh -D连接,后半部分通过curl调用twitter告诉大家你在“为自由而奋斗”,最后一句是语音反馈,告知你一切已经就绪。

就那么简单。把这个脚本打包成app文件,放在dock上,点击一次就能实现ssh -D翻墙了,一切一切只需要一次点击,自由的曙光离我们越来越近了。

下面提供程序给大家复制,大家可以根据自己的需要随意修改!祝你们好运!

(*
Version 0.3
Code by Leask Huang
http://www.leaskh.com
i@leaskh.com
*)

global ServerName
global LocalPorts
global UserName
global Passwd
set ServerName to "ssh.*****.com" -- Set ServerName
set LocalPort to "7070" -- Set LocalPorts
set UserName to "*****" -- Set UserName
set Passwd to "*****" -- Set Password
set SSHCommand to "nohup ssh -D " & LocalPort & " " & UserName & "@" & ServerName
tell application "Terminal"
    activate
    do script "killall ssh" in window 1
    do script "killall ssh-agent" in window 1
    do script SSHCommand in window 1
    delay 5
    do script Passwd in window 1
    quit
end tell

global TwitterUsername
global TwitterPassword
global TwitterLogin
global TwitterStatus
set TwitterUsername to "*****"
set TwitterPassword to "*****"
set TwitterLogin to quoted form of (TwitterUsername & ":" & TwitterPassword)
set TwitterStatus to quoted form of ("status=" & "@Leaskh I am @" & TwitterUsername & " , and I am crossing the #GFW with #ssh -D now!")
do shell script "curl --user " & TwitterLogin & " --data-binary " & TwitterStatus & "
https://twitter.com/statuses/update.json"

say "Congratulations! Your Socks proxy over SSH dashes D has been successfully connected."

如何分享ssh新鲜-D空气?

很多人问我ssh -D的“新鲜空气”如何分享给别的计算机?又或者如何讲Mac Host Machine的ssh -D代理分享给VMware或者PD里面的虚拟机?

其实稍稍想一下就能想到办法了。以我的例子说一下,望能抛砖引玉。

我的ssh -D在Mac上建立,我想在VM里用IE看“外贸网站”。

首先我们明确一点,IE是不支持通过Socks代理打开网页的,所以我们需要把Socks代理转化为IE能够识别的HTTP代理。工具上理论上用Privoxy或者SocksCap都可以的。但是Privoxy支持配置文件,能够智能选择那些通过Privoxy,那些不通过Privoxy,所以我选择了它。

这里主要考虑到ssh -D主机大多都是算流量的,所以能不通过ssh -D的站点还是直接连接比较划算,Privoxy就提供这个可能性。

看图(我不解释了,有心人一下子就看明白了):

Screen shot 2009-10-15 at 2.49.16 PM

当然,如果你需要看的“外贸网站”比较多,你可以用pac文件做一下智能筛选。pac文件如何写?在终端执行:

       curl https://dl.getdropbox.com/u/873345/download/gfwlist.pac

你就能得到一个很好的范例(基本上是Javascript的语法),这个pac文件也能附加到IE的代理设置里面:

Screen shot 2009-10-15 at 2.52.03 PM

祝大家好运!

万丈红尘心ssh不染,空谷无人水-D自流

Screen shot 2009-10-15 at 1.50.16 PM 

我的blog已经又一次被万能的*G*F*W*评选为“优秀网站”了,在这里我再次表达内心的“狂喜”和“激动”,感谢d-ang的欣赏,因为在我看来,只有很优秀的网站,如Google等才有资格被隔在墙外的。

最近一次被“墙歼”(普通话念)的这段时间以来,心态也转变了很多,从最初的愤怒到现在的理智,其中的辛酸哪怕是有点“互联网良知”的人都会知道的。直到昨天,无意中在一个高人的blog看到,原来ssd -D的技术目前已经相当成熟了(应该说商业运作已经相当成熟)。

//twitter上有人(@lovexshan)问我什么是ssh -d,有一个网页解释得很好:https://dl.getdropbox.com/u/873345/index.html

于是我也终于购买了专业的ssh linux服务器了。测试了一天,效果还算满意。但是抱歉,我承诺过不能在这里提供售卖方的任何信息,如果有人有兴趣,请文下发邮件或GTalk问我。(只能说是价廉物美得很)

目前我主要在做一些web开发工作,涉及到Social Networking和商城网站的整合开发,再加上自己写blog的需要,这两点是我购买ssh -D服务器的主要原因。

简单地说,ssh -D能在执行命令的终端生成一个ssh连接到远程计算机,发起连接的终端提供一个socks代理使得第三方的应用能够分享远程宿主机的Internet资源。

所以,使用ssh -D能够远程使用宿主机的网络身份访问网站。所以诸如facebook、twitter、blogger等这些邪恶的“外贸网站”(最近的提法,大家不许联想),都能高速访问。

经过一番折腾,加上自己的一些实践,目前我的Mac和虚拟的Win2k8r2均实现ssh -D访问“外贸网站”,当然了,这也是我能再次更新我的blog的原因。

这次回归Spaces后,如果时间允许,我打算写一些关于ssh -D访问“外贸网站”的文章,和一些反“墙歼”的经验教训,我也在探索开发一个分布式服务器的理论模型,集合p2p技术的特点,看能不能在“推墙”方面有所作为,但是目前在探索阶段,具体的行动,我还需要仔细思量。现实太残酷。

好了,写到这里,也是我一个人探出墙外胡乱写写东西,国人要看,使用Google Reader或者自行翻墙吧。我照顾不了那么多了。

http://www.leaskh.com

http://feed.leaskh.com

上面第一个是本站地址,第二个是feed订阅地址。祝大家好运。

/*
好久没上来写过东西,不想再多讨论这方面的事情,中国网民其实很无力,集体的网络“暴力”过后,其实剩下的除了所谓的粗俗的几句“网络流行语言”以外,什么也没有留下来。如果真的是那么愤青,真的是想为咱们伟大的祖国贡献一下的话,想一想,你们还有很多事情可以做。
能力越大,责任越大。无聊的人们,好自为之。
*/

本贴用于测试

本贴用于测试通过ssh -d发布,请大家主动忽略之。

用上Windows Server 2008 R2正版了,告别盗版激活Windows 7,发文纪念

 Screen shot 2009-09-15 at 3.57.29 PM

昨天意外得到消息,Microsoft已经向学生帐号发放R2正版授权了,于是登录DreamSpark,果然R2已经能下载并能申请KEY了。

今天一边研究Facebook和Twitter的API(工作需要),一边安装激活R2,然后果断地把Windows 7 Professional的VM文件扔进了垃圾桶。

Screen shot 2009-09-16 at 9.19.04 PM