2015年12月25日 星期五

五種開源授權規範的比較 (BSD, Apache, GPL, LGPL, MIT)

當Adobe、Microsoft、Sun等一系列巨頭開始表現出對"開源"的青睞時,"開源"的時代即將到來!

現今存在的開源協議很多,而經過Open Source Initiative組織通過批准的開源協議目前有58種(http://www.opensource.org/licenses/alphabetical)。我們在常見的開源協議如BSD, GPL, LGPL,MIT等都是OSI批准的協議。如果要開源自己的代碼,最好也是選擇這些被批准的開源協議。

這裡我們來看四種最常用的開源協議及它們的適用範圍,供那些準備開源或者使用開源產品的開發人員/廠家參考。

BSD開源協議(original BSD license、FreeBSD license、Original BSD license)


BSD開源協議是一個給於使用者很大自由的協議。基本上使用者可以"為所欲為",可以自由的使用,修改源代碼,也可以將修改後的代碼作為開源或者專有軟件再發佈。

但"為所欲為"的前提當你發佈使用了BSD協議的代碼,或則以BSD協議代碼為基礎做二次開發自己的產品時,需要滿足三個條件:

如果再發佈的產品中包含源代碼,則在源代碼中必須帶有原來代碼中的BSD協議。
如果再發佈的只是二進制類庫/軟件,則需要在類庫/軟件的文檔和版權聲明中包含原來代碼中的BSD協議。
不可以用開源代碼的作者/機構名字和原來產品的名字做市場推廣。
BSD 代碼鼓勵代碼共享,但需要尊重代碼作者的著作權。BSD由於允許使用者修改和重新發佈代碼,也允許使用或在BSD代碼上開發商業軟件發佈和銷售,因此是對 商業集成很友好的協議。而很多的公司企業在選用開源產品的時候都首選BSD協議,因為可以完全控制這些第三方的代碼,在必要的時候可以修改或者二次開發。

Apache Licence 2.0(Apache License, Version 2.0、Apache License, Version 1.1、Apache License, Version 1.0)


Apache Licence是著名的非盈利開源組織Apache採用的協議。該協議和BSD類似,同樣鼓勵代碼共享和尊重原作者的著作權,同樣允許代碼修改,再發佈(作為開源或商業軟件)。需要滿足的條件也和BSD類似:

需要給代碼的用戶一份Apache Licence
如果你修改了代碼,需要再被修改的文件中說明。
在延伸的代碼中(修改和有源代碼衍生的代碼中)需要帶有原來代碼中的協議,商標,專利聲明和其他原來作者規定需要包含的說明。
如果再發佈的產品中包含一個Notice文件,則在Notice文件中需要帶有Apache Licence。你可以在Notice中增加自己的許可,但不可以表現為對Apache Licence構成更改。
Apache Licence也是對商業應用友好的許可。使用者也可以在需要的時候修改代碼來滿足需要並作為開源或商業產品發佈/銷售。

GPL(GNU General Public License)


我們很熟悉的Linux就是採用了GPL。GPL協議和BSD, Apache Licence等鼓勵代碼重用的許可很不一樣。GPL的出發點是代碼的開源/免費使用和引用/修改/衍生代碼的開源/免費使用,但不允許修改後和衍生的代 碼做為閉源的商業軟件發佈和銷售。這也就是為什麼我們能用免費的各種linux,包括商業公司的linux和linux上各種各樣的由個人,組織,以及商 業軟件公司開發的免費軟件了。

GPL協議的主要內容是只要在一個軟件中使用("使用"指類庫引用,修改後的代碼或者衍生代碼)GPL 協議的產品,則該軟件產品必須也採用GPL協議,既必須也是開源和免費。這就是所謂的"傳染性"。GPL協議的產品作為一個單獨的產品使用沒有任何問題, 還可以享受免費的優勢。

由於GPL嚴格要求使用了GPL類庫的軟件產品必須使用GPL協議,對於使用GPL協議的開源代碼,商業軟件或者對代碼有保密要求的部門就不適合集成/採用作為類庫和二次開發的基礎。

其它細節如再發佈的時候需要伴隨GPL協議等和BSD/Apache等類似。

LGPL(GNU Lesser General Public License)


LGPL是GPL的一個為主要為類庫使用設計的開源協議。和GPL要求任何使用/修改/衍生之GPL類庫的的軟件必須採用GPL協議不同。LGPL允許商 業軟件通過類庫引用(link)方式使用LGPL類庫而不需要開源商業軟件的代碼。這使得採用LGPL協議的開源代碼可以被商業軟件作為類庫引用並發布和 銷售。

但是如果修改LGPL協議的代碼或者衍生,則所有修改的代碼,涉及修改部分的額外代碼和衍生的代碼都必須採用LGPL協議。因此LGPL協議的開源代碼很 適合作為第三方類庫被商業軟件引用,但不適合希望以LGPL協議代碼為基礎,通過修改和衍生的方式做二次開發的商業軟件採用。

GPL/LGPL都保障原作者的知識產權,避免有人利用開源代碼複製並開發類似的產品

MIT(MIT)


MIT是和BSD一樣寬範的許可協議,作者只想保留版權,而無任何其他了限制.也就是說,你必須在你的發行版裡包含原許可協議的聲明,無論你是以二進制發佈的還是以源代碼發佈的.

reference : http://inspiregate.com/internet/trends/74-comparison-of-five-kinds-of-standard-open-source-license-bsd-apache-gpl-lgpl-mit.html

2015年12月10日 星期四

Placeholders.js

Placeholders.js is a JavaScript polyfill for the HTML5 placeholder attribute. It's lightweight, has zero dependencies and works in pretty much any browser you can imagine.


reference : http://jamesallardice.github.io/Placeholders.js/

2015年12月9日 星期三

Trick to use static variables in javascript

Maybe people that have background in C language know how to do this because in C language there is a static keyword to declare a static variable. What is about Javascript?

Well, Javascript doesn't have static keyword. One way to solve this problem, you may use global variable. However, for some people, it will pollute the global namespace. Last night, I read a javascript book, Javascript - The Definitive Guide, 5th edition. The author used closure to achieve this by returning back the anonymous function.


var uniqueID = (function() {
   var id = 0; // This is the private persistent value
   // The outer function returns a nested function that has access
   // to the persistent value.  It is this nested function we're storing
   // in the variable uniqueID above.
   return function() { return id++; };  // Return and increment
})(); // Invoke the outer function after defining it.



uniqueID(); // 0

uniqueID(); // 1
uniqueID(); // 2

reference : http://chamnapchhorn.blogspot.tw/2008/07/trick-to-use-static-variables-in.html

2015年12月7日 星期一

PHPUnit - Serialization of Closure is not allowed

The answer to your literal question "Why does PHPUnit interfere with setting HTTP headers in this code?" is given fairly clearly in the answer to Test PHP headers with PHPunit. PHP's header() will fail with the Cannot modify header information warning if anything has been written to stdout. When running your code via PHPUnit, content has been sent to stdout long before your code under test has been reached.
You noted a separate issue when using the @runInSeparateProcess annotation to fork a clean PHP process for your test:
Unexpected non-MediaWiki exception encountered, of type "Exception", exception 'Exception' with message 'Serialization of 'Closure' is not allowed' in /usr/share/pear/PHPUnit/Util/GlobalState.php:354
By default PHPUnit attempts to backup all of the $GLOBALS data before each test and restore it afterwards. MediaWikiTestCase turns this behavior off but it looks like your extension's tests are not. It seems likely that the configuration for your extension includes a closure and is causing the serialization failure. Adding a @backupGlobals disabled annotation to your PHPUnit_Framework_TestCase class should get you past this problem.

reference : http://stackoverflow.com/questions/20076467/why-does-phpunit-interfere-with-setting-http-headers-in-this-code

2015年12月1日 星期二

Mockery: returning values and throwing exceptions

Last week, I had to wrote a piece of code that contains retry logic. Naturally, I want to test it. That proved trickier than expected.
The application code looks like this:
    class Sender
    {
        protected $connection;

        public function send()
        {
            $success = false;

            $i = 0;
            do {
                $i++;

                try {
                    $success = $this->doSend($i);
                } catch (SenderException $e) {
                    $success = false;
                }

            } while (!$success && $i < 3);

            return $success;
        }

        protected function doSend($data)
        {
            // Can throw SenderException
            $response = $this->connection->send($data);

            if ('OK' === $response) {
                return true;
            }

            return false;
        }
    }

I specifically want to test the retry logic, so I have to mock the ::doSend() method. Then I can simulate the different outcomes (returning true or false, or throwing a SenderException).
I use Mockery to do the real work. It is a great library. If you don't know it yet, please check it out. I will wait right here...
Now, since ::doSend() is a protected method, Mockery must be instructed to allow that.
So after the first try, I ended up with:
    public function testItWillRetrySending()
    {
        $sender = M::mock('Sender');
        $sender->shouldAllowMockingProtectedMethods()

        $sender->shouldReceive('doSend')
            ->andReturn(false, new Exception());
    }

To my surprise, this did not work. Instead of throwing the exception, Mockery returns it. So my next try was this:
    $sender->shouldReceive('doSend')
        ->andReturn(false)
        ->andThrow(new Exception());
Another surprise: with this code, Mockery will always throw the exception, and ignore the first return value (false). After some debugging, I found out that Mockery just overwrites the return values in this case.
Fortunately, there is another way to return multiple return values: the ::andReturnUsing() method. It gives full control over the return values.
So I ended up with this testing code:
    $return_value_generator = function () {
        static $counter = 0;

        $counter++;

        switch ($counter) {
            case 1: return false;
            case 2: throw new SenderException();
            case 3: return true;
            default: throw new Exception("Should never reach this."); 
        }
    };

    $sender = M::mock('Sender');

    $sender->shouldAllowMockingProtectedMethods()
        ->shouldReceive('doSend')
        ->andReturnUsing($return_value_generator);

This works perfectly. It feels a bit like a hack though. So if you know a better way or have any other remarks, please let me know.

refer : https://jacobkiers.net/post/multiple-return-values-with-mockery

wibiya widget