928 ℉

14.12.03

Learn lua by example - 2 类型与值

第2章 类型与值

2.1 八种基本类型

|空|布尔|数字|字符串|自定义类型|函数|线程|表| |-|-|-|-|-|-|-|-| |nil|boolean|number|string|userdata|function|thread|table|

2.2 type函数

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> = type("hello")
string
> type(12*23/2+2.4)
> =type(12*23/2+2.4)
number
> =type(print)
function
> =type(type)
function
> =type(true)
boolean
> =type(nil)
nil
> =type(type(2))
string
> =type(type(X))
string
> type(abc)
> =type(abc)
nil
> abc = print
> =type(abc)
function
> abc("world")
world
>

2.3 nil

  • 一种类型
  • 唯一的值nil
  • 未赋值的变量为nil

2.4 boolean

  • 两个值 true and false
  • false and nil为假 其余全部为真 0""也为真

2.5 number

  • lua不区分浮点和整形
  • 详见luaconf.h
  • number表示法 4,0.42,4.75e-3,0.3e12, 5e+20

example:

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> =4
4
> =0.42
0.42
> =4.57e-3
0.00457
> =0.3e12
300000000000
> =5e+20
5e+020
>

2.6 string

  • lua string完全采用8位编码
  • lua字符串不可变
  • lua字符串处理高效
  • 单双引号皆可
  • 自动垃圾回收

example:

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> print("hello 世界!")
hello 世界!
> a = "one string"
> b = string.gsub(a, "one", "two")
> =b
two string
> =a
one string
> c = 'string'
> =c
string

转义字符列表

|字符|意义| |-|-| |\a|响铃| |\b|退格(back space)| |\f|提供表格(form feed)| |\n|换行| |\r|回车| |\t|水平tab| |\v|垂直tab| |\\|反斜杠| |\"|双引号| |\'|单引号|

example:

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> ="hello"
hello
> ="this is a test.\n test1 \n \"string\", 'yes'"
this is a test.
 test1
 "string", 'yes'
> ="this is a test.\ntest1 \n\"string\", 'yes'"
this is a test.
test1
"string", 'yes'
>

数值转义(ASCII)

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> ="alo"
alo
> ="\97lo"
alo
>

多行块字符串 + 忽略首回车 + 忽略其中转义字符

example:

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> page = [[
>> hello \n\n\n\n\n
>> lll
>> fffff
>> <ffff>
>> <a>kkk<>a
>>
>>
>>
>> ]]
> =page
hello \n\n\n\n\n
lll
fffff
<ffff>
<a>kkk<>a




>
>

=多行字符串与注释,为了屏蔽互相干扰

example:

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> page=[===[
>> hello \r\t\y
>> ]
>> ]]
>> ]]]
>> ]==]
>> ]====]
>> ]===]
> =page
hello \r\t\y
]
]]
]]]
]==]
]====]

> --[====[
>> print(10)
>> ]]
>> print(1)
>> ]]--
>> print(1)
>> ]===]--
>> print(1)
>> ]====]--
> print(1)
1
>

字符与数字转换

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> ="10" + 1
11
> ="10 + 1"
10 + 1
> ="-5.3e-10" * 10
-5.3e-009
> "hello" + 1
stdin:1: unexpected symbol near '"hello"'
> "hello" + "1"
stdin:1: unexpected symbol near '"hello"'
> ="hello" + 1
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
> ="hello" + "1"
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
> a="hello" + "1"
stdin:1: attempt to perform arithmetic on a string value
stack traceback:
        stdin:1: in main chunk
        [C]: in ?
> a="hello" .. "1"
> =a
hello1
> a="11" .. "1"
> =a
111
> =tonumber("123")
123
> =tonumber("123a")
nil
> =tonumber("a12")
nil
> =tonumber("a")
nil
>

字符串长度

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> =#"123456789"
9
> =#"\97bcd"
4
>

2.7 table

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> a = {}
> a["k"] = "kk"
> =a
table: 003E8F50
> a[20] = 20
> =a[20]
20
> =a[0]
nil
> b= a
> =b["k"]
kk
> a = nil
> =b["k"]
kk
> b = nil -- 无引用table  垃圾回收
> a = {}
> a.k = 9
> =a.k
9
>

maxn

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> a = {}
> =table.maxn(a)
0
> a.a = 9
> =table.maxn(a)
0
> a[1] = 9
> =table.maxn(a)
1
> a[-1] = 19
> =table.maxn(a)
1
> a[1000] = 9
> =table.maxn(a)
1000
>

2.8 function

lua 函数是第一类值

2.9 userdata

pass

jack.zh 标签:lua 继续阅读

963 ℉

14.12.03

Learn lua by example - 1 开始

第1章 开始

1.1 hello world

print("hello world")

1.2 阶乘

function fact(n)
    if n == 0 then
        return 1
    else
        return n * fact(n-1)
    end
end

print("enter a number:")
a = io.read(**number)
print(fact(a))

1.3 程序块

-- 方式1
a = 1
b = a * 2

-- 方式2
a = 1;
b = a * 2;

-- 方式3
a = 1; b = a * 2

-- 方式4
a = 1 b = a * 2 -- 丑陋 但却合法

1.4 lua交互命令行

1.4.1 基本交互

-> /d $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> print("hello")
hello
>

1.4.2 文件交互

-> /d/lua $ ls
hello.lua
-> /d/lua $ cat hello.lua
a = 2
b = a * 2
print(a)
-> /d/lua $ lua -i hello.lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
2
> print(b)
4
>

1.5 lua保留字

|保留字|保留字|保留字|保留字|保留字|保留字|保留字| |:-|:–|:–|:–|:–|:–|:–|:–| |and|break|do|else|elseif|end|for| |function|false|if|in|local|nil|not| |or|repeat|return|then|true|until|while|

1.6 基本注释

-- print(10) 单行注释

-- 多行注释
--[[
print(10)
...
--]] 

1.7 全局变量

-- 声明全局变量
b = 10

-- 消除全局变量
b = nil

1.8 解释器程序

1.8.1 脚本声明
#!/usr/bin/lua

or

#!/usr/bin/env lua

1.8.2 lua启动选项说明

lua [选项参数] [脚本[参数]]

-e直接输入代码

-> /d/lua $ lua -e "print(math.sin(12))"
-0.53657291800043
-> /d/lua $

-l加载库文件, -i执行完进入交互模式(a为库文件)

lua -i -l a -e "x = 10"
-- 先加载a 再执行`x = 10`,然后进入交互

_PROMPE更改提示符

-> /d/lua $ lua -i -e "_PROMPT='jack-lua>>'"
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
jack-lua>>print("hello")
hello
jack-lua>>

交互模式打印举例

-> /d/lua $ lua
Lua 5.2.0  Copyright (C) 1994-2011 Lua.org, PUC-Rio
> math.sin(20)
> =math.sin(20)
0.91294525072763
> a = 10
> =a
10
>

jack.zh 标签:lua 继续阅读

854 ℉

14.12.01

来自HeroKu的HTTP API 设计指南(中文版)

来自HeroKu的HTTP API 设计指南(中文版)

翻译 by @Easy

简介

本指南描述了一系列 HTTP+JSON API 的设计实践, 来自并展开于 Heroku Platform API 的工作。本指南指导着Heroku内部API的开发,我们希望也能对Heroku以外的API设计者有所帮助。

目录

基础

  • 总是使用TLS
  • 在Accepts头中带上版本号
  • 通过Etags支持缓存
  • 用Request-Ids追踪请求
  • 用Ranges来分页

请求

  • 返回适当的状态码
  • 总是返回完整的资源
  • 在请求body中接收JSON序列
  • 使用一致的路径格式
  • 小写所有路径和属性
  • 支持非ID的参数作为快捷方式
  • 少用路径嵌套

响应

  • 总是提供资源(UU)ID
  • 提供标准的时间戳
  • 使用ISO8601格式的UTC时间
  • 嵌入外键数据
  • 总是生成结构化的错误信息
  • 显示频率限制的状态
  • 在所有的响应中压缩JSON数据

文档及其他

  • 提供机器可读的JSON格式
  • 提供人类可读的文档
  • 提供可执行的示例
  • 描述稳定性

基础

总是使用TLS

总是使用TLS(就是https)来访问API,没有必要指出什么时候需要用,什么时候不需要用,只管任何时候都用它就好。

对所有非TLS的请求返回403 Forbidden,不要用重定向,这会允许一些不良的客户端行为,而又没有任何好处。依赖重定向的客户端会使流量翻倍,而让TLS毫无意义 —— 敏感数据已经在第一次请求时发送出来了。

在Accepts头中带上版本号

从一开始就为API分配版本。使用Accepts头来发送版本信息,可以使用自定义的内容类型,如:

Accept: application/vnd.heroku+json; version=3

不要提供默认版本,而由客户端显式指定它使用哪一个特定的版本。

通过Etags支持缓存

在所有的请求中带上 ETag 头 , 用于识别特定版本的返回资源。用户可以在随后的请求中通过提供If-None-Match头的值来检查内容是否过期。

用Request-Ids追踪请求

在每个API相应中提供Request-Id头,带上一个唯一的UUID值。如果服务器和客户端都记录了这些值,在跟踪和调试请求时会派上大用场。

用Ranges来分页

对所有可能产生大量数据的响应进行分页。使用Content-Range 头来标记分页请求。可以参考这个例子,来了解请求和响应头、状态码、Limit、排序和翻页:Heroku Platform API on Ranges

请求

返回适当的状态码

为每个请求返回适当的状态码,成功的请求应该遵守如下规则:

  • 200: 当GET请求成功完成,DELETE或者PATCH请求同步完成。

  • 201: 同步方式成功完成POST请求。

  • 202: POST,DELETE或者PATCH请求提交成功,稍后将异步的进行处理。

  • 206: GET请求成功完成,但只返回了部分数据。参见用ranges分页

注意认证和认证错误的使用:

  • 401 Unauthorized: 请求失败,因为用户没有进行认证。
  • 403 Forbidden: 请求失败,因为用户被认定没有访问特定资源的权限。

返回合适的状态码可以为错误提供更多的信息:

  • 422 Unprocessable Entity: 你的请求服务器可以理解,但是其中包含了不合法的参数。
  • 429 Too Many Requests: 请求频率超配,稍后再试。
  • 500 Internal Server Error: 服务器出错了,检查网站的状态,或者报告问题。

根据HTTP response code 规范的指导来设计用户错误和服务器错误情况下的状态码。

总是返回完整的资源

对于200和201的响应,总是尽可能在响应中返回完整的资源(比如一个对象的所有属性),包括PUT,PATCH和DELETE请求,如:

$ curl -X DELETE \  
  https://service.com/apps/1f9b/domains/0fd4

HTTP/1.1 200 OK
Content-Type: application/json;charset=utf-8
...
{
  "created_at": "2012-01-01T12:00:00Z",
  "hostname": "subdomain.example.com",
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "updated_at": "2012-01-01T12:00:00Z"
}

202响应则不用包含完整的资源,如:

$ curl -X DELETE \  
  https://service.com/apps/1f9b/dynos/05bd

HTTP/1.1 202 Accepted
Content-Type: application/json;charset=utf-8
...
{}

在请求body中接收JSON序列

不要将额外信息放到form-encoded里边,而是将其JSON序列放到PUT,PATCH或POST请求的Body中。这样才能和同为JSON序列的响应Body对称(作者你是处女座么),如:

$ curl -X POST https://service.com/apps \
    -H "Content-Type: application/json" \
    -d '{"name": "demoapp"}'

{
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "name": "demoapp",
  "owner": {
    "email": "username@example.com",
    "id": "01234567-89ab-cdef-0123-456789abcdef"
  },
  ...
}

使用一致的路径格式

资源名称

使用复数来命名资源,除非该资源在系统中是单件(比如,在绝大多数系统中,一个用户只能拥有一个账户)。这样在你引用特定资源时可以保持一致性。

动作

对独有的资源使用不需要特定动作的endpoint格式。这样当需要特定的动作,只需要把它们放到标准的actions前缀后边,就可以清晰的描述它们:

/resources/:resource/actions/:action

如:

/runs/{run_id}/actions/stop

小写所有路径和属性

使用小写字母和减号命名路径,这样Hostname可以对齐(作者你真的是处女座):

service-api.com/users
service-api.com/app-setups

同样小写属性,但使用下划线来分割,这样属性名在JavaScript中可以不用加引号:

service_class: "first"

支持非ID的参数作为快捷方式

有时候要求最终用户提供ID来表示资源会比较麻烦,比如,用户可能只想得起Heroku的Appname,而应用本身却是由UUID来区分的。在这种情况下,我们可以同时接收ID和Name:

$ curl https://service.com/apps/{app_id_or_name}
$ curl https://service.com/apps/97addcf0-c182
$ curl https://service.com/apps/www-prod

绝不要只接收名称来排除某些ID。

少用路径嵌套

在嵌套了父子资源的数据模型中,路径可能深度嵌套:

/orgs/{org_id}/apps/{app_id}/dynos/{dyno_id}

可以通过从根路径定位来限制嵌套层数。使用嵌套来标识作用域内部的数据集。比如,上边那个dyno属于一个app,而app又属于一个org的例子:

/orgs/{org_id}
/orgs/{org_id}/apps
/apps/{app_id}
/apps/{app_id}/dynos
/dynos/{dyno_id}

响应

总是提供资源(UU)ID

为每个资源提供默认的ID属性。除非有特殊理由,总是使用UUID。不要用那些在服务的实例间或资源间不全局唯一的ID,特别是自增ID。

以8-4-4-4-12的格式小写UUID:

"id": "01234567-89ab-cdef-0123-456789abcdef"

提供标准的时间戳

为资源提供默认的 created_at 和 updated_at 时间戳:

{
  ...
  "created_at": "2012-01-01T12:00:00Z",
  "updated_at": "2012-01-01T13:00:00Z",
  ...
}

如果这些时间戳对某些资源真的没有意义,那么你也可以去掉它。

使用ISO8601格式的UTC时间

只接受和返回UTC时间,以ISO8601格式显示:

"finished_at": "2012-01-01T12:00:00Z"

嵌入外键数据

将外键引用通过序列化的嵌入对象显示:

{
  "name": "service-production",
  "owner": {
    "id": "5d8201b0..."
  },
  ...
}

而不是这样:

{
  "name": "service-production",
  "owner_id": "5d8201b0...",
  ...
}

这使得我们可以在inline使用相关的数据,而不需要改变响应的格式,或者引入更多高层的响应字段:

{
  "name": "service-production",
  "owner": {
    "id": "5d8201b0...",
    "name": "Alice",
    "email": "alice@heroku.com"
  },
  ...
}

总是生成结构化的错误信息

为错误生成一致的,结构化的响应Body。包含机器可读的id,人类可读的message,以及可选的url指向关于错误的更多信息,还有如何解决它:

HTTP/1.1 429 Too Many Requests
{
  "id":      "rate_limit",
  "message": "Account reached its API rate limit.",
  "url":     "https://docs.service.com/rate-limits"
}

为客户端常见的错误的格式和id撰写文档。

显示频率限制的状态

对客户端的频率限制可以保护服务的健康,并对其他的客户端提供高质量的服务。你可以使用token bucket 算法 来量化请求限制。

在每次请求的响应头中,通过RateLimit-Remaining 返回剩余的请求次数。

在所有的响应中压缩JSON数据

额外的空格增大了响应的大小,而很多人性化的客户端可以自动美化JSON输出。所以最好将JSON响应进行压缩:

{"beta":false,"email":"alice@heroku.com","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z", "created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T12:00:00Z"}

不要这样:

{
  "beta": false,
  "email": "alice@heroku.com",
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "last_login": "2012-01-01T12:00:00Z",
  "created_at": "2012-01-01T12:00:00Z",
  "updated_at": "2012-01-01T12:00:00Z"
}

你可以考虑提供一个可选的方式来为客户端输出更长的响应,比如通过请求参数(如?pretty=true)或者通过 Accept头(如Accept: application/vnd.heroku+json; version=3; indent=4;)。

文档及其他

提供机器可读的JSON格式

提供机器可读的schema来描述你的API,可以用prmd来管理你的schema,用过prmd verify来确保它通过验证。

提供人类可读的文档

提供人类可读的文档帮助客户端开发者们理解你的API。

如果你使用了prmd来创建schema,那么你可以简单的通过prmd doc命令来生成Markdown的endpoint级别的文档。

除了endpoint级别的描述,还要提供概要级别的信息,比如:

  • 授权,包括获得和使用授权Token。
  • API的稳定性和版本,包括如何选择现有的API版本。
  • 通用请求和响应头。
  • 错误的序列化格式。
  • 各种语言的客户端如何使用API的例子。
  • 提供可执行的示例

提供可执行的例子,这样用户可以直接在终端输入并看到可以用的API请求。最好的情况是,这些例子可以直接复制粘贴,以最小化用户试用API的成本,如:

$ export TOKEN=... # acquire from dashboard
$ curl -is https://$TOKEN@service.com/users

如果你使用prmd来生成Markdown文档,你就免费获得了可执行的示例。

描述稳定性

描述你API的稳定性,以及哪些endpoint依赖于其成熟度,比如使用prototype,development或者production的标识。

可参考 Heroku API compatibility policy 了解哪些接口是稳定的,哪些可能有变动。

一旦你的API宣布为 production-ready 和 稳定版,不要在该API版本上做任何不向前兼容的修改。如果你需要做不向前兼容的修改,创建一个新的版本号。

英文原版 → https://github.com/interagent/http-api-design

jack.zh 标签:HTTP API RESTFUL 继续阅读

734 ℉

14.12.01

慢慢的 都没了

  前几天我想在豆瓣上查看一下《天注定》, 虽然我不喜欢贾樟柯,但还是想看一下国人是怎么评价这个电影的,可神奇的是,豆瓣上居然搜不到。Mtime依然。这些结果就像是这部电影从来不曾存在过一样,而曾经存在过得,也慢慢的,都不存在了。

  几年以前,我曾经嘲笑过某科技界大佬。当时他说:也许90后、95后会慢慢不知道谷歌是什么网站。

  那一年,这对于我来说简直就是世界上最好笑的笑话。谷歌,全世界最卓越的互联网公司,活在互联网的一代中国人,会不知道他们的网站?

  今天,我收回这句嘲笑。因为这件不可能的事,它慢慢变成了现实。

  没有人再关注什么谷歌不谷歌。对他们来说,百度也蛮好用的,反正他们几乎没用过谷歌。没有谷歌又怎样?大家还是开心的刷微博,看微信,听歌,看娱乐节目。对于从来就不知道谷歌的人来说,少了谷歌又有什么影响?

慢慢的,就没有了,就像从未存在过

  多年前,我们也是可以登陆Facebook的。其实这个网站和校内一样,也挺蠢的。可在上面你能看到老外们的生活,可以轻易的跟一万公里以外的人互相拜访,可以看到很多根本不会开到校内上的主页。你用汉语回复,下面给你聊起来的可能是香港仔,可能是台湾人。你用英语回复,说不定有比你英语用的更蹩脚的寂寞的北欧人来跟你搭讪。你感觉地球真的变成了地球村,你还没拉门走出去,别人就推门走了进来。

  然后,它就没有了。起初,它的失踪激起了很大的声音,后来,声音就消失了。

  多年前,我们也是可以登陆Twitter的。其实这个网站和微博一样,也不过是些信息流,刷上一整天,也不见得有什么用处。但至少,你可以以最快速度获取你想知道的任何新事,你会真正了解什么事情在全世界是流行的,而不是经过各种截图、翻译、转发,甚至曲解、断章取义、黑白颠倒的东西。你知道的是真相,赤裸裸的,也许有点太短的真相。但至少中间不会有无数人的加工与再加工,偏激、片面,就在这个过程中产生了,不管后来者有意还是无意。

  然后,它就没有了。首先是它的本体没有了,然后它的模仿者也没有了,模仿者的模仿者也没有了。只剩一个模仿者的模仿者的模仿者,现在你每天能在上面看到无数广告。

  多年前,我们也是可以登陆YouTube的。对于有的人来说,这个网站就是个大型优酷,当年有人信誓旦旦的说,没有YouTube,我们中国人会很快让优酷超过YouTube。可这么多年过去了,视频还是那么卡,内容还是那么垃圾,原创还是那么容易被盗窃,视频丰富度还是那么的可怜。在YouTube上,你能看到全世界最棒的手艺人,最逗乐的笑话,最天马行空的创意,最激荡人心的音乐,最美好的完美瞬间,可在优酷上,你想看一分钟视频,请先看半分钟广告。

  哦,对了。Instagram,有些人可能感觉它和QQ空间也差不多。可我在上面关注了六百多个摄影师,它们都是顶好顶好的影像记录者,每天看他们的作品,我感觉到很幸福,那种即使没有到那里去,也身临其境的幸福。我还在上面认识了一个日本的爱自拍的帅小伙,一个爱喝酒的韩国大叔,一个十年前到过中国今天会在每张我发的紫禁城照片下点赞的美国大爷,一个美丽无比的俄罗斯妹子,我和他们基本上都难以交流,语言是很大的障碍,但几个简单的单词,心意也就到了,这种感觉,有时候比多年老友相聚还兴奋。因为这是人类不同族群自由交流互相沟通的过程,这种过程很神奇,真的很神奇。

  可现在,它没有了,它之所以没有就因为在某个特定的时间你在搜索特定的词汇时,会搜出来特定的照片。虽然这么搜的人并不多,虽然看到的人也不会大惊小怪,也不会觉得天黑了,天亮了,天要塌了,天要变了。可它就是没了,Instagram,就这么没了。谷歌也是这么没的,Twitter也是这么没的,Facebook也是这么没的。不知道是什么人,在什么场合,说了什么话,下了什么决定。就要有超过十亿人像陷于哥谭市的孤岛里一样,看着一座又一座桥梁被炸掉,又被炸掉,又被炸掉,然后,就什么都没了。

  我时常觉得悲哀,真的好悲哀,一个我根本不认识也不知道是谁的人,也许是一个群体,在不断抢走我身边的东西,而我却无能为力。我抱怨一声,他听不到,任何人都听不到。我怒吼一句,身边的大多数人却像看疯子一样的看着我。我哀嚎一声,这声音被阻碍在黑黑的幕墙以里。我发出尖锐的嘶吼,这声音传不了多远,就和我那被抢走的东西一样,消失了,不见了,就像从来没存在过一样。

  对于本来就没存在过的东西,有谁又会觉得在意呢?那些本来拥有又被掠夺的人的哀愁,后来的人又怎么懂呢?我曾经是拥有一切的,我曾经是拥有世界的,我站在这片土地上,呼吸的是自由的空气,饮下的是自由的琼浆玉液。就在长的无法计数的时间里,我自由生命的一部分又一部分就这么被杀死了,突然就杀死了。可我还始终觉得,它们还奄奄一息的活着,就像它们是慢慢的死去的一样。

  可它们终归是死了,而且随着它们的死,愈来愈多的事情慢慢的发生了,很慢很慢,几乎不被人察觉,可还是发生了。

  没有谷歌,我可以用百度呀。可某些结果被越挪越后,越挪越后,最后就不见了。就像本来就不该搜出这个结果一样。

  没有Facebook,我可以用校内呀。可你想发只有在Facebook上能发的文章,很快在校内上就失踪了。接着,校内变成了人人,话题变成了人人都关心的话题。大家都在抢着看星座、明星、八卦、娱乐。没有人会关心什么消失了,反正它们本来也没多少存在感。

  没有YouTube,我可以用优酷呀。可你却经常只能在优酷上看到抄袭别人的作品,而且还不署名,而且还洋洋得意,而且还自我陶醉,就好像那个idea本来属于他自己一样。你看了还要惊呼,他是如此的有创意!好一个抄袭的创意,可你却不知道,因为你不知道这个世界上有个网站叫YouTube。

  没有Twitter,我还可以用微博呀。可你想知道最近发生了什么,你搜的越勤快,越能看到越明显的“根据相关法律法规,相关搜索结果不予显示”。时间长了,你想,反正知道了也没什么用,不如不看了。

  慢慢的,一扇又一扇的门关上了。今天你打开世界上最大的博客网站,发现它没了。明天你一看,世界上最好的设计师分享网站没了,一开始是刷新的很慢很慢,后来它就没了。过两天再一看,平常每天都会读两篇文章的媒体网站没了,那里的文章缤纷多彩,最后都变成了该页无法显示几个字。再过几个月,大学的网站不让上了,摄影师的网站不让上了,就连百度日本这种自家网站,也没了。

  接着,漫画看不了了,接着,动画看不成了。接着,美剧英剧失踪了。下载美剧英剧的网站又又又失踪了。尊重正版,保护权益,行吧,然后字幕网站也没了。

  游戏没了,你习惯性登陆的游戏网站,发现下载栏正在整治中。论坛关了,天天都在看的论坛,突然接到相关部门的电话,因为“报备问题”不让办了。个人网站,私人博客,对不起,说没就没有,你在上面存了多少多年辛勤耕耘的东西都没用。

  你关注的人,有一天你登陆微博,发现他怎么好久都没说话了,然后你搜索了一下,发现他的账号不存在了,而且你搜他的名字,他的名字未予显示。

  一盏一盏的灯,灭了。四面八方的光源,消失了。我们生活的五光十色的世界,变成了一片黑色。

  天黑了,那么睡觉吧,但愿长醉不复醒。

  最后,我们变成了一群做梦的人,这个梦的名字,叫根据相关法律法规,相关搜索结果不予显示梦。

  转自月光博客

jack.zh 标签:杂文 继续阅读

614 ℉

14.11.28

你们这些还魂尸

你们这些还魂尸(豆瓣)

作者: [美]罗伯特·海因莱恩

1970年11月7日,第5时区(东部标准时间)22:17。纽约市“老爹”酒吧。

我正在擦净一只喝白兰地酒用的矮脚杯时,“未婚妈妈”进来了。我注意了一下时间:1970年11月7日,第5时区或东部时间下午10点17分。干时空这一行的人总是注意时间和日期:我们必须如此。

“未婚妈妈”是一个二十五岁的男子。他个头还没我高,显得稚气和急躁。我不喜欢他那副模样——我一直不喜欢——不过他是我要招收的人,是我需要的人。我对他报以一个酒吧老板最殷勤的微笑。

或许我是太挑剔了。他确实说不上英俊。他所以得了这个绰号是因为每次当某个爱管闲事的人问起他的行业时他总是说:“我是个未婚妈妈。”如果他兴致好一点的话还会加上一句:“——一个字四分钱。我写忏悔故事。”

如果他情绪恶劣,他会等什么人来闹一场。他有一种类似女警察的近身殴斗的凶猛风格。——这是我看中他的一个理由,当然不是唯一的理由。

他喝了不少,脸上的表情看上去比平时更鄙视别人。我没有说话,倒了一杯双份的老恩酒给他,倒完后把酒瓶放在他手边。他喝完后又倒了一杯。

我用布擦了一下柜台面。“‘未婚妈妈’的骗局怎样了?”

他的手指紧紧攥着玻璃杯,那副样子像是要朝我扔过来。我把手伸下柜台去抓棍子。在瞬间的冲动下你得防备一切可能发生的事情,然而,有多种因素使你永远不会冒不必要的险。

我见他神经松弛了一点。在局里办的训练学校里他们就教你如何察颜观色。“对不起,”我说,“这就像要问‘生意怎么样’而说的却是‘天气怎么样’?”

他仍很愠怒。“生意嘛还可以。我写故事,他们去印,我受用。”

我给自己倒了一杯酒,上身靠拢他。“事实上,”我说,“你这根笔杆不错,我挑了几篇看过。你有一种令人吃惊的明确格调,带着妇女观看问题的眼光。”

我必须冒一下险。他从未承认过他使用什么笔名。不过也许是太激怒了,他只顾及了最后那几个字。“妇女的眼光!”他哼着鼻子重复着。“是的,我懂得女人的眼光。我应该懂。”

“是吗?”我诧异地问,“有姐妹吗?”

“没有。我就是告诉你你也不会相信。”

“不错,”我温和地回答,“没有比真相更稀奇的东西了,这一点无论是酒吧老板还是精神学家都明白。听着,年轻人,如果你听了我说的故事,哈,你会发财呢。难以置信。”

“你根本不懂‘难以置信,是什么意思!”

“是吗?没有什么事会让我吃惊。我总是听到最坏的消息。”

他又哼了起来。“想赌一下瓶里的剩酒吗?”

“我愿意赌一整瓶酒。”我把一瓶酒放在柜台上。

“喂——”我招呼另一个酒吧招待来照看生意。我们坐到酒吧尽头一块狭小的地方,我在里面堆放了一些酒具杂物和腌蛋之类的东西,这地方也就专属我使用了。在酒吧另一端有几个人在看打架,有一个人在摆弄自动电唱机——完全没有人注意这地方。“好!”他开始讲述,“先要说明的是,我是个私生子。”

“这在这儿不稀奇。”我说。

“我不是开玩笑。”他急促地说,“我的父母亲并没有结婚。”

“这没什么稀奇,”我还是说。“我父母也没有结婚。

“当时——”他停顿住,给予我热切的一瞥,我还从未见过他有这种表情。“你当真?”

“当真。一个百分之百的私生子。事实上,”我补充道,“我的家庭里没有一个人曾经结过婚。全是私生子。”

“别想着来盖过我——你就结婚了。”他指着我的戒指。

“噢,这个。”我伸手给他看,“它看上去像个结婚戒指;我戴它是为了避开娘儿们。”这只戒指是一件古物,是我1985年从一个同行那里买来的,而他是从基督诞生前的希腊克里特岛弄来的。

他心不在焉地瞧了戒指一眼。“如果你真是私生子,你知道这种滋味。当我还是个小姑娘时——”

“唏——”我说,“我没有听错吧?”

“谁在唬你?当我是个小姑娘时——听着,听说过克里斯廷.乔根森吗?或是罗伯特·考埃尔吗?”

“噢,性别改变?你想告诉我——”

“不要打断我,也不要逼我,否则我就不讲了。我是个弃儿,1945年在我刚满月时被遗弃在克里夫兰的一个孤儿院里。当我是个小姑娘时,我羡慕有父母亲的孩子。以后,当我懂得男女情欲的时候——真的,老伯,一个人在孤儿院里懂得很快——”

“我明白。”

“我发了一个庄严的誓言,我的每个孩子将都有一个父亲和一个母亲。于是我表现得十分‘纯洁’,在那种环境中可称得上圣女了——我必须学习怎样竭力维护这种状况。后来我长大了,我意识到我几乎没有缔婚的机会——理由同样是因为没人收养我。”他的脸绷得紧紧的,“我长着一张马脸,牙齿东倒西歪,胸脯平平一点不丰满,头发直直的没有一个弯。”

“你的样子比我还是要强一些。”

“谁会在乎一个酒吧老板长得什么样?或者一个作家外貌怎么样?可是人们谁都想认领那种金发碧眼的小蠢货。男孩子们要的是那种漂亮脸蛋,乳房鼓鼓的,还要有一副‘你真够帅气,的嗲劲。”他耸耸肩膀。“我无法竞争。于是我决定参加妇总。”

“嗯?”

“妇女危机全国总部游览分部,现在人们管它叫‘太空天使’——外星军团辅助护理队。”

这两个名字我都知道,我曾经把它们记下来过。只是我们现在用的是第三个名称,那个军队化的精英服务团:妇女太空工作者后援团。在时空跳跃中最大的不便就是词汇变更——你知道吗,“服务站”曾经是指石油分离物的检测所。一次我到丘吉尔时代去执行一项任务,一个女子对我说,“在隔壁的服务站里等我”——这句话可不是现在这个意思,那时的服务站绝不会放一张床在里面。

他说下去:“那时他们第一次承认不可能让人到太空工作几个月或几年而不造成紧张心态。你还记得狂热的清教徒是怎样尖声喊叫的吗?——这增加了我的机会,因为自愿者很少。必须是一个品行端正的姑娘,一个货真价实的处女(他们要从零开始训练她们),智力要中上水平,此外情绪要稳定。可是大多数的自愿者都是些老娼妓,或是离开地球不到十天就会垮掉的神经病人。所以我不需要外表怎样。如果他们接受我,他们在训练我如何适应主要任务之外,自然会校正我的歪牙齿,把我的头发烫出波浪,教我走路的步态和跳舞和怎样愉快地听男人谈话,以及等等的一切。如果需要的话他们甚至会采用整形手术——直到让我们的小伙子无可挑剔为止。

“最令人高兴的是,他们保证你在服务期间不会怀孕——同时在服务期结束时你几乎肯定可以结婚。今天也同样,‘天使,嫁给太空工作者——他们彼此说得来。

“在我十八岁时我被安排作为‘母亲的仆人’。这个家庭需要一个费用便宜的仆人,而我也不在意,因为我要到二十一岁才可以被征招a我做家务后还去夜校上学——声称是继续我在高中时学过的打字和速记课程,但实际上是去上‘魅力课,以增加我被招收的机会。

“此后我遇到了那个城市骗子和他的百元大钞。”他阴沉着脸说,“这个瘪三倒确实有一叠百元钞票。一天晚上他拿给我看,还说我可以随意拿用。

“我没有拿。我喜欢他。他是我遇到过的第一个对我好又不想脱我裤叉的男人。为了能更多见到他,我从夜校退了学。这是一段我一生中最快活的时光。

“然后,一天晚上,在公园里我的裤叉还是脱了下来。”

他停住。

我说,“后来呢?”

“后来什么也没有了!我再也没有见到他。他步行送我回家,告诉我他爱我——和我吻别,以后就一去不返了。”他的脸色很阴沉,“如果我能找到他,我要杀了他!”

我说:“我表示同情。我明白你怎么想。不过杀了他——就为了那种必然会发生的事——嗯……你反抗了吗?”

“嘿,这有什么关系?”

“有关系。他遗弃了你,他的手臂活该被抓破,不过——”

“他应当受到的惩罚比这要重!你听着,别急。我不至于对任何人都不再信任,我认为事事皆天意。我并没有真正爱他,或许我永远不会爱任何人——而我比以往更迫切地想参加妇总。我并没有被取消资格,他们并不坚持一定要处女。”我开心起来了。

“直到我的裙子紧了以后我才明白。”

“怀孕?”

“这个私生子让我意乱心迷,不知怎么才好!那些住在一起的小气鬼只要我还能干活也不来理会——但后来还是把我逐了出去,孤儿院不再收容我了。我进了一家收容了不少‘大肚子’的济贫院,百无聊赖地躺在床上等着那一刻的来临。

“一天晚上我忽然被人抬上了手术台,一个护士对我说:‘别紧张。深呼吸。’

“我醒着躺在床上,胸部以下没有一点知觉。为我手术的外科医生走进来‘你感觉怎样?,他快活地说。

“‘像一个木乃伊’。

“‘这很自然。你被包得严严实实还打了足量的麻药让你感不到疼痛。你会恢复的——不过剖腹产毕竟不同于手指上的一根刺’。

“‘剖腹产?’我说,‘医生——孩子死了吗?’ 

“‘噢,活着。你的孩子很好。’

“嗯。男孩还是女孩?’

“‘一个健康的小姑娘。5磅3盎司。’

“我放心了。生下孩子多少是一种宽慰。我对自己说,应当到一个别的地方去,在我的名字前加上‘太太,的称号,同时让孩子认为她的爸爸已经死了——我的孩子绝不能再去孤儿院!

“外科医生还在说话。‘告诉我,这个——,他避开我的名字。‘——你有没有想到过你的腺组织有些特别?’

“我说,‘噢?当然没有。你想说什么?,

“他犹豫着。‘这个药你一次把它服下,然后我给你打一针让你睡一觉,你的过敏症就会好的。我这就去给你拿。’

一这是为什么?’我坚持要知道。

“‘听说过那个直到三十五岁时还是个女人的苏格兰医生吗——那以后她动了手术,在法律上和医学上都成了一名男子。结了婚,一切正常。’

“‘那和我有什么关系?’

“‘这就是我要说的。你是个男人。’

“我想坐起来。‘什么?’

“‘别紧张。在我剖开你的腹部后,我只见乱糟糟的一团。我一边把婴儿取出来一边让人去找外科主任医生。我们就在手术台上为你会诊——一连干了几个小时,尽我们所能进行挽救。你有两套完整的器官,都没有发育成熟,不过女性器官发育得相当充分,所以你怀上了孩子。它们已经永远不会对你有用了,所以我们将它们取出来并且重新整理了你的内脏,以便让你正常地发育成为一名男子。’他把一只手搭在我身上。‘不要担心。你还年轻,你的骨骼会逐渐适应。我们将观察你的腺平衡——让你成为一个出色的小伙子。’

“我开始喊叫。‘我的孩子怎么办?,

一嗯,你不能哺育她。你的奶水连喂一只小猫都不够。如果我是你,我就不再见她——交给别人去收养。’

“‘不!’

“他耸耸肩膀。‘决定当然由你来做:你是她的母亲——嗯,她的父母亲。不过现在别操这个心:我们先让你恢复身体。’

“第二天他们让我看了孩子,我每天都见到她——我试着习惯她。我从未见过一个刚出生的婴儿,也根本不知道它们看上去会这么丑怪——我的女儿看起来像一只小棕猴。我平静下来了,决心好好照顾她。不过,几星期后这已经没有任何意义了。”

“哦?”

“她被偷走了。”

“偷走?”

“未婚妈妈”几乎碰倒我们压赌的那瓶酒。“被绑架了——从医院的育婴室偷走的!”他喘着气,“把一个人生活的最后一点希望夺去了,这算什么?”

“太不幸了,”我表示同情,“让我给你再倒上一杯。没有一点线索吗?”

“警察找不到任何线索。一个人来探望她,谎称是她的叔叔。当护士背过身去时他就抱着她走了。”

“他长得什么样?”

“一个男子,一张极普通的脸,就像你的或我的脸。”他皱着眉说,“我想会不会是孩子的父亲。护士却一口咬定是一个年龄较大的人,不过他很可能化装过。别人谁会来拐我的孩子?没有孩子的女人有时会铤而走险——可是谁听说过一个男人会干这样的事?”

“那以后你怎么样呢?”

“我在那鬼地方又呆了十一个月,动了三次手术。四个月后我开始长出胡子。在我离开那里之前我就开始经常刮胡子了……而且我不再怀疑自己是个男人。”他咧开嘴苦笑了一下,“我开始盯住护士们的胸口往里看了。”

“嗯,”我说,“看来你顺利地挺了过来。现在瞧你,一个正常的男人,能赚钱,没有大的麻烦。而一个女人的生活就不那么容易了。”

他盯着我,说,“你想必知道得很多了!”

“什么?”

“听说过‘一个堕落的女人’这种说法吗?”

“嗯,几年前听说过。现在已经没有多少意义了。”

“我就像一个堕落的女人那样完全毁了。那个畜生的确毁了我——我已不再是一个女人……而我却不知道怎样成为一个男人。”

“努力习惯它吧,我想。”

“你不懂。我不是说学会怎样穿衣戴帽,或是不要走错到男女有别的场所。这些我在医院就学会了。只是我怎样生活?我可以做什么工作?妈的,我甚至连开车都不会。我不会任何手艺,不能干体力活——我全身各处组织大多动过手术,十分纤弱。

“我也恨他毁了我参加妇总的希望。我是直到想去加入太空军团时才明白事情的严重性。只需瞧一眼我的肚子就够了,我被打上不适宜服兵役的标记。那个医务官仅仅是为好奇才在我身上化费时间,他读过关于我的医案的报道。

“于是我换了名字来到纽约。我先是当一个油煎食品的厨师勉强混混,后来租了一架打字机干起了公共速记员——多么可笑!在四个月里我打了四封信和一份手稿。这份手稿是投给《真人真事》杂志的,不过是一叠废纸,可是写故事的这个小子居然把它卖出了。这倒让我产生了一个想法。我买了一大叠忏悔故事杂志进行研读。”他现出玩世不恭的神态,“现在你明白我在讲述一个未婚妈妈的故事时怎么会具有一个道地的妇女的眼光了……我还保留着这种眼光,真正的眼光,我是不是赢了这瓶酒?”

我把酒瓶推给他。我有些焦虑不安,事情并没有完。我说,“年轻人,你还想逮住那个负心汉吗?”

他的眼睛闪着亮光——一种野性的凶光。

“算了吧!”我说,“你不会杀了他吧?’

他咯咯地笑起来,声音显得很淫秽。“那就审判我吧。”

“慢着。我对这件事知道得比你认为的要多。我可以帮助你。我知道他在什么地方。”

他从柜台一侧探过来,一把抓住了我,“他在哪里?”

我压低声音说,“放开我的衬衣,年轻人——要不你会有麻烦的。我要告诉警察你喝醉了。”我挥动了一下棍子。

他松了手。“对不起。他在哪里?”他看着我,“再说你怎么会知道得这么多?”

“世间的事在一个‘巧’字。我可以看到各种记录——医院的病例、孤儿院的档案。你那所孤儿院的女总管是费瑟雷思太太——对吗?她后来由格伦斯坦太太接任——对吗?你的名字,姑娘时的名字,是‘珍妮’——对吗?而你刚才并没有告诉我这一切——对吗?”

他被我弄得呆愣愣并有几分畏缩。“什么意思?你想找我麻烦吗?”

“哪里的话。我真心为你着想。我可以把这个人送到你的鼻子下面。你认为怎样合适就怎样处置他——我相信你会骂他混蛋,叫他滚。不过我认为你不会杀死他。如果杀死他你就是个傻瓜——而你不傻。根本不傻。”

他没有心思听这些。“别瞎胡说了。他在哪里?”

我给他添了一点酒。他醉了,不过愤怒压过了醉意。“别这么急嘛。我为你做件事——你也为我做件事。”

“嗯……什么事?”

“你不喜欢你的工作。要是有一个工作,工资高,工作稳定,开支不受限制,自己能独立做主,同时又富于变化和冒险,你会怎么说?”

他眼睛睁得大大的。“我会说,‘少来你那一套天方夜谭式的神话!’去你的,老伯——根本没有这样的工作。”

“那么,这样说吧:我把他交给你,你和他了结恩怨,然后试试我干的工作。如果不像我说的——那好,我就随你便了。”

他的身体在晃动,这是最后那杯酒的缘故。

“如果同意成交——现在!”

他使劲晃着头:“同意成交!”

我向手下人示意照看一下买卖,记下了时间:23点——就俯身穿过柜台下的门——这时自动电唱机高声放出《我是我老子》的歌曲。因为我不喜欢1970年的“音乐”,我让服务员在电唱机上装上早期的美国歌曲和古典音乐,可是我不知道那盒磁带还在里面。

我叫道,“关掉它!把顾客的钱退还给他。”我加上一句,“我去储藏室,一会就回来,”就径直往里走去,“未婚妈妈”在后面跟着。

沿着走廊拐过厕所间后就是储藏室,房间有一扇铁门,除了我的日班经理和我自己外别人都没有钥匙。里面有一扇门通向内室,只有我才有钥匙。我们来到那里。

他醉眼惺忪地张望着没有窗户的墙壁:“他在哪?”

“马上。”我打开一只箱子,这是房间里唯一的东西。这是一部美国制造的92系列Ⅱ型外携式座标式变换器——美观、利落,全重21公斤,外型设计得正好放入一只手提箱。这天早晨我刚调整好,我所需做的只是晃动限制变换场的金属网。

我这样做了。“这是什么?”他问。

“时间机器。”我说着将金属网抛出。

“哎!”他喊叫着倒退了一步。这里有一种技术,金属网必须抛出使相关人本能地倒退而踏在网上,然后你就把已经完全包围着你们两人的金属网收束起——不这样的话你也许会遗留下一只鞋或一只脚,或者是刮起一块地板。当然这种技法说穿了也没什么了。有些代理商连哄带骗地把相关人弄进网里。我却告诉他们实话,利用对方刹那间的极度惊讶而启动机关:我正是这样做了。

1963年4月3日,第5时区10:30。克里夫兰,“俄亥俄之顶”大楼。

“哎!”他又在喊,“把这鬼东西拿掉!”

“对不起,”我向他道歉并收起金属网,将它装入提箱,关上箱子。“你说的你想找到他。”

“可是——你说这是一部时间机器!”

我指指窗外。“这里看上去像11月份吗?或是像纽约吗?”在他呆呆地看着嫩绿的枝芽和一片春色时我又打开了提箱,拿出一叠百元面额的美钞,检查了一下钞票的编号和戳记都与1963年份符合。时空旅行局并不在乎你花了多少(这与它无干),不过他们并不喜欢发生不必要的年代错误。若是你犯了太多这样的错误,一个综合军事法庭会把你流放到一个恶劣的年代去呆上一年,譬如说去实行严格食品配给和强制劳动的1974年。我从来没有犯过这类错误,这些钱没有问题。他回过头问我:“发生了什么事?”

“他在这里。到外面去,找到他。这是给你花的钱。”我塞给他时又补充了一句,“和他了断,然后我来接你。”

成叠的百元钞对于一个不习惯于使用它们的人,具有一种近乎催眠的作用。我送他进了楼厅。叫他宽心,就把他关出在门外。他这时还一直难以置信地捏着那一叠钞票。下一步的跳跃是太容易了,仅仅是在同一时代的一个小小的挪步。

1964年3月10日,第5时区17:00。“克里夫兰之顶”大楼。

门的下方有一个通知,说我的租房合同下周要满期了,除此之外这个房间看上去与刚才并无两样。外面,树木光秃秃的,天空像要下雨的样子。我十分匆忙,仅仅停留了片刻,取走了我租房间时留在那里的现钱、上衣和大衣。我雇了一部车来到医院。我化了二十分钟才把育婴室的看护弄得不耐烦起来,于是我便乘她不注意偷走了婴儿。我们回到“克里夫兰之顶”.大楼。这种用标度盘的时间装置是更为复杂的,因为大楼在1945年还不存在。不过我预计到了。

1945年7月20日,第5时区01:00。克里夫兰“雪景”旅馆。

时间机器,婴儿和我都到了城外的一家旅馆。早些时候我就以“俄亥俄州沃伦市的乔治·约翰逊”登了记。于是我们来到了一个窗帘拉上、窗户和房门紧闭的房间。地板也进行了清理使其能够承受机器的不规则的震动。你的身体可能会碰上一张原不该在那里的椅子而出现一块令人不快的乌青——当然并非椅子,而是变换场能量的回冲。

一切顺利。珍妮正在熟睡着。我把她抱出来,放在我事先放置在汽车座位上的一只食品箱里,驱车到孤儿院。我把她放在台阶上,开车过了两个街区来到一个“服务站”,打了一个电话给孤儿院。我驱车回来时正好看见孤儿院的人把食品箱拿进去。我继续开了一阵,把汽车丢弃在旅馆附近,步行来旅馆后就“跳跃”到1963年的“克里夫兰之顶”大楼。

1963年4月24日,第5时区22:00。“克里夫兰之顶”大楼。

我把时间划分得十分精细——时间的精确性取决于跨度,当然你如果是回到起始点时例外。如果我是正确的话,在这里温和的春天的夜晚珍妮正在公园里发现她并非像她以前所想的那样是一个“纯真的”姑娘。我拦了一辆出租车来到那些小气鬼的住处,我让司机在拐角上等着,自己藏在阴影处。

很快我发现他们正在街上走,胳膊互相勾搭着。在门口他把她搂起,长时间亲吻她祝她晚安——时间之长超过我的想象。然后她进屋去了,他转身走下人行道。我窜上台阶抓住他的一只胳膊。“结束了,年轻人,”我平静地说,“我回来接你。”

“你!”他吓了一跳,喘着气说。

“我。现在你知道他是谁了——而且你仔细想过以后你会明白你是谁……而且如果你再好好想想,你会猜出这个婴儿是谁……还有我是谁。”

他没有回答,身子抖得厉害。当事实证明你无法抗拒勾引你自己的话这对你的精神是一个很大的震动。我带着他去“克里夫兰之顶”大楼,再次进行了时空跳跃。

1985年8月12日,第5时区23:00。洛基地下城。

我叫醒值班军士,给他看了我的身份证,告诉军士给他吃一片药后好好地睡下,第二天早晨招收他。军士的表情很难看,不过军阶就是军阶,这与时代没有关系。他照我说的做了——毫无疑问他在想下次我们相遇时他可能是上校而我是军士。在我们的军团里这是有可能的。“他叫什么名字?”他问。

我写给他。他的眉毛扬了起来。“像这样的人,嗯?这——”

“你干你的工作,军士。”我转身对我的伙伴说,“年轻人,你的麻烦已经过去。你就要开始从事一个男人所能有的最好的工作——你会干好的。我知道。” “可是二” “没那么多‘可是’。好好睡一觉。然后考虑一下这个建议。你会喜欢它的。”

“你一定会的!”军士表示同意。“瞧我——生于1917年——仍然健旺,年轻,享受着生活。”我回到进行时空跳跃的房间,把一切拨到预定的零点上。

1970年11月7日,第5时区23:01。纽约市“老爹”酒吧。

我从储藏室走出来,拿了1/5桶的苏格兰制威士忌利乔酒,算是说明我离去的那一分钟。我的助手还在与那个点播《我是我老子》的顾客争辩。我说,“算了,让他放吧,放完后就关掉。”我已十分疲倦。

这种工作的确很艰辛,可是总必须有人来做。自从1972年的灾变发生以后,近来要招募到人是很难的。

我提前五分钟关了店门,在现金出纳机上留下一封信给我的日班经理,说我准备接受他的主意,松弛一下,弦别绷得太紧了。在我外出长期度假时他可以找我的律师。局里最关心的是事情必须井井有条,收入多少还在其次。我来到储藏室里面的那个房间,跳跃到1993年。

1993年1月12日,第7时区22:00。洛基地下城附设时空劳工总部。

我向值勤官出示了证件后进去,来到我的住处,打算睡它一个星期,在写报告前我抓起我们下赌的那瓶酒(不管怎么说我赢得了它)喝了一杯。酒的味道太差劲了,我奇怪以往怎么会喜欢上老恩酒的。不过它总比没有强,我不想像一根木头那样清醒着,我思考得太多了。

我口授了我的报告:为太空军团进行的四十次招募活动都得到了局里的批准——包括我自己的这次,我知道会被批准的。我现在回来了,不是吗?接着我用磁带录下了一份请调工作的报告。我对招募活动感到厌倦了。我要急流勇退。我向床头走去。

我的目光落在床头上方的《时间准则》上:

永远不要把明天要做的事搬到昨天去做。

如果你终于成功了,永远不要再次尝试。

及时一秒胜过事后九亿秒。

似是而非的事可以用似是而非的方法来处置。

你想到的时候事情已经发生了。

祖宗也是凡人。

真神也有瞌睡时。

当我是一个时间商人时,这些话曾经激励过我,现在却不同了。在时空跳跃的三十年的身不由己的生活,完全把人累垮了。我脱去衣裤,当身体裸露出来时我瞧了瞧我的肚子。剖腹产留下一道长长的疤痕,只是我现在身上的汗毛又浓又密,要是不仔细看就不会注意到它。

然后我瞧了一眼手指上的那个戒指。

蛇吞吃了它自己的尾巴,周而复始,何谓始,何谓终……我知道我是从什么地方来的了——可是你们是从什么地方来的呢,你们这些回魂尸?

我觉得一阵头痛袭来,不过我是不吃头痛药粉的。

于是我钻进床铺,吹口哨关了灯。

修根本就不在那里。不是别人而是我——珍妮——孤独地呆在这黑暗中。

我真想你!

jack.zh 标签:小说 继续阅读

1585 ℉

14.11.28

CURL粗解

cURL使用

指令:curl

在linux中curl是一个利用URL规则在命令行下工作的文件传输工具,可以说是一款很强大的http命令行工具。它支持文件的上传和下载,是综合传输工具,但按传统,习惯称url为下载工具。

语法:

$ curl [option] [url]

常见参数:

-A/--user-agent <string>              设置用户代理发送给服务器
-b/--cookie <name=string/file>        cookie字符串或文件读取位置
-c/--cookie-jar <file>                操作结束后把cookie写入到这个文件中
-C/--continue-at <offset>             断点续转
-D/--dump-header <file>               把header信息写入到该文件中
-e/--referer                          来源网址
-f/--fail                             连接失败时不显示http错误
-o/--output                           把输出写到该文件中
-O/--remote-name                      把输出写到该文件中,保留远程文件的文件名
-r/--range <range>                    检索来自HTTP/1.1或FTP服务器字节范围
-s/--silent                           静音模式。不输出任何东西
-T/--upload-file <file>               上传文件
-u/--user <user[:password]>           设置服务器的用户和密码
-w/--write-out [format]               什么输出完成后
-x/--proxy <host[:port]>              在给定的端口上使用HTTP代理
-#/--progress-bar                     进度条显示当前的传送状态

例子:

0. 服务器端代码(基于python tornado)
import tornado.httpserver
import tornado.ioloop
import tornado.options
import tornado.web

from tornado.options import define, options

import json


define("port", default=8888, help="run on the given port", type=int)


class MainHandler(tornado.web.RequestHandler):
    def get(self):
        arguments = self.request.arguments;
        print(json.dumps(arguments, indent=2))
        self.write("get hello.")

    def post(self):
        arguments = self.request.arguments;
        print(json.dumps(arguments, indent=2))
        self.write("post world")

    def delete(self):
        arguments = self.request.arguments;
        print(json.dumps(arguments, indent=2))
        self.write("delete world")

    def patch(self):
        arguments = self.request.arguments;
        print(json.dumps(arguments, indent=2))
        self.write("patch world")

    def head(self):
        arguments = self.request.arguments;
        print(json.dumps(arguments, indent=2))
        self.write("head world")

    def put(self):
        arguments = self.request.arguments;
        print(json.dumps(arguments, indent=2))
        self.write("put world")

    def options(self):
        arguments = self.request.arguments;
        print(json.dumps(arguments, indent=2))
        self.write("optons world")


def main():
    tornado.options.parse_command_line()
    application = tornado.web.Application([
        (r"/", MainHandler),
        ])
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(options.port)
    tornado.ioloop.IOLoop.instance().start()


if __name__ == "__main__":
    main()
1、基本用法

1 基本 # curl http://www.example.com get hello. 2 保存 # curl http://www.example.com >out.txt get hello. 或者 # curl -o out.txt http://www.example.com get hello.

会有如下进度条

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100    10  100    10    0     0    875      0 --:--:-- --:--:-- --:--:--   909

保存文件 可以使用curl的内置option:-O(大写)保存网页中的文件

要注意这里后面的url要具体到某个文件,不然抓不下来

# curl -O http://www.example.com/hello.sh
3. 测试网页返回值
# curl -o /dev/null -s -w %{http_code} www.example.com
200
4、指定proxy服务器以及其端口

很多时候上网需要用到代理服务器(比如是使用代理服务器上网或者因为使用curl别人网站而被别人屏蔽IP地址的时候),幸运的是curl通过使用内置option:-x来支持设置代理

# curl -x 192.168.100.100:1080 http://www.example.com
5、cookie

有些网站是使用cookie来记录session信息。对于chrome这样的浏览器,可以轻易处理cookie信息,但在curl中只要增加相关参数也是可以很容易的处理cookie

5.1:保存http的response里面的cookie信息。内置option:-c(小写)

# curl -c cookiec.txt  http://www.example.com

执行后cookie信息就被存到了cookiec.txt里面了

5.2:保存http的response里面的header信息。内置option: -D

# curl -D cookied.txt http://www.example.com

执行后cookie信息就被存到了cookied.txt里面了

注意:-c(小写)产生的cookie和-D里面的cookie是不一样的。

5.3:使用cookie

很多网站都是通过监视你的cookie信息来判断你是否按规矩访问他们的网站的,因此我们需要使用保存的cookie信息。内置option: -b

# curl -b cookiec.txt http://www.example.com
6、模仿浏览器

有些网站需要使用特定的浏览器去访问他们,有些还需要使用某些特定的版本。curl内置option:-A可以让我们指定浏览器去访问网站

# curl -A "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0)" http://www.example.com

这样服务器端就会认为是使用IE8.0去访问的

7、伪造referer(盗链)

很多服务器会检查http访问的referer从而来控制访问。比如:你是先访问首页,然后再访问首页中的邮箱页面,这里访问邮箱的referer地址就是访问首页成功后的页面地址,如果服务器发现对邮箱页面访问的referer地址不是首页的地址,就断定那是个盗连了

curl中内置option:-e可以让我们设定referer

# curl -e "www.example.com" http://mail.example.com

这样就会让服务器其以为你是从www.example.com点击某个链接过来的

8、下载文件

8.1:利用curl下载文件。

#使用内置option:-o(小写)

# curl -o dodo1.jpg http:www.example.com/dodo1.JPG

#使用内置option:-O(大写)

# curl -O http://www.example.com/dodo1.JPG

这样就会以服务器上的名称保存文件到本地

8.2:循环下载

有时候下载图片可以能是前面的部分名称是一样的,就最后的尾椎名不一样

# curl -O http://www.example.com/dodo[1-5].JPG

这样就会把dodo1,dodo2,dodo3,dodo4,dodo5全部保存下来

8.3:下载重命名

# curl -O http://www.example.com/{hello,bb}/dodo[1-5].JPG

由于下载的hello与bb中的文件名都是dodo1,dodo2,dodo3,dodo4,dodo5。因此第二次下载的会把第一次下载的覆盖,这样就需要对文件进行重命名。

# curl -o #1_#2.JPG http://www.example.com/{hello,bb}/dodo[1-5].JPG

这样在hello/dodo1.JPG的文件下载下来就会变成hello_dodo1.JPG,其他文件依此类推,从而有效的避免了文件被覆盖

8.4:分块下载

有时候下载的东西会比较大,这个时候我们可以分段下载。使用内置option:-r

# curl -r 0-100 -o dodo1_part1.JPG http://www.example.com/dodo1.JPG

# curl -r 100-200 -o dodo1_part2.JPG http://www.example.com/dodo1.JPG

# curl -r 200- -o dodo1_part3.JPG http://www.example.com/dodo1.JPG

# cat dodo1_part* > dodo1.JPG

这样就可以查看dodo1.JPG的内容了

8.5:通过ftp下载文件

curl可以通过ftp下载文件,curl提供两种从ftp中下载的语法

# curl -O -u 用户名:密码 ftp://www.example.com/dodo1.JPG

# curl -O ftp://用户名:密码@www.example.com/dodo1.JPG

8.6:显示下载进度条

# curl -# -O http://www.example.com/dodo1.JPG

8.7:不会显示下载进度信息

# curl -s -O http://www.example.com/dodo1.JPG
9、断点续传

在windows中,我们可以使用迅雷这样的软件进行断点续传。curl可以通过内置option:-C同样可以达到相同的效果

如果在下载dodo1.JPG的过程中突然掉线了,可以使用以下的方式续传

# curl -C -O http://www.example.com/dodo1.JPG
10、上传文件

curl不仅仅可以下载文件,还可以上传文件。通过内置option:-T来实现

# curl -T dodo1.JPG -u 用户名:密码 ftp://www.example.com/img/

这样就向ftp服务器上传了文件dodo1.JPG

11、显示抓取错误
# curl -f http://www.example.com/error

其他参数(此处翻译为转载):

-a/--append                     上传文件时,附加到目标文件
--anyauth                       可以使用“任何”身份验证方法
--basic                         使用HTTP基本验证
-B/--use-ascii                  使用ASCII文本传输
-d/--data <data>                HTTP POST方式传送数据
--data-ascii <data>             以ascii的方式post数据
--data-binary <data>            以二进制的方式post数据
--negotiate                     使用HTTP身份验证
--digest                        使用数字身份验证
--disable-eprt                  禁止使用EPRT或LPRT
--disable-epsv                  禁止使用EPSV
--egd-file <file>               为随机数据(SSL)设置EGD socket路径
--tcp-nodelay                   使用TCP_NODELAY选项
-E/--cert <cert[:passwd]>       客户端证书文件和密码 (SSL)
--cert-type <type>              证书文件类型 (DER/PEM/ENG) (SSL)
--key <key>                     私钥文件名 (SSL)
--key-type <type>               私钥文件类型 (DER/PEM/ENG) (SSL)
--pass  <pass>                  私钥密码 (SSL)
--engine <eng>                  加密引擎使用 (SSL). "--engine list" for list
--cacert <file>                 CA证书 (SSL)
--capath <directory>            CA目录 (made using c_rehash) to verify peer against (SSL)
--ciphers <list>                SSL密码
--compressed                    要求返回是压缩的形势 (using deflate or gzip)
--connect-timeout <seconds>     设置最大请求时间
--create-dirs                   建立本地目录的目录层次结构
--crlf                          上传是把LF转变成CRLF
--ftp-create-dirs               如果远程目录不存在,创建远程目录
--ftp-method [multicwd/nocwd/singlecwd]     控制CWD的使用
--ftp-pasv                      使用 PASV/EPSV 代替端口
--ftp-skip-pasv-ip              使用PASV的时候,忽略该IP地址
--ftp-ssl                       尝试用 SSL/TLS 来进行ftp数据传输
--ftp-ssl-reqd                  要求用 SSL/TLS 来进行ftp数据传输
-F/--form <name=content>        模拟http表单提交数据
-form-string <name=string>      模拟http表单提交数据
-g/--globoff                    禁用网址序列和范围使用{}和[]
-G/--get                        以get的方式来发送数据
-h/--help                       帮助
-H/--header <line>              自定义头信息传递给服务器
--ignore-content-length         忽略的HTTP头信息的长度 
-i/--include                    输出时包括protocol头信息
-I/--head                       只显示文档信息
-j/--junk-session-cookies       读取文件时忽略session cookie
--interface <interface>         使用指定网络接口/地址
--krb4 <level>                  使用指定安全级别的krb4
-k/--insecure                   允许不使用证书到SSL站点
-K/--config                     指定的配置文件读取
-l/--list-only                  列出ftp目录下的文件名称
--limit-rate <rate>             设置传输速度
--local-port<NUM>               强制使用本地端口号
-m/--max-time <seconds>         设置最大传输时间
--max-redirs <num>              设置最大读取的目录数
--max-filesize <bytes>          设置最大下载的文件总量
-M/--manual                     显示全手动
-n/--netrc                      从netrc文件中读取用户名和密码
--netrc-optional                使用 .netrc 或者 URL来覆盖-n
--ntlm                          使用 HTTP NTLM 身份验证
-N/--no-buffer                  禁用缓冲输出
-p/--proxytunnel                使用HTTP代理
--proxy-anyauth                 选择任一代理身份验证方法
--proxy-basic                   在代理上使用基本身份验证
--proxy-digest                  在代理上使用数字身份验证
--proxy-ntlm                    在代理上使用ntlm身份验证
-P/--ftp-port <address>         使用端口地址,而不是使用PASV
-Q/--quote <cmd>                文件传输前,发送命令到服务器
--range-file                    读取(SSL)的随机文件
-R/--remote-time                在本地生成文件时,保留远程文件时间
--retry <num>                   传输出现问题时,重试的次数
--retry-delay <seconds>         传输出现问题时,设置重试间隔时间
--retry-max-time <seconds>      传输出现问题时,设置最大重试时间
-S/--show-error                 显示错误
--socks4 <host[:port]>          用socks4代理给定主机和端口
--socks5 <host[:port]>          用socks5代理给定主机和端口
-t/--telnet-option <OPT=val>    Telnet选项设置
--trace <file>                  对指定文件进行debug
--trace-ascii <file>            Like --跟踪但没有hex输出
--trace-time                    跟踪/详细输出时,添加时间戳
--url <URL>                     Spet URL to work with
-U/--proxy-user <user[:password]>  设置代理用户名和密码
-V/--version                    显示版本信息
-X/--request <command>          指定什么命令
-y/--speed-time                 放弃限速所要的时间。默认为30
-Y/--speed-limit                停止传输速度的限制,速度时间'秒
-z/--time-cond                  传送时间设置
-0/--http1.0                    使用HTTP 1.0
-1/--tlsv1                      使用TLSv1(SSL)
-2/--sslv2                      使用SSLv2的(SSL)
-3/--sslv3                      使用的SSLv3(SSL)
--3p-quote                      like -Q for the source URL for 3rd party transfer
--3p-url                        使用url,进行第三方传送
--3p-user                       使用用户名和密码,进行第三方传送
-4/--ipv4                       使用IP4
-6/--ipv6                       使用IP6

实战

使用curl可以下载网络内容,那如何获取curl下载时的下载速度呢,使用下面的命令即可:

# curl -Lo /dev/null -skw "%{speed_download}\n" http://mirrors.163.com/ubuntu/ls-lR.gz
226493.000

当然,还可以获取连接时间、重定向时间等更多的数据:

# curl -Lo /dev/null -skw "time_connect: %{time_connect} s\ntime_namelookup: %{time_namelookup} s\ntime_pretransfer: %{time_pretransfer} s\ntime_starttransfer: %{time_starttransfer} s\ntime_redirect: %{time_redirect} s\nspeed_download: %{speed_download} B/s\ntime_total: %{time_total} s\n\n"  http://www.sina.com
time_connect: 0.154 s
time_namelookup: 0.150 s
time_pretransfer: 0.154 s
time_starttransfer: 0.163 s
time_redirect: 0.157 s
speed_download: 324679.000 B/s
time_total: 1.692 s

打开百度

curl http://www.baidu.com

接着你就会看到百度的页面源代码输出。

如果要把这个网页保存下来,可以这样:

curl http://www.baidu.com > /tmp/baidu.html

你会看到一条进度条,然后源码就被重定向到了/tmp/baidu.html。

或者:

curl -o /tmp/baidu.html http://www.baidu.com

GET请求

默认直接请求一个url就是发出一个get请求,参数的话直接拼接在url里就好了,如

curl http://www.baidu.com/s?wd=curl

上述请求会上百度发起一条查询请求,参数是wd=url

POST请求

curl -d "name=test&page=1" http://www.baidu.com

-d参数指定表单以POST的形式执行。

只展示Header

curl -I  http://www.baidu.com

可以看到只返回一些header信息

HTTP/1.1 200 OK
Date: Fri, 07 Nov 2014 09:48:58 GMT
Content-Type: text/html; charset=utf-8
Connection: Keep-Alive
Vary: Accept-Encoding
Set-Cookie: BAIDUID=E9DB2F0AC95CB6BFDAD9D5CFDCED0A12:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BAIDUPSID=E9DB2F0AC95CB6BFDAD9D5CFDCED0A12; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BDSVRTM=0; path=/
Set-Cookie: BD_HOME=0; path=/
Set-Cookie: H_PS_PSSID=9725_9165_1465_7800_9452_9498_6504_9509_6018_9700_9757_9531_9478_7798_9453_9793_9024; path=/; domain=.baidu.com
P3P: CP=" OTI DSP COR IVA OUR IND COM "
Cache-Control: private
Cxy_all: baidu+3057b288b211c770a1463cc8519b62a8
Expires: Fri, 07 Nov 2014 09:48:17 GMT
X-Powered-By: HPHP
Server: BWS/1.1
BDPAGETYPE: 1
BDQID: 0xfa28eff900012706
BDUSERID: 0

显示通信过程

-v参数可以显示一次http通信的整个过程,包括端口连接和http request头信息

curl -v www.baidu.com

* Adding handle: conn: 0x7ffe4b003a00
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x7ffe4b003a00) send_pipe: 1, recv_pipe: 0
* About to connect() to www.baidu.com port 80 (#0)
*   Trying 61.135.169.125...
* Connected to www.baidu.com (61.135.169.125) port 80 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: www.baidu.com
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Fri, 07 Nov 2014 09:49:49 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: Keep-Alive
< Vary: Accept-Encoding
< Set-Cookie: BAIDUID=062E02D23FBB651CF8455B699DF02B64:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
< Set-Cookie: BAIDUPSID=062E02D23FBB651CF8455B699DF02B64; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
< Set-Cookie: BDSVRTM=0; path=/
< Set-Cookie: BD_HOME=0; path=/
< Set-Cookie: H_PS_PSSID=7744_1429_7801_9583_9499_6506_6018_9769_9699_9757_9532_9477_7799_9453_9716_9023; path=/; domain=.baidu.com
< P3P: CP=" OTI DSP COR IVA OUR IND COM "
< Cache-Control: private
< Cxy_all: baidu+7dcb6b3c03d32c334d42f311919a14d6
< Expires: Fri, 07 Nov 2014 09:49:20 GMT
< X-Powered-By: HPHP
* Server BWS/1.1 is not blacklisted
< Server: BWS/1.1
< BDPAGETYPE: 1
< BDQID: 0xadb706860000088f
< BDUSERID: 0

如果你觉得上面的信息还不够,那么下面的命令可以查看更详细的通信过程。

curl --trace output.txt www.baidu.com

或者

curl --trace-ascii output.txt www.baidu.com

运行后,请打开output.txt文件查看。

HTTP方法

curl默认的HTTP方法是GET,使用-X参数可以支持其他动词。

curl -X POST www.example.com

curl -X DELETE www.example.com

Referer字段

有时你需要在http request头信息中,提供一个referer字段,表示你是从哪里跳转过来的。

curl --referer http://www.example.com http://www.example.com

User Agent字段

这个字段是用来表示客户端的设备信息。服务器有时会根据这个字段,针对不同设备,返回不同格式的网页,比如手机版和桌面版。

iPhone4的User Agent是

Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7

curl可以这样模拟:

curl --user-agent "[User Agent]" [URL]

增加头信息

有时需要在http request之中,自行增加一个头信息。–header参数就可以起到这个作用。

curl --header "Content-Type:application/json" http://example.com

jack.zh 标签:linux 继续阅读

840 ℉

14.11.18

Linux-tips

整理自左耳朵耗子

屏幕录制


如果你想把我的屏幕操作的过程录下来,在Linux下只需要一个ffcast的命令就可以搞定了。

$ ffcast -s ffmpeg -r 20 -vcodec huffyuv out.avi

上面的命令会让你选择一个要录制的区域,然后呢,就会你就可以操作了,操作完后退回去按 q 键退出结束。如果你想制作成 gif 文件,你可以用 convert命令:

$ convert -layers Optimize -set delay 1 out.avi out.gif

上面会有如下效果:

安装
// 安装 ffcast

$ sudo add-apt-repository ppa:minos-archive/main
$ sudo apt-get update
$ sudo apt-get install ffcast

// 安装 ffmpeg
$ sudo apt-add-repository ppa:mc3man/trusty-media
$ sudo apt-get update
$ sudo apt-get install ffmpeg gstreamer0.10-ffmpeg

// 安装convert
$ sudo apt-get install imagemagick

命令行剪切版

如何把命令行的输出copy到剪贴版中?

在Windows下,你可以使用clip命令,如:

tree | clip

Linux下,你可以安装xclip,如:

cat file | xclip

xclip 是拷贝,xclip -o是粘贴

mac OS X上,你可以使用pbcopy/pbpaste命令,如:

pbcopy < .ssh/id_rsa.pub

cygwin上是putclipgetclip

INT_MIN坑

32位的int型的取值是2147483647 到 -2147483648,但是,在C/C++语言中,你不能直接使用 -2147483648 来代替最小负数,因为它不是一个数,而是一个表达式。表达式是:“对正数2147483648取负”,所以,2147483648已经溢出了。这就是为什么INT_MIN总是定义成 (-INT_MAX - 1) 的原因.

shell管道退出码

我们知道,linux命令行上一个命令的退出码放在了$?环境变变中,但是,如果这个命令是一串管道符连接和多个命令,怎么知道每个命令的退出码?你可以使用 PIPESTATUS环境变量。比如这个测试:

true | false | true; echo “${PIPESTATUS[@]}”

jack.zh 标签:linux 继续阅读

754 ℉

14.11.14

css基本动画

朋友要我帮我做一张转动的图片 可是我不会flash,就想着html做一个。

做的步骤:

1 以前见过的类似效果

曾几何时,在魅族的官网上见过一个类似的效果

MX4

2 分析他的实现

通过分析他的实现发现,其实使用了css 的transform,于是就把他的代码精简,得到了自己的DEMO(点击下载)

3 分析代码

css:

@-webkit-keyframes rotate {
  from {
    -webkit-transform: rotate(0);
  }
  to {
    -webkit-transform: rotate(360deg);
  }
}
@keyframes rotate {
  from {
    transform: rotate(0);
  }
  to {
    transform: rotate(360deg);
  }
}

.standby-img {
  height: 631px;
  position: relative;
}

.standby-img img {
  position: absolute;
  top: 50%;
  left: 50%;
}

.standby-img-in {
  margin: -170px 0 0 -140px;
}

.standby-img-roll {
  margin: -331px 0 0 -331px;
}

.standby-img-roll {
  -webkit-animation-name: rotate;
  -webkit-animation-duration: 5s;
  -webkit-animation-timing-function: linear;
  -webkit-animation-iteration-count: infinite;

  animation-name: rotate;
  animation-duration: 5s;
  animation-timing-function: linear;
  animation-iteration-count: infinite;
}

.bosy-div {
  height: 1075px;
  text-align: center;
  padding-top: 100px;
  background: #101010 url(../images/www/standby-1.jpg) repeat 0 0;
}
.bosy-div h1 {
  height: 60px;
  color: #fff;
  font-size: 45px;
}

html:

<div class="bosy-div">
    <h1>Roll</h1>
    <div class="standby-img">
        <img class="standby-img-in" src="static/in.jpg" alt="">
        <img class="standby-img-roll" src="static/roll.png" alt="">
    </div>
</div>
4 拓展
  • 相应的js库(jQuery-Transit.js
  • 我们完全可以通过这个东西做一个时钟啊 说做就做
  • 时钟不在讲解

jack.zh 标签:css3 继续阅读

838 ℉

14.11.13

C语言基础(3-4)-位运算

语言位运算符:与、或、异或、取反、左移和右移


位运算是指按二进制进行的运算。在系统软件中,常常需要处理二进制位的问题。C语言提供了6个位操作运算符。这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型。

C语言提供的位运算符列表:

&   按位与 如果两个相应的二进制位都为1,则该位的结果值为1,否则为0
|   按位或 两个相应的二进制位中只要有一个为1,该位的结果值为1
^   按位异或 若参加运算的两个二进制位值相同则为0,否则为1
~   取反 ~是一元运算符,用来对一个二进制数按位取反,即将0变1,将1变0
<<  左移 用来将一个数的各二进制位全部左移N位,右补0
>>  右移 将一个数的各二进制位右移N位,移到右端的低位被舍弃,对于无符号数,高位补0

1、“按位与”运算符(&)

按位与是指:参加运算的两个数据,按二进制位进行“与”运算。如果两个相应的二进制位都为1,则该位的结果值为1;否则为0。这里的1可以理解为逻辑中的true,0可以理解为逻辑中的false。按位与其实与逻辑上“与”的运算规则一致。逻辑上的“与”,要求运算数全真,结果才为真。若,A=true,B=true,则A∩B=true 例如:3&5 3的二进制编码是11(2)。(为了区分十进制和其他进制,本文规定,凡是非十进制的数据均在数据后面加上括号,括号中注明其进制,二进制则标记为2)内存储存数据的基本单位是字节(Byte),一个字节由8个位(bit)所组成。位是用以描述电脑数据量的最小单位。二进制系统中,每个0或1就是一个位。将11(2)补足成一个字节,则是00000011(2)。5的二进制编码是101(2),将其补足成一个字节,则是00000101(2)

按位与运算:

00000011(2)
&00000101(2)
00000001(2)

由此可知3&5=1 c语言代码:

#include <stdio.h>
main()
{
  int a=3;
  int b = 5;
  printf("%d",a&b);
}

按位与的用途: +++++ (1)清零 若想对一个存储单元清零,即使其全部二进制位为0,只要找一个二进制数,其中各个位符合一下条件:

原来的数中为1的位,新数中相应位为0。然后使二者进行&运算,即可达到清零目的。 例:原数为43,即00101011(2),另找一个数,设它为148,即10010100(2),将两者按位与运算: 00101011(2) &10010100(2) 00000000(2) c语言源代码: #include main() { int a=43; int b = 148; printf(“%d”,a&b); } #####(2)取一个数中某些指定位

若有一个整数a(2byte),想要取其中的低字节,只需要将a与8个1按位与即可。

a 00101100 10101100
b 00000000 11111111
c 00000000 10101100

#####(3)保留指定位: 与一个数进行“按位与”运算,此数在该位取1. 例如:有一数84,即01010100(2),想把其中从左边算起的第3,4,5,7,8位保留下来,

运算如下:

01010100(2)
&00111011(2)
00010000(2)
即:a=84,b=59
    c=a&b=16

c语言源代码:

#include <stdio.h>
main()
{
    int a=84;
    int b = 59;
    printf("%d",a&b);
}

2、“按位或”运算符(|)

两个相应的二进制位中只要有一个为1,该位的结果值为1。借用逻辑学中或运算的话来说就是,一真为真。

例如:60(8)|17(8),将八进制60与八进制17进行按位或运算。

00110000
|00001111
00111111 

c语言源代码:

#include <stdio.h>
main()
{
    int a=060;
    int b = 017;
    printf("%d",a|b);
}

应用:按位或运算常用来对一个数据的某些位定值为1。例如:如果想使一个数a的低4位改为1,则只需要将a与17(8)进行按位或运算即可。

3、按位异或

例如:a=3,即11(2);b=4,即100(2)。

想将a和b的值互换,可以用以下赋值语句实现:

a=a∧b;
b=b∧a;
a=a∧b;
a=011(2)
(∧)b=100(2)
a=111(2)(a∧b的结果,a已变成7)
(∧)b=100(2)
b=011(2)(b∧a的结果,b已变成3)
(∧)a=111(2)
a=100(2)(a∧b的结果,a已变成4)

等效于以下两步:

① 执行前两个赋值语句:“a=a∧b;”和“b=b∧a;”相当于b=b∧(a∧b)。
② 再执行第三个赋值语句: a=a∧b。由于a的值等于(a∧b),b的值等于(b∧a∧b),

因此,相当于a=a∧b∧b∧a∧b,即a的值等于a∧a∧b∧b∧b,等于b。

c语言源代码:

#include <stdio.h>
main()
{
    int a=3;
    int b = 4;
    a=a^b;
    b=b^a;
    a=a^b;
    printf("a=%d b=%d",a,b);
}

4、“取反”运算符(~)

他是一元运算符,用于求整数的二进制反码,即分别将操作数各二进制位上的1变为0,0变为1。 例如:~77(8)

源代码:

#include <stdio.h>
main()
{
  int a=077;
  printf("%d",~a);
}

5、左移运算符(<<)

左移运算符是用来将一个数的各二进制位左移若干位,移动的位数由右操作数指定(右操作数必须是非负值).其右边空出的位用0填补,高位左移溢出则舍弃该高位。 例如:将a的二进制数左移2位,右边空出的位补0,左边溢出的位舍弃。若a=15,即00001111(2),左移2位得00111100(2)。

源代码:

#include <stdio.h>
main()
{
  int a=15;
  printf("%d",a<<2);
}

左移1位相当于该数乘以2,左移2位相当于该数乘以2*2=4,15<<2=60,即乘了4。但此结论只适用于该数左移时被溢出舍弃的高位中不包含1的情况。

假设以一个字节(8位)存一个整数,若a为无符号整型变量,则a=64时,左移一位时溢出的是0,而左移2位时,溢出的高位中包含1。

6、右移运算符(>>)

右移运算符是用来将一个数的各二进制位右移若干位,移动的位数由右操作数指定(右操作数必须是非负值),移到右端的低位被舍弃,对于无符号数,高位补0。对于有符号数,某些机器将对左边空出的部分用符号位填补(即“算术移位”),而另一些机器则对左边空出的部分用0填补(即“逻辑移位”)。

注意:对无符号数,右移时左边高位移入0;对于有符号的值,如果原来符号位为0(该数为正),则左边也是移入0。如果符号位原来为1(即负数),则左边移入0还是1,要取决于所用的计算机系统。有的系统移入0,有的系统移入1。移入0的称为“逻辑移位”,即简单移位;移入1的称为“算术移位”。

例: a的值是八进制数113755:

 a:1001011111101101 (用二进制形式表示)
 a>>1: 0100101111110110 (逻辑右移时)
 a>>1: 1100101111110110 (算术右移时)

在有些系统中,a>>1得八进制数045766,而在另一些系统上可能得到的是145766。Turbo C和其他一些C编译采用的是算术右移,即对有符号数右移时,如果符号位原来为1,左面移入高位的是1。

源代码:

#include <stdio.h>
main()
{
  int a=0113755;
  printf("%d",a>>1);
}

7、位运算赋值运算符

位运算符与赋值运算符可以组成复合赋值运算符。

   例: &=, |=, >>=, <<=, ∧=
   例: a & = b相当于 a = a & b
         a << =2相当于a = a << 2

jack.zh 标签:C 继续阅读

1 2 3 4 5 6 7 8 9 10
Fork me on GitHub