杂记

陪媳妇在医院待产。

进产房的头一天晚上,陪媳妇在医院,一晚上我和老婆一分钟都没睡,肚子一阵比一阵疼,疼得越来越频繁,最后那一个小时,媳妇真快要坚持不住了,我只能在一旁紧紧地握着她的手,鼓励她说医生教的方法不断地呼气化解一点疼痛。经过了那一晚上,才真正觉得女人的伟大,我更爱我媳妇了。一个女人生孩子前,还必须要经过这么一段难熬的疼痛期,最终把一个小生命生出来,还有什么比这更令人尊敬的。

在疼房里陪着,亲眼目睹一个小生命的降生。既紧张又兴奋,看着仪器表监测的波线,每一次跳动都无比紧张和害怕,但又不能表现出来,因为媳妇还在旁边,真正的主角是她。当孩子从露一点头,到整个头部出来,再到整个身体全部都出来,这比我平生所看到的任何一部电影,见过的任何一种大自然风景都令我震撼和永生难忘。每一个人都应该好好地爱自己的母亲,没有什么比她生育和抚养了你更重要。

成功升级为老爸后,日子了是若逼的,半夜起床免不了,于是这几天睡眠严重不足,也得给娃起个名字,全家人都得围着这个小家伙转。

最后,希望他快乐健康成长,以后可以做他喜欢的事,选择他的爱好,选择他的人生。

 

git对象存储

之前提到当存储数据内容时,同时会有一个文件头被存储起来。我们花些时间来看看 Git 是如何存储对象的。你将看来如何通过 Ruby 脚本语言存储一个 blob 对象 ,有必要了解一下对象是如何被存储的。以git设计哲学中的test1.txt为例分析blob对象如何被计算校验和?如何被存储?是否和直接调用git命令的结果一致?

sha-1校验和计算

我们需要验证通过ruby计算出来的检验和与这个一致。

为了验证,新建一个git仓库

$ git init
Initialized empty Git repository in /Users/lyc/Desktop/tg/.git/

同样新建一个文件test1.txt,内容为test1,并把它加入暂存区

 

gitt使用’blob ‘ + len(content) + ‘\0’ + content作为文件内容
blob表示对象类型为blob类型,

len表示内容的长度

\0为空字节

其中’blob ‘ + len(content) + ‘\0’ 来组成一个header,然后再将这个header与真正的内容拼接起来,并计算拼接后的新内容的 SHA-1 校验和。

使用 irb 命令进入 Ruby 交互式模式:

可见计算出来的校验后与刚开始设定的校验和是一致的。

 

git对象存储

在git设计哲学中我们了解到test1.txt被git add命令添加到git仓库后,存储的路径如下

 

我们通过ruby命令来对数据进行压缩然后存储,看看会发生什么。

Git 用 zlib 对数据内容进行压缩,在 Ruby 中可以用 zlib 库来实现。

最后将用 zlib 压缩后的内容写入磁盘。

git的存储的规则是:sha1值的前2位作为文件夹名,后38位作为文件名

把它存储在.git的objects目录下

这样就完成了一次blob对象的创建。

退出irb后,用git命令验证下创建对象的内容

结果与test1.txt的内容一致。

执行git st命令查看下状态,

发现是untracked

再用git add命令

再看.git/objects目录下,目录没变,还是

 

结论:Git 以对象类型为起始内容构造一个文件头,本例中是一个 blob。然后添加一个空格,接着是数据内容的长度,最后是一个空字节 (null byte),接着用这个文件头和真正的内容拼接起来(不是文件名)计算校验和,然后用zlib对数据进行压缩,按照SHA-1 值的头两个字符作为子目录名称,剩余 38 个字符作为文件名保存压缩后的数据。这样就把一个文件存储到了git仓库中。

git设计哲学

刚开始使用git的时候,总想拿git来和cvs或者svn来作对比,但不久后发现这个想法本身就是错的,git完全就是另外一种物种,一种本属于未来的物种。它的对象存储方式,快照,分支等,都是完全不同的。

相信每个使用git的人,都想了解git内存文件的存储对象,快照,提交在历史和分支等内部的原理。都想知道它是否有传说中的那么强大?

Git 对象

先从本地创建一个空git仓库开始

这时会发现目录下只有一个.git文件夹,进去后长这样

description文件仅供GitWeb使用,不用关心它。
config文件包含了项目特有的配置选项,如最常用的用户名和邮箱。
info目录保存了一份不希望在 .gitignore 文件中管理的忽略模式 (ignored patterns) 的全局可执行文件。这个用得比较少,也不用太关心。
hooks目录保存了客户端或服务端钩子脚本,一般我们都是用默认的,很少改,也不用太关心。

因此,我们需要重点关心另外四个重要的文件或目录:HEAD和index文件,objects和refs目录,因为它们是Git的核心:

objects 目录存储所有数据内容。
refs 目录存储指向数据 (分支) 的提交对象的指针。
HEAD 文件指向当前分支。
index 文件保存了暂存区域信息。

刚初使化的一个 Git 仓库, objects 目录是空的:

Git 初始化了 objects 目录,同时在该目录下创建了 pack 和 info 子目录,但是该目录下没有其他常规文件

接下来,我们新建一个文件test1.txt,内容为test1,并把它加入暂存区

发现.git目录下多了2个文件,且内容都为字节码:

在.git目录下多了一个index文件
在objects下面多了一个a5文件夹,文件夹下有一个文件名为bce3fd2565d8f458555a0c6f42d0504a848bd5的文件

使用如下命令查看test1.txt的hash值

发现结果的前2位是文件夹的名字,后38位是文件的名字。

a5bce3fd2565d8f458555a0c6f42d0504a848bd5这个文件是用zlib压缩的
通过git cat-file 命令可取出文件存储的内容

内容就是test1.txt的文件内容

看看index文件,刚刚了解了index 文件保存了暂存区域信息, 用git ls-files —stage命令可查看index内容

此时index保存的就是新加入暂存区的文件快照

gitt使用’blob ‘ + len(content) + ‘\0’ + content作为文件内容,其sha1值的前2位作为文件夹名,后38位作为文件名
 

Tree(树)对象

接下去来看 tree 对象,tree 对象可以存储文件名,同时也允许存储一组文件。Git 以一种类似 UNIX 文件系统但更简单的方式来存储内容。所有内容以 tree 或 blob 对象存储,其中 tree 对象对应于 UNIX 中的目录,blob 对象则大致对应于 inodes 或文件内容。一个单独的 tree 对象包含一条或多条 tree 记录,每一条记录含有一个指向 blob 或子 tree 对象的 SHA-1 指针,并附有该对象的权限模式 (mode)、类型和文件名信息。

现在把test1.tst提交,作为仓库的第一次提交

发现在objects目录下多了两个文件夹,文件夹下面是对面的sha1文件

分别查看一下内容

其中第一个是commit对象,第二个是tree对象

这个tree对象可以认为是git仓库的根目录,类似unix文件系统中的”/”。

Commit(提交)对象

我们在根目录新建一个文件夹temp,在temp下面添加一个文件test2.txt,文件内容为test2,并提交

发现objects下面又多了4个文件夹,以及文件夹下对面的sha-1文件

通过git log命令来查看提交历史

发现最后一次提交的sha-1文件是d25d2289339c751ff3f7e1ef1865a58c71d0f51c,对应文件是

我们查看d25d2289339c751ff3f7e1ef1865a58c71d0f51c里的内容

发现其中;
tree 35592c587f70cf6ec1b99bb382bec2ef92f83396 是本次提交指向的tree对象(即根目录)对应文件是

parent a3951d57b1413275b171d967fa67fd90eecff648是第二次提交指向第一次提交对象的指针
author和committer分别是作者是提交者

再来看 35592c587f70cf6ec1b99bb382bec2ef92f83396文件的内容

 

这个tree对象也指向一个tree对象和一个blod对象,分别代表temp目录和test1.txt文件的sha1文件
这一行 040000 tree 9e7b8054ac3ca530d8e69556dff5903cdcbdc4d3    temp 的对应文件是

 

再继续看tree对象9e7b8054ac3ca530d8e69556dff5903cdcbdc4d3里面的内容

 

文件内容中只有一个指向blob对象的指针(即test1.txt对象的sha1文件),对应的文件为

至此,新增加的4个文件的关系已找到。

两次提交的关系如图:

这就是git的对象系统,本质上是一个key-value的内容寻址文件系统。

当用git add命令把一个文件或者目录添加到git跟踪的时候,会生成一个blob对象或者tree对象
当用git commit 来提交的时候,会创建一个commit对象,commit包含了提交者信息,还包含一个指向仓库根目录的tree对象。
然后tree对象再包含指向文件的blob对象或者子目录tree对象

android本地定时通知

android本地通知略有不同,分为立即触发和延时触发

1.即时通知

android默认的Notification为立即触发

 

2.延时触发

想让一定时间后再触发通知,其实是用系统的AlarmManager来实现的。

具体的AlarmManager解释参考

http://yuanzhifei89.iteye.com/blog/1131523

http://blog.csdn.net/ryantang03/article/details/9317499

添加一个ALARM_SERVICE

 

添加一个系统通知类,用于在倒计时间到时,接收系统轮询通知

配置文件中添加

 

升级xcode7开发问题汇总

1.The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.

Xcode7 编译程序无法连接网络,是因为Xcode7下,Apple要求数据传输协议必须支持Https协议(AST),否则将会默认无法连接网络。

目前网上已经给出临时解决办法:

2. fembed-bitcode is not supported on versions of iOS prior to 6.0

原因:Xcode7 及以上版本会默认开启 bitcode 。  

Xcode 7.0中, enable_bitcode选项是默认YES,导致所有的对象,静态库和用户框架中使用时必须包含bitcode,否则,编译发出错误。如果你使用了第三方提供的库或框架,需要更新包含bitcode的版本(包括第三方库)。

解决办法:

(1).更新library使包含Bitcode,否则会出现以上问题。
(2).关闭Bitcode,简单粗暴。

如果不想打开enable_bitcode,可以设置成NO。

 

3.Scheme白名单问题

-canOpenURL: failed for URL: “weixin://app/wxdaae92a9cfe5d54c/” – error: “This app is not allowed to query for scheme weixin”

 

近期苹果公司iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。
受此影响,当你的应用在iOS 9中需要使用微信SDK的相关能力(分享、收藏、支付、登录等)时,需要在“Info.plist”里增加如下代码:

<key>LSApplicationQueriesSchemes</key><array>
<string>mqqOpensdkSSoLogin</string>
<string>mqzone</string>
<string>sinaweibo</string>
<string>alipayauth</string>
<string>alipay</string>
<string>safepay</string>
<string>mqq</string>
<string>mqqapi</string>
<string>mqqopensdkapiV3</string>
<string>mqqopensdkapiV2</string>
<string>mqqapiwallet</string>
<string>mqqwpa</string>
<string>mqqbrowser</string>
<string>wtloginmqq2</string>
<string>weixin</string>
<string>wechat</string></array>

 

为wordpress文章评论添加算术验证码

从网上搜到http://www.yuju.org/379.html使用的方法,
但也许是我用的workpress版本不同,没有找到相关的代码,于是参考了作者文章的基础了,研究了下,最终这样实现。

修改wordpress根目录下的 wp-comments-post.php

修改源代码其实没那么难,只是任何源代码的修改都记得先备份一个就是了。

网站根目录下的 wp-comments-post.php,查找:

if ( ” == $comment_content )
在此代码的上面增加:

 

 

然后修改wp-includes文件夹下的的文件comment-template.php
找到function comment_form( $args = array(), $post_id = null ) 方法

查找相关代码,我修改后如下

 

 

效果如风潇潇的评论验证码效果

苹果审核踩过的坑

最近一段时间由于有三款应用需要申请appstore,三款应用加起来先后被拒绝了七八次,好在这些应用现在都通过了。其中包含了一些条款理解不浅析,也踩过一些坑,收集一下,为以后不会再踩上同一个坑。

1.包含竞赛与赌博
程序内有抽奖的,在评级处必须选上竞赛与赌博。
也必须在抽奖页面加上抽奖规则与说明。
在抽奖规则里必须声明苹果并不是这些抽奖与赌博的发起者和参与者。说白了就是声明这些活动都与苹果无关。

2.不能包含显示的版本信息和检查版本更新

3.提供测试账号
即使是只需要输入手机和手机验证码,也需要提供一个可登录的手机号的验证码,不然会登录不进去直接被拒。

3.包含注册登录
如果包含注册功能,必须包含有相应的用户信息系统(比如登录,个人中心之类的和用户注册的必须要性相关的功能),或者你在审核备注里添加说明为什么需要注册,不然会直接被拒,因为苹果怀疑你收集个人信息。

如果注册包含隐私信息(如手机号,性别等)也必须在注册页包含一个隐私条款的说明。

4.有黄色和侮辱性内容
比如图片内容涉及黄色内容,或者恶心等侮辱等内容。会被拒绝,比如我们有一张漫画看上去是竖中指,就被拒绝了

5.支付
苹果条款里说明购买虚拟产品或者内容,支付不能用第三方支付,只能使用苹果支付。但购买线下产品或者实际产品的,可以接入第三方支付(如微信,支付宝)。

App Store 审核条款

1.1
As a developer of Apps for the App Store you are bound by the terms of the Program License Agreement (PLA), Human Interface Guidelines (HIG), and any other licenses or contracts between you and Apple. The following rules and examples are intended to assist you in gaining acceptance for your App in the App Store, not to amend or remove provisions from any other agreement.

为App Store开发程序,开发者必须遵守 Program License Agreement (PLA)、人机交互指南(HIG)以及开发者和苹果签订的任何协议和合同。以下规则和示例旨在帮助开发者的程序能获得
2.1
Apps that crash will be rejected

崩溃的程序将会被拒绝。
2.2
Apps that exhibit bugs will …

skynet中的协程

这篇是转来的,http://www.cnblogs.com/iirecord/p/skynet_coroutine.html
也是这一直很想写的,作者已经把skynet处理消息过程中的协程解释得很清析了,如下文

——————

阅读云大的博客以及网上关于 skynet 的文章,总是会谈服务与消息。不怎么看得懂代码,光读这些文字真的很空洞,不明白说啥。网络的力量是伟大的,相信总能找到一些解决自己疑惑的文章。然后找到了这篇讲解 skynet 消息队列的文章(最新的 skynet 消息队列代码已经有更新,变得更简洁易读)。了解了 skynet 消息是如何派发的,就想知道消息被派发出去到一个服务后,如何调用服务的 callback 函数,从而处理此消息。碰巧博主写了这篇讲解 skynet 如何注册回调函数的文章,于是 skynet 的概念“服务与消息”便在代码中得到了定位,便可以此为入口点探究 skynet 实现。

消息派发

这里云大已经很详细的介绍了,我就仅仅在这里略提一下。skynet 把消息分为不同的类别,不同类别的消息有不同的编码方式,若编写一个服务,你需要为此服务关注的消息类型注册 dispatch 函数用来接收此类别的消息。skynet 注册类别消息的 dispatch 函数有两种方式。

调用 skynet.register_protocol 注册。函数的参数是一个 table ,以”lua”类消息为例,里面有若干字段含义如下:

指定了 table 中的 dispatch 字段,以后”lua”类消息到达时便会调用此函数。

调用 skynet.dispatch 函数注册。为此,云大给出了一个惯用写法,以”lua”类消息为例,如下:

两种方式可以根据喜好选择,毕竟一个服务可能需要处理多种类型的消息,需要注册多个 dispatch 函数。

在 skynet 中用 Lua 编写一个服务必须调用 skynet.start 启动函数启动此服务。

skynet.start 其中在一个作用是调用 c.callback 函数把 skynet 框架的消息派发与你自定义的 dispatch 函数联系起来,这个联系的纽带就是 dispatch_message(skynet.lua) 函数。当服务的消息队列有消息到达时,框架从消息队列中取出消息经过一些转换调用到 dispatch_message 函数,然后 dispatch_message 函数根据协议类型调用相应的 dispatch 函数,最终到具体某条消息的处理函数。

消息执行

skynet 是基于服务的,服务间通过消息进行通信。实现方面 skynet 为每个服务创建一个 lua_State ,不同的服务 lua_State 是不同的,因此服务是相互独立互不影响的。对于消息,”skynet 的 lua 层会为每个请求创建一个独立的 coroutine”。经过上面一节,了解到消息会到达我们自定义的 dispatch 函数,此时进入了业务相关的代码逻辑中,我们只关注业务的逻辑而不关注底层消息如何到达这儿的。于是猜测应该是在 dispatch_message 函数中 skynet 会创建 coroutine 来具体处理某个消息。然后,我们猜想消息执行流程大概应该是这样的:

一条消息到达,服务的主线程创建 coroutine 处理此消息,处理完后执行权回到主线程,继续下一条消息处理。
一条消息到达,服务的主线程创建 coroutine 处理此消息,假设此服务是 A …

配置mac自带的php-fpm和安装phpreids插件

直接运行,有报错找不到配置文件。
$ php-fpm
[11-Jan-2014 16:03:03] ERROR: failed to open configuration file ‘/private/etc/php-fpm.conf’: No such file or directory (2)
[11-Jan-2014 16:03:03] ERROR: failed to load configuration file ‘/private/etc/php-fpm.conf’
[11-Jan-2014 16:03:03] ERROR: FPM initialization failed
可以在/private/etc/ 目录下生成配置文件,需要root权限(sudo)
或者在普通用户有权限的目录里放置配置文件,通过–fpm-config参数指定配置文件的位置,如下:
# cp /private/etc/php-fpm.conf.default /usr/local/etc/php-fpm.conf

$ php-fpm –fpm-config /usr/local/etc/php-fpm.conf
[11-Jan-2014 16:10:49] ERROR: failed to open error_log (/usr/var/log/php-fpm.log): No such file or directory (2)
[11-Jan-2014 16:10:49] ERROR: failed to post process the configuration
[11-Jan-2014 16:10:49] ERROR: FPM initialization failed
错误信息显示:不能正确的打开”日志“文件,原因是默认在/usr/var目录下工作,可以修改配置文件指定正确的日志文件路径

$ vim /usr/local/etc/php-fpm.conf
修改php-fpm.conf文件中的error_log项,默认前缀是/usr/var ,但并没有这个路径

error_log = /usr/local/var/log/php-fpm.log
pid = /usr/local/var/run/php-fpm.pid
或者不修改配置文件中配置项的路径,在php-fpm的运行参数中(-p)指定放置运行时文件的相对路径前缀

$ php-fpm –fpm-config /usr/local/etc/php-fpm.conf –prefix /usr/local/var
到此,php-fpm守护进程已经基本可以正确的启动了。

下面我们看下php.ini配置

# cp /etc/php.ini.default /etc/php.ini

变更own,以后修改不用老是切换root,生产环境最好不要改

# chown …