2023-01-02

哇10年沒寫文章了!

這10年來,我先是開了公司,然後結婚,到了德國工作,回台灣生下長子,之後前往美國南加州唸博士班,在那裡生了第二個孩子。之後開了第二家公司,回台灣開了第三家公司。在回饋母校彰化高中清華大學後,又開了第四五家公司。

現在我到美國繼續唸未完的博士班,可能以後就待在這裡長住了。往後的人生,又會發生什麼奇妙的事呢?

2012-01-09

如何在 Windows 底下添加系統服務(system service)

以下程式碼呼叫方法:

註冊服務
ruby name.rb reg

註銷服務
ruby name.rb del

服務執行之程式碼位於 service_main 區塊內

require 'rubygems'
require 'win32/service'
require 'win32/daemon'
include Win32

SERVICE_NAME = "RubyService"
SERVICE_DISPLAY_NAME = "A Ruby Service by vegafish"

if ( ARGV[ 0 ] == "reg" )
    Service.create({
        :service_name     => SERVICE_NAME,
        :service_type     => Service::WIN32_OWN_PROCESS,
        :description      => 'A custom service I wrote just for fun',
        :start_type       => Service::AUTO_START,
        :error_control    => Service::ERROR_NORMAL,
        :binary_path_name => 'c:\\ruby187\bin\ruby.exe ' + File.expand_path($0),
        :load_order_group => 'Network',
        :dependencies     => ['W32Time','Schedule'],
        :display_name     => SERVICE_DISPLAY_NAME
   })

    puts( "Service " + SERVICE_DISPLAY_NAME + " Registered." )
    Service.start( SERVICE_NAME )
    exit( 0 )
elsif ( ARGV[ 0 ] == "del" )
    if Service.status( SERVICE_NAME ).current_state == "running"
        Service.stop( SERVICE_NAME )
    end
    Service.delete( SERVICE_NAME )
    puts( "Service " + SERVICE_DISPLAY_NAME + " Removed." )
    exit( 0 )
end

class Daemon
    def service_init
        sleep( 5 )
    end
    
    def service_main
        filecount = 0
        watchfile = "c:\\vegafish.txt"
        while( running?() )
            sleep( 3 )
            if ( File.exists?( watchfile ) )
                filecount++
                File.rename( watchfile, watchfile + filecount.to_s )
            end
        end
    end
end

Daemon.mainloop()

2012-01-08

The Bug of Google Picasa Public URL

If you upload pictures via mobile Google+, your Picasa public URL will be changed* automatically.

This bug is not fixed at 2012-01-08.

* Changed from Gmail account to Google+ account number, e.g. http://picasaweb.google.com/vegafish -> http://picasaweb.google.com/117166741167778447153

2011-10-03

以 Java 實作 Base 64 Encoder

或許有人會覺得奇怪,Java 本身已經有支援 Base 64 Encoder 了,為什麼還要自己重新寫一個? 事實上,Java 平台的 Base64Encoder 需要 import sun.misc.BASE64Encoder,然而這個類別卻不是在所有平台上面都可以正常執行(我個人的經驗是,在 android 執行時會當機)。 以下為 Base 64 Encoder 實作程式碼,歡迎各位朋友切磋學習。
private static String base64_encode( byte[] bytes ) {
        String[] base64 = { "A", "B", "C", "D", "E", "F", "G", "H",
                            "I", "J", "K", "L", "M", "N", "O", "P",
                            "Q", "R", "S", "T", "U", "V", "W", "X",
                            "Y", "Z", "a", "b", "c", "d", "e", "f",
                            "g", "h", "i", "j", "k", "l", "m", "n",
                            "o", "p", "q", "r", "s", "t", "u", "v",
                            "w", "x", "y", "z", "0", "1", "2", "3",
                            "4", "5", "6", "7", "8", "9", "+", "/" };
        String encoded = "";

        int pad_length = 0;
        if ( bytes.length % 3 == 1 )
            pad_length = 2;
        else if ( bytes.length % 3 == 2 )
            pad_length = 1;
        
        byte[] padded = new byte[ bytes.length + pad_length ];

        for( int i = 0; i < bytes.length; ++i ) {
            padded[ i ] = bytes[ i ];
        }
        if ( pad_length == 1 ) {
            padded[ padded.length - 1 ] = 0;
        } else if ( pad_length == 2 ) {
            padded[ padded.length - 1 ] = 0;
            padded[ padded.length - 2 ] = 0;
        }
        
        for( int i = 0; i < padded.length; i += 3 ) {
            encoded += base64[ ( ( padded[ i ] & 255 ) >>> 2 ) ];
            encoded += base64[ ( ( ( padded[ i ] & 3 ) << 4 ) | ( ( padded[ i + 1 ] & 255 ) >>> 4 )  ) ];
            encoded += base64[ ( ( ( padded[ i + 1 ] & 15 ) << 2 ) | ( ( padded[ i + 2 ] & 255 ) >>> 6 )  ) ];
            encoded += base64[ ( padded[ i + 2 ] & 63 ) ];
        }
        
        encoded = encoded.substring( 0, encoded.length() - pad_length );
        
        if ( pad_length == 1 ) {
            encoded += "=";
        } else if ( pad_length == 2 ) {
            encoded += "==";
        }

        return encoded;
    }

2011-09-02

再玩一下 AES 加密解密

上次在這篇「玩了一下AES加密解密」裡面寫的程式碼有些缺點,就是加密過後的結果是 byte[] 而不是 String,對於 Java 的操作上不是很方便。看了幾位高手的博文,自己做了些改良,同時也將程式碼放上來拋磚引玉。主要的改良是透過 BASE64Encoder 和 BASE64Decoder 將 byte[] 轉為可讀的英文字母 + 數字字串,這在網址的傳遞上也有好處,不需要變成%xx%xx的 UTF-8 形式,更容易偵錯與閱讀,也不減少其安全性。
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

import sun.misc.BASE64Encoder;
import sun.misc.BASE64Decoder; 

public class Base64AES {

    public static String decrypt( String key, String text ) throws Exception {
        byte [] results = decrypt( key.getBytes(), new BASE64Decoder().decodeBuffer( text ) );
        return new String( results );
    }

    public static String encrypt( String key, String text ) throws Exception {
        byte[] results = encrypt( key.getBytes(), text.getBytes() );
        return new BASE64Encoder().encode( results );
    } 
    
    public static byte[] encrypt( byte[] key, byte[] msg ) throws Exception {
        if ( key.length != 16 ) {
            throw new IllegalArgumentException( "Key length should be 16." );
        }
        SecretKeySpec spec = new SecretKeySpec( key, "AES" );
        IvParameterSpec ivSpec = new IvParameterSpec( key );
        Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" );
        cipher.init( Cipher.ENCRYPT_MODE, spec, ivSpec );
        return cipher.doFinal( msg );
    }
    
    public static byte[] decrypt( byte[] key, byte[] msg ) throws Exception {
        if ( key.length != 16 ) {
            throw new IllegalArgumentException( "Key length should be 16." );
        }
        SecretKeySpec spec = new SecretKeySpec( key, "AES" );
        Cipher cipher = Cipher.getInstance( "AES/CBC/PKCS5Padding" );
        IvParameterSpec ivSpec = new IvParameterSpec( key );
        cipher.init( Cipher.DECRYPT_MODE, spec, ivSpec );
        return cipher.doFinal( msg );
    }
    
    public static void main( String[] args ) throws Exception {
        String msg = "This is so easy.";
        
        System.out.println( "原字串: " + msg );
        System.out.println( "加密後: " + encrypt( "vegafish12345678" , msg ) );
        System.out.println( "解密後: " + decrypt( "vegafish12345678", encrypt( "vegafish12345678" , msg ) ) );
    }

}
執行結果如下:
原字串: This is so easy.
加密後: KczRl5uSsrgfwWRKpfR5FoKEIVU0jPvxX1VsEYl/jl0=
解密後: This is so easy.