標籤

Web (5) 電腦 (4) 免費小工具 (2) 創意 (2) 雲端 (2) 電影 (2) PHP (1) jQuery (1) 吃的 (1) 好書 (1) 手機 (1) 網路 (1) 自我勉勵 (1)

2008-08-11

吸收知識的態度

我的學歷不好, 可以怪我是太不愛讀書, 也或是說我當時渾然不知為何目的而活.
書沒讀完就休學了, 當時是二專一年級, 好不容易考上的學校就這樣放棄了, 讓家人直跳腳, 讓老師與同學感到訝異.

我依然記得, 那時我離開學校前, 打給高中的級任老師, 她沒多加思索就問我, 我是不是退學了?
我的個性, 真的是被摸透了!

確實的, 我一直都不認為學歷很重要, 但是我必須承認, 學歷是很多評鑑的門檻.
這是就比較而言的, 若是要以學歷相對於知識, 當然是知識為重了, 學歷不過是為了證明知識程度的眾多方法之一.

幾年前, 我初次擔任主管職務, 並初次參與新人招募面試審核工作.
當時我是技術小組的主管, 希望能招募到技術能力尚可, 但是積極度與基本底子夠的人, 並不對學歷設限.
期間面試了五六個人, 其中有兩件面試的內容, 讓我現在依然記得並用來警惕我自己.

那是一位大學生, 履歷表上洋洋灑灑寫滿了程式語言與技術, 態度稱不上是傲慢, 但絕不是謙虛, 當我依照他的履歷一一詢問相關的問題時, 竟然會有如下的對答:
「你會Java嗎?」
「會!」
「可以描述一下你所知道的物件導向的特性嗎?」
支支吾吾....
「可以說一下Java的特性嗎?」
支支吾吾....
「你有寫過Java嗎?」
「沒有!」
「那你為何會說你會Java?」
「我有看過書」
「那應該會有些記憶啊!?」
「我只看過封面」
這位大學生對於「會」的定義很有意思, 我當然立刻停止了面試, 甚至還懷疑我對於「會」的定義是否太嚴苛了?

讓我很喜愛的是另一位專科生, 他會多種的程式語言與技術, 看著他的履歷, 我知道, 那些都不是學校會教的.
我問了他程式語言上的問題, 並且把程式語言交叉組合來問他差異與優劣, 他都能很有想法的回答出來.
他若是能在"必須而為的事"之外, 另行研究與拓展自己的知識, 則將來就算是遇到常規外的問題, 他幾乎都會設法解決的.

我曾經有看過對於"智商"的解釋, "智商" = "心理年齡" / "生理年齡".
也就是說, 若是有一個小女孩的年齡是十歲, 而若是她的判斷力與反應力等的心理年齡表現, 類似於常人的二十歲時, 則她的智商相當於200.
換個說法, 若是剛剛那位小女孩一直成長到四十歲, 而她的心理年齡一直保持在二十歲的話, 則她的智商大約只剩50.

所以, 智商就是心理成長的最佳準則?
我不是專家, 我不會對智商的這件事做評論.
但是卻可以大致上知道, 若是沒有積極的增強自己的心理年齡, 則我會越來越笨.

平常有多少機會可以鍛鍊自己的心理? 並不是每個人都能夠遇上鍛鍊的機會, 何況遇上了也不見得會是好事.
那該如何鍛鍊呢? 我認為, 可以藉由知識的質與量來增進.
大多數的資訊是由他人的經驗所導出的, 不論是否好與壞, 是充實或空泛, 都是可以汲取的.
我無法阻擋資訊的流竄, 但是可以依據經驗選擇我要的資訊, 藉由吸收資訊的經驗累積, 我將可以更容易更快速的取得我要的知識, 以增強我的判斷力與思考速度.

不景氣的時代就是要以充實自己為優先, 投資自己最保值, 因為自己可以掌幄.
但是知識會過時, 過時的知識就沒有高度價值了, 要不斷的補充更新資訊, 尚且能保住不落後的心理年齡.

最後, 我導出了另一個公式:
"心理年齡" := "心理年齡" + "經驗" * "獲取知識"

2008-08-02

Enhance Select 讓網頁更美觀

最近玩 jQuery, 這工具不錯用, 但是在入門方面, jQuery確實需要較多的時間才能熟悉.

jQuery 是由 Google 所做的, 原本的目的是為了方便進行 HTML 文件的節點查詢, 應該算是輔助工具, 是作為快速選擇出節點的一種方法, 後來為了更多的應用需求, 就有了 Plugin 的能力(其實也不是特別去加強什麼Plugin, 而是因為 JavaScript的語法本來就較為鬆散, 所以 jQuery 就把某一種方式的語法規劃為 Plugin的語法).

更多的 jQuery 請看看官方網站(http://docs.jquery.com/Main_Page)囉!

至於 Enhance Select 這東西, 則是我對 IE 的無奈下的產物, 我一向是非常不爽 M$, 他把啥都綁在一起, IE 這麼多年來不見任何長進...

任何, 對! 我說的是任何長進都沒有! 就連我新買的 NB 的 Vista 上的 IE7, 連它都說它自己"還是 IE6"(User-Agent的內容), 所以, Firefox竄起是應該的.

有在寫網頁的都知道, IE的 Select物件是不支援大多數的 Style 的, 若是想改變 IE 的 Select 的框框粗細、大小、顏色, 這些是不可能的!

絕對不是 IE 不支援邊框的 style 喔! Input、TextArea、Table的邊框在 IE 上都被支援, 為何獨獨 Select 沒有, 可以說是 IE 的 Bug!? 不, 應該說是 M$ 懶得改! (所以我痛恨托拉斯, 也痛恨美國司法部的懦弱)

那, 難道為了一個 Select 所以我整個網頁設計都要被迫跟隨嗎?

還好有 jQuery... 我利用 jQuery 自己寫了一個 Enhance Select (jQuery的Plugin), 管它是 IE 還是 FF, 這個程式都會把原有的 Select 物件隱藏起來, 換上另一個較為美觀而且更容易自定 Style 的一個 Select 組件.

(注意! 要先會用 jQuery 喔! 這是 jQuery 的 Plugin!)

使用範例(將該網頁上所有的 Select 換成 Enhance Select):
<script type='text/javascript' src='jquery.enhance_select.0.6.js'></script>
<script type='text/javascript'>
$(document).ready(function(){
$('select').enhanceSelect();
});
</script>


範例圖(這是我開發中的產品的一角):

(那個"系統編碼"就是Enhance Select的效果)

程式碼如下:
/*
* jQuery enhance_select plugin
*
* Copyright (c) 2008 Howard Chen
*
* Licensed under the GPL license:
*   http://www.gnu.org/licenses/gpl.html
*
* Revision: $Id$
* Version: 0.6
*/

;(function($) {

$.fn.extend({
enhanceSelect: function(options)
{
if (parseInt(this.attr('size')) == 0)
return this.each(function(){
new $.enhanceSelectComboBox(this, options);
});
else
return this.each(function(){
new $.enhanceSelectMultiLine(this, options);
});
}
});

$.enhanceSelectComboBox = function(selectobj, options)
{
var mSelect = $(selectobj);

var opt = $.extend({
inputClass: 'enhanceSelect',
listClass: 'enhanceSelectList',
hoverClass: 'hover',
selectedClass: 'selected',
edit: false,
width: mSelect.css('width') == 'auto' ? mSelect.width()+20 : parseInt(mSelect.css('width'))+20
}, options);

var mSelectId = selectobj.id;
var mMove = -1;
var mMouseOver = false;
var mMouseDown = false;
var mFocused = false;
var mList = null;
var mInput = null;
var mInputModified = false;
var mSelectOptions = null;
var mDropDownList = false;
var mSelectedTop = -1;

genList();
genInput();
genOptions();

mSelect.hide().before(mInput).before(mList);
mList.append(mSelectOptions).hide();

mInput
.click(function(){
if (!mDropDownList)
dropDown(true);
else
dropDown(false);
mInput.select();
})
.focus(function(){
updateFocus(true);
})
.keydown(function(event){
switch(event.keyCode)
{
// up
case 38:
var li = $($('li.'+opt.selectedClass, mList).get(0));
if (li.prev('li').size() > 0)
{
li.removeClass(opt.selectedClass);
li.prev('li').addClass(opt.selectedClass);
updateSelect();
mInput.select();
}
return false;
// down
case 40:
var li = $($('li.'+opt.selectedClass, mList).get(0));
if (li.next('li').size() > 0)
{
li.removeClass(opt.selectedClass);
li.next('li').addClass(opt.selectedClass);
updateSelect();
mInput.select();
}
return false;
case 9:
case 13:
return true;
default:
if (!opt.edit)
mInput.select();
return false;

if (event.keyCode >= 32)
{
if (mDropDownList)
dropDown(false);
mInputModified = true;
}
}
})
.blur(function(){
if (!mMouseOver)
{
dropDown(false);
if (mInputModified)
{
updateSelect(mInput.val());
mInputModified = false;
}
else
updateSelect();
updateFocus(false);
}
});

mList
.mouseover(function(event){
mMouseOver = true;
})
.mouseout(function(event){
mMouseOver = false;
})
.dblclick(function(eve){
if (window.getSelection)        window.getSelection().removeAllRanges();
else if(document.selection)     document.selection.empty();
})
.mousemove(function(){
if (window.getSelection)        window.getSelection().removeAllRanges();
else if(document.selection)     document.selection.empty();
})
.click(function(){
dropDown(false);
})
.blur(function(event){
if (!mMouseOver)
{
dropDown(false);
updateSelect();
updateFocus(false);
}
});

function genList()
{
mList = $(document.createElement('div'));
mList
.addClass(opt.listClass)
.attr('id', mSelectId+'_list');
}

function genInput()
{
mInput = $(document.createElement('input'));
mInput
.addClass(opt.inputClass)
.attr({
id: mSelectId+'_input',
type: 'text',
autocomplete: 'off',
tabIndex: mSelect.attr('tabindex')
})
.css({
width: opt.width
});

if (!opt.edit)
mInput.attr('readonly', 'readonly');
}

function genOptions()
{
mSelectOptions = document.createElement('ul');
mSelect.children('option').each(function(){
addOption({
val: $(this).val(),
html: $(this).html(),
selected: $(this).is(':selected')
});
});
}

function addOption(options)
{
var aopt = $.extend({
html: '',
val: '',
selected: false
}, options);

if (aopt.val == '' && options.html)
aopt.val = options.html;
if (aopt.html == '' && options.val)
aopt.html = options.val;

var li = document.createElement('li');
mSelectOptions.appendChild(li);

li = $(li);
li
.attr('id', aopt.val)
.html(aopt.html)
.mouseover(function(event){
$(event.target, mList).addClass(opt.hoverClass);
})
.mouseout(function(event){
$(event.target, mList).removeClass(opt.hoverClass);
})
.click(function(event){
$('li', mList).removeClass(opt.selectedClass);
$(this).addClass(opt.selectedClass);
updateSelect();
dropDown(false);
mInput.select();
});

if (aopt.selected)
{
mInput.val(aopt.html);
$('li', mList).removeClass(opt.selectedClass);
li.addClass(opt.selectedClass);
}

return this;
}

function dropDown(val)
{
if (val === null)
return mDropDownList;
if (val != mDropDownList)
{
if (val === true)
{
updateFocus(true);
var MaxHeight = parseInt(mList.css('max-height'));
MaxHeight = MaxHeight > 0 ? MaxHeight : 200;
if (mList.height() > MaxHeight)
mList.css('height', MaxHeight);
mList.css('width', opt.width+18).show();
mDropDownList = true;
mInputModified = false;
mList.attr('scrollTop', 0);
if ($('li.selected', mList).size() > 0)
mList.attr('scrollTop', $('li.selected', mList).offset().top-$('li', mList).offset().top);
}
else
{
mList.hide();
mDropDownList = false;
}
}
return this;
}

function val(newVal)
{
if (newVal === null)
return mInput.val();
$(mSelectOptions).children('li').removeClass(opt.selectedClass);
$(mSelectOptions).children('li #'.newVal).addClass(opt.selectedClass);
updateSelect();
}

function updateFocus(val)
{
if (val != mFocused)
{
mFocused = val;
if (mFocused)
mInputModified = false;
}
}

function updateSelect(val)
{
if (val != null)
{
var newOption = document.createElement('option');
mSelect.get(0).appendChild(newOption);
newOption.value = val;
newOption.selected = true;
mInput.val(val);
}
else
{
var li = $($('li.'+opt.selectedClass, mList).get(0));
mSelect.val(li.attr('id'));
mInput.val(li.html());
}
mSelect.trigger('change');
}
};

$.enhanceSelectMultiLine = function(selectobj, options)
{
var mSelect = $(selectobj);

var opt = $.extend({
listClass: 'enhanceSelectList',
hoverClass: 'hover',
selectedClass: 'selected',
width: mSelect.css('width') == 'auto' ? mSelect.width()+20 : parseInt(mSelect.css('width'))+20
}, options);

var mSelectId = selectobj.id;
var mFocused = false;
var mList = null;
var mSelectOptions = null;
var mSelectedTop = -1;

genList();
genOptions();

mSelect.hide().before(mList);
mList.append(mSelectOptions);

mList
.dblclick(function(eve){
if (window.getSelection)        window.getSelection().removeAllRanges();
else if(document.selection)     document.selection.empty();
})
.mousemove(function(){
if (window.getSelection)        window.getSelection().removeAllRanges();
else if(document.selection)     document.selection.empty();
})
.focus(function(){
updateFocus(true);
})
.blur(function(event){
updateSelect();
updateFocus(false);
});

function genList()
{
mList = $(document.createElement('div'));
mList
.addClass(opt.listClass)
.attr('id', mSelectId+'_list')
.css({
width: opt.width
});
}

function genOptions()
{
mSelectOptions = document.createElement('ul');
mSelect.children('option').each(function(){
addOption({
val: $(this).val(),
html: $(this).html(),
selected: $(this).is(':selected')
});
});
}

function addOption(options)
{
var aopt = $.extend({
html: '',
val: '',
selected: false
}, options);

if (aopt.val == '' && options.html)
aopt.val = options.html;
if (aopt.html == '' && options.val)
aopt.html = options.val;

var li = document.createElement('li');
mSelectOptions.appendChild(li);

li = $(li);
li
.attr('id', aopt.val)
.html(aopt.html)
.mouseover(function(event){
$(event.target, mList).addClass(opt.hoverClass);
})
.mouseout(function(event){
$(event.target, mList).removeClass(opt.hoverClass);
})
.click(function(event){
$('li', mList).removeClass(opt.selectedClass);
$(this).addClass(opt.selectedClass);
updateSelect();
});

if (aopt.selected)
{
$('li', mList).removeClass(opt.selectedClass);
li.addClass(opt.selectedClass);
}

return this;
}

function val(newVal)
{
if (newVal === null)
return $($('li.'+opt.selectedClass, mList).get(0)).attr('id');
$(mSelectOptions).children('li').removeClass(opt.selectedClass);
$(mSelectOptions).children('li #'.newVal).addClass(opt.selectedClass);
updateSelect();
}

function updateFocus(val)
{
if (val != mFocused)
mFocused = val;
}

function updateSelect(val)
{
if (val != null)
{
var newOption = document.createElement('option');
mSelect.get(0).appendChild(newOption);
newOption.value = val;
newOption.selected = true;
}
else
mSelect.val($($('li.'+opt.selectedClass, mList).get(0)).attr('id'));
mSelect.trigger('change');
}
};

})(jQuery);

換了顆硬碟, 大容量可以讓工作更迅速

自從新的光華商場啟用以來, 我一直都苦無時間也沒有理由去光華商場.

直到最近, 發現到我的工作越來越需要大量的硬碟空間, 加上硬碟的運作速度越來越慢, 總算下定決心, 動手去換顆硬碟.

我主要是用我的Vaio筆電工作的, 家裡還有另外兩台電腦, 一台做伺服器, 一台做測試與玩Game用, 都是輔助工作的角色.

這次要換硬碟的, 當然是以筆電的優先, 也順便多買一顆大的硬碟為測試機加大容量.

我已經很久沒有更新硬體的知識了, 距離我以前的那份電腦裝修工作已經有十年餘了; 該忘的都忘了, 就算記得也早就不能用了, 現在的硬碟幾乎都是 SATA 跟 SATA II 規格, 容量也是飛快的進步, Google上查到的討論區網頁還在說200G容量(2.5")的事, 文章的時間是今年年初, 但是去一些網拍上看, 卻已經是300G了, 連文章都趕不上了.

依照計畫, 到了光華商場, 買了 2.5"320GB 硬碟 跟 3.5"640GB 硬碟, 一顆筆電用, 一顆測試機用, 另外再買了 2G的Mini SD卡供手機用, OK!

640GB 只要 2300, 320GB那顆也只要台幣 2600, 科技的進步還是令人恐懼啊! 去年買手機的 SD卡時, 那時的價格 1G 大約等於 1000元, 現在的 1G 卻只要100多塊, 看來, 明年的主流儲存設備可能會以 TB 為單位了喔!?

依照這樣的趨勢與成熟度, 這個"新容量等級"的時代, 要如何利用它成為商機呢?

我粗略的想, 應該最少有"影像"這一類吧? 例如: DVR、MOD, 或是我自己想像的一種新技術(可能已經有了?), 那就是"雙影像疊合立體成像"技術, 但是不是只像立體電影院那種的喔, 應該是要把 DV 做成雙鏡頭、雙麥克風、頭戴式, 儲存設備配掛於腰部, 可以稱為"生活體驗記錄器", 然後可以隨時將這些影音以 3G 同步至部落格.......

我還真是愛作夢, 好希望夢想能夠實踐!

2008-07-30

瓦力: 當 Wall-E 愛上 Eve

皮克斯真的很厲害, 做出了這樣一部令人感動的動畫片.

我認為, 這部電影的真正要說的是愛的故事, 絕不是有些人或是電影商所述的"拯救人類"; 拯救人類-這種幾近英雄式的主題, 相對於這電影的主旨而言, 不過是一個橋段罷了.

雖然在電影院, 一如以往的迪斯奈-皮克斯電影一樣, 有很多的大人帶著小朋友, 以看待卡通的感覺來看待這部電影, 但是, 我卻覺得, 應該有很多的小朋友對這電影的最終一幕, 甚至是整個電影所想要表達的主軸精神, 很難有所感覺.

最後那一幕, 我落淚了, 可能是因為我曾有過那種相同的信念, 曾為了這信念而努力.

它描述了愛, 為了愛竭盡全力, 那種感覺, 沒有身歷過其境的人很難感受到.

劇情僅有一點點的曲折, 而從頭到尾不過是為了一個機器人的小願望, "Wall-E 想要牽到 Eve 的手", 就這樣, 看似不是多轟轟烈烈, 但是皮克斯卻能把機器人間的愛戀做得如此栩栩如生.

尤其那一幕, Eve 一再喊著 Wall-E 的名字, 在近乎絕望之際, Eve 碰著 Wall-E 的額頭, 那個景象, 讓我想起了好多的"感動".

我太喜歡這部片了, 如果您有過戀愛的體驗, 您可以去看看喔!

Wall-E 官方網站



兩天了, 為了測一個不明原因的錯誤, 差點被搞瘋了.

最近, 為了產品 HowIM 如火如荼的研發與測試, 總是搞到早上才睡.

HowIM 是什麼? 以後再介紹了.

至於那個讓我測了兩天的問題, 就是 eAccelerator 所產生的, 且聽我概略的描述一下.

首先, 這個 HowIM 產品使用了 Apache + PHP + Sqlite3 作為網頁端的程式架構, 並且在 PHP 多加了 eAccelerator 模組, 以作為加速之用.

由於這產品的某些網頁對於資料的讀取速度有著相當高的要求, 故需要一種共用記憶體的功能, 最好是類似於 ASP 的 Application, 用以減少資料庫的存取.

大約在上個月, 我在網上檢索了所有有關的功能選項, 經大量測試後發現, 在 Windows 上 eAccelerator 提供的共用記憶體功能較為穩定, 而且程式還滿好寫的.

在相關的測試完成後, 我開始在這產品大量使用 eAccelerator 的共用記憶體功能, 主要的函數包括: eaccelerator_lock, eaccelerator_unlock, eaccelerator_get, eaccelerator_put.

在此一階段的開發告一段落時, 我用了其他手邊的電腦測一下, 發現了一個重大的問題, 那就是 eAccelerator 有將共用記憶體依照 $_SERVER['SERVER_NAME'] 分類.

怪怪, 我先前的測試自認是很充足的, 這部分也曾測試過無誤才對, 竟然到現在才發現此一問題.

這問題害我多花了四個小時找替代方案, 在所有的替代方案皆失敗時, 我才又回去找原因起頭.

偏偏網路上對於 eAccelerator 的都是"天下文章一大抄", 少有見解與詳細說明的, 而官方的網站卻又是亂七八糟(據說是停站或是eAccelerator停止開發? eAccelerator網址).

再另外花下了數小時的搜尋時間後, 總算想到了方法, 就是回去看看 eAccelerator 的 Source Code.

終於被我找到了(在 eaccelerator.c 與 cache.c), 原來 eAccelerator 在 php.ini 裡可以設置 eaccelerator.name_space, 這個 eaccelerator.name_space 是所有 eAccelerator 鍵值的 name_space.

當 eaccelerator.name_space 沒被設置時, eAccelerator 會把 $_SERVER['SERVER_NAME'] 當作 Name Space.

也就是說, 假定本機的 IP 是 192.168.11.22, 則在本機使用 http://localhost 與 另一台遠端電腦用 http://192.168.11.22 的網址, 同樣查詢本機的 Apache 時, 所使用的鍵值是被隔開的, 就算是同樣存取同一鍵值也會完全不相干.

在改了 php.ini, 加了 eaccelerator.name_space 後, OK了, 鍵值都相同了.

附加說一下, Windows 下的 PHP 還有其他的共用記憶體方案, 如: MMCache, shmop, 這些方案的問題更大, 會導致 Apache 莫名其妙的當掉, 完全不能用.