
|
最 新 文 章 |
|
|
|
民主的贫困(节录1、 扩展1、 扩展2) 孕龄妇女就业 |
|
|
引入思想比引入方法更重要 语言学假说 无题 双重反思 |
|
|
宗教趣谈(一、 二、 三、 四) 苦地迦南 (上篇) |
|
|
从推广角度看网站分类及其他 |
|
|
什么是烟花?几时是三月?何处是扬州? 春风十里扬州路 |
|
|
确定且复杂的世界(概要) |
|
|
CSDN博客 英文技术博客 MSN 我的人人 我的公司 |
我是热烈的
作者:kmzs 日期:2010-09-01
[REAL Studio]保存文件位置信息
作者:kmzs 日期:2010-08-15
SaveInfo需要通过FolderItem类的GetSaveInfo方法来获取,这个方法有两个参数,第一个是相对路径(也是一个FolderItem实例),后一个是个可选的模式参数。
举例如下(假设有个全局字符串变量s):
Dim f,d as FolderItem
f=Volume(0).Child("Doc").Child("abc.txt")
d=Volume(0).Child("Doc")
s=f.GetSaveInfo(d)
在Windows上,f是C:\Doc\abc.txt,d是其所在的文件夹,但其实d可以是任何一个文件或文件夹。上述代码执行后,s中就保存了文件f的SaveInfo,可以将其写入程序设置文件、某个数据库、注册表或defaults中,以便于以后读取。
要从SaveInfo中解析出文件,只要这样:
Dim f As New FolderItem
f=f.GetRelative(s)
那么使用SaveInfo有什么好处呢?主要有两点:
1)用于通过相对路径找到文件。比如某个文件夹A中有文件b,在调用GetSaveInfo时,将A传入,即s=b.GetSaveInfo(A);随后如果你整体移动了文件夹A(b仍在A内),在试图解析出b时,通过b=A.GetRelative(s),仍然可以找到b,当然这里的A必须是指向移动后的文件夹。
2)即便不需要上面这个好处,也应该使用GetSaveInfo,它不光保存了相对、绝对路径,还保存了其他信息,使得更名或移动过的文件(主要在Unix系统上)仍能被找到。比如在Mac上,使用s=f.GetSaveInfo(Volume(0))并将s的值保存起来,以后即使文件f被改名或移动(严格的说是在当前磁盘分区,或者说卷内移动,当然在Mac上跨磁盘移动不容易,要Command+Shift+拖曳文件),仍然能通过所保存的SaveInfo解析到更名或移动后的文件。对这种用法,向GetSaveInfo中传入什么都没问题,此处传入Volume(0),是因为Volume(0)是系统盘根目录,只要不是无盘工作站之类,这个FolderItem都不会为Nil,而且它的“位置”通常极少可能会改变。
因此在REAL Studio中首选应该保存SaveInfo而不是AbsolutePath。这样至少在Mac上,不会由于文件移动或更名而找不到。大部分Mac软件的Open Recent子菜单都不会由于文件被移动而无效,但一些只追求跨平台而忽视native特性的公司的产品或许会这样,比如Adobe的一些软件。
[确定且复杂的世界]十二条概要
作者:kmzs 日期:2010-08-11
人类每每在物理或人文的世界里向前踏出一步后,在获得新的知识以归纳或解释以往看到的现象的同时,我们总是很疑惑地发现,新的理论要么是一种只在更大范围内有效的,可能在未来会被推翻的,不甚完备的假说,要么是观察分析所得到的更深一步的现象,而导致这些现象的进一步原因,或者说这些现象所对应的本质还在更深处。
因此《确定且复杂的世界》一文,虽然是本人对自己当下的世界观的一个总结,但也不过是从某个角度,在某个层次上进行思考的所感所得。这些思考肯定是有失片面的,而且在一些地方混用了略有差异的词汇,或选择了不太恰当的术语,但是或许仍然多少有些启发作用。
原文冗长而带有较多细节上地推导或阐述(还有一小半仍是草稿或提纲),提取一些核心内容进行梳理是有必要的。在此对其中大部分主要观点简要概述如下:
1、世界的未来存在确定的结果,人类一定无法准确预测到世界在未来某时刻的精准的状态,但不能由此认为世界有多种结果或可能有或然的结果。
2、人所生活的世界,是一个极为复杂的世界,那些看似无关主旨的因素所带来的影响与误差往往不可以被完全忽略。它们的累积,会使世界在表象上看起来是极具偶然性和随机性的。但是,由于任何具有偶然性的事物都有几乎无限多的使其不得不发生的诱因,而任何具有随机性的事物不过是相关影响因素过多而使人无法事先预测到其最终的结果。这些诱因或因素中的哪个都不会无理由的出现或不出现,因此世界在未来的状态是确定的,但又是处于世界之中的人类而无法准确预测的。
3、将所发生的任何一个事件作为结果,向上逆推都会得到一个庞大无垠的因果树,这些“树”上的每个枝丫和叶子都是一个导致结果的直接或间接的必要条件。真正的或者说绝对意义上的充分条件是不存在的。可以说,所有事件的结果都是由多个条件引致的,这些条件甚至都不是有限可列的,因此能用语言描述的严格的规律是不存在的。世界为逆蕴含关系所充满,随处可见的都是些被称为规律的不完全的“真全称命题”。这也导致许多人只愿意用“趋势”之类模糊的词汇来称呼一些事件中含有的规律性。
4、内因并非是完全内生的因素,它们只是在特定时点静态地观察和分析某物体而得到的。从历史角度动态地来看,内因是历史上各种外生性原因在集聚、融合和抵充、消解后的所得的产物,或者说是历史上种种外因的综合与凝结,而不像听上去的那样是由内部自行产生的,更不是外因的严格对立面。
5、对于某个事件或物体(包括个人或组织等复杂物体),当某个外部事物出现时,它需要先通过由此前的外因所综合凝结成内部状态的过滤和筛选。一些外物会被完全排斥,剩余的会对内部状态进行一定程度的增加、强化,或破坏、抵消,最终以复杂的形式构成了此后内部状态,即后续问题的内因。随后的外物(对人来说比如外部物质和信息的摄入)会不会对物体起作用,会起什么样的作用,以及会其多大的作用,则在很大程度上由内因──历史上的外因的综合凝结体──来决定。以此循环往复,从而决定了这个物体的现在并影响到它的未来。总之,从历史的角度看,每个内因都是由一些历史上的外因和当时的各种内因交互影响而成的,并非字面看上去那样像是完全内生的。
6、文化是一个民族或地区在历史上的外因的综合凝结和内化,并随着历史的发展逐渐形成和演变。经济因素亦是要通过一种内化的外因而起作用的,这种内化的外因就是作为生物体的人的个体,在孕生和成长过程中形成的对物的欲望。文化与经济因素之间也会彼此的影响,这是一种复杂的相互作用。从马克思的视角来看,这是生产关系和生产力之间的作用与反作用,但应该不仅限于此。
7、任何物体都经历了从无到有的形成过程,这并不是说从虚无中会诞生物质,而是说任何物体都是由本不属于它的外来因子,以或简单或复杂的形式物组合或结合而成的。
8、从无到有的过程,准确地说是个从非到是的过程。非与是之间的分水岭往往不甚明确,这一般而言也是量变与质变之间的分水岭。在这个分水岭前的许多因素,对其后的状况仍有不可忽视的影响。因此,或许可以得到这样一个假说:越早出现的外部因素对物体通常有越本质性的、决定性的作用。如果最初的基因决定将诞生的是一只猴子的话,即使在怀胎时和诞生后摄入的物质对大脑、神经系统和内分泌系统等的改善作用再大,即使进行再好的胎教和出生后的教育,这个东西也不可能具有人的智慧。
9、作为个体的人也经历了从无到有,从非到是的形成阶段,并继续发展。构成人体的每个分子、每个基因都不不是人体中内生的,它们来源于外界,前者还会通过新陈代谢而与外界交换。影响人的思想的形成的每条信息也都来自于外部,且会互相影响,互相增强,或者互相抵消。各种物体的性质和人的思想,在形成和发展过程中都主要受外物的影响,这些外部事物在为人所遇见前(事)或要进入人体前(物)是外因,在影响发生后则由综合凝结而内化,转换为了内因。
10、与其说人的精神世界(心理、性格、思想、意识等)是被基因和环境所决定的,不如说是被体质和信息所决定的。由于体质的决定因素可以归结为基因和摄入物两者。因此可以说人的精神世界是由基因、摄入物和所接触到的信息这三类外物的相互作用所决定的。
1)来自父母的基因,几乎是最早出现的外因,对大脑和身体状况有显著的决定性影响。其中,对大脑组织结构的决定性影响,很大程度上决定了人的大脑、神经系统等功能和人智力水平。而大脑功能(比如大脑的各个部分分泌的各种激素和脑髓液的能力等)及受大脑功能决定的智力水平等都可以直接影响到人的心理、性格和思维方式。而基因对身体其他系统的体质的决定性作用,则会逐渐地间接地对人的心理、性格等产生影响。
2)在出生前从母体摄入的各种物质(严格地说,还应该包含配子本身提供的少量物质),和出生后从外界摄入的各种物质,不但对身体发育产生影响,对大脑、神经和内分泌系统的功能有重要的影响,因而会对来自基因的决定性因素予以增强或抵消,从而影响人的精神世界。
3)人在未出生之前就会先产生意识并通过尚未发育完全的器官获取一些信息。随后,人的每时每刻(可能除了少数深度休克状态之外)都在获取信息,这些信息(外部因素)依照其被人所感知的先后顺序进行内化,与当时人的思想意识相互增强、融合、抵消或被排斥,最终或大或小的对人的精神世界施予了影响。
总之,精神世界从产生之初就受物质世界(基因、构成身体的各种物质──当然都源于外部)的影响和控制,在形成发展过程中,还要不停地受外部信息的强化或扰动。
11、要改变一个人的某种行为,就要施予足够强烈的外部刺激,以抗衡或在一定程度上转变由以往的外因逐渐综合凝结而成的精神世界。因此,改变一个人的某个行为的成本可能非常高。这需要耗费大量的资源和时间去思考和寻找对其有效的刺激,并予以施行。如果这种成本超出可接受的阀值,人又无法改变自己去适应和接受对方,那么人们可能会放弃改变他人,而采取更激进的策略:对于自己的合作者(比如同事、情侣、配偶等),将设法予以弃离或更换;对于对手和敌人,则甚至会设法干脆将其消灭。
12、人作为一种高级而复杂的生命体,存在主观能动性是毋容置疑的。但从上述各点可知,所谓的人的主观状况并非是一种纯粹的内生的主观,而是受历史上的外部因素决定的主观,即受从两个配子结合开始至今经历或摄入的各种事物决定的主观。因而作为个人,其主观能动性是受限的。也正是由于这种有限性,如何认识自我和突破自我才是一个永恒的命题。
(此概要着笔于2010年3月中旬,初定于2010年8月11日)
通过编程访问Google账户和服务
作者:kmzs 日期:2010-07-31
1、Google账户登录
通过程序登录Google账户的方法有很多,最简单的方法是使用ClientLogin这个API,在桌面程序中一般可以使用这种方式。为了测试,可以直接在浏览器中调用这个API来看结果,URL类似这样:
https://www.google.com/accounts/ClientLogin?accountType=HOSTED_OR_GOOGLE&Email=YourAccount@gmail.com&Passwd=PASSWORD&service=xapi&source=YourCompany-YourApp-Version
其中Email=YourAccount@gmail.com是你的Google账户Email地址,Passwd=PASSWORD是账户的密码。service是要访问的服务名,对于Google Calendar服务,要传递cl。source是登录来源,也就是你的程序的名称之类。注意上面的关键字是区分大小写的,比如“Email=”中的“E”一定要大写。
以REALbasic语言为例,来看看怎么用程序来处理。在这里我们使用同步模式的HTTPSecureSocket来发送请求。
Dim https As New HTTPSecureSocket
https.Yield=True // 同意让渡CPU时间,以防在发送请求过程中界面长时间停止响应
Const PostURL="https://www.google.com/accounts/ClientLogin"
Dim form As New Dictionary // 使用字典组装表单,这比用“+”运算符连接字符串来组装URL要方便
form.Value("accountType")="HOSTED_OR_GOOGLE"
form.Value("Email")=“YourAccount@gmail.com"
form.Value("Passwd")="PASSWORD"
form.Value("service")="cl" // 指定访问Google Calendar服务
form.Value("source")="REALSoftware-REALStudio-"+RBVersionString
https.SetFormData(form) // 将表单指派给https,会对特殊字符编码,比如空格会被转为“%20”。
Dim ResultValue As String
ResultValue=https.Post(PostURL,20) // POST表单到指定地址,20秒无返回则自动超时
如果成功(https.HTTPStatusCode=200),ResultValue中将得到类似这样的3行返回结果(失败的话https.HTTPStatusCode=403并会返回错误信息):
SID=DQAAAH4AAADifYYKy7p9Lg7KdT4BW3zb7RvFmKJm7iJgQ2hjpTG6CLhVnQPFybD8t_odSpU5ZgODxcXnGi50cc-Ky8u-O0KaQiCEydE9RurCkoLEywY7a6trnN6mQW5SmcgjiNCwqiIzhAvQcu-0RFrvKQNJX78GQE4fFE_fs4uX2GTYleQGQg
LSID=DQAAAIAAAABWZhQlKvg2elXVWVttR23V2AWMu57XXvOiJJbGrHlUZW-96nsaokBwCzxs8_edWSDZOU3lU71R14u8QntrODC7WAFlBMkG04GZzIND7WPqX73t--dUAkYVlDoyfwP4N7bTNrg5VsOeeYervrxs_ADg8MBpqlnw-bbjIcyIub8org
Auth=DQAAAIAAAABWZhQlKvg2elXVWVttR23V2AWMu57XXvOiJJbGrHlUZW-96nsaokBwCzxs8_edWSC5iZ0YUERmdfIogOo05uk-YFGm0na7lYS_yT-_BNOLSBZeDcwtOOp9osxbv_7oUdGHbfhOoDza6G-ISUZM4dYgkDNmWyOqjTUwwbWAbbjU4w
这里我们只需要使用最后一行“Auth=”后面的内容(称为验证令牌)。将它解析出来保存到字符串变量AuthToken中(解析过程略),然后要设置一下后续的Google账户访问时需要发送的HTTP报头:
https.SetRequestHeader("Authorization","GoogleLogin auth="+AuthToken) // 将验证令牌放入Authorization请求头中
https.SetRequestHeader("GData-Version","2") // 如本文开头所说,我们要使用2.0版的API,所以设置GData-Version头
2、调用Google Calendar API
下面这个API用于获取已登录的用户的所有日历:
https://www.google.com/calendar/feeds/default/allcalendars/full
要使用这个API,只要继续用上面那个设置好验证令牌的HTTPSecureSocket实例向这个地址发送GET命令即可。
Const AllCalendarURL="https://www.google.com/calendar/feeds/default/allcalendars/full"
dim v As String=https.Get(AllCalendarURL,20) // 这次用GET(不要用POST),超时仍然选20秒
但得到的返回值v中的多半不是XML格式的日历列表,而是像这样一个HTML页面:
- <HTML>
- <HEAD>
- <TITLE>Moved Temporarily</TITLE>
- </HEAD>
- <BODY BGCOLOR="#FFFFFF" TEXT="#000000">
- <H1>Moved Temporarily</H1>
The document has moved <A HREF="https://www.google.com/calendar/feeds/default/allcalendars/full?gsessionid=gC7NAlsQASjnE_wXPF1kxQ">here</A>.
- </BODY>
- </HTML>
此时,如果检查https的HTTPStatusCode属性,会发现它的值是302,而不是200(OK,正常)。 302在HTTP协议里是Redirect(重定向)的意思,重定向到了上面那个HTML中显示的地址。我们不需要从HTML里解析它,一则这样太麻烦,二则Google可以自己决定对于302这个状态应该返回什么样的正文文本,如果Google做了些改动,我们解析方法可能就失效了。那怎么办呢?应该想到HTTP协议返回的内容不光只有页面正文,还有页面报头。我的经验是,进行通过HTTP访问某个网站开放的API一类的开发,经常检查一下返回的页面的报头是个好习惯。可以通过HTTPSecureSocket的PageHeaders方法,或在调试器中看_pageHeaders属性来查看报头,对于上面的GET操作,我们会看到这样一组报头:
Expires: Sat, 31 Jul 2010 12:43:48 GMT
Date: Sat, 31 Jul 2010 12:43:48 GMT
Set-Cookie: S=calendar=gC7NAlsQASjnE_wXPF1kxQ;Expires=Sun, 31-Jul-2011 12:43:48 GMT;Secure
Location: https://www.google.com/calendar/feeds/default/allcalendars/full?gsessionid=gC7NAlsQASjnE_wXPF1kxQ
Content-Type: text/html; charset=UTF-8
Cache-Control: private, max-age=0
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
可以看到Location头的值正是跳转目标的URL,和HTML中显示的URL一致。
那么我们也进行“重定向”,向新地址发送GET命令:
Dim headers As InternetHeaders=https.PageHeaders // 读出所有InternetHeaders
Dim Result As String
If headers<>Nil Then
Dim RedirectTo As String=headers.Value("Location") // 读取Location头,以得到重定向地址
If RedirectTo<>"" Then Result=https.Get(RedirectTo,20) // 继续GET,向新地址请求数据
End If
但是结果很可惜,我们得到了又一个类似上面那样的HTML和一个新的302,如果继续下去你会得到永无止境的大体相同的HTML和302状态。为什么会这样呢?比较一下各次得到的正文内容或Location头,你会发现差异在URL里的gsessionid=xxxxxxxx一段。这段内容给出了会话ID(或者叫会话种子,Seed),这意味着我们必须使用这个会话才能继续执行后续的API。
要注意,HTTP协议是一种无连接协议,客户端发送请求时建立连接,服务器响应请求返回了数据后,连接立即断开。对于Google API,为了避免每执行一个API函数就进行一次登陆验证,服务器端会以会话ID为索引保存一个上下文。相应地,在客户端向服务器发送请求时也必须同时发送这个会话ID,以使服务器知道它所保存的哪个上下文和这个客户端对应。因此客户端也要保存这个会话ID和一些信息,以便在发送请求时使用,客户端所保存的东西被称为Cookie。
在REALbasic语言的HTTPSecureSocket类中怎么使用这些“曲奇饼干”呢?回过头来再看上面的那组报头,发现有一个名为Set-Cookie报头,可以看到其中也包含gsessionid的内容。这就是我们要保存并在后续访问中使用的Cookie了。所谓的“在后续访问中使用”,意思就是在后续的请求中作为报头发送给服务器。因此可以不必使用额外的变量,只要像上面保存验证令牌和GData版本号那样将Cookie缓存到https对象的RequestHeader里面就行了。现在修改上面的代码如下:
Dim headers As InternetHeaders=https.PageHeaders // 读出所有InternetHeaders
Dim Result As String
If headers<>Nil Then
Dim Cookie As String=headers.Value("Set-Cookie") // 从Set-Cookie头读出Google要求我们使用的Cookie
Dim RedirectTo As String=headers.Value("Location") // 从Location读出重定向地址
If RedirectTo<>"" Then
If Cookie<>"" Then https.SetRequestHeader("Cookie",Cookie) // 将Cookie写入请求报头中
Result=https.Get(RedirectTo,20) // 向新地址请求数据
End If
End If
这回Result中将收到含有日历列表的一个XML格式的字符串(实际上是Google Data格式的,也可以是RSS或Atom格式)。接下来只要用XMLDocument和相关的类进行解析,就能获取我们想要的数据了。
(转载请注明来源:http://www.3exware.com/home/default.asp?id=77)
[枕上文]堂兄妹与表兄妹数量差不多?
作者:kmzs 日期:2010-07-25
但同辈的表亲则要复杂多了,劳动了一下脑细胞,发现可以分为以下十一类:
1、外祖父及其兄弟的孙子、孙女(舅表,与母亲同姓)
2、外祖父的姐妹的孙子、孙女(舅表,姓氏不定)
3、外祖父及其兄弟姐妹的外孙、外孙女(舅表,姓氏不定,自己不算哦)
4、外祖母的兄弟的孙子、孙女(舅表,与外祖母同姓)
5、外祖母的姐妹的孙子、孙女(舅表,姓氏不定)
6、外祖母的兄弟姐妹的外孙、外孙女(舅表,姓氏不定)
7、祖父的姐妹的孙子、孙女(姑表,姓氏不定)
8、祖母的兄弟的孙子、孙女(姑表,与祖母同姓)
9、祖母的姐妹的孙子、孙女(姑表,姓氏不定)
10、祖父及其兄弟姐妹的外孙、外孙女,其中包括父亲的姐妹(姑姑)所生的儿女(姑表,姓氏不定)
11、祖母及其兄弟姐妹的外孙、外孙女(姑表,姓氏不定)
总之,我把仨爷爷家的所有同辈堂亲加载一起也不会超过10个,但表兄弟姐妹却多得……十有八九能编成一个团。








