非官方百度云 Go 语言 SDK baidubce-sdk-go

baidubce-sdk-go 是非官方百度云API的Go语言SDK。目前提供了BOS(百度云对象存储)Go SDK。简化了API调用。

安装

go get github.com/guoyao/baidubce-sdk-go/...

范例

import (
    "log"

    "github.com/guoyao/baidubce-sdk-go/bce"
    "github.com/guoyao/baidubce-sdk-go/bos"
    "github.com/guoyao/baidubce-sdk-go/util"
)

var credentials = bce.NewCredentials("AK", "SK")
var bceConfig = bce.NewConfig(credentials)
var bosConfig = bos.NewConfig(bceConfig)
var bosClient = bos.NewClient(bosConfig)

func CreateBucket() {
    bucketName := "baidubce-sdk-go"
	err := bosClient.CreateBucket(bucketName, nil)

	if err != nil {
		log.Println(err)
	} else {
		err := bosClient.DeleteBucket(bucketName, nil)

		if err != nil {
			log.Println(err)
		}
	}
}

项目地址:https://github.com/guoyao/baidubce-sdk-go

Posted in Go. Tags: . 没有评论 »

一步一步实现一个Javascript模板引擎(三)

前两篇文章介绍了js模板引擎的基本原理,同时给出了核心代码,本文列出重构后的代码,当没提供数据的时候,返回一个渲染函数,具体如下:

/**
 * 模板引擎
 * @name    myTemplate
 * @param   {String}  模板字符串
 * @param   {Object}  数据
 * @return  {String, Function}  渲染好的HTML字符串或者渲染方法
 */
var myTemplate = function template() {
    'use strict';
    
    var args = Array.prototype.slice.call(arguments),
        tmpl = args.shift().replace(/\r|\n/g, "").replace(/"/g, '\\"'), //转义"号
        funcBody = 'var result = "";',
        func;

    funcBody += ' result += "' + tmpl + '";'; 
    funcBody = funcBody.replace(/<%=\s*([^>]*)\s*%>/g, function(match, $1) {
        return '" + ' + $1.replace(/\\"/g, '"') + ' + "'; //替换的同时,恢复<%=%>中被转义的"号
    });
    funcBody = funcBody.replace(/<%\s*([^>]*)\s*%>/g, function(match, $1) {
        return '";' + $1.replace(/\\"/g, '"') + 'result += "'; //替换的同时,恢复<%=%>中被转义的"号
    });

    funcBody += " return result;";

    func = new Function(funcBody);
    if (args.length > 0) {
        return func.apply(args.shift(), args); //返回渲染好的HTML字符串
    }
    
    return function() { //返回渲染方法
        args = Array.prototype.slice.call(arguments);
        return func.apply(args.shift(), args);
    }
};

myTemplate.version = '0.1.0';

该项目已经开源在Github上了,感兴趣的童鞋可以去查看源码及相关文档和demo。

项目名称:myTemplate
项目地址:https://github.com/guoyao/myTemplate

Posted in Web前端开发. Tags: , . 没有评论 »

一步一步实现一个Javascript模板引擎(二)

上一篇文章实现了一个简单的js模板引擎,但当时我们只是考虑了模板中的输出,没考虑模板中的js逻辑,下面我们来处理模板中的js逻辑问题。我们来处理一个复杂的模板,模板代码如下:

<script type="text/tmpl" id="template">
    <p><strong>Name:</strong> <%= this.name %></p>
    <p><strong>Age:</strong> <%= this.age %></p>
    <% if (this.gender) { %>
        <p><strong>Gender:</strong> <%= this.gender %></p>
    <% } %>
    <% if (this.children) { %>
        <p><strong>Children:</strong></p>
        <% for (var i = 0, len = this.children.length, child; i < len; i++) { 
            child = this.children[i]; 
        %>
            <ul style="background-color: #f5f5f5;">
                <li><strong>Name:</strong> <%= child.name %></li>
                <li><strong>Age:</strong> <%= child.age %></li>
                <% if (child.gender == "female") { %>
                    <li><strong>Gender:</strong> <%= child.gender %></li>
                <% } %>
            </ul>
        <% } %>
    <% } %>
</script>

以上模板中包含了较多的js逻辑代码,看起来很复杂,不好解析,其实不然,原理还是一样的,使用正则表达式替换,功能增强后的模板引擎代码如下:

var guiTemplate = (function () {
    function template(tmpl, data) {
        var funcBody = 'var result = "";',
            func;

        tmpl = tmpl.replace(/\r|\n/g, "").replace(/"/g, '\\"'); //转义"号
        funcBody += ' result += "' + tmpl + '";'; 
        funcBody = funcBody.replace(/<%=\s*([^>]*)\s*%>/g, function(match, $1) {
            return '" + ' + $1.replace(/\\"/g, '"') + ' + "'; //替换的同时,恢复<%=%>中被转义的"号
        });
        funcBody = funcBody.replace(/<%\s*([^>]*)\s*%>/g, function(match, $1) {
            return '";' + $1.replace(/\\"/g, '"') + 'result += "'; //替换的同时,恢复<%=%>中被转义的"号
        });

        funcBody += " return result;";

        func = new Function(funcBody);
        return func.call(data);
    }
    return {
      template: template
    };
})();

调用代码如下:

var template = document.getElementById("template").innerHTML,
    html = guiTemplate.template(template, {
        name: 'guoyao',
        age: 26,
        gender: 'male',
        children: [
            {
                name: 'child 1',
                age: 5,
                gender: 'female'
            },
            {
                name: 'child 2',
                age: 3,
                gender: 'male'
            }
        ]
    });

生成的html如下:

<p><strong>Name:</strong> guoyao</p>        
<p><strong>Age:</strong> 26</p>                    
<p><strong>Gender:</strong> male</p>                            
<p><strong>Children:</strong></p>                            
<ul style="background-color: #f5f5f5;">                    
    <li><strong>Name:</strong> child 1</li>                    
    <li><strong>Age:</strong> 5</li>                                            
    <li><strong>Gender:</strong> female</li>                                    
</ul>                            
<ul style="background-color: #f5f5f5;">                    
    <li><strong>Name:</strong> child 2</li>                    
    <li><strong>Age:</strong> 3</li>                                    
</ul>

本文我们基本上实现了一个比较完整的js模板引擎,当然跟目前流行的开源模板引擎比较起来,我们的还不够完善,有空的时候我会继续完善它,不久将开源在Gitbub上,有兴趣的可以关注一下。

Posted in Web前端开发. Tags: , . 没有评论 »

一步一步实现一个Javascript模板引擎(一)

目前Web前端越来越复杂,Javascript MVC / MVVM思想也开始流行起来。Javascript模板引擎作为数据与界面分离工作中最重要一环,越来越受开发者关注。那么什么是模板引擎?简单点说,模板引擎的功能就是将一个字符串中的待定变量用js对象的对应属性来替换。目前流行的js模板引擎有:Mustache、Underscore、doT、Handlebars、Juicer等。其实要自己实现一个模板引擎并不太困难,其原理都大同小异。接下来就跟着我一步一步来实现一个js模板引擎。

示例模板字符串如下:

<p>Name: <%= this.name %></p>
<p>Age: <%= this.age %></p>

模板引擎处理后的字符串如下:

<p>Name: Guoyao</p>
<p>Age: 27</p>

模板引擎代码如下:

var guiTemplate = (function () {
    function template(tmpl, data) {
        var funcBody = 'var result = "";',
            func;

        tmpl = tmpl.replace(/\r|\n/g, "").replace(/"/g, '\\"'); //转义"号
        funcBody += ' result += "' + tmpl + '";'; 
        funcBody = funcBody.replace(/<%=\s*([^>]*)\s*%>/g, function(match, $1) {
            return '" + ' + $1.replace(/\\"/g, '"') + ' + "'; //替换的同时,恢复<%=%>中被转义的"号
        });

        funcBody += " return result;";

        func = new Function(funcBody);
        return func.call(data);
    }
    return {
      template: template
    };
})();

调用代码如下:

var tmpl = '<p>Name: <%= this.name %></p><p>Age: <%= this.age %></p>';
guiTemplate.template(tmpl, {name: 'Guoyao', age: 27});

至此,我们只是考虑了模板中的输出,没考虑模板中的js逻辑,下一步我们来处理模板中的js逻辑问题。

Posted in Web前端开发. Tags: , . 没有评论 »

js双向数据绑定的简单实现

双向数据绑定是指在UI上绑定数据对象的某个属性,当该对象的此属性发生变化时,所有绑定了该对象此属性的UI元素同时更新;同理,当绑定了对象属性的UI更新时(如用户输入),数据对象同时被更新,同时其它绑定了此属性的UI也同样被更新。许多流行的JS MVC框架例如Ember.js,AngularJS以及KnockoutJS都实现了双向数据绑定。总的来说,实现双向绑定的基本思想是一样的:

1、哪些UI元素绑定了对象的哪个属性
2、监听对象属性的变化,变化后通知到所有绑定了该对象属性的UI元素
3、监听UI元素的变化,变化后通知对象,更新对象对应属性和其它所有绑定了同样属性的UI元素

<!DOCTYPE html>
<html>
<head>
    <title>Two Way Binding</title>
</head>
<body>
    <input type="text" data-bind="user.name"/>
    <input type="text" data-bind="user.name"/>
    <input type="text" data-bind="user.name"/>
    <input type="text" data-bind="user.name"/>
    <input type="text" data-bind="user.name"/>
    <textarea data-bind="user.name"></textarea>
    <input id="changeModelPropertyButton" type="button" value="Change Model Property"/>
    <script src="js/two-way-binding.js"></script>
</body>
</html>

js/two-way-binding.js

(function () {

    var _ = {
            toArray: function (value) {
                return Array.prototype.slice.call(value);
            },
            isFunction: function (value) {
                return Object.prototype.toString.call(value) === "[object Function]";
            },
            extend: function (destination, source) {
                for (var property in source) {
                    destination[property] = source[property];
                }
                return destination;
            }
        },
        Class = (function () { //类工厂
            var tempFunc = function () {},
                emptyInitializeFunc = function () {};

            function Class() {
                var superclass = null,
                    properties = _.toArray(arguments);

                if (_.isFunction(properties[0])) {
                    superclass = properties.shift();
                }

                function klass() {
                    this.initialize.apply(this, arguments);
                }

                if (superclass) {
                    tempFunc.prototype = superclass.prototype;
                    klass.prototype = new tempFunc();
                    klass.superclass = superclass.prototype;
                }

                for (var i = 0, length = properties.length; i < length; i++) {
                    _.extend(klass.prototype, properties[i]);
                }

                if (!klass.prototype.initialize) {
                    klass.prototype.initialize = emptyInitializeFunc;
                }

                klass.prototype.constructor = klass;

                return klass;
            }

            return Class;
        })(),
        EventUtil = {
            on: function (element, type, handler) {
                if (document.addEventListener) {
                    element.addEventListener(type, handler, false);
                } else if (document.attachEvent) {
                    element.attachEvent("on" + type, handler);
                } else {
                    element["on" + type] = handler;
                }
            },
            getEvent: function (e) {
                return e || window.event;
            },
            getTarget: function (e) {
                var event = this.getEvent(e);
                return event.target || event.srcElement;
            }
        },
        DataBinder = function (objectId) {
            var binder = {
                    callbacks: {},
                    subscribe: function (message, callback) {
                        this.callbacks[message] || (this.callbacks[message] = []);
                        this.callbacks[message].push(callback);
                    },
                    publish: function (message) {
                        this.callbacks[message] || (this.callbacks[message] = []);
                        for (var i = 0, len = this.callbacks[message].length; i < len; i++) {
                            this.callbacks[message][i].apply(this, arguments);
                        }
                    }
                },
                message = objectId + ":change";

            EventUtil.on(document, "input", function (e) {
                var target = EventUtil.getTarget(e),
                    bindInfo = target.getAttribute("data-bind");
                if (bindInfo.indexOf(objectId) !== -1) {
                    binder.publish(message, bindInfo.split(".")[1], target.value);
                }
            });

            binder.subscribe(message, function (message, prop, value) {
                var elements = document.querySelectorAll("[data-bind='" + objectId + "." + prop + "']"),
                    i, element, tagName;
                for (i = 0; element = elements[i]; i++) {
                    tagName = element.tagName.toLowerCase();
                    if (tagName === "input" || tagName === "textarea") {
                        element.value = value;
                    } else {
                        element.innerHTML = value;
                    }
                }
            });

            return binder;
        },
        Bindable = new Class({ //所有可绑定对象的基类
            initialize: function (objectId) {
                this._objectId = objectId;
                this._attributes = {};
                this._binder = new DataBinder(objectId);
            },
            set: function (prop, value) {
                this._attributes[prop] = value;
                this._binder.publish(this._objectId + ":change", prop, value);
            },
            get: function (prop) {
                return this._attributes[prop];
            }
        }),
        User = new Class(Bindable),
        user = new User("user");

    user.set("name", "hello world");

    EventUtil.on(document.getElementById("changeModelPropertyButton"), "click", function () {
        user.set("name", "hello " + Math.round(Math.random() * 100));
    });

})();

升级Ubuntu 12.04下的gcc & g++到4.8

Ubuntu12.04默认的是使用gcc4.6,而只有gcc4.7以上才支持C++11,使用如下办法升级Ubuntu 12.04下的gcc :

更新Ubuntu源
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
sudo apt-get update
sudo apt-get install gcc-4.8
sudo apt-get install g++-4.8

升级完成使用gcc –version 显示版本依然是4.6.3,需要改变gcc软链接文件,来把4.8版设置为默认:
cd /usr/bin
sudo ln -sf gcc-4.8 gcc
sudo ln -sf g++-4.8 g++

Posted in Linux. 一条评论 »

修改导出模板解决PhysicsEditor选择CitrusEngine导出的问题

前一篇文章提到如何修改导出后的文件来解决PhysicsEditor选择CitrusEngine导出的问题,这样每次导出后都要修改,其实还有一个一劳永逸的方法,就是修改PhysicsEditor的CitrusEngine模板,具体方法如下:
找到PhysicsEditor的安装路径,进入其bin\exporters\citrus-engine目录下,用你最喜欢的文本编辑器(推荐Sublime)打开citrusengine.as文件,将Box2DAS.Collision.Shapes.b2PolygonShape替换成Box2D.Collision.Shapes.b2PolygonShape,将Box2DAS.Common.V2替换成Box2D.Common.Math.b2Vec2,将com.citrusengine.objects.PhysicsObject替换成citrus.objects.Box2DPhysicsObject,最后再将文件中所有用到V2这个类的地方全部替换成b2Vec2。

PhysicsEditor选择CitrusEngine导出的问题

PhysicsEditor(1.0.10)中选择以Citrus Engine导出的类不能在Citrus Engine中直接使用,可能是PhysicsEditor是根据老版本的Citrus Engine导出的,导出的类结构如下:

import Box2DAS.Collision.Shapes.b2PolygonShape;
import Box2DAS.Common.V2;

import com.citrusengine.objects.PhysicsObject;

/**
* @author Aymeric
* <p>This is a class created by the software http://www.physicseditor.de/</p>
* <p>Just select the CitrusEngine template, upload your png picture, set polygons and export.</p>
* <p>Be careful, the registration point is topLeft !</p>
* @param peObject : the name of the png file
*/
public class PhysicsEditorObjects extends PhysicsObject  {
    ...
}

而Box2DAS.Collision.Shapes.b2PolygonShape、Box2DAS.Common.V2和com.citrusengine.objects.PhysicsObject类在Citrus Engine中并不存在,编译当然出错,其实只需要将Box2DAS.Collision.Shapes.b2PolygonShape替换成Box2D.Collision.Shapes.b2PolygonShape,将Box2DAS.Common.V2替换成Box2D.Common.Math.b2Vec2,将com.citrusengine.objects.PhysicsObject替换成citrus.objects.Box2DPhysicsObject,就可以在Citrus Engine中使用了。

Android中利用ViewStub实现Tab中TabContent的延迟加载

应用程序对各项资源的消耗(CPU, Memory, Battery and so on)是开发过程中一个非常重要的考虑因素,尤其是移动开发,这将直接决定应用程序运行的流畅与否。面对有限的资源,开发过程中必须合理利用。延迟加载可以在一定程度是缓解应用程序对资源(主要是内存)的消耗,提高其启动速度,尤其当应用程序比较大的时候,延迟加载的作用就更大了。依本人的了解,简单的说,延迟加载就是不必在程序初始化的时候就去加载所需的所有资源,而是将对资源的加载时间延迟到当程序真正需要该资源的时候。

Android中我们可以利用ViewStub来实现layout资源的延迟加载,至于ViewStub是什么,请参考Android Reference。一个很常见的情况就是在实现Tab布局时,我们可以让每个Tab页面对layout资源的加载延迟到用户点击该Tab时,这样显然节省了程序启动时对资源的消耗,加快其启动速度。具体的做法(当然不是唯一的),可以让Activity实现TabContentFactory接口,实现接口中定义的方法createTabContent,在该方法中构造所需的View,该方法只在每个Tab第一次显示时才调用,再次显示该Tab就不会再次调用。有一点需要注意,createTabContent是在Tab页面内容没有完全创建前调用的,因此在createTabContent里面是不能调用getCurrentTabView等之类的函数的。关键代码如下:

public View createTabContent(String tag) {
    ViewStub viewStub = null;
    if(tag.equals("tab1")) {
        viewStub = (ViewStub)findViewById(R.id.tab1);
        //必须显示调用setLayoutResource方法,即使你在layout资源定义的xml文件中已经设置了ViewStub的layout属性,否则运行时会报错,这一点本人也一直没明白原因。
        viewStub.setLayoutResource(R.layout.tab1);
    }
    return viewStub.inflate();
}
Posted in Android. Tags: . 6条评论 »

用AIR实现断点续传

上篇文章讲到了用AIR实现一个简单的的下载工具,但如今的下载工具基本上都支持断点续传,本文就用AIR来实现断点续传。其实也并不是很难,还是用代码说话吧。关键代码如下:

public static function resumeBrokenTransfer(url:String, file:File, downloadedCallback:Function = null):void 
		{
			var request:URLRequest = new URLRequest(url);
			var urlLoader:URLLoader = new URLLoader();
			urlLoader.addEventListener(IOErrorEvent.IO_ERROR, function (event:IOErrorEvent):void {
				if(downloadedCallback != null)
					downloadedCallback();
			});
			urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (event:SecurityErrorEvent):void {
				if(downloadedCallback != null)
					downloadedCallback();
			});
			urlLoader.addEventListener(ProgressEvent.PROGRESS, function (event:ProgressEvent):void {
				var bytesTotal:int = urlLoader.bytesTotal;
				urlLoader.close();
				var startPoint:int = getBytesAvailableOfFile(file);
				if(startPoint < bytesTotal)
				{
					var headerItem:URLRequestHeader = new URLRequestHeader("Range", "bytes=" + startPoint + "-" + bytesTotal);
					request.requestHeaders.push(headerItem);
					urlLoader = new URLLoader();
					urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
					urlLoader.addEventListener(IOErrorEvent.IO_ERROR, function (event:IOErrorEvent):void {
						if(downloadedCallback != null)
							downloadedCallback();
					});
					urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, function (event:SecurityErrorEvent):void {
						if(downloadedCallback != null)
							downloadedCallback();
					});
					urlLoader.addEventListener(Event.COMPLETE, function (event:Event):void {
						var bytes:ByteArray = urlLoader.data as ByteArray;
						var fs:FileStream = new FileStream();
						fs.openAsync(file, FileMode.UPDATE);
						fs.position = startPoint;
						fs.writeBytes(bytes, 0, bytes.length);
						fs.addEventListener(Event.COMPLETE, function (event:Event):void {
							fs.close();
						});
						fs.addEventListener(IOErrorEvent.IO_ERROR, function (event:IOErrorEvent):void {
							fs.close();
						});
						if(downloadedCallback != null)
							downloadedCallback();
					});
					urlLoader.load(request);
				}
				else
				{
					if(downloadedCallback != null)
						downloadedCallback();	
				}
			});
			urlLoader.load(request);
		}

参数说明请参考上一篇文章~

Posted in AIR. Tags: . 没有评论 »