2011年度总结

2011年度总结
来源:人人网 作者:唐申强

和往年一样,这是蛋疼的一年,坑爹的一年,杯具的一年,纠结的一年。

这一年,“我爸是李刚”拉开了中国人拚爹的序幕,大量的富二代官二代用他们的行动告诉我们:人生最重要的不是你所朝的方向,而是取决于你是谁的精子。

这一年,重庆的打黑运动让我们明白:电视上经常看到的那些衣着光鲜,人模狗样的公仆,他们往往在下一刻就变成了黑老大。而你是公仆还是黑社会,关键看你有没有站错队。

这一年,日本9.0级地震震垮了核电站,也震碎了国人愚昧的神经,那些买不起房而被迫单身的人们,因为手里有几袋碘盐而变得奇货可居。

这一年,国与民争利达到高潮,财政收入连创新高,人民饭碗却营养不良。GDP世界第二,百姓收入勉强苟活,房子彻底沦为多数人的浮云。而盛会,依然在一个叫隆重的地方举行。

这一年,苹果砸中牛顿沉寂数百年后,以数码产品的姿态席卷全球。世界上最遥远的距离是:我们一起出门,你去买苹果四代,而我却只能买四袋苹果。

这一年,谢霆锋终于意识到自己对柏芝的了解始终超越不了天涯上的民工,于是他放弃了。我固执的认为他一定看到了杂谈那个万人景仰的回复。男人,无论好坏,都翻不过那道绿帽砌成的坎,有的秋后算帐,有的立马摊牌。

这一年,芙蓉姐姐从大S变成了小S,凤姐的绿卡让我们彻底断了成功可以复制的念想。但不管是李宇春,还是曾轶可,都是我的哥,我的哥。。

这一年,南科大45名学子以非暴力不合作表达了对中国教育的鄙视,一潭死水总算荡起了一丝波浪。但死水原本就不应该有波浪,所以,他们在潭中注满了水泥。

这一年,转基因和地沟油让中国人坚信他们是核战争最后的幸存者。在网上,他们表达吐血身亡的语句变成了:遂吐3公升地沟油而亡。

这一年,各地下雨全是100年不遇,武汉的海景超过公交成为新的城市名片。成都,长沙,南京纷纷在报纸上表示自己是特大号护舒宝,流量再多也不用担心,随即就被老天爷一个无情的耳光扇过去。。分析认为:此护舒宝为山寨品,也就是:made in china。

这一年,绿皮火车见到了蒸汽火车,感叹世间人情冷暖,我们终究都逃不过鸟尽弓藏的命运。开明的蒸汽火车说:历史的车轮在前进,我们都尽到了自己所处位置的责任,现在是高铁的时代了,你再不退下就是开历史的倒车,中国人民才被历史的车轮碾过,还没爬起来,一回头却看见你在倒车,你叫他们情何以堪呐。

这一年,高铁恍如一夜之间长满祖国各地,人们用高于普车数倍的价格向铁道部购买时间,而那些时间充裕的人因普车的取消也不得不买几个小时,然后在目的地玩手机来消磨时间。

这一年,号称世界领先的动车出轨了,人们悲怆的发现,吃的,住的,坐的竟没有一种让人蛋定,以河蟹着称的媒体也开始草泥马了,在经历了出事→微博讨论→小秘书删帖→微博疯狂讨论→小秘书来不及删帖→问责呐喊声四起→传统媒体跟进→微博谣言四起→政府辟谣→产生新的流行语→李承鹏发文→韩寒发文→讽刺段子出炉→五毛辟谣搅混水→讨论进入高潮→总理现身→微博一片体贴谅解→和谐,删帖,噤声→搞笑段子出炉→下次。。。后,酱油瓶仍旧在手,真相的高度永远高于酱油瓶的高度,对于善良的中国人来说,打酱油比抢碘盐还来得更轻松和毫无风险。

这一年,黑社会败给了社会黑,社会黑又催生了黑监狱,黑监狱关的却不是黑社会。黑社会说:监狱,本就是黑色,黑夜给了中国黑色的监狱,它们却用来禁锢冤屈。

这一年,灰太郎对喜洋洋说:我咬你,你不要动,我们要和谐。

这一年,五毛依旧凶猛,天涯沦落的不仅是国关,还有八卦。而在杂谈,五毛还是一如既往的苦逼。

这一年,人民仍然相信,皇帝是好的,中央是清白的,坏的只是地方。当不公降临在他身上时,他最期待的不是改良制度,而是渴望清官。

这一年,雷公也成了弱势群体,悲催的替铁道部背了黑锅。当我们在盘点中国事故责任人时,发现他们分别是临时工、临时工、临时工。。。还有雷公,这时玉帝大叫道:他也是临时工。

这一年,央视和百度,一个婊子一个奴才,为争牌坊打起来了。请问你支持谁?—-废话,当然是支持google。那么假如央视和百度同时落水,你是去吃火锅还是去K歌?—-废话,当然是掏出鸡鸡往水里尿尿。

这一年,我想对日本人说:不用担心,你们的国家不会抛弃你们!最后我要对中国人民说:不要幻想太多,你只能靠自己。

JW Player 编译及修改

修改方法去掉右键官方连接及官方logo水印:

  1. 去掉Logo水印;
    在文件“/com/longtailvideo/jwplayer/view/View.as ”中找到“_logo = new Logo(_player);及setupComponent(_logo, n++);”将其注释掉即可。【如果想保留logo,只是更改掉官方logo,查相关使用文档或者修改logo.as, 修改到logo.png的地址即可】
  2. 去掉右键about官网地址链接。
    在文件“/com/longtailvideo/jwplayer/view/RightclickMenu.as ”中找到“setAboutText();及addItem(about, aboutHandler);”将其注释掉即可。

我在flash builder 下面编译【Flex下面编译,同理】,建立文件pl.as:

package
{
	import com.longtailvideo.jwplayer.player.Player;

	public class pl extends Player
	{
		public function pl()
		{

		}
	}
}

最新jw player 5.7下载:点击下载 jw player 5.7 –采用GPU加速

附加问题:

  1. jw player源码问题,首先jw player是开源的,不需要破解反编译获得源码的,jw player源码现在地址为: http://developer.longtailvideo.com/svn/trunk/fl5
  2. 如果去编译jw player, 这个是基本Flash程序员需要学的基本知识,我是在src目录下建立fla文件的,需要将../lib目录中的as3corelib.swc设置好, 否则会提示json函数问题,虽然不影响基本使用。

HTML5游戏开发之一:动画制作

虽然目前几乎所有的webgame动画都使用Flash来实现,但是使用用JS来实现一场RPG的战斗动画,一直以来都不是什么难题。

去年我通过JS方式实现战斗引擎播放,效果也可以做的很绚丽,所有浏览器下,都测试通过,尚未发现卡的问题,但是,由于IE6下面,需要使用了VML()方式来处理PNG透明问题,并且要注意IE6缓存图片BUG的问题,解决这两个问题之后,JS耗CPU较少,但占用内存明显增大。基于兼顾IE6用户的考虑等等,我仍然会选择Flash来完成战斗动画。

由于将完成的一个游戏,是关卡玩法的游戏,PVE部分,比较适合放到手机平台上当做手机单机游戏来玩,所以我考虑,是否使用HTML5来完成战斗引擎,针对Webkit内核的等等支持HTML5的浏览器,我们可以使用HTML5来完成战斗动画播放,则可以直接使用在Andriod、iOS、WP7等手机平台上。

由于我从05年开始,我使用JavaScript越来越多,其中大部分是使用Prototype,所以下面这个例子,是基于了Prototype JS的。

注:如Internet Explorer的一些浏览器,不支持canvas标签或本演示。的Chrome、Firefox、Safari、Opera浏览器的最新版本正常工作。

不使用HTML5来完成动画的时候,通过css改变背景图片的偏移量可以做出战斗动画。使用HTML5来完成,只需要在Canvas上面循环画出图片上面不同帧即可。

如下例子中,使用了如下图片,一个攻击动画:
战斗动画图片

最好的说明是实例:

配置动画参数:

var attack = {
    name: 'attack',
    totalFrames: 10,
    loop: true,
    step: 4,
    width: 150,
    height: 150,
    sY: 0,
    sX: 0
}; //set initial animation set

角色动画:

/**
 * Sprite 系统,雏形
 *
 * @file_name   Sprite.js
 * @version     1.0
 * @author      黄新泽
 * @date        2011/1/14
 */

var	Sprite = Class.create({
	initialize : function(x, y, width, height, img, animation)//initialize sprite
    {
        this.canvas = document.createElement('canvas'); //动画canvas

        this.canvas.setAttribute('width', width);
        this.canvas.setAttribute('height', height);
        this.ctx = this.canvas.getContext('2d'); //get canvas drawing context

		this.x = x; // X position of this sprite
		this.y = y; //Y position of this sprite
		this.animation = 0; //current animation for this sprite
		this.currentFrame = 0; //current animation frame for this sprite
        this.width = width;
        this.height = height;

		this.image = img; //image that is being drawn to the canvas
		this.currentStep = 0; //number of frames since this sprite's animation was updated
		this.isReady = true; //sprite has finished loading and can be used

        this.animation = animation;
    },

    drawImage: function()
    {
        //draw image into sprite canvas
        this.ctx.clearRect(0, 0, this.width, this.height); //clear previous frame

        if(this.isReady)
        {
            //do not draw if sprite is not ready
            //calculate values for sprite based on animation
            var srcX = this.animation.sX + (this.currentFrame * this.animation.width);
            var srcY = this.animation.sY ;
            var srcWidth = this.animation.width;
            var srcHeight = this.animation.height;
            this.ctx.drawImage(this.image, srcX, srcY, srcWidth, srcHeight, 0, 0, srcWidth, srcHeight); //draw image
            this.stepSprite(); //advance animation
        }
    },

    stepSprite: function()
    {
        //advance animation based on animation speed (step value)
        if(this.currentStep >= this.animation.step)
        {
            this.currentStep = 0;
            this.currentFrame++;

            if(this.currentFrame >= this.animation.totalFrames)
            {
                if(this.animation.loop)
                {
                    this.currentFrame = 0; //loop animation back to start
                }
                else
                {
                    this.currentFrame = this.animation.totalFrames -1;	//if loop not set, hold on final frame
                }
            }
        }
        else
        {
            this.currentStep++; //advance step counter if step limit not reached
        }
    }
});

播放战斗动画:

var	FightAnimation = Class.create({

	canvas: 0, //main canvas object
	ctx: 0, //main canvas drawing context
	sprite: 0, //sprite object

	width: 900,
	height: 450,
	timer: 0,  //hold reference to game loop timer
	background: 0, //background image - for now is drawn right onto main canvas which is not ideal
	foreground: 0, //foreground object

	initialize: function(img)
    {
        //initialize FightAnimation
		this.canvas = document.getElementById('main');  //get canvas element from html
		this.ctx = this.canvas.getContext('2d'); //create main drawing canvas

		this.canvas.setAttribute('width', FightAnimation.width); //set attributes of canvas
		this.canvas.setAttribute('height', FightAnimation.height);

		this.sprite = new Sprite(0, 0, 150, 150, img, attack); //init sprite //create new Sprite object

        //document.body.insert(FightAnimation.sprite.canvas);
        this.timer = setInterval(this.drawFrame.bind(this), 40);
	},

	drawFrame: function()
    {
        //main drawing function
		this.ctx.clearRect(0, 0, this.width, this.height);  //clear main canvas

		//FightAnimation.ctx.drawImage(FightAnimation.background, 0, 0); // draw canvas background
		if(this.sprite)
        {
			this.sprite.drawImage(); //cause sprite to draw itself on its internal canvas
			this.ctx.drawImage(this.sprite.canvas, this.sprite.x, this.sprite.y);//draw sprite canvas onto main canvas
		}
	}
});

初始化战斗:

function startCanvas(e)
{
    new FightAnimation(img_res.successList['129_1_1'].img);  //initialize main Expermient object
}

document.on('img:oneloaded', startCanvas);  //处理进度条,........

var  img_res = ImgManage.getInstance();
img_res.addResourcesBag([["129_1_1", "/Images/actionicon/56/1/2.png"]]);

游戏中NPC 人工智能对话技术实现

其实就是08年,设想的,针对上班族,开发一个MSN机器人,通过对MSN机器人发送指令,来玩策略类网页游戏。 当初已经完成了MSN机器人的所有程序部分。通过MSN发送指令,可以完成游戏中几乎所有的建设、军事、消息指令…..

当继续想完善时候,发现完全使用中文是实现,目前缺少完善的AIML中文语料库,这个很难有现有资源利用……

# -*- coding: utf-8 -*-

import aiml
import sys
import time
import os.path
import thread
import re
from datetime import datetime
import marshal

loginemail="xinze@live.cn" # that robot will login to
loginpassword="11111" # account password
botname="Xinze...." # Robot's nickname
admin_email="xinze@live.cn" # emailaddress for admin the robot

# ==== normally nothing needs to be changed below ====

rootdir=os.getcwd()
configfile="%s/chatbot.ini" % rootdir
sessiondir="%s/sessions/%s" % (rootdir,loginemail)
os.system("mkdir -p %s" % sessiondir)
logfilename="%s/log" % sessiondir
sessionfilename="%s/session" % sessiondir

os.system("mkdir -p %s/tmp/" % rootdir)
msn_fortune="%s/tmp/msn-fortune" % rootdir
msn_fortune_zh="%s/tmp/msn-fortune-zh" % rootdir

blacklist=['sample@blacklist.org' ] # put here email addresses you want to block
blacklist=set(blacklist)
adminlist=[admin_email] # the 'admin' account's email address from which you send admin command
adminlist=set(adminlist)

dlist=[]
talkedto=[]

use_brain=True

def config(configfile, k):
    # setup bot properties such name, birthplace etc
    f=open(configfile)
    g=f.readlines()
    f.close()
    for i in g:
        h=i.split('=')
        if len(h)==2:
            k.setBotPredicate(h[0].strip(), h[1].strip()) 

    print sessionfilename
    # load session
    if os.path.exists(sessionfilename):
        f=open(sessionfilename)
        g=f.read()
        f.close()
        g=g.split('\n')
        for i in g:
            if i!='':
                talkedto.append(i)
                sessionFile = file("%s/%s.ses" %(sessiondir, i), "rb")
                session = marshal.load(sessionFile)
                sessionFile.close()
                for pred,value in session.items():
                    k.setPredicate(pred, value, i)

def dolog(message):
	global logfile
	logfile.write(message)
	logfile.flush()

def filter(message):
	message=message.replace("ALICE", botname)
	return message

def test_msg(senderemail, message):
    global dlist

    sender=senderemail.split("@")

    if senderemail in blacklist:
        return	

    dlist=[]

    if not senderemail in set(talkedto):
        talkedto.append(senderemail)

    logtime='%s/%s/%s %s:%s:%s' %( datetime.now().month, datetime.now().year, datetime.now().day, datetime.now().hour, datetime.now().minute, datetime.now().second)

    if not senderemail in adminlist:
        dolog('=== %s === Recv from %s < %s> ===\n%s\n' % (logtime, sender[0], senderemail, message))
    if message=='admquit' and senderemail in adminlist:
        message="%s is offline!" % botname
        #quit()

    if message=='admlist' and senderemail in adminlist:
        return

    if k.getPredicate("name", senderemail) =='':
        dispname=senderemail.split("@")
        if len(dispname) ==2:
            k.setPredicate("name", dispname[0], senderemail)
    remsg=k.respond(message, senderemail)
    remsg=filter(remsg)

    logtime='%s/%s/%s %s:%s:%s' %( datetime.now().month, datetime.now().year, datetime.now().day, datetime.now().hour, datetime.now().minute, datetime.now().second)
    if not senderemail in adminlist:
        dolog('=== %s === Send to %s < %s>===\n%s\n\n' % (logtime, sender[0], senderemail, remsg))

    print remsg

def savesession():
    # =========== save session
    f=open(sessionfilename, 'w')
    for i in talkedto:
        session = k.getSessionData(i)
        sessionFile = file("%s/%s.ses" % (sessiondir, i), "wb")
        marshal.dump(session, sessionFile)
        sessionFile.close()
        f.write("%s\n"% i)
    f.close()

def do_work():
    time.sleep(5)
    savesession() # save session data every 10 min
    thread.start_new_thread(do_work, ())

thread.start_new_thread(do_work, ())

# ================== Initialization
if __name__ == '__main__':
    k = aiml.Kernel()
    config(configfile, k)
    #k.verbose(False)

    # ================== load brain
    if use_brain and os.path.isfile("standard.brn"):
        k.bootstrap(brainFile = "standard.brn")
    else:
        k.bootstrap(learnFiles = "startup.xml", commands = "load aiml b")
        k.saveBrain("standard.brn")

    if os.path.exists(logfilename):
        logfile=open(logfilename, "a")
    else:
        logfile=open(logfilename, "w")

    player_email="alex@live.cn"

    while True:
        message = raw_input('>')
        test_msg(player_email, message)

在CentOS及Ubutun下安装Percona-Server和HandlerSocket注意事项

见: http://www.percona.com/docs/wiki/repositories:start

一、CentOS下安装Percona-Server及HandlerSocket

安装Percona Yum Repository

rpm -Uhv http://www.percona.com/downloads/percona-release/percona-release-0.0-1.i386.rpm
rpm -Uhv http://www.percona.com/downloads/percona-release/percona-release-0.0-1.x86_64.rpm
#自行选择对应的平台

yum install Percona-Server-server-51.i386
yum install Percona-Server-client-51.i386

编辑my.cnf

[mysqld]
plugin-load=handlersocket.so

loose_handlersocket_port = 9998 # 指定读请求端口号
# the port number to bind to (for read requests) 

loose_handlersocket_port_wr = 9999 # 指定写请求端口号
# the port number to bind to (for write requests)

loose_handlersocket_threads = 16 # 指定读线程数目
# the number of worker threads (for read requests)

loose_handlersocket_threads_wr = 1 # 指定写线程数目
# the number of worker threads (for write requests)

open_files_limit = 65535
# to allow handlersocket accept many concurrent
# connections, make open_files_limit as large as
# possible.

重启MySQL后,查看handlersocket是否正常运行

netstat -lnp | grep 9998
netstat -lnp | grep 9999
#查看端口是否被监听

或者在mysql中查看
mysql> INSTALL PLUGIN handlersocket SONAME "handlersocket.so";
mysql>SHOW PLUGINS; # 查看插件是否加载成
mysql>SHOW PROCESSLIST; # 查看handlersocket是否正常运行

#如果handlersocket没有正常运行, 则先关闭SELinux后再试试看看。

二、Ubuntu下安装Percona-Server及HandlerSocket

安装apt-get源

gpg --keyserver  hkp://keys.gnupg.net --recv-keys 1C4CBDCDCD2EFD2A
gpg -a --export CD2EFD2A | apt-key add -

在ubuntu下其它操作同上,如果没有正常运行,
mysql> INSTALL PLUGIN handlersocket SONAME “handlersocket.so”; 提示: “errno: 2 failed to map segment from shared object: Permission denied”

可以先 /etc/init.d/apparmor stop 然后重启MySQL, 然后 /etc/init.d/apparmor start

php handlersocket

一、安装php-handlersocket模块:

php-handlersocket, PHP extension for interfacing with MySQL Handler Socket.

wget http://php-handlersocket.googlecode.com/files/php-handlersocket-0.1.0.tar.gz
tar zxvf php-handlersocket-0.1.0.tar.gz
cd php-handlersocket
phpize
./configure
make
make install

二、php-handlersocket 使用示例:

	/*
	 * String  $host:MySQL ip;
	 * String  $port:handlersocket插件的监听端口,它有两个端口可选:一个用于读、一个用于写
	 */
	$hs = new HandlerSocket($host, $port);
	打开一个数据表:
	/*
	 * Int       $index:这个数字相当于文件操作里的句柄,HandlerSocket的所有其他方法都会依据这个数字来操作由这个	 openIndex打开的表,
	 * String  $dbname:库名
	 * String  $table:表名
	 * String  $key:表的“主键”(HandlerSocket::PRIMARY)或“索引名”作为搜索关键字段,这就是说表必须有主键或索引
	 *                 个人理解:要被当做where条件的key字段,这样可以认为handlersocket只有一个where条件
	 * String  $column:'column1,column2' 所打开表的字段(以逗号隔开),就是说$table表的其他字段不会被操作
	 */
	$hs->openIndex($index, $dbname, $table, $key, $column);
	查询:
	/*
	 * Int     $index: openIndex()所用的$index
	 * String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持'=', '>=', '< =', '>',and '< ';可以理解为where条件
	 * Array   $value
	 * Int       $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
	 * Int     $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
	 */
	$retval = $hs->executeSingle($index, $operation, $value, $number, $skip);
	插入(注意:此处的openIndex要用$port_wr,即读写端口):
	/*
	 * Int     $index: openIndex()所用的$index
	 * Array   $arr:数字元素数与openIndex的$column相同
	 */
	$retval = $hs->executeInsert($index, $arr);
	删除(注意:此处的openIndex要用$port_wr,即读写端口):
	/*
	 * Int     $index: openIndex()所用的$index
	 * String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持'=', '>=', '< =', '>',and '< ';可以理解为where条件
	 * Array   $value
	 * Int     $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
	 * Int     $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
	 */
	$retval = $hs->executeDelete($index, $operation, $value, $number, $skip);
	更新(注意:此处的openIndex要用$port_wr,即读写端口):
	/*
	 * Int     $index: openIndex()所用的$index
	 * String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持'=', '>=', '< =', '>',and '< ';可以理解为where条件
	 * Array   $value
	 * Int       $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
	 * Int     $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
	 */
	$retval = $hs->executeUpdate($index, $operation, $value, $number, $skip);
CREATE TABLE `user` (
  `user_id` int(10) unsigned NOT NULL,
  `user_name` varchar(50) DEFAULT NULL,
  `user_email` varchar(255) DEFAULT NULL,
  `created` datetime DEFAULT NULL,
  PRIMARY KEY (`user_id`),
  KEY `INDEX_01` (`user_name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT INTO `user` VALUES ('1', 'aaa', 'aaa@dsf.com', '2011-04-07 18:26:03');
INSERT INTO `user` VALUES ('2', 'bbb', 'bbb@dsf.com', '2011-04-07 18:26:03');
INSERT INTO `user` VALUES ('3', 'ccc', 'ccc@test.com', '2011-04-07 18:26:03');
< ?php
$host = '192.168.5.28';
$port = 9998;
$port_wr = 9999;
$dbname = 'test';
$table = 'user';

//GET
$hs = new HandlerSocket($host, $port);
if (!($hs->openIndex(1, $dbname, $table, HandlerSocket::PRIMARY, 'user_id,user_name,user_email,created')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

$retval = $hs->executeSingle(1, '>=', array('0'), 10, 0);

var_dump($retval);

$retval = $hs->executeMulti(
    array(array(1, '=', array('1'), 1, 0),
          array(1, '=', array('2'), 1, 0)));

var_dump($retval);

unset($hs);

//UPDATE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(2, $dbname, $table, '', 'user_name,user_email,created')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeUpdate(2, '=', array('2'), array('aaa', 'xun@dsf.com', '2011-04-07 18:26:03'), 1, 0) === false)
{
    echo $hs->getError(), PHP_EOL;
    die();
}

unset($hs);

//INSERT
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(3, $dbname, $table, '', 'user_id,user_name,user_email,created')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeInsert(3, array('5', 'aaa5', 'xun@dsf.com', '2011-04-07 18:26:03')) === false)
{
    echo $hs->getError(), PHP_EOL;
}
if ($hs->executeInsert(3, array('6', 'aaa6', 'xun@dsf.com', '2011-04-07 18:26:03')) === false)
{
    echo 'A', $hs->getError(), PHP_EOL;
}
if ($hs->executeInsert(3, array('7', 'aaa7', 'xun@dsf.com', '2011-04-07 18:26:03')) === false)
{
    echo 'B', $hs->getError(), PHP_EOL;
}

unset($hs);

//DELETE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(4, $dbname, $table, '', '')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}

if ($hs->executeDelete(4, '=', array('1')) === false)
{
    echo $hs->getError(), PHP_EOL;
    die();
}
?>

MySQL插件HandlerSocket

HandlerSocket 是MySQL的一个插件,用来实现 NoSQL 功能,用于跳过MySQL的SQL层面,直接访问内部的InnoDB存储引擎。

wget http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-client-5.5.11-1.rhel4.i386.rpm
wget http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-devel-5.5.11-1.rhel4.i386.rpm
wget http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-server-5.5.11-1.rhel4.i386.rpm
wget http://dev.mysql.com/get/Downloads/MySQL-5.5/MySQL-shared-5.5.11-1.rhel4.i386.rpm

rpm -ivh MySQL-client-5.5.11-1.rhel4.i386.rpm MySQL-devel-5.5.11-1.rhel4.i386.rpm MySQL-server-5.5.11-1.rhel4.i386.rpm MySQL-shared-5.5.11-1.rhel4.i386.rpm 

wget http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.11.tar.gz

一、安装HandlerSocket
获取安装包:https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL.git

tar -zxvf ahiguti-HandlerSocket-Plugin-for-MySQL-1.0.6-73-g0e63366.tar.gz
cd ahiguti-HandlerSocket-Plugin-for-MySQL-0e63366/
./autogen.sh
./configure --with-mysql-source=/home/xinze/software/mysql-5.5.11 --with-mysql-bindir=/usr/bin  --with-mysql-plugindir=/usr/lib/mysql/plugin
make && make install

修改/etc/my.cnf 配置

[mysqld]
plugin-load=handlersocket.so

loose_handlersocket_port = 9998 # 指定读请求端口号
# the port number to bind to (for read requests) 

loose_handlersocket_port_wr = 9999 # 指定写请求端口号
# the port number to bind to (for write requests)

loose_handlersocket_threads = 16 # 指定读线程数目
# the number of worker threads (for read requests)

loose_handlersocket_threads_wr = 1 # 指定写线程数目
# the number of worker threads (for write requests)

open_files_limit = 65535
# to allow handlersocket accept many concurrent
# connections, make open_files_limit as large as
# possible.

在mysql里加载HandlerSocket插件:

mysql> INSTALL PLUGIN handlersocket SONAME "handlersocket.so";
mysql>SHOW PLUGINS; # 查看插件是否加载成
mysql>SHOW PROCESSLIST; # 查看handlersocket是否正常运行

* 如果SHOW PROCESSLIST没有handlersocket 进程, 则先关闭SELinux后再试试看看。
* 在ubuntu下,可以先 /etc/init.d/apparmor stop 然后重启MySQL, 然后 /etc/init.d/apparmor start

二、安装 php-handlersocket 模块:

wget http://php-handlersocket.googlecode.com/files/php-handlersocket-0.1.0.tar.gz
tar zxvf php-handlersocket-0.1.0.tar.gz
cd php-handlersocket
phpize
./configure
make
make install

JW Player 5.5 去水印破解

自从根据JW Player源代码,编译破解去掉了官方水印之后,有很多网友下载使用了,但是从JW Player 5.3之后,我就再没有去编译,认为按照我们说的方法,很简单就编译出来,但是仍不停收到E-mail,求破解JW Player的最新版本………. 所以我就编译了最新版本的JW Player 5.5 去水印破解版本!

采用GPU加速的JW Player 5.5最新版本flash视频播放器,编译破解去除水印! 最新jw player 5.5下载

根据源代码编译方法见:去掉JW Player水印及右键官方菜单

Android and HTML5 开发手机应用

作为一个WEB开发者,HTML5让我兴奋,因为它可以将桌面应用程序功能带入浏览器中。但在国内,看着到处横行的IE8版本以下的浏览器,觉得到能大规模使用HTML5技术的那天,还遥遥无期。但面对iOS及Android等平台的手机用户越来越多,基于Webkit内核的移动浏览器一定能让HTML5先大规模应用起来。这将对对移动 Web 应用程序开发具有重大影响。

作为非常看好未来手机网络的我,也在一直研究Android平台的应用的开发,也许是因为自己更熟悉HTML及CSS、JS,并受到之前使用HTML和VC开发程序的影响,我也更愿意使用HTML来做Android程序的UI….

09年,在开发《华夏风云》游戏的时候,使用了基于Google Gear插件来做了很多离线应用,可惜Gear已经不在更新开发,被HTML5取代。下面介绍基于HTML 5 的Web 应用程序的本地存储,不再废话,例子说明一切。

 

一、离线应用缓存 HTML 5 Offline Application Cache

  • 在服务器上添加MIME TYPE支:text/cache-manifest
  • 如果在Apache下添加:

    AddType text/cache-manifest manifest

    如果为Nginx,在添加:

     text/cache-manifest                   manifest;

    或者通过动态程序生成:

    header('Content-type: text/cache-manifest; charset=UTF-8');
  • 创建 NAME.manifest:
  • 新建清单文件 manifest

    CACHE MANIFEST
    # This is a comment.
    # Cache manifest version 0.0.1
    # If you change the version number in this comment,
    # the cache manifest is no longer byte-for-byte
    # identical.
    
    /app/static/default/js/models/prototype.js
    /app/static/default/js/controllers/init.js
    
    NETWORK:
    # All URLs that start with the following lines
    # are whitelisted.
    
    http://a.com/
    
    CACHE:
    # Additional items to cache.
    /app/static/default/images/main/bg.png
    
    FALLBACK:
    demoimages/ images/
  • 给 <html> 标签加 manifest 属性
  • 建立manifest文件之后,需要在HTML文档中声明:
    声明清单文件 manifest

    
    
    <!doctype html> 
    <html manifest="notebook.manifest"> 
        <head> 
            <meta charset="UTF-8" /> 
    		<meta name = "viewport" content = "width = device-width, user-scalable = no"> 
            <title>NoteBook</title> 
        </head> 
        <body> 
        </body> 
    </html>

二、Key-Value Storage

三、Using the JavaScript Database

四、Android下使用WebView来做基于HTML5的App

见如下AndroidManifest.xml

< ?xml version="1.0" encoding="utf-8"?>

    
        
            
                
                
            
        
    
	

注意:

, 允许网络应用,必须!!

Android主程序代码:

package com.xinze.joke;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;

import android.content.DialogInterface;

import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.webkit.JsPromptResult;
import android.webkit.JsResult;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;

import android.webkit.WebStorage ;

public class Joke extends Activity {

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		final WebView wv = new WebView(this);

		// 覆盖默认后退按钮的作用,替换成WebView里的查看历史页面
		wv.setOnKeyListener(new View.OnKeyListener() {

			@Override
			public boolean onKey(View v, int keyCode, KeyEvent event) {
				if (event.getAction() == KeyEvent.ACTION_DOWN) {
					if ((keyCode == KeyEvent.KEYCODE_BACK) && wv.canGoBack()) {
						wv.goBack();
						return true;
					}
				}
				return false;
			}
		});

		// 设置支持Javascript
		wv.getSettings().setJavaScriptEnabled(true);

		wv.getSettings().setJavaScriptCanOpenWindowsAutomatically(true);
		wv.getSettings().setDatabaseEnabled(true);
		wv.getSettings().setDatabasePath("/data/data/com.xinze.joke/databases"); 

		// 创建WebViewClient对象
		WebViewClient wvc = new WebViewClient() {

			@Override
			public boolean shouldOverrideUrlLoading(WebView view, String url) {
				wv.loadUrl(url);
				// 记得消耗掉这个事件。给不知道的朋友再解释一下,Android中返回True的意思就是到此为止吧,事件就会不会冒泡传递了,我们称之为消耗掉
				return true;
			}
		};

		// 设置WebViewClient对象
		wv.setWebViewClient(wvc);

		// 创建WebViewChromeClient
		WebChromeClient wvcc = new WebChromeClient() {

			// 处理Alert事件
			@Override
			public boolean onJsAlert(WebView view, String url, String message, final JsResult result) {
				// 构建一个Builder来显示网页中的alert对话框
				Builder builder = new Builder(Joke.this);
				builder.setTitle("笑死不偿命");
				builder.setMessage(message);
				builder.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						result.confirm();
					}
				});
				builder.setCancelable(false);
				builder.create();
				builder.show();
				return true;
			}

			// 处理Confirm事件
			@Override
			public boolean onJsConfirm(WebView view, String url, String message, final JsResult result) {
				Builder builder = new Builder(Joke.this);
				builder.setTitle("删除确认");
				builder.setMessage(message);
				builder.setPositiveButton(android.R.string.ok, new AlertDialog.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						result.confirm();
					}

				});
				builder.setNeutralButton(android.R.string.cancel, new AlertDialog.OnClickListener() {

					@Override
					public void onClick(DialogInterface dialog, int which) {
						result.cancel();
					}

				});
				builder.setCancelable(false);
				builder.create();
				builder.show();
				return true;
			}

			// 处理提示事件
			@Override
			public boolean onJsPrompt(WebView view, String url, String message, String defaultValue,
					JsPromptResult result) {
				// 看看默认的效果
				return super.onJsPrompt(view, url, message, defaultValue, result);
			}

			@Override
		       public void onExceededDatabaseQuota(String url, String
		    		   databaseIdentifier, long currentQuota, long estimatedSize, long
		    		   totalUsedQuota, WebStorage.QuotaUpdater quotaUpdater) {
		    		                   quotaUpdater.updateQuota(204801);
		    		               } 

		};

		wv.loadUrl("http://192.168.1.14/index.html");

		// 设置setWebChromeClient对象
		wv.setWebChromeClient(wvcc);
		setContentView(wv);
	}
}

使用 JavaScript Database 的时候,需要特别注意:setDatabaseEnabled 以及 onExceededDatabaseQuota!

Ajax 二进制

javascript如何处理二进制数据?
Ajax 有没有读取二进制流的好办法?

通过ajax与服务器交互过程中,我们大部分传递html,xml,json等文本数据根式,能否以二进制的形式来传递数据? 比如,通过ajax,来处理amf格式的二进制数据?

AS3下面,通过ByteArray来操作二进制数据非常方便,在JS下,可以根据算法,搞一份JS下的ByteArray。
在传输二进制数据的时候,需要注意在不同浏览器下发送不同的头文件信息:

注意要点:

	this.options.overrideMimeType = "text/plain; charset=x-user-defined";
	this.options.overrideHeaders = ["Accept-Charset", "x-user-defined"];

	if (!Prototype.Browser.IE && this.options.overrideMimeType)
	{
		if (this.options.overrideMimeType && this.transport['overrideMimeType'])
		{
			this.transport.overrideMimeType(this.options.overrideMimeType);
		}
		else
		{
			this.transport.setRequestHeader(overrideHeaders[0], overrideHeaders[1]);
		}
	}

通过在各种浏览器下测试,都可以正常运行,哈哈。
这是Ajax 读取二进制流示例:ajax 通过二进制方式传输数据 demo

Page 1 of 1812345...10...Last »