随便看看Chrome OS

随便看看Chrome OS

和Chrome给我的感觉一样,Chrome OS中,简洁是第一第一第一的印象,这一点很重要。 与Chrome给我的不同是,我喜欢Chrome,我需要Chrome,但是我虽然喜欢Chrome OS,却不需要Chrome OS。 就目前我的体验来说,我用Windows可以做我全部的事情,Linux也可以,基于Unix的Mac OS更加可以,但是用Chrome OS我却不可以。 就一个很简单的要求,我需要Photoshop,就目前而言(不预测未来的情况下)Web上的图像软件没有可以达到Photoshop或者Gimp的水平的。 就不再谈如何搭建各种开发环境了,那么是不是到达“云端的世界”以后开发者、设计者和最终用户会出现一次彻底的分化?是不是就要严格区分开,最终用户运行类Chrome OS的thin客户端,而开发者或者设计师等就需要更强大的fat客户端?就正如把Server OS和Desktop OS割裂开一样?如果事实是这样,那么无疑是互联网的一次实质性的倒退,如果不是的话,各种web apps能不能在Chrome OS到来之前彻底成熟到可以完全取代桌面软件的水平呢?我的意思说,就工作上,我需要的不单单是Office(或者Google Apps)就能完全胜任的。很多很多的应用,就目前而言,抛弃传统Desktop OS还是很不现实的(我很负责任地说)。 每个人都可以预测未来,但是却没有人能对未来下一个定论,每一家公司都在积极备战,在云时代来临之前准备好自己的解决方案,只是各家公司说理解的云,其实千差万别,关键是云所对客户端依赖的程度更是差异万千。理论上来说彻底的云计算(没有客户端)其实没有可能,因为浏览器就是云的一种客户端,然而现实中,Google Gears,Active X等其实正恰恰成为了云时代的障碍,因为其正在不断扩展浏览器和硬件之间的联系,然而这种联系并不在开放的HTML协议中,这将导致应用和接口的进一步私有化和垄断化,可见其实Google和Microsoft、Apple一样,并不是真心希望彻底的云的世界,而是“他们自己”的“云的世界”。其结果是从一种垄断进入另外一种垄断。我心中想的云的时代,并不是需要专门的“硬件(搭载Chrome OS的设备、搭载Mac OS X的设备等)”而是彻底的依赖一个公开的标准的协议搭建的一系列的应用所造就的云,然而任何基于这一标准的thin客户端或者fat客户端软件,都能完全完全地使用所有的功能。“不搞特殊”,才是云的将来。在这一个层面来说,Google没有必要发布Web OS,因为Chrome本来就是很优秀的浏览器,云的应用完全可以很便利地运行其中,所以Chrome OS图的并不是所谓的云计算,而是另外一种商业阴谋(从Chrome不允许自己下载安装,需要在专门的硬件上运行)就可见一斑。 我不敢说未来,虽然大家也知道云端才是未来。所以我更加不知道如何谈未来,“云”正在成为“组织数据”的中心,但是否能成为“应用”的中心这一点我还有保留,而且是否除了“云”和“本地”还会有其他的更加出乎意料的“方式”?所以,Chrome OS能否成功还有待市场的考验,只能说Chrome OS所体现的探索精神,的确很值得很多公司学习,例如所谓的“腾讯”。 // 补充:Google已经决定使用HTML5技术实现Web应用离线工作,而不是仅仅依靠Gears。[Dec 1st, 2009]

Flora_ssh-D Version 2.47发布!//主要修正:iTunes更新大量Podcast的时候脚本超时的Bug。

Flora_ssh-D Version 2.47发布!//主要修正:iTunes更新大量Podcast的时候脚本超时的Bug。

这个版本早就做好了,但是一直徘徊要不要放出来。因为这段时间我在尝试修改autossh的源代码。autossh是一个很优秀的开源项目,我希望build一个带有更完善翻墙功能的autossh版本,目前还是遇到很多问题。由于工作比较忙,可能一时三刻还完成不了,所以还是放出这个版本。这个版本对于一般的用户已经比较完美了,但是对于用Terminal比较多的用户,还是会有一点不适应的,因为脚本中连接ssh的时候会独占Terminal,这个问题我暂时还没有比较好的解决办法。 另外为了提高安全性,我尝试把各种用户名和密码保存在Mac的Keychain里面,但是不知道是不是因为Mac OS X 10.6.x中比较烦人的脚本安全规则作怪,脚本每次访问Keychain都需要弹出对话框让用户确认,所以最终还是放弃了这个做法,希望有解决办法的朋友指教一下。 好了,不多说,最后还是放出源代码(和往常一样,我将在Google Code放出封装好的app和源代码,有需要的朋友直接去下载更新吧): ( Flora_ssh-D Version 2.47 Open Source Project Home/开源项目主页:* http://code.google.com/p/flora-ssh-d/ Code by/程序编写: 黄思夏 / Leask Huang Blog: https://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 with timeout of 3600 seconds if isOLast is “online” then fnTwitter(“I am offline now! // “ & (current date), true) fnShellSSHEnd(true) fnAppQuit() continue quit end timeout end quit on idle with timeout of 3600 seconds 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 end timeout return 60 end idle ( ======= Functions ======= ) to fnCheckNet() try do shell script “curl –connect-timeout 30 “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 30 “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 30 –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 30 “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 30 “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

再度遭遇中国电信智障Web设计师

再度遭遇中国电信智障Web设计师

周末,朋友的天翼189电话疑似被乱扣费,要我帮她上网查询一下通话记录,于是我又一次登录中国电信的网上营业厅,又一次被震撼。 很难想象国内的3G能带来什么优秀的用户体验,我再一次被中国电信的Web设计师的设计能力所震撼(我的Blog中有上一次被震撼的经历,大家可以自行Google)。 登录你会发现有两个验证码?这是我见过的“最安全”的站点,中国电信!“好样的”!不过有趣的是填着填着,其中一个验证码框框就消失了,好神奇呀!换用各个浏览器,效果都是如此,这回长见识了: 其次,不支持Safari、Firefox!!如果你使用非IE浏览器调用话费查询的功能,你根本无法找到开始查询的按钮,换用IE,按钮就出来了,IE真“强大”。如下图,非IE浏览器下账单显示的地方变成了“温馨提示”,好神奇呀!电信想告诉我:“黄先生,您的话费是人民币 温馨提示.00 元整!”: 好了,迫不得已又换用IE登录,这回更厉害了!我一不小心,把“手机号码”写错了,程序提示我“手机号码错误”,然后我更正。又一不小心,把密码填错了,程序提示我“密码错误”。神奇的事情开始了,我按一下“OK”,提示“手机号码”错误,再按一下“OK”,提示“密码错误”,我不停按,不停交替显示两个错误。然而这个对话框并没有“Cancel”的按钮。我一直按,按了不下30次,反复出现两个错误。我彻底死心了,整个IE被这个死循环卡住了,最终我只能强制退出IE了。 朋友们,不要说我偏激,当一切都在吹嘘“与世界接轨”的时候我们不妨想想,如此的Web交互水平,比好多国内的网站都不不上,不要说什么Google、Apple!!什么的了,到时候老外来了,带着各种各样的设备(浏览器千差万别)以及勉强可交流的汉语,如何使用你如此“高级”的服务呀!?我相信国内不是没有“牛人”,错了,不是没有“智力正常”的人,为什么如此神奇的设计可以出现在我们伟大的“国家电信公司”里面!?估计是某人的“废物子弟”通过不知哪个狗洞钻进去了吧。 失望,苦恼。为什么我要说那个不知名的设计师智障呢?因为我的智商本来就很低了,我觉得既然连我这么笨的人都可以做好的事情,那这个做不好事儿的可怜虫只能算是个智障的孩子了。不开放竞争式的人才制度,谈什么与国际接轨!?根本就是放屁。不单单电信产业这样,悲哀的是国有企业几乎都如此。 我还有大量类似的例子,有时间再一一分享给大家。 如果真有某人看了觉得被冒犯,敬请原谅,就事而论,想得到别人的尊重,请先把事情做好。

Flora c^2发布!当前测试版0.7

Flora c^2发布!当前测试版0.7

程序员通常会遇到需要计算的时候,然而并不单单是加减乘除,我们需要带有表达式支持的计算功能。我想在*nix上没有比bc更加便利的了,但是bc有一点让我很压抑的就是bc的小数处理需要在每次进入bc的时候设置,十分不友好。于是就萌生了用shell脚本封装一下bc的想法。于是我封装出一个计算器[C]alculator。 设计师常常有截取网页全图的需要,于是我曾撰文《在Mac上通过Terminal截取网页全图 / Full Page Screenshots by Terminal On a Mac》(URL:http://honeonet.spaces.live.com/blog/cns!15BAC1A170471DB!15092.entry)提出通过webkit2png截取网页全图的方法。但是webkit2png使用也并不太便利:默认情况下每次使用都要求输入webkit2png脚本所在的位置,默认参数会输出3个尺寸的图片,默认参数下图片会存储在shell当前的工作目录(并不人性化),默认情况下不能识别“www.yourdomain.com”或者“yourdomain.net”这样的地址(webkit2png要求输入完整的,如“http://www.yourdomain.com”这样的地址),默认情况下webkit2png生成的文件名也不符合Mac上截图热键生成的带有时间信息的文件名的习惯!!有没有办法让webkit2png更加聪明好用呢?于是我又把webkit2png封装了一下,得到一个Web Pages [C]atcher。 昨晚突发奇想,把两个类似的脚本整合一下: [C]alculator * Web Pages [C]atcher = c * c = c ^2 于是我把我的脚本命名为Flora c^2,主要是应付我的工作要求,顺便写出来分享给大家,希望也能为大家的工作提高一点点效率。 脚本需要你先下载好webkit2png,方法见我上面提到的文章,然后在脚本中注释掉以下这行,如: # bitmapdata.representationUsingType_properties_(AppKit.NSPNGFileType,None).writeToFile_atomically_(filename + “-full.png”,objc.YES) 【去掉】 添加下面一行: bitmapdata.representationUsingType_properties_(AppKit.NSPNGFileType,None).writeToFile_atomically_(filename + “.png”,objc.YES) 【添加】 然后保存我下面的代码为shellscript,然后和webkit2png放在同一个文件夹,设置好文件夹和脚本的权限都是允许执行的,如果不和你的程序名称冲突,建议把文件名存为“c”(就一个小写c就好了,便于执行)。 // 注意了,别忘记你可能还需要把你的脚本文件夹添加到$PATH环境变量中! 代码如下: *#!/bin/bash ################################################# Flora c^2 0.7 ################################################# What’s c^2? c^2 for [C]alculator & Web Pages [C]atcher Code by LeaskH.com November 7, 2009 #################################################* header () { echo “Flora c^2 0.7 by LeaskH.com // based on bc 1.06 & webkit2png 0.5”; echo “”; } fnwebkit2png() { python “$(dirname “$0”)”/webkit2png -W 1024 -H 768 -F -o “Web shot date "+%Y-%m-%d at %H.%M.%S %p"” -D “~/Downloads” $1; echo “”; } fnbcexec() { echo “scale=7; $1” | bc; echo “”; } calexec() { while true; do if [ -n “$strfloratc” ]; then if [ “$strfloratc” != “” ] && [ “$strfloratc” = “h” ]; then echo “Options include:”; echo “ h - This help file”; echo “ hb - bc help file”; echo “ hw - webkit2png help file”; echo “ c - Clears the screen”; echo “ q - Quits the program”; echo “”; strfloratc=””; fi if [ “$strfloratc” != “” ] && [ “$strfloratc” = “hb” ]; then bc -h; strfloratc=””; fi if [ “$strfloratc” != “” ] && [ “$strfloratc” = “hw” ]; then fnwebkit2png –help; strfloratc=””; fi if [ “$strfloratc” != “” ] && [ “$strfloratc” = “q” ]; then exit; fi if [ “$strfloratc” != “” ] && [ “$strfloratc” = “c” ]; then clear; header; strfloratc=””; fi if [ “$strfloratc” != “” ] && [ “${strfloratc:0:4}” = “http” ]; then fnwebkit2png $strfloratc; strfloratc=””; fi if [ “$strfloratc” != “” ] && ([ “${strfloratc:0:3}” = “www” ] || [ “${strfloratc:0:3}” = “wap” ]); then fnwebkit2png http://$strfloratc; strfloratc=””; fi if [ “$strfloratc” != “” ] && ([ “${strfloratc:(-3):3}” = “com” ] || [ “${strfloratc:(-3):3}” = “net” ]); then fnwebkit2png http://$strfloratc; strfloratc=””; fi if [ “$strfloratc” != “” ]; then fnbcexec $strfloratc; strfloratc=””; fi fi if [ $1 = true ]; then read -p “” strfloratc; calexec true $strfloratc; else exit; fi done } header; strfloratc=$1; if [ -n “$1” ]; then calexec false; else calexec true; fi exit 0; ok,就那么简单。 下面看看执行效果: 上图演示内容: 通过 c + [空格] + [表达式] 直接计算; 通过 c + [空格] + [网址] 截取网页全图; 通过 c 启动程序,程序启动后,输入表达式直接计算,输入网址自动截取; 查看Downloads文件夹,三张网页截图已经安静地呆在里面了。 文件名的设定我按照Mac的习惯设置,Mac上的图片截取文件名为:“Screen shot 2009-11-06 at 12.25.15 PM.png”,于是我设定的截图文件名为:“Web shot 2009-11-08 at 17.17.46 PM.png”。 截图文件保存在~/Downloads文件夹。通过h命令查看程序帮

关于ssh -D翻墙分享的一些遗补(附pac文件的改进探索)

我曾在过去的文章中提到过,由于购买的商业ssh服务器大多数只允许一个用户在一个机器上登录,因此如果你家里有超过2个电脑需要翻墙,又或者你的iPhone或者iPod touch、PSP等和你的电脑位于同一个无线路由器下,你希望你的设备同样能分享主机的ssh -D连接。 前文中我写到可以把代理服务器指向你已经创建ssh -D代理的主机,这样做在我的VM虚拟机里面是能够分享到宿主机Mac上的ssh -D连接。但是上个星期我购买了一款叫做Simplenote的软件,正当我想要同步Mac上的笔记到iPod touch上的时候发现同步失败。经过研究发现Simplenote同步需要连接Google appspot服务器,然而appspot在我所在的区域已经被“墙歼”了,于是我尝试在iPod touch上分享我Mac上的ssh -D连接,意外地失败了。测试手上的P1i通过wifi分享来自Mac上的ssh -D连接,同样失败。经过一番折腾,发现原来ssh -D默认是不响应来自远程主机发起的连接的,如果确实需要分享,你需要在ssh -D后面再加上一个-g的参数,如: ssh -D 7070 -g username@ssh.yourdomain.com 用这个参数创建的连接能够顺利把ssh -D的代理分享出去,当然了,你可能还会遇到pac文件的烦恼,毕竟每个人所要求翻墙访问的站点都不同。下面我分享一下我的pac文件的写法: // Flora AntiGFW PAC // Version 5.0 // by LeaskH.com // i@leaskh.com function FindProxyForURL(url, host) { // AntiGFW var arrStrGFWSites = [ “appspot.com”, “honeonet.spaces.live.com”, “blogger.com”, “blogspot.com”, “w3schools.com”, “box.net”, “bit.ly”, “j.mp”, “vimeo.com”, “mediafire.com”, “wordpress.com”, “tistory.com”, “aol.com”, “aim.com”, “bebo.com”, “cnn.com”, “hellotxt.com”, “dougscripts.com”, “iphone-dev.org”, “dailymotion.com”, “yylyyl.co.cc”, “googlevideo.com”, “imageshack.us”, “cafepress.com”, “twitterfeed.com”, “hotspotshield.com”, “youtube.com”, “twitpic.com”, “mckaywei.com”, “mimima.com”, “no-ip.com”, “oikos.com.tw”, “////”, “ytimg.com”, “sesawe.net”, “freemorenews.com”, “theappleblog.com”, “chinagfw.org”, “chinadigitaltimes.net”, “dropbox.com”, “facebook.com”, “s.leaskh.com”, “sites.weborigin.co.nz”, “docs.weborigin.co.nz”, “calendar.weborigin.co.nz”, “google.com/search?twitter”, “google.com/search?@”, “google.com/search?youtube”, “sites.leaskh.com”, “docs.leaskh.com”, “openvpn.net”, “simplenoteapp.com”, “code.leaskh.com”, “moderator.leaskh.com”, “calendar.leaskh.com”, “mail.weborigin.co.nz”, “mail.leaskh.com”, “yfrog.com”, “viewmorepics.myspace.com”, “messaging.myspace.com”, “*http://*twitter.com”* *]; // Block unsafe sites var arrStrUNSSites = [“74.55.154.140”]; var strActProxy = “DIRECT”; for(var iAS = 0; iAS < arrStrGFWSites.length; iAS++) { if(shExpMatch(url.toLowerCase(), “” + arrStrGFWSites[iAS].toLowerCase() + “”)) { switch (myIpAddress()) { // When I using Virtual Machine case “172.16.49.133”: // My Virtual Machine’s IP strActProxy = “PROXY 127.0.0.1:8118”; // My Privoxy Proxy on VM shared from Mac’s ssh -D break; // When I using iPod touch case “10.0.1.253”: // My iPod touch’s IP strActProxy = “SOCKS 10.0.1.254:7070”; // My iPod touch can visit my My by this IP break; // When I using Mac default: strActProxy = “SOCKS 127.0.0.1:7070”; // My real ssh –D break; }; }; }; for(var iAS = 0; iAS < arrStrUNSSites.length; iAS++) { if(shExpMatch(url.toLowerCase(), “” + arrStrUNSSites[iAS].toLowerCase() + “”)) { strActProxy = “PROXY honeonet.spaces.live.com”; // Input a site which is already blocked by GFW }; }; return strActProxy; }; 以上就是我的pac脚本,应该说用pac分配代理服务器是非常便利和强大的。pac配合ssh -D简直就是“奔向自由”的两件神器。我的pac主要有如下特点: 通过单独一个pac文件,管理你所有设备的代理服务器,不再需要为每个不同的设备配置不同的pac文件了; 把Twitter的适配URL写为:[http://twitter.com](http://twitter.com),区别于网上的写法,因为Twitter是能够通过https访问的(改host),当我们通过https访问的时候,我们不需要通过代理,对于Tiwtter重度使用者,这样能够节省下很大程度的ssh流量,这样写只有使用普通http协议访问的时候才会通过代理; 引入 google.com/search?twitter* 的写法,就是当你的Google搜索关键字包含“Twitter”的时候,也通过代理访问Google,这个写法是很有用的,当然了根据实际用途,你要把“Twitter”改为你关心的,被和谐了的关键字哦,例如“六四”等等(不许联想)。 引入 //// 的写法,就是加入一个网站你突然访问不到,你可以在URL地址后面加////,然后再尝试打开,那么这个地址就 会通过代理访问了,那就不需要每次都改pac文件才知道站点是不是被墙了,十分便利哦; 引入 google.com/search?*@ 的写法,由于Google出于私隐保护的需要,Email地址中的@符号是不会被Google索引的,所以@在搜索关键字中会被自动忽略,利用这一特性,我们在搜索一个敏感关键字的时候在关键字中插入一个@符号,那么就会自动通过代理访问Google了,由于Google会自动忽略@,所以并不会影响你的搜索结果,特别是在屏蔽比较多的图片搜索中,这个方法十分管用; 出于安全考虑,有一些站点虽然没有被墙但是我们是不愿意访问的,例如带有病毒的站点或者钓鱼站点等,这些站点也能够利用pac文件来屏蔽,因此,我的pac脚本中带有两个数组,第一个是用来分辨是否被gfw墙的站点的,这个数组叫做arrStrGFWSites,然而我还引入了另一个数组arrStrUNSSites,用来过滤不安全的站点,你把自己认为不安全的站点写在里面就行了,脚本将把这个URL指向一个被墙的站点,达到过滤的目的。 本文的pac文件大家是不能直接用在自己的网络环境里的,写出来只是为了抛砖引玉,期待有喜欢折腾的高手写出更加智能的pac文件。 服务于生活,这正是编程的意义所在。今天就写到这里。 // 补充:如果你只需要在iPhone或者iPod touch上翻墙,那么由于iPhone OS基于Unix,是可以直接创建ssh链接的,只需要Cydia安装Openssh、Openssl和Mobile Terminal就可以了。基于Linux的设备也大同小异,例如Google的Android电话。

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

在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 https://leaskh.com/ 执行效果如下: 然后你就会发现网页已经被截图放在你的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 [https://leaskh.com](https://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性能大不如前,稳定性下降,风扇噪音越来越大。 今天由于温度过高,突然断电,我可怜的写了一个多小时的数据分析告吹了,于是向公司反映,请假维修MacBook。 推测是散热风扇出毛病了,Google了MacBook的风扇价格,高得惊人,只能考虑自己修一下。 经高人(我哥)指点,找来一瓶“防锈润滑剂”,我选的叫做“WD-40”(现在买免费加送20%哦)。 其实一瓶也就10块钱,买一个原装风扇可以买几十瓶了。 大概这个样子的: 动手!开始拆开: 翻开上盖,尘封程度惨不忍睹,风扇基本上已经被灰尘堵住转不起来: 用废旧牙刷刷干净主板,使用润滑剂对着风扇轴承处,使劲喷。 注意,润滑剂使用二氧化碳推进,喷劲十足! 喷出来会是雾状,而且有腐蚀性,最好不要沾到手,而且最理想的情况是用纸巾把屏幕也遮蔽一下,大致情况如下: 来一张清洁前后的效果对比图: 然后按照拆开的方法装回去,机器立刻变得安静凉爽,如果你的是MacBook,并且使用时间达到一年左右,你应该会遇到和我一样的问题(网友大量反映),建议你试试我的方法。因为较低的温度会延长你风扇和内部零件的寿命。而且用起来,也不再烫手了。 // 最后提醒大家拆机有风险,要求胆大心细。祝你好运! // 对了,拆机的教程我是看ifixit的,一个很著名的Mac全系列拆解网站,里面的教程很详细,十分具有参考价值,网址请自行Google。