2015年12月31日 星期四

如何在 GAE 上佈署 jQuery EasyUI 專案 (二) : CDN 資源

今天是 2015 年的最後一天了, 以往都是必休假已休完, 只得乖乖上班到年尾; 今年則是該怎麼請休假拿捏不定, 乾脆年底一起請, 變成連休五天, 真是爽 (同事說這樣社會觀感不好 ...).

早上在家看以前寫的 GAE 程式, 已經很久沒摸 Python 了有點生疏 (我是為了要用 GAE 服務才接觸 Python 的), 不過複習一下馬上就能恢復戰力. 參考去年十月底寫的這篇 :

# 如何在 GAE 佈署 jQuery EasyUI 專案

當時我的作法是採用自備框架資源的方式, 也就是自行下載 jQuery 與 EasyUI 檔案到 GAE 的專案目錄下, 但由於 GAE 對於免費帳戶有檔案數目限制, 而 EasyUI 又包含了一堆 UI 排版的圖檔與樣式檔, 上傳到 GAE 後就佔硬碟空間; 比較理想的方式是採用 CDN 供檔方式, 反正 GAE 專案本來就是要佈署到 Internet 上才有意義的. 因此我把 jqueryeasyui.htm 修改為 jqueryeasyui_1.htm 如下 :

{% extends "html5.htm" %}
{% block link %}
  <link rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/default/easyui.css">
  <link rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/icon.css">
{% endblock %}
{% block javascript %}
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/jquery.min.js"></script>
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/locale/easyui-lang-zh_TW.js"></script>
{% endblock %}

關於 Template 用法可參考這篇 :

# Google App Engine 初學(8) – 共用 Template (Layout)

然後就可以寫一個 easyui_1.htm 來測試 Datagrid 了 :

{% extends "jqueryeasyui_1.htm" %}
{% block body %}
  <table class="easyui-datagrid" title="台股" style="width:600px;height:230px"
    data-options="singleSelect:true,collapsible:true,rownumbers:true">
    <thead>
      <tr>
        <th data-options="field:'name',width:80">股票名稱</th>
        <th data-options="field:'id',width:80">股票代號</th>
        <th data-options="field:'close',width:100,align:'right'">收盤價 (元)</th>
        <th data-options="field:'volumn',width:100,align:'right'">成交量 (張)</th>
        <th data-options="field:'meeting',align:'left'">股東會日期</th>
        <th data-options="field:'election',width:80,align:'center'">董監改選</th>
        <th data-options="field:'category',width:60,align:'center'">類股</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>台積電</td>
        <td>2330</td>
        <td>123</td>
        <td>4425119</td>
        <td>2014-06-04</td>
        <td>0</td>
        <td>半導體</td>
      </tr>
      <tr>
        <td>中華電</td>
        <td>2412</td>
        <td>96.4</td>
        <td>5249</td>
        <td>2014-06-15</td>
        <td>0</td>
        <td>通信</td>
      </tr>
      <tr>
        <td>中碳</td>
        <td>1723</td>
        <td>192.5</td>
        <td>918</td>
        <td>2014-07-05</td>
        <td>0</td>
        <td>塑化</td>
      </tr>
      <tr>
        <td>創見</td>
        <td>2451</td>
        <td>108</td>
        <td>733</td>
        <td>2014-06-30</td>
        <td>0</td>
        <td>模組</td>
      </tr>
      <tr>
        <td>華擎</td>
        <td>3515</td>
        <td>118.5</td>
        <td>175</td>
        <td>2014-07-20</td>
        <td>0</td>
        <td>主機板</td>
      </tr>
      <tr>
        <td>訊連</td>
        <td>5203</td>
        <td>97</td>
        <td>235</td>
        <td>2014-05-31</td>
        <td>0</td>
        <td>軟體</td>
      </tr>
    </tbody>
  </table>
{% endblock %}

但是為了符合 MTV 設計要求, 我在專案目錄下面建了一個 templates 目錄, 把上面的 htm 模板 (Template) 檔案通通放到 templates 下, 這樣檔案結構比較不會凌亂, 如下圖所示 :


所以路由分派程式 main.py 中的 url 必須加上 templates 路徑 :

# -*- coding: utf-8 -*-
import os
from google.appengine.ext.webapp import template
import webapp2

class easyui_1(webapp2.RequestHandler):
    def get(self):
        url="templates/easyui_1.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

class MainHandler(webapp2.RequestHandler):
    def get(self):
        url="templates/default.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/easyui_1', easyui_1)
], debug=True)

這裡 templates 下還有一個 default.htm 是做為程式目錄列表的, 當存取網站根目錄 (即上面的 "/") 時, 會執行 MainHandler 類別, 抓取 templates 下的 default.htm 來渲染 (輸出). 其內容暫時如下, 當程式增加時就增加 li 項目即可 :

{% extends "jqueryeasyui_1.htm" %}
{% block style %}
  body {font: 80% "Trebuchet MS", sans-serif; margin: 50px;}
{% endblock%}
{% block body %}
<b><p>EasyUI on GAE</p></b>
<ol>
  <li>
    <a href="easyui_1" target="_blank">easyui_1</a>
    (Datagrid : 顯示股價資訊)
  </li>
</ol>
{% endblock%}

這樣就大功告成了, 在 SDK 上執行 OK, 結果與之前第一篇文章一樣. 上傳到 GAE 時顯示不超過十個檔案, 使用 CDN 的好處就是可以節省硬碟容量, 檔案結構也很清爽.

 接下來我想測試 EasyUI 主題布景的切換, 直覺是用一個下拉式選單來選取主題, 然後提交時傳一個參數給 GAE, 用來置換樣式表路徑中預設的 default 主題:

<link rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/default/easyui.css">

這可以用 template 引擎來傳送參數, 在上面 main.py 程式中呼叫 render 方法時, 所傳入的第二參數為一個空串列 template.render(path,{}), 那是因為我們沒有變數要傳給模板檔案的緣故; 我們可以用 self.request.get() 方法擷取網頁中下拉式選單傳來的主題布景參數, 然後透過此串列變數傳給模板.

我把 jqueryeasyui_1.htm 模板加入變數 theme, 改成 jqueryeasyui_2.htm 如下

{% extends "html5.htm" %}
{% block link %}
  <link rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/{{theme}}/easyui.css">
  <link rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/icon.css">
{% endblock %}
{% block javascript %}
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/jquery.min.js"></script>
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/locale/easyui-lang-zh_TW.js"></script>
{% endblock %}

注意這裡樣式表路徑中, 用兩個大括弧括起來的 theme 就是從 main.py 程式傳來的模板變數, 而 main.py 則是從 url 處理中從前端網頁取得我們傳送之樣式參數. 而前端網頁則繼承 jqueryeasyui_2.htm, 加入 Combobox 選單, 改為 easyui_2.htm 如下 :

{% extends "jqueryeasyui_2.htm" %}
{% block body %}
  <form id="theme_form" method="get"  action="/easyui_2">
    <select id="theme_sel" name="theme" class="easyui-combobox" panelHeight="auto">
      <option value="default">主題布景</option>
      <option value="gray">gray</option>
      <option value="black">black</option>
      <option value="bootstrap">bootstrap</option>
      <option value="metro">metro</option>
      <option value="metro-blue">metro-blue</option>
      <option value="metro-gray">metro-gray</option>
      <option value="metro-green">metro-green</option>
      <option value="metro-orange">metro-orange</option>
      <option value="metro-red">metro-red</option>
      <option value="ui-cupertino">ui-cupertino</option>
      <option value="ui-dark-hive">ui-dark-hive</option>
      <option value="ui-pepper-grinder">ui-pepper-grinder</option>
      <option value="ui-sunny">ui-sunny</option>
    </select><br>
  </form><br>
  <table class="easyui-datagrid" title="台股" style="width:600px;height:230px"
    data-options="singleSelect:true,collapsible:true,rownumbers:true">
    <thead>
      <tr>
        <th data-options="field:'name',width:80">股票名稱</th>
        <th data-options="field:'id',width:80">股票代號</th>
        <th data-options="field:'close',width:100,align:'right'">收盤價 (元)</th>
        <th data-options="field:'volumn',width:100,align:'right'">成交量 (張)</th>
        <th data-options="field:'meeting',align:'left'">股東會日期</th>
        <th data-options="field:'election',width:80,align:'center'">董監改選</th>
        <th data-options="field:'category',width:60,align:'center'">類股</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>台積電</td>
        <td>2330</td>
        <td>123</td>
        <td>4425119</td>
        <td>2014-06-04</td>
        <td>0</td>
        <td>半導體</td>
      </tr>
      <tr>
        <td>中華電</td>
        <td>2412</td>
        <td>96.4</td>
        <td>5249</td>
        <td>2014-06-15</td>
        <td>0</td>
        <td>通信</td>
      </tr>
      <tr>
        <td>中碳</td>
        <td>1723</td>
        <td>192.5</td>
        <td>918</td>
        <td>2014-07-05</td>
        <td>0</td>
        <td>塑化</td>
      </tr>
      <tr>
        <td>創見</td>
        <td>2451</td>
        <td>108</td>
        <td>733</td>
        <td>2014-06-30</td>
        <td>0</td>
        <td>模組</td>
      </tr>
      <tr>
        <td>華擎</td>
        <td>3515</td>
        <td>118.5</td>
        <td>175</td>
        <td>2014-07-20</td>
        <td>0</td>
        <td>主機板</td>
      </tr>
      <tr>
        <td>訊連</td>
        <td>5203</td>
        <td>97</td>
        <td>235</td>
        <td>2014-05-31</td>
        <td>0</td>
        <td>軟體</td>
      </tr>
    </tbody>
  </table>
  <script>
    $(document).ready(function(){
      $("#theme_sel").combobox({
        onSelect:function(rec){
          $("#theme_form").submit();
          }
        });
      });
  </script>
{% endblock %}

這裡下拉式選單列舉了 EasyUI 的各種主題, 注意 select 元素須給予 name 屬性, 當有選取動作時呼叫 submit() 方法將表單傳送給自己 (/easyui_2). 其次, 為了簡單起見, 表單用 get 方法提交, 因為若使用 post, 則 main.py 裡面也要有處理 post 的方法 (否則會出現 405 Method Not Allowed : The method POST is not allowed for this resource. 錯誤). 以下是修改路徑處理之 main.py :

# -*- coding: utf-8 -*-
import os
from google.appengine.ext.webapp import template
import webapp2

class easyui_1(webapp2.RequestHandler):
    def get(self):
        url="templates/easyui_1.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

class easyui_2(webapp2.RequestHandler):
    def get(self):
        theme=self.request.get('theme',default_value='default')
        url="templates/easyui_2.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{'theme':theme})
        self.response.out.write(content)

class MainHandler(webapp2.RequestHandler):
    def get(self):
        url="templates/default.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/easyui_1', easyui_1),
    ('/easyui_2', easyui_2)
], debug=True)

此處我們用 self.request.get() 取得前端傳來的 theme 參數 (第一次存取網頁時不會傳參數, 因此用 default_value 設置預設為 default), 然後在呼叫 render() 渲染網頁時, 將此 theme 變數傳給 easyui_2.htm 模板, 從而代換了 jqueryeasyui_2.htm 中的決定主題布景之樣式表路徑.

不過實際操作會發現, 這種每次選取就提交表單的做法不好, 因為這樣會重新載入頁面, 導致前端會短暫看到 UI 尚未套用前的原始面貌. 理想上應該不須重載頁面, 直接利用 jQuery 去操作 DOM 裡的 link 元素即可, 因此我修改模板, 在 link 元素中加入 id 屬性方便 jQuery 操作, 同時恢復預設之 default 主題, 改為如下的 jqueryeasyui_3.htm 模板 :

{% extends "html5.htm" %}
{% block link %}
  <link  id="theme" rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/default/easyui.css">
  <link rel="stylesheet" href="http://www.jeasyui.com/easyui/themes/icon.css">
{% endblock %}
{% block javascript %}
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/jquery.min.js"></script>
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/jquery.easyui.min.js"></script>
  <script type="text/javascript" src="http://www.jeasyui.com/easyui/locale/easyui-lang-zh_TW.js"></script>
{% endblock %}

然後寫一個 easyui_3.htm 繼承此模板如下 :

{% extends "jqueryeasyui_3.htm" %}
{% block body %}
  <form id="theme_form">
    <select id="theme_sel" name="theme" class="easyui-combobox" panelHeight="auto">
      <option value="default">主題布景</option>
      <option value="gray">gray</option>
      <option value="black">black</option>
      <option value="bootstrap">bootstrap</option>
      <option value="metro">metro</option>
      <option value="metro-blue">metro-blue</option>
      <option value="metro-gray">metro-gray</option>
      <option value="metro-green">metro-green</option>
      <option value="metro-orange">metro-orange</option>
      <option value="metro-red">metro-red</option>
      <option value="ui-cupertino">ui-cupertino</option>
      <option value="ui-dark-hive">ui-dark-hive</option>
      <option value="ui-pepper-grinder">ui-pepper-grinder</option>
      <option value="ui-sunny">ui-sunny</option>
    </select><br>
  </form><br>
  <table class="easyui-datagrid" title="台股" style="width:600px;height:230px"
    data-options="singleSelect:true,collapsible:true,rownumbers:true">
    <thead>
      <tr>
        <th data-options="field:'name',width:80">股票名稱</th>
        <th data-options="field:'id',width:80">股票代號</th>
        <th data-options="field:'close',width:100,align:'right'">收盤價 (元)</th>
        <th data-options="field:'volumn',width:100,align:'right'">成交量 (張)</th>
        <th data-options="field:'meeting',align:'left'">股東會日期</th>
        <th data-options="field:'election',width:80,align:'center'">董監改選</th>
        <th data-options="field:'category',width:60,align:'center'">類股</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>台積電</td>
        <td>2330</td>
        <td>123</td>
        <td>4425119</td>
        <td>2014-06-04</td>
        <td>0</td>
        <td>半導體</td>
      </tr>
      <tr>
        <td>中華電</td>
        <td>2412</td>
        <td>96.4</td>
        <td>5249</td>
        <td>2014-06-15</td>
        <td>0</td>
        <td>通信</td>
      </tr>
      <tr>
        <td>中碳</td>
        <td>1723</td>
        <td>192.5</td>
        <td>918</td>
        <td>2014-07-05</td>
        <td>0</td>
        <td>塑化</td>
      </tr>
      <tr>
        <td>創見</td>
        <td>2451</td>
        <td>108</td>
        <td>733</td>
        <td>2014-06-30</td>
        <td>0</td>
        <td>模組</td>
      </tr>
      <tr>
        <td>華擎</td>
        <td>3515</td>
        <td>118.5</td>
        <td>175</td>
        <td>2014-07-20</td>
        <td>0</td>
        <td>主機板</td>
      </tr>
      <tr>
        <td>訊連</td>
        <td>5203</td>
        <td>97</td>
        <td>235</td>
        <td>2014-05-31</td>
        <td>0</td>
        <td>軟體</td>
      </tr>
    </tbody>
  </table>
  <script>
    $(document).ready(function(){
      $("#theme_sel").combobox({
        onSelect:function(rec){
          var css="http://www.jeasyui.com/easyui/themes/" + rec.value + "/easyui.css";
          $("#theme").attr("href", css);
          }
        });
      });
  </script>
{% endblock %}

這裡重點是在 onSelect() 方法中, 透過傳回值的 value 屬性取得所選取之值, 然後重組主題樣式的路徑, 再用 jQuery 的 attr() 方法將 href 屬性更換掉. 當然控制程式 main.py 也要添加 easyui_3 的路徑處理器, 但其實只要複製 easyui_1 的過來改即可, 如下所示 :

# -*- coding: utf-8 -*-
import os
from google.appengine.ext.webapp import template
import webapp2

class easyui_1(webapp2.RequestHandler):
    def get(self):
        url="templates/easyui_1.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

class easyui_2(webapp2.RequestHandler):
    def get(self):
        theme=self.request.get('theme',default_value='default')
        url="templates/easyui_2.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{'theme':theme})
        self.response.out.write(content)

class easyui_3(webapp2.RequestHandler):
    def get(self):
        url="templates/easyui_3.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

class MainHandler(webapp2.RequestHandler):
    def get(self):
        url="templates/default.htm"
        path=os.path.join(os.path.dirname(__file__), url)
        content=template.render(path,{})
        self.response.out.write(content)

app = webapp2.WSGIApplication([
    ('/', MainHandler),
    ('/easyui_1', easyui_1),
    ('/easyui_2', easyui_2),
    ('/easyui_3', easyui_3)
], debug=True)

這個做法比較好, 切換主題時完全不會閃動, 可說是無縫變換, 只有在第一次載入頁面時可能會看到尚未化妝完畢的原始頁面. 後續的測試將以此作法所使用的模板 jqueryeasyui_3.htm 為標準, 故複製一份為 jqueryeasyui.htm 做後續繼承之用.


以上網頁可以在下列網址看到實際效果 :

http://jqueryeasyui.appspot.com/

OK, 今天先做到這邊, 今天是休假耶, 我卻寫了一整天的程式. 昨晚睡覺前菁菁問我說, 今天我休假可不可以先煮菜, 放學後回來洗完澡吃完趕去補習班. 所以我三點半就開始準備, 趁四點菁菁回來前煮了一小鍋豬肉丼, 她吃第一口就說讚讚讚, 這就是讓我愛上烹飪的原因啦.

以上範例程式碼可在下列網址下載 :

下載原始碼


2015年12月30日 星期三

驗車

本年特休還有一天七個小時, 明天得請整天, 剩下的七小時畸零假該怎麼處理呢? 今天多請一小時併成一天也是可以, 只是還有一點公事要處理, 所以早上就去辦公室待了一個小時, 匆匆做完就下班; 也因此今天沒有背背包上班, 只帶一個手提袋去公司, 感覺無比輕鬆.

早上九點下班前發現手錶又進水了, 兩個月前花一千元大修以來已經第二次, 下班就直接拿去寶島修 (一年保固). 騎到那邊才發現他們十點才開門, 只好到文化中心圖書館逛, 但也沒找到啥好書. 修完錶回到家, 再開車去驗車, 代驗廠說下次是明年六月, 原來我這台大灰熊 (Serena) 已經是十歲的老車啦! 變成每半年就得驗一次.

驗完車順路去家樂福, 主要是要買三層櫃, 用來收納鄉下電視汰舊換新後, 原本放在電視上方平台上的物品, 剛好有特價.

今天突然想到很久沒玩 GAE 了, 連到 GAE 管理畫面才知道, Google 已經重新整合雲端服務, 把 GAE 納入 Google Cloud Platform 平台裡面, 新用戶開始要收費了 (有 300 美元試用金), 而且介面跟以前 GAE 不一樣了. 所幸舊用戶還是可以繼續免費使用, 但新開專案就要加入試用方案, 真後悔當初沒把專案都開滿 (跟當初 appfog 一樣, 若那時多申請幾個帳戶多好). 整個下午在研究以前寫的將 EasyUI 佈署於 GAE 的方法. 一陣子沒摸就生疏了, 還好有認真寫部落格筆記, 要不然幾乎得從頭來一遍, 那就累了.


2015年12月28日 星期一

第 52 周記事

已經來到本年度最後一周, 還有三天假沒休, 所以週五 (12/25) 就請了一天假, 本來是想要好好整理冰箱和大掃除的, 但看到跟總圖借的 "從相對論到上帝粒子" 已經一個月了還沒看完, 就拿來看, 越看越有興趣, 花了一整天終於解決了.

週六則是整天花在整理冰箱與廚房. 既然冰箱不換新了, 那就好好清一下, 不清還好, 一清才發現裡面塞了這麼多東西, 而且多數是過期的, 最扯的是一瓶 2009 年的福菜, 那年同學邀我去苗栗聯合大學幫他的學生上課, 講解 Praat 語音分析與大量語音資料處理自動化的方法, 要回來時送給我一盒禮物, 這瓶精美包裝的苗栗特產福菜即為其一. 因為塞在冰箱不起眼的內側, 沒想到一放就是 6 年. 過期當然只能丟掉, 真是可惜, 也是罪過, 每次因為自己的該注意卻沒注意導致必須曝畛天物時, 我都感到非常自責 (所以雖然我咒罵頂新, 但卻對秒買秒退不能苟同). 

此外廚房流理台底下也是一堆雜物, 全部毫不留情丟掉, 只有一瓶母親以前給我的一瓶蘿蔔乾, 應該也是放太久過期了, 但我捨不得丟. 清理工作還沒完, 本周還有兩天假要請, 反正過年也快到了, 就提前作大掃除吧, 因為過年前要把時間花在鄉下的大掃除.

週五晚上接到阿興電話, 說他升格當爸爸了. 我本來想下周請休假時去台中看看, 但他說打算滿月後帶來高雄給爸看, 順便去註生娘娘那裏還願. 阿興剛結婚時不想生, 但想生時卻一直不能如願. 去年他們南下參加母親的告別式後, 回台中前我帶他們去山下的註生娘娘那裏祈福, 果真今年就懷胎了. 新手爸爸要學的可多了.

本周因姐姐要補畫室的課, 還是只有我跟菁菁回鄉下. 週日將兩月前所種 20 株玉米剩餘部分全部摘掉, 約 26 支玉米, 若加計上周收成, 將近 40 支, 以市場價一支 10 元算, 價值 400 元, 本錢包括苗 20 元, 肥料不超過 50 元, 還是很划算的. 更何況是任其生長, 全然不施農藥的 (農藥很貴哩), 比較放心. 週日再買 20 株來種, 其中十株為白玉米, 但因為沒有分開兩處來種, 到時混色是難免的, 那就當作生物實驗好了.

週六下午新購的電視就寄來了, 剛好趕得上帶回鄉下安裝. 吃過晚飯後就把那台已經兩光的舊電視換下來, 簡單裝機後送電, 竟然沒訊號! 原來是我把第四台電纜接在 "Air" (數位電視天線) 孔, 難怪掃不到. 但改至 Cable 後還是掃不到! 只好打 0800 問 SHARP, 原來是要設 ATV (第四台還是類比的). 這台 32 吋的 LED 電視寬度剛好跟底下的收納櫃同寬, 實在非常速配, 只是原來放在舊電視上面的任天堂遊戲機與 DVD 播放器沒地方擺, 打算最近去家樂福買兩個置物櫃來放. 這台新電視看來還不錯, 有兩組 HDMI 與 USB 端子, 剛好適合連接 Raspberry Pi 或 PcDuino 來當作顯示器用.


2015年12月25日 星期五

好書 : 從相對論到上帝粒子

這本書是上回參加 Nissan 愛手作活動後, 順路去市圖總館首度參訪時借的, 內容是介紹 1901~2013 年歷屆的諾貝爾物理學獎得主之生平與主要貢獻. 隨手翻閱時剛好看到 2010 年物理學獎頒給發現石墨烯的兩位英國曼徹斯特大學俄裔學者, 因為不久前才剛聽同事談到石墨烯技術, 所以便借回來看.

# 從相對論到上帝粒子

Source : 博客來

以下摘要我比較感興趣的物理學家與其事蹟.

比較早期的諾貝爾物理學得獎者中, 具有劃時代意義的是原子模型三個粒子 (電子, 質子, 與中子) 的發現者, 因為他們的貢獻開啟了人類一窺微觀世界奧秘之門, 依發現之先後順序列表如下 :

 粒子 發現年 發現者 國籍 諾貝爾獎
 電子 1897 年 約翰湯姆森 英國  1906 年物理學獎
 質子 1919 年 拉塞福 紐西蘭 1908 年化學獎
 中子 1935 年 查德威克 英國  1935 年物理學獎

這三位得獎人其實都出自英國卡文狄許實驗室 (即劍橋大學物理系實驗室), 三人一脈相承是師生關係, 湯姆森與拉塞福師徒兩人還長期擔任實驗室主任. 此實驗室自 1871 年由馬克斯威爾創立以來的 144 年間, 目前為止總共產生了 29 位諾貝爾獎得主, 平均每五年就有一位, 真是成果豐碩產量驚人. 其中化學獎 6 位, 生醫學獎 3 位, 物理學獎 20 位, 對於上個世紀的物理學成就功不可沒.

電子的發現者約翰湯姆森 (John Thomson) 是卡文狄許實驗室的第三任主任, 他在利用陰極射線管進行氣體導電的實驗中發現, 陰極射線是由一種帶負電的粒子組成, 他將之取名為電子. 由於比原子小很多 (是第一個被發現的次原子粒子), 此發現推翻了之前原子是最小粒子的假說. 除了陰極射線的研究外, 湯姆森在陽極 (離子) 射線方面的實驗則發現了同位素, 並催生了質譜儀的發明. 這些成就使其獲頒 1906 年物理學獎. 

電子的發現開啟了往後一連串的物理大發現. 1905 年愛因斯坦以光電效應揭開光的波粒二元性, 這給了法國理論物理學家德布羅意 (Louis de Broglie) 非常大的啟發, 他在 1923 發表的論文中就把光的波粒二元性推展到任何物質均具有波動性質 (稱為物質波), 認為不只是光, 任何運動粒子也會產生波動, 並依此預測當電子束穿過小孔時也會如同光波那樣出現繞射現象. 愛因斯坦得知後非常高興, 而德布羅意也因為愛因斯坦的推介而聲名大噪.

德布羅意的推論在 1927 年被約翰湯姆森的兒子喬治湯姆森 (George P. Thomson) 以晶體的電子繞射實驗證實了, 使得德布羅意於 1929 年因為發現電子的波動性而獲得物理學獎. 喬治湯姆森的實驗給後來的量子力學理論提供了堅實的實證基礎, 因此他也獲頒 1937 年物理學獎. 約翰湯姆森與喬治湯姆森是目前為止諾貝爾物理學獎唯一的父子檔. 父親證明電子是一個粒子, 而兒子則證明電子是一種波動, 電子的波粒二元性都在他們父子倆手中被發現與證實, 真是個傳奇. 附帶一提, 既然物質也含有波的性質, 那為何我們日常經驗中感受不到呢? 德布羅意在他的博士論文中提出此物質波的公式, 其波長與質量成反比. 生活中所見物質之質量太大, 其波長極小, 因此感受不到物體的波動現象, 要在像電子那樣的次原子微觀世界中才會顯現.

質子的發現者拉塞福被稱為是核子物理學之父, 他因為發現放射性物質會衰變成另外一種物質, 並放射出 α 粒子與 β 粒子 (其實除此之外還有後來萊因斯在 1956 年才發現的中微子) 而獲頒 1908 年的諾貝爾化學獎, 據說拉塞福對此不太高興, 因為他認為自己是物理學家而非化學家, 應該頒給他物理學獎才對. 這本書是針對物理學獎, 因此沒有列入拉塞福, 但是在湯姆森與查德威克兩章中有提及拉塞福的貢獻.

拉塞福的名言 : "科學只有物理一個學科, 其他不過相當於集郵活動而已", 言下之意, 物理學是科學中的科學, 其他的學問不過是建築在其上的衍生物而已. 以前在教科書上讀到拉塞福的名字時, 並沒有留下甚麼印象; 但現在讀到這句話, 拉塞福在我的腦海中將與馬克斯威爾以及愛因斯坦等偉人並立. 我對科學的定義相當狹隘 (嚴謹), 但是比拉塞福的稍寬, 即物理學加上其描述語言-數學而已. 我認為, 能經過重複實驗而得到相同結果的學問才能稱為科學. 社會科學應該稱為社會人文學才對, 如果社會學也稱得上是科學, 那麼不同媒體同時做的總統候選人支持率應該結果一致啊!

# 拉塞福的黃金火花
# 拉塞福 (Ernest Rutherford)和原子核的發現

中子其實源自拉塞福在 1920 年一次演講中, 為了解釋原子量與原子序差距而提出的一個假說, 認為原子核中應該存在一個電中性的粒子 (他原先假想是質子與電子的結合). 而發現中子的查德威克是拉塞福的學生, 他是在老師的理論指導下, 經多次實驗才終於在 1932 年成功捕捉到中子. 中子的發現使人類找到釋放核能之門的鑰匙 (開啟潘朵拉之盒?), 因為用中子來轟擊鈾原子核, 可以引起核分裂的連鎖反應. 

這三種粒子的發現開啟了往後幾十年高能粒子物理學的高速發展, 實驗物理學家陸陸續續發現了更多次原子粒子, 不斷地證實或否定了理論物理學家的預測與猜想. 例如電子在之後的粒子物理學的標準模型中, 與渺子 (muon), 中微子 (neutrino) 以及濤子 (tauon) 一起被歸類為輕子 (lepton, 不參與強交互作用的粒子), 而且是所有輕子中質量最輕的 (事實上輕子這名詞取得不好, 因為輕子中的濤子不但不輕, 還非常重, 是質子的 2 倍重, 是電子的 3500 倍重). 1995 年的物理學獎就是頒給發現濤子的史丹福大學教授佩爾 (Martin Perl, 丁肇中的老師) 以及首次以實驗捕獲中微子的加州大學教授萊因斯.

2013 年物理學獎頒給英國愛丁堡大學的希格斯教授與比利時理論物理學家恩格勒, 以表彰他們在粒子物理學中建構標準模型的貢獻, 因為就在前一年 (2012), 歐洲核子研究組織 (CERN) 以大型強子對撞機 (LHC) 實驗捕捉到所謂的上帝粒子-希格斯坡色子, 驗證了希格斯與恩格勒等人於 1964 年所提出的希格斯場希格斯機制理論. 此理論認為有一個遍布全宇宙的希格斯場, 而希格斯玻色子是希格斯場的振動. 所以找到上帝的粒子就間接證明了希格斯場的存在.

希格斯坡色子是標準模型所預測的 61 種基本粒子中最後被找到的粒子. 其特徵是 : 電中性, 自旋為 0, 與極不穩定 (生成後立刻衰變). 在量子力學中, 基本粒子被分成兩種 : 自旋為整數的坡色子 (波函數對稱) 與自旋為半整數的費米子 (波函數反對稱), 分別遵守兩種不同的統計規律 (坡色-愛因斯坦統計費米-狄拉克統計). 費米子是組成物質的要素, 例如電子與原子核內的質子與中子都屬於費米子, 我們所見的物質世界都是由費米子構成的; 而坡色子是傳遞作用力的, 例如光子 (電磁力), 膠子 (強作用力), 以及尚未被發現的重力子都是坡色子. 物質會結合為一團是靠坡色子傳遞的作用力將費米子黏在一起, 例如質子是由兩個上夸克與一個下夸克組成; 而中子是由一個上夸克與兩個下夸克組成, 就是靠膠子在夸克之間傳遞強作用力, 將它們黏在一起; 而原子核中帶正電的各個質子, 也是靠膠子傳遞強作用力, 才能抵抗質子之間的電磁力, 將它們束縛在原子核內.

今天休假一天在家, 終於把這本書大致看完, 可以拿去還了. 要搞懂物理學真不容易, 這些物理學家真是神人. 研究物理好比是王陽明的格物致知, 從窮究萬物之理來反看我們的心, 或許能打破物質與心靈的藩籬, 將物與心融合在一起. 我在想, 這遍佈宇宙的希格斯場該不會就是所謂的佛法無邊吧! 坡色子會不會就是業力呢? 費米子與希格斯場交互作用取得質量, 這是萬法惟心造嗎? 或許有一天量子物理學家能貫通這一切, 用數學語言來闡釋佛法也說不定.


改買新電視機

上週五在公司福利社網站下訂購買 Panasonic 有 Econavi 節電功能的新冰箱後, 終於把即將到期的 8000 元福利金用掉, 總價 22690 元, 本周一匯款自付 14690 元, 如果節能補助 2000 元下來, 相當於只花了 12690 就買到 485 公升的冰箱, 很划算.

但是晚上回到家準備清理冰箱, 突然覺得這台已經運轉超過 19 年的三洋冰箱還很好用, 冰凍效果依舊, 只是門封有一段鬆鬆的, 但也不會漏氣. 新冰箱一來, 它就必須報廢, 淪為丟在回收廠一角等待被支解的命運, 霎時觸動了我悲天憫人胸懷, 本來好好地能用的冰箱, 你忍心讓它變成一堆廢鐵嗎?

越想越不對勁, 我幹嘛換冰箱啊! 就為了花掉 8000 元的福利金? 為了 2000 元的節能補助? 就算省了 10000 元, 但還是花了 14690 不是嗎? 再把近兩年電費單拿出來看, 非夏季平均每月電費約 500 元上下, 夏季有用冷氣約 1000~1500 左右. 這 500 元裡估計洗衣機用掉100 元, 冰箱 200 元, 其餘為電腦, 吹風機, 以及電燈電視等. 換成變頻節能冰箱的話, 或許每月可省下 100 元, 一年節省 1200 元, 這樣換冰箱實際支出的 12690 元要十年後才能回本! 更何況現今的製造商已經覺醒了, 電器設備已經不像以前大同電扇那樣用 40 年都不會壞, 搞不好保固期剛過就壞了. 新冰箱能像這台三洋堪操 20 年以上嗎?

之前會想要換冰箱是因為辦公室的老冰箱壞了一陣子, 同事建議我把家裡的冰箱換新領結能補助, 然後這台汰換下來搬到公司繼續用, 我想反正每天都還會用到它, 又不是要報廢, 就答應了. 哪知買下去後, 上司改變心意, 決定要大家攤 300 元買台小一點新冰箱, 導致我的這台三洋沒地方去, 必須報廢變成垃圾, 讓我覺得它好可憐, 思考有必要現在換冰箱嗎?

趕緊上網詢問福利社是否還可以退訂改買別的, 還好來得及, 所以今天就線上退貨了. 但要改買甚麼好呢? 兩個月前有在考慮掃地機器人, 福利社有賣一款 LG 稍舊型產品 VR6430LV, 只要 9900 元,  特力屋與 Yahoo 還要 14000 以上, 讓我很心動 :

特力屋 : LG清潔機器人6340 $14155
Yahoo : LG 清潔機器人-好正簡約款 (VR6340LV) $14900 (有詳細解說, 但已停售)

但上網查資料後, 發覺掃地機不是買來就一切勞務免除, 還得每天清濾網, 倒垃圾, 濾網與電池都是消耗品, 定時要花錢更換, 更重要的是有些房間不讓它去掃還得想辦法阻擋, 為了免除掃地卻增加了照顧機器的工作, 似乎也沒輕鬆多少, 所以雖然比市價便宜 4000 元, 還是打消念頭了. 參考 :

掃地機器人能掃的乾淨嗎?重點特色、採購技巧解析
打掃也要講雲端!掃地、吸地、拖地一次完成,8款打掃機器人真機評測
不專業之掃地機器人比較評論
決定要買一台掃地機器人了,請推薦~~

摘要如下 : 

"只能說你要用機器人,那你的家具就真的要慎選....."
"LG這台,是個相當聰明的機器人,他是真的會記憶路線的!也就是說,你無法在他工作到一半,把它搬走,他在那裡死掉,你記得就要讓他在哪裡復活!不然他會找不到回家的路!"
"也要機器人適合你才行。不然它幫不上忙,還把你氣個半死,是何苦咧!"
"我婆婆用了幾個月之後,跟我反映,LG變成史上最笨機器人,常常出來掃五分鐘就說掃完了,重設也沒用"

最後決定改買夏普的 32 吋電視, 因為這兩周回鄉下時, 發現餐廳那台已使用超過 10 年的映像管電視會突然無畫面, 機箱拍幾下又恢復, 上週更惡化為不管怎麼拍都無效, 讓它冷靜十幾分鐘又自動開啟, 顯見已到不堪使用地步, 那就乾脆改買電視機好了, 也是有 2000 元節能補助. 於是到福利社找了這台 SHARP 32 吋電視, 價格 9300 元 (比 Yahoo 便宜 300 元), 福利金加節能補助共 10000 元, 還倒賺 700 元 :

# SHARP夏普 32吋 LED液晶電視 LC-32LE265T $9600

這樣總算把福利金解決了. 關於換不換冰箱的決定, 我主要是看了下面兩篇中的意見 :

換冰箱記
如何讓冰箱看起來像是快故障?

節錄如下 :

"我認為沒壞為什麼要換新,東西會冰壞,或是不冰?省電要省多久才能達成新冰箱價格?"
"買新的變頻冰箱也要好幾萬丫... 你有想到你所謂的省電...你要省多少年才能省到一萬元嗎?說不定你省不到一萬你又想換一台了"
"電子產品通常有下列趨勢:舊的東西已經用很久,不代表它不能再用很久!新的東西剛沒用多久,不代表它可以再用很久!"
"除非真的必要......或者是冰箱的循環出了問題.....不然就別換了.."
"冰箱夠冷就好!多少年根本無所謂,反而是用越久越划算。現在很多冰箱加入很多新科技,但是最先壞掉的也是那部份。例如:微電腦...etc, 簡單反而長久阿!!!"

2015年12月22日 星期二

第 51 周記事

本周姊姊要去畫室補課與漫研社幫忙, 故僅菁菁與我回鄉下了. 10 月 20 日 (第 42 周) 種植的玉米本周採收, 成長期大約 60 天左右. 其實週四小阿姨從台北下來已經幫我採收一遍了, 還特地錄影傳 Line 給我, 謂之 "蝗蟲過境". 本期因施肥較少而且沒有進行摘除多餘玉米穗, 幾乎每株都結了三支玉米, 結果僅有一支勉強及格, 其餘均營養不良. 另外病蟲害也較多, 玉米桿內有黑色黴菌.


這次摘了十餘支, 約一半是營養不良的 :


南瓜也首次結果, 這次學到經驗, 南瓜必須種在稍微乾旱之地, 如果三不五時灌水, 大概都結不出果實來 :



除非是周六早上就回鄉下, 不然只有周日一天實在沒多少時間整理書房與雜物. 以後若姊姊不能回鄉下, 那就週六早上回去好了. C 語言也是沒進度, 似乎只要一停下來, 要重新開始就有點沒勁, 所以打鐵趁熱是有道理的.


日文輸入法

自從小狐狸們陸續上中學後, 要出國旅行就不好喬時間. 二哥國小畢業時, 曾想幫他跟老爸報名日本環球影城團, 但老爸婉拒了. 明年二哥就國三畢業, 有想要重遊京都, 水某說要自由行, 但我的日文已多年沒用, 生鏽了. 前陣子聽姐姐說她同學去考日文檢定, 讓我對日文的興趣又重新燃起. 十多年前考過舊制日檢三級後, 正準備朝二級邁進時, 卻因為去進修英文而停了下來. 這幾天把以前的教材找出來, 打算一天一課把流失的戰力補回來.

今天要在網頁上記錄日文單詞時想到, 要怎樣在電腦上輸入日文呢? 很簡單, 只要新增微軟日文輸入法即可. 以下是 Win7 作法 : 首先在右下角的輸入法工具列按滑鼠右鍵, 選 "設定值" :


在選單中按 "新增" :


找到 "日文" 後點開, 勾選 "鍵盤" 中的 "Microsoft 輸入法" ("日文" 不用勾選, 因為我沒有日文鍵盤), 再按 "確定" :


這樣就會出現日文輸入法了 :


按 "確定" 後, 右下角輸入法工具列就會出現日文選項了 :


切換到日文輸入法後, 第三個按鈕可以切換平假名/片假名/英文字母 (半形/全形) :


此微軟之日文輸入法是用英文拼音來輸入日文字型, 拼音組合參考下面這兩篇 :

新增「日文」成為日常使用的輸入法
# WIndowsXP日文輸入法安裝方法

我用 Word 切換輸入模式結果如下 :

あいうえお (Hiragana)
アイウエオ  (Full-width Katagana)
AIUEO  (Full-width Alphanumeric)
アイウエオ    (Half-width Katagana)
AIUEO    (Half-width Alphanumeric)

第四個按鈕則是可選擇漢字的選字方式, 預設是 General (一般), 可以改為 Bias for Name (偏好人名), 或 Bias for Speach (偏好演講), 或 No Conversion (不選字) :


當用英文拼音拼出假名後, 按一下 Space 空白鍵會依選擇之偏好轉換為漢字, 再按一次 Space 則顯示漢字選單讓我們選擇. 如果要輸入全部都是假名的文章, 可以選 No Conversion, 這樣 Space 鍵就會還原為空白鍵, 而失去轉換漢字的功能. 例如我輸入 zassi (重複)


其他參考 :

# 知識網 : 日語輸入法
# 如何解決在Windows 7 中,找不到日文輸入的進階功能 ?

Win8 系統的輸入法設定與 Win7 不同, 要到 "控制台/時鐘, 語言與區域/語言/新增語言", 新增 "日本語" 即可, 用法與 Win7 一樣, 可以用 Windows + Space 切換新注音與日文輸入法 :


參考下面這兩篇 :

# [Windows 8] 新增內建IME日文輸入法
# 在 Windows 8 中新增、變更輸入法設定


2015年12月19日 星期六

陳賡與蔣介石

昨晚去取左新取書時, 意外在書架上瞄到這本靈活文化出版, 王曉華與張慶軍寫的 "黃埔十大恩怨", 隨便翻閱了幾頁, 看到其中講述蔣介石與得意門生陳賡從賞識到分道揚鑣, 甚至反目成仇刀劍說話的來龍去脈, 當即決定借回來看.

這本書是大陸人寫的, 自然是偏向左派角度來論述. 但從歷史探勘者角度來看, 當作小說軼事參考就好, 因為寫歷史故事要跳脫主觀框架並不容易. 以下是其中 "陳賡與蔣介石" 這一章的讀後心得與摘要. 
Source : 博客來

陳賡出身黃埔一期, 名列1955 年解放軍十大將排名第四. 此君湖南湘鄉人 (與晚清曾國藩同鄉), 年方 14 即加入湘軍, 1923 年考入黃埔軍校就讀, 與蔣先雲, 賀衷寒三人並稱 "黃埔三傑", 巧的是這三個黃埔一期生都是湖南人. 蔣先雲與陳賡早在進黃埔之前的1921 與1922 年就加入共產黨, 在黃埔軍校組織了左派的青年軍人聯合會; 而賀衷寒則組織孫文主義學會, 與青年軍人聯合會互相較勁. 賀衷寒一路跟著蔣介石, 是蔣的愛將;  但蔣介石其實更欣賞陳賡, 把陳賡調到身邊當警衛連上尉連長, 希望爭取過來引為己用. 陳賡也不負蔣的厚愛, 在黨軍第二次東征陳炯明時, 由於蔣的輕敵誤判遭到叛軍包圍, 是陳賡揹著蔣介石跑了好幾里路才脫險, 可說是蔣介石的救命恩人.  參考 :

# 蒋介石最后放走“救命恩人”陈赓的详情

陳賡的得寵讓賀衷寒吃味忌妒, 不斷在蔣面前挑撥, 說陳是共產黨不可輕信. 雖然蔣一直想用溫情感化陳賡, 但心眼小的蔣介石卻也提防起來. 陳賡感覺到蔣介石似乎對自己有些冷淡了, 便去找政治部主任周恩來, 周告訴他聽說蔣有本小冊子專門記錄對人的評價, 建議他去找看看. 沒想到應該很隱密的記事本竟然讓陳賡找到了, 上面真的有他的名字, 註記是 : 此人為共產黨員, 不可帶兵. 陳賡閱後大怒, 認為蔣薄情寡義, "共產黨人以誠相待, 他卻不能推心置腹" 云云 ... 從此蔣陳師生關係生變, 最後變成戰場上刀劍相向的仇敵.

這段故事表面看來似乎相當有傳奇性, 但作者的描述我覺得有可疑之處. 首先, 周恩來如何知道蔣有這本小冊子? 該不會是周自己早就偷看過了吧? 那為何不直接告訴陳賡, 還要他自己去找?作者認為蔣介石是想測試一下陳賡的忠誠度, 才把原本私密的小冊子放在容易找到的地方, 我覺得未免太過粗略. 難道蔣不會覺得冊子中還有其他紀錄是不方便讓陳賡也瞄到的嗎? 我不認為蔣介石會只為了要測試陳賡, 卻讓他有機會看到全部秘密. 我倒是覺得這搞不好是周恩來的伎倆, 組織方面可能察覺到陳賡有可能被蔣介石搶過去, 所以弄了本甚麼品人錄的冊子讓陳賡死了這條心吧! 我發現讀歷史跟寫程式一樣, 邏輯要特別清楚, 不然很容易被拐.

黃埔三傑際遇各殊, 賀衷寒畢業後並未在戰場上表現, 而是從事政治與特工工作, 是蔣的法西斯組織藍衣社的要角, 來台後曾擔任交通部長, 1972 年因骨癌死於台大醫院. 蔣先雲是黃埔一期最優秀的學生, 1927 年 4 月蔣介石發動清黨, 剷除國民黨內的共產黨勢力, 陳賡與蔣先雲看到同志被殺, 氣得把蔣介石派來送信的黃埔同學楊引之與陳紹平槍斃祭旗 ... 作者說 "蔣先雲不願見到同門相殘局面", 1927 年 5 月參加武漢政府二次北伐, 在河南與奉軍作戰時中彈身亡. 這裡又有一個矛盾了, 既然蔣先雲不願看到同學相殘, 為何又要殺了來規勸的同班同學呢? 還是殺了同學後心裡有愧, 乾脆跑去打北洋軍閥?

其實讀這些歷史總是讓我感嘆, 國共內戰史其實就是黃埔同學的相殺史. 沙場衝殺各為其主(義), 美其名是為革命為人民, 其實最後成就的只是吾皇萬歲. 陳賡算是好命的, 跟蔣介石分道揚鑣後打出了新局面, 他的蔣校長還真的沒看走眼. 他在新中國建立後名列十大將, 又在 1961 年因心臟病死於上海 (心臟病是好死), 躲過了 1966 年老毛發起的文化大革命. 要不然, 憑他是蔣介石救命恩人這一條, 紅衛兵會安他甚麼罪呢?   

關於蔣陳師生反目, 還有一說是蔣介石帶兵作戰不忘上海炒股, 蔣曾在十里洋場玩股票確有其事, 但一邊指揮作戰一邊聽股市消息是否為真, 我就當作妄講妄聽囉.

陳賡看不起蔣介石原因:蔣指揮作戰時聽股市訊息

"陳賡為什麼看不起蔣呢?臺軍現在一個老的將領曾經給陳賡的家裏來了封信,他說我的老班長當年就看不起蔣,就嫌蔣介石在一邊指揮作戰,作戰指揮間隙打開收音機聽上海的股市,認為蔣不是一個真正的革命者,最後陳賡棄蔣而去。"


補記國內旅遊

這幾天忙開會與工作, 年底又到了, 休假還很多, 旅遊補助也還沒請, 就訂了週三晚上西子灣的會館, 與菁菁及水某三人入住, 周四早上一大早就退房, 直接載菁菁去上學. 週四還必須請休假一天, 所以一整天都待在家. 這幾年都是忙到年底才趕著休假, 而且都是市內 (室內) 旅遊, 上一次真正出遊大概是四年前帶媽媽與左營阿姨去日月潭玩吧!

周四早上回到家, 把跟市圖借的 "AngularJS 建置與執行" 看到第三章就看不下去了. 我覺得在前端導入軟體工程的 MVC 是不錯的點子, 但那是對開發大型網頁應用比較有用, 對於中小型專案似乎有點殺雞用牛刀之感. 我還是覺得用 jQuery 直接操控 DOM 比較直觀, 反正我又不是要寫大型專案, 況且不過就是在前端輸出網頁而已, 有必要搞得這麼複雜嗎?

中午吃完飯後本想打個盹, 電視頻道卻切到台視的 "神機妙算劉伯溫", 卡好, 連續劇不看則已, 一看就像陷入流沙一樣, 無法自拔. 劇中角色都是歷史人物, 但劇情根本就是編劇亂掰, 而我卻看得津津有味! 這對自封為歷史探勘者的我來說, 簡直是此可忍孰不可忍!

不過編劇會亂掰其來有自, 像劇中說四皇子朱棣 (即明成祖) 尋找失蹤的母親和娘娘, 明史中說成祖為馬皇后所出, 但這很有可能是燕王朱棣在發動靖難, 成功登上皇位後, 為了加強權力的合法性, 竄改了太常寺志 (皇室族譜), 而明史修撰者張廷玉就據此論述所致. 關於燕王生母的傳說甚多, 有說是元順帝北逃時未及帶走的懷胎妃子弘吉喇氏 (這樣朱棣不就是蒙古人?), 但學者考證發現時間對不攏, 因為徐達等人攻陷北京時, 朱棣已經九歲矣, 怎可能是元妃所生? 殘暴的朱元璋怎會放過順帝之子? 也有說是出身高麗的碽妃, 但碽妃到底是誰, 歷史線索也是杳然. 應該是出於政治原因, 很多證據都被朱棣銷毀了吧!

參考 :

# 維基 : 明成祖
# 維基 : 碽妃
# 明成祖朱棣生母之谜


兩本 Win8 好書

前陣子為了將二哥抽獎抽到的主機板組裝起來, 換掉舊電腦的主機與硬碟, 從市圖借到下面兩本好書來參考, 現期限已到, 摘要紀錄如下 :

第一本是碁峰出版的 "跟我學 Windows 8.1", 主要介紹 Win8.1 的功能與操作, 其實我只對製作系統映像與如何還原有興趣而已. Win8.1 安裝也很簡單, 比安裝 XP 系統要快且容易. 以前認為 XP 用得很習慣, 沒必要換 Win8, 但考慮有些軟體 (例如瀏覽器) 已不支援 XP, 甚至新的主機板能否安裝 XP 也是個問題. 現在連 Win10 也已出來而且免費升版, 不過目前還不考慮升版.

Source: 博客來

這本書還不錯的是將紙本放不下的內容做成電子書 (例如家用群組與家長監護等), 可在碁峰網站下載 :

# http://books.gotop.com.tw/download/ACA019300

第二本是上奇出版的 "電腦組裝+選購+測試調校+維護一本通 Windows 8 大顯神威", 此書包含了所有 PC 組裝的知識, 從主機板, 顯示卡, 記憶體, 到硬碟等等無所不包, 是 DIY 新手的絕佳參考書. 更棒的是書附光碟將書中主要內容做成多媒體教材 (CD-ROM),可以直接在電腦播放, 靜不下來看書的人可以利用此教材學習.

Source: 博客來

最近借書總量已快破表, 必須加速消化才行.


2015年12月15日 星期二

第 50 周記事

今年已過去 50 周, 離 2016 只剩兩周啦! 再說甚麼時光如梭就很老套, 不痛不癢的, 反正日子就是一天一天過, 開心就好啦. 本周主要就是完成工作日誌改版, 還有就是 Arduino 停下來補一下 C 語言的功力. 以前搭檔的同事說想建議上面把我的工作調換回來, 我說先別急, 等我把工作用的工具軟體寫完再說.

週六早上菁菁學校辦園遊會, 她們班賣冰淇淋, 但我十點半去的時候都賣完了, 我就各樓層繞一圈, 除了剛好遇到二哥跟他同學在走廊吃冰外都沒認識的, 就直接回家了. 這次沒辦音樂會感覺比較不熱鬧.


週日經過種子行又買了 20 株甜玉米, 然後鋤一塊地, 叫姊姊與菁菁各種十株, 預計春節前夕可收成. 同事給我的七顆北海道水果玉米種子放在鉛筆盒中久矣, 下周務必育苗看看, 順利的話將來留兩條玉米做種. 本來想再買五六棵桃太郎番茄來種, 可惜缺貨. 


週日中午小舅來訪, 提到明年底要退休, 待在鄉下的時間會比較多, 這樣可以到我家多走動, 有個照應, 我也不用每周回鄉下. 我覺得鄉下能多個可以互相照應的親戚這樣挺好, 特別是爸是獨居老人, 但周末我不回鄉下, 待在都市會很無聊哇! 除非有特別活動.

年底快到了, 我的休假還有四天未休, 剩下兩周得周休四日才能打消. 另外福利金購買節能冰箱也必須在本周搞定才行, 不然到期失效就會被辦公室那幫人恥笑哩.


2015年12月12日 星期六

關於 AngularJS

今天想起同學仲仔跟我提到的 Bootstrap 框架, 就來調查一下底細, 結果看到下面這篇 :

比較Angular/jQueryUI/Extjs:沒有一個框架是萬能的

哇咧, 這作者下筆還真幽默. 不過看完才知原來 AngularJS 這麼好用, 也讓快一年沒摸前端技術的我燃起心中一把火, 突然想找一本書來研究研究 (還真是喜新厭舊). 雖然原文書已經非常多, 但是很可惜, 目前中文書只有一本 :

# AngularJS 建置與執行 (歐萊里)

這本書譯自 Oreilly 的 "AngularJS : Up and Running", 雖然讀原文書對我是家常便飯, 但如果有中文譯本, 老實說還是看中文翻頁速度較快, 畢竟中文是圖像語言, 而英文是聲音語言. 此書市圖有進, 不需要買, 目前通閱申請中.

AngularJS 是一種前端 Javascript 框架, 是 Google 工程師為了加速專案開發而發展出來的一種技術, 主要的構想是希望在前端網頁中也使用後端常見的軟體工程 MVC 架構來加速開發速度, 並且提高程式的可測試性. 關於 AngularJS 的介紹可參考下列文章 :

# https://zh.wikipedia.org/wiki/AngularJS
# 前端工程的極致精品: AngularJS 開發框架介紹
# 比較Backbone.js, Angular.js, Ember.js, Knockout.js 心得
# AngularJS 、Backbone.js 和 Ember.js 的比较
Day1- 入門AngularJS筆記與前端領域的學習筆記分享介紹

以下是我閱讀後的一些摘要 :
  1. AngularJS 使用宣告式語法在傳統的 HTML 語法中加入特定屬性來擴展其能力, 函式庫在讀取這些屬性後, 依照其中的指令將網頁中的輸入或輸出與模型中的 Javascript 變數雙向綁定起來, 從而達成動態即時反映的效果.
  2. AngularJS 的範本引擎使用 DOM Template, 即直接以 DOM 物件當作網頁片段的範本, 有別於其他架構以字串來定義之範本, 這樣便省掉變數替換時所需的型別轉換時間, 效能較優.
  3. AngularJS 的目標是要規範與後端 CRUD (增查修刪) 作業以其所規定的標準方式進行. 除了 CRUD 網頁應用程式外, AngularJS 幾乎毫無用武之地. 如果想要操控 DOM, 應該使用 jQuery 之類的框架. 
  4. AngularJS 與 jQuery 等專注於 DOM 操控的函式庫是不一樣的, 主要的目的是要將程式邏輯與 DOM 的操控分離開來, 讓客戶端與伺服端地開發可以同時進行而不會互相牽制.
AngularJS 最新版 (目前是 1.5.0) 可在官網下載, 壓縮檔約 149KB :

https://angularjs.org/

只要在網頁中指定此函式庫即可 :

<!DOCTYPE html>
<html>
<head>
<script src="angular.min.js"></script>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
</body>
</html>

如果專案是放在 Internet 上, 也可以直接使用 Google 提供的 CDN :

https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.0/angular.min.js

一個簡單的雙向資料繫節範例可在下面這篇的後半部找到 :

# 前端工程的極致精品: AngularJS 開發框架介紹

另外, 這篇也介紹了一個好用的 Javascript 線上編譯平台 jsbin, 這跟我之前所用的 jsfiddle 很像, 都是免費使用的, 不過它是用 Git 帳號登入的, 而且對於 AngularJS 函式庫的支援較多. 這兩個線上平台都很好用, 只要連上網, 不須配置環境, 馬上就可以調用各個框架編寫程式進行測試.
 

小狐狸早餐

自從姊姊上高中後, 早上六點半前要去搭捷運上學, 即使六點起床去早餐店買也有點趕, 所以幾乎都是自己準備早餐. 以前她們讀小學時 7:45 前要到校, 七點起床即可, 我六點半去運動回來就順便買早餐. 現在每天晚上都要先講好明天早餐吃甚麼, 晚上去載姊姊時順便去全聯採買 (雞蛋, 吐司, 蔥油餅, 麻醬, 海苔, 餛飩, 可可亞), 早餐選項如下 :
  1. 粥 + 肉鬆
  2. 肉鬆壽司
  3. 麻醬麵
  4. 餛飩麵
  5. 水餃
  6. 吐司夾蛋
  7. 蛋炒飯
  8. 蔥油餅
若要吃蛋炒飯, 晚上睡覺前便須洗米先煮好; 若要吃粥配肉鬆, 那也須睡前洗好米放冷凍庫, 這樣第二天早上大約 10 分鐘就能煮好粥, 這是我從阿基師的書上學來的.


2015年12月9日 星期三

第 49 周記事

2016 年只剩三周了, 好快呀, 時光如流水般飛逝, 人生宛如在河流中泛舟一樣, 眼前不斷有新風景出現, 而過去卻如浮光掠影般一閃而逝. 

本周暫時將 C 語言停下來搞 ASP 與工作日誌, 因為月底前必須升版完畢才能符合資安要求. 這兩天應該就可以收工了.

這次段考菁菁數學與生物不及格, 補習班老師也打電話來要求補課. 我看得花點時間督促她, 不能全靠補習. 二哥仍是第十名, 不進也沒退. 姊姊則可望進入前三.

前陣子用鄉下的平底鍋煎魚都煎得慘不忍睹, 因為那只不沾鍋中間部分的塗料都被磨光, 不管是煎豆腐還是魚, 都搞得皮開肉綻. 最近突然想起以前阿基師書裡有提到如何煎魚不黏鍋, 就是在下鍋前用少許麵粉塗在表面, 這兩周我測試發現果然有效! 就算不沾鍋已經很沾了, 只要用麵粉就不會煎出體無完膚的魚了.


2015年12月5日 星期六

如何在網頁中使用網頁編輯器 CKEDITOR

這兩天為了解決公司工作日誌中的舊版網頁編輯器 FCKEDITOR 在 IE10 以上無法運作問題, 找到了這款 CKEDITOR, 基本上符合我要求 (例如超連結可以設 target 在新視窗開啟等), 下面紀錄如何將此 Javascript 函式庫使用在我的 ASP 網頁專案上.

首先到 CKEDITOR 首頁下載最新版函式庫 (目前是 4.5.5 版), 下載 Standard 版本即可, 安裝方式都一樣 :

http://ckeditor.com/download

解壓縮 ckeditor_4.5.5_standard.zip 後會在目前資料夾下產生一個 ckeditor 資料夾, 目錄結構如下 :


將此 ckeditor 資料夾整個複製到我的專案目錄 myasp/plug-in/ 底下, 大小為 3.22MB, 如果要減重, 可以刪掉 samples 資料夾, 三個 .md 檔, 以及 lang 底下用不到的語言檔, 只留下 en.js 與 zh.js 即可, 這樣可減重到 2.7MB 以下 :


然後就可以開始撰寫測試網頁了, 如下 test.html 所示 :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>CKEditor 測試</title>
    <script src="ckeditor.js"></script>
  </head>
  <body>
    <form>
      <textarea id="editor1">
      Hello World! 這是 CKeditor!
      </textarea>
    </form>
    <script>
      CKEDITOR.replace( 'editor1' );
    </script>
  </body>
</html>

參考 :

http://docs.ckeditor.com/#!/guide/dev_installation

這裡最重要的當然是匯入 ckeditpr.js 這個函式庫, 由於 test.html 是放在 ckeditor 下, 所以這裡不需要加上相對路徑. 如果專案是放在 Internet 上, 則可以使用 CDN 供檔, 如此就不用自己準備上面這些環境 :

<script src="//cdn.ckeditor.com/4.5.5/standard/ckeditor.js"></script>

參考 :

http://cdn.ckeditor.com/

其次是要用一個表單元件 textarea 當作編輯器的容器, 而且務必指定 id 屬性, 像這裡我只用到一個編輯器, 如果有多個, 就可以取名 editor2, editor3, ... 或任何其他名稱. 最後是用 Javascript 程式來將 textarea 變裝為美美的 HTML 編輯器, 很簡單, 只要呼叫 CKEDITOR 物件的 replace() 函數, 傳入 textarea 的 id 即可 :

CKEDITOR.replace("editor1");

用瀏覽器檢視 test.html 結果如下 :


介面比十幾年前的 FCKEDITOR 漂亮. 它預設會將寬度撐大到父容器的寬度, 即使 textarea 有設定 cols (行數) 也是一樣, 所以 rows 與 cols 其實都不用設.

接下來是要如何用在我的 myasp 專案上呢? 我的工作日誌系統裡的 JLOG 子系統中的 add_task_form (新增工作) 模組就是要用到 HTML 編輯器以儲存來自 email 或 WORD 的內容, 我把原來套用的 FCKEDITOR 移除,  改換為 CKEDITOR 如下 :

case "add_task_form" : {
%>
...
<form method="post" action="admin.asp?op=jlog&tab=jlog&function=add_task">
...
  <textarea id="editor1"></textarea>
  <script src="plug-in/ckeditor/ckeditor.js"></script>
  <script>CKEDITOR.replace('editor1');</script>
  ...
  ...
  <input type="button" onclick="check_addtask(this.form)" value="新增">
  <input type="hidden" name="task_content" value="">

  <script language="javascript">
    function check_addtask(formObj) {
      var content=CKEDITOR.instances.editor1.getData();
      ... (對 content 進行處理, 例如去除可能的 form 元素, 以免兩層表單)
      formObj.task_content.value=content;  //處理後放入隱藏元素
      formObj.submit();
      }
  </script>
<form>
<%
  break;
  }

在這個範例中, 我有一個新增工作的表單, 放在 add_task_form 模組裡, 當按下新增工作按鈕時, 就會向伺服器提出 admin.asp?op=jlog&tab=jlog&function=add_task_form 這個 URL 要求, 在 admin.asp 所含括的 jlog.asp 程式裡, 經過解析 URL 路徑後, 就會進入上述的 case, 向前端展示一個輸入表單, 其中最重要的便是填入工作內容, 因為所紀錄的工作牽涉各方寄來的 email, WORD 或 EXCEL 內容等, 為了求真實以及閱讀方便 (開啟附檔多一道操作程序), 內容少的就直接貼到工作紀錄裡, 內容太多太複雜的就以附檔上傳處理, 這樣要追蹤工作就比較方便. 要記錄這三種多媒體內容就必須用到像 CKEDITOR 這種網頁編輯器.

由於我把 ckeditor 目錄放在我的專案 myasp/plug-in 子目錄下, 因此要匯入 cckeditor.js 時必須指明相對路徑. 填好工作內容, 按下 "新增" 按鈕時, 會執行前端 Javascript : check_addtask() 方法, 首先是要取出 CKEDITOR 的資料內容, 這要呼叫 CKEDITOR 物件中的 textarea 實體的 getData() 方法來取得 :

var content=CKEDITOR.instances.editor1.getData();

參考 :

# http://docs.ckeditor.com/#!/guide/dev_savedata

然後做一些輸入欄位值的檢查, 例如有些欄位是必填不得空白, 特別是禁止在工作內容中輸入另一張表單, 這會造成表單套疊, 使程式無法運作, 所以須去除 form 元素. 最後將調整後的輸入內容放入隱藏的 task_content 元素裡再 submit 表單.




如果貼上來自網頁, email 或 WORD 等內容時, 在 Chrome 瀏覽器會因為安全性設定的關係跳出一個視窗來讓我我們貼資料 :


但在 IE11 就直接貼上去了, 可能 IE11 對剪貼簿的安全性設定預設較鬆.

如此便完成了這次的工作日誌改版, 於 IE11, Chrome 等瀏覽器測試均無問題, 暫時可以應付這次的升版要求矣. 這個解決方案也將移植到以 PHP 開發的新版工作日誌上, 其實 ASP, JSP 與 PHP 這三種技術就像孿生兄弟一樣. 一通百通.

CKEDITOR 物件是可以設定的, 例如預設語言, 以及要顯示哪些功能按鈕等, 參考 :

http://docs.ckeditor.com/#!/guide/dev_configuration

在上面的範例中, 我們僅使用 textarea 的 id 屬性來建立 CKEDITOR 物件, 但根據 API 文件, 其實用 name 也是可以的, 或者兩個都用亦可, 不過建議僅使用 id 就可以, 參見下面文件中關於 replace() 的敘述 :

http://docs.ckeditor.com/#!/api/CKEDITOR-method-replace

由此文件可知, replace() 方法會以一個 CKEditor 物件來取代 DOM 中的 textarea 或 dir 元素, 除了傳入 textarea 的 id 或 name 外, 還可傳入一個 config 物件實體來初始化 CKEditor 物件的設定值, 也就是將預設的設定值覆蓋掉 :

replace(element, [config])

關於 config 物件實體之屬性可參考 :

http://docs.ckeditor.com/#!/api/CKEDITOR.config

在上面的範例中, 編輯器預設會偵測作業系統語言, 顯示中文介面, 而且會撐到 100% 父容器寬度, 我們可以用 config 指定語為英文, 寬度為 800px 如下 :

CKEDITOR.replace('editor1', {width:800,language:'en'} );

寬度也可以用百分比, 但必須用引號括起來, 例如 :

CKEDITOR.replace('editor1', {width:'50%',language:'en'} );

如果不想讓使用者直接編輯 html 原始碼, 可以用 removePlugins 屬性來取消 "原始碼" 按鈕 :

CKEDITOR.replace('editor1', {removePlugins:'sourcearea'});

參考 :

how to disable source button in ckeditor 4

如果對工具列的排列方式不滿意, 可以利用 toolbarGroups 屬性來設定, 它將同類型的工具按鈕合為一群, 範例如下 :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>CKEditor 測試</title>
    <script src="ckeditor.js"></script>
  </head>
  <body>
    <form>
      <textarea name="editor1" id="editor2">
      Hello World! 這是 CKeditor!
      </textarea>
    </form>
    <script>
      var tg=[{name:'clipboard',groups:['clipboard','undo']},
              {name:'editing',groups:['find','selection','spellchecker']},
              {name:'links'},
              {name:'insert'},
              {name:'forms'},
              {name:'tools'},
              {name:'document',groups:['mode','document','doctools']},
              {name:'others'},
              '/',
              {name:'basicstyles',groups:['basicstyles','cleanup']},
              {name:'paragraph',groups:['list','indent','blocks','align','bidi']},
              {name:'styles'},
              {name:'colors'},
              {name:'about'}];
      CKEDITOR.replace('editor1', {toolbarGroups:tg,removePlugins:'sourcearea'});
    </script>
  </body>
</html>

這裡跳行要用斜線 "/", 排列效果如下 :


也可以用 toolbars 屬性直接設定工具列要放哪些按鈕, 範例如下 :

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>CKEditor 測試</title>
    <script src="ckeditor.js"></script>
  </head>
  <body>
    <form>
      <textarea name="editor1" id="editor2">
      Hello World! 這是 CKeditor!
      </textarea>
    </form>
    <script>
      var toolbar=[['Cut','Copy','Paste','PasteText','PasteFromWord',
                    'Undo','Redo'],
                   ['Scayt','SpellChecker'],
                   ['Link','Unlink','Anchor'],
                   ['Image','Table','HorizontalRule','Smiley',
                    'SpecialChar','PageBreak'],
                   ['Maximize'],
                    '/',
                   ['Bold','Italic',
                    'Underline','Strike','Subscript',
                    'Superscript','-','RemoveFormat'],
                   ['NumberedList','BulletedList','-','Outdent','Indent',
                    '-','Blockquote'],
                   ['Styles','Format'],
                   ['About']];
      CKEDITOR.replace('editor1',{toolbar:toolbar});
    </script>
  </body>
</html>

這裡使用二維陣列來宣告要顯示的工具按鈕, 然後在 replace() 的 config 參數中設為 toolbar 屬性之值即可, 效果與上面用 toolbarGroups 的完全一樣. 注意, 每一個一維陣列就是一個工具列群組, 群組內的按鈕可用 "-" 再分出子群. 如果需要顯示原始碼按鈕, 可以添加 ['Source'].

如果把 toolbar 屬性設為 null, 就會顯示此 package (basic/standard/full) 的全部工具列 :

CKEDITOR.replace('editor1',{toolbar:null});

此外還有一點要注意, 有些在完整版才有的工具列按鈕 (例如文字的前景與背景色 TextColor 與 BgColor) 在標準版設了也不會出現, 因此如果需要自訂工具列的話, 最好下載 Full 版來改裝.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>CKEditor 測試</title>
    <script src="http://cdn.ckeditor.com/4.5.5/full/ckeditor.js"></script>
  </head>
  <body>
    <form>
      <textarea name="editor1" id="editor2">
      Hello World! 這是 CKeditor!
      </textarea>
    </form>
    <script>
      var toolbar=[['Cut','Copy','Paste','PasteText','PasteFromWord',
                    'Undo','Redo'],
                   ['Scayt','SpellChecker'],
                   ['Link','Unlink','Anchor'],
                   ['Image','Table','HorizontalRule','Smiley',
                    'SpecialChar','PageBreak'],
                   ['Maximize'],
                   ['About'],
                    '/',
                   ['Bold','Italic',
                    'Underline','Strike','Subscript',
                    'Superscript','-','RemoveFormat'],
                   ['NumberedList','BulletedList','-','Outdent','Indent',
                    '-','Blockquote'],
                   ['Styles','Format'],
                   ['TextColor','BGColor']];
      CKEDITOR.replace('editor1',{toolbar:toolbar});
    </script>
  </body>
</html>

如果不想在每一個要用到 CKEDITOR 的網頁中進行設定, 其實可以在 CKEDITOR 資料夾中找到一個 config.js, 只要在這裡做設定, 所有專案中用到 CKEDITOR 的網頁都會套用相同設定, 範例如下 :

CKEDITOR.editorConfig=function(config) {
  // Define changes to default configuration here. For example:
  //config.language = 'en';
  //config.uiColor = '#AADC6E';
  config.toolbar = [['Cut','Copy','Paste','PasteText','PasteFromWord',
                    'Undo','Redo'],
                   ['Scayt','SpellChecker'],
                   ['Link','Unlink','Anchor'],
                   ['Image','Table','HorizontalRule','Smiley',
                    'SpecialChar','PageBreak'],
                   ['Maximize'],
                    '/',
                   ['Bold','Italic',
                    'Underline','Strike','Subscript',
                    'Superscript','-','RemoveFormat'],
                   ['NumberedList','BulletedList','-','Outdent','Indent',
                    '-','Blockquote'],
                   ['Styles','Format'],
                   ['TextColor','BGColor'],
                   ['About']];
  };

CKEDITOR 很棒的地方是提供客製化套件, 在下載頁面點選 "Let me customerize CKEditor", 再按下載鈕 :


然後點選 basic/stadard/full, 於下方將需要的工具按鈕移到右方再下載, 這樣它會將設定都寫在 config,js 中. 不過工具列 plugin 實在玲瑯滿目, 要從中挑選也是個問題.

參考 :

# 讓 CKEditor 更好用
CKeditor編輯器選項配置

2015-12-12 補充 :

前天完成工作日誌改版後, 發覺編輯時按 enter 跳行似乎間距過大, 我之前已知悉 CKEditor 是用段落標籤 p 來處理跳行, 而非用 br, 昨日在下列網站找到解決辦法 :

CKEditor 編輯器 換行 空格 解決 辦法

就是在 config.js 中加入下列兩行 :

config.enterMode = CKEDITOR.ENTER_BR;
config.shiftEnterMode = CKEDITOR.ENTER_P;

2016-03-01 補充 :

今天因為同事反映 TinyMCE 編輯器貼上頗長的信件內容時一直 Waiting, 三十分鐘後出現沒有回應訊息問題, 就去網搜是否有此問題的解決辦法, 結果找到一篇很棒的文章, 但與 TinyMCE 問題無關, 反而是我想取代掉的 CKEditor :

# 神調校讓 CKEditor 更好用


2015年12月4日 星期五

買新冰箱?

今年公司福利社點券有 8000 元, 前陣子促銷 LG 掃地機器人時本想買, 後來看一些婆婆媽媽的部落格後又打消念頭. 時序來到年底再不花就要失效了, 最近看到上面有賣 Zenfone2, 想說買新手機給菁菁吧! 但前天聽同事說現在馬政府為了救經濟, 對購買冷氣冰箱等大電器有補助 2000 元, 就想到家裡那台用了 18 年的三洋電冰箱, 門上的磁條已經鬆脫了, 而且以前的冰箱也比較耗電, 所以似乎也該換了.

一般冰箱和變頻冰箱耗電量差異會很大嗎?

記得當初買房子時, 到鳳山萬客隆去選購了三洋電視, 洗衣機, 電冰箱三件組, 前兩位已經在過去兩三年汰換了, 只有這台 三洋 SR5638-HN 碩果僅存, 容量 410 公升, 尺寸為寬73公分*高170公分*深66公分.

福利社網站上找到下面幾款是寬度 73 以內的機種, 都可以在 PCHOME 或 YAHOO 找到, 而且他們賣得比較貴.

國際牌435公升變頻雙門冰箱NR-B435HV-N1 $25900 (Yahoo) (燦坤)

尺寸 : 寬694*高1714*深793公分
年耗電量 : 372 度
耗電量(kW.h/月):
能源因數 E.F. : 17.7

#【NR-B486GV-DH】PANASONIC 485公升ECONAVI雙門變頻冰箱 $22699

尺寸 : 寬697*高1828*深757公分
年耗電量 : 372 度
耗電量(kW.h/月):32
能源因數 E.F. : 17.3

P 是紫羅蘭色, DH 是燦銀色.

#【國際牌NR-B427TG】422公升玻璃智慧節能變頻雙門冰箱 $24390 (yahoo)
尺寸 : 寬697*高1649*深759公分
年耗電量 : 360 度
耗電量(kW.h/月):32
能源因數 E.F. : 17.3

LG 樂金 315公升變頻雙門冰箱GN-L392W $18888

尺寸 : 寬600*高1690*深665公分
年耗電量 : 348 度
耗電量(kW.h/月):29
能源因數 E.F. : 12.9

# LG 樂金 414公升變頻負離子雙門冰箱GN-M562GP $22900 (Yahoo)

尺寸 : 寬75.5x高177.7x深70.7
年耗電量 : 360 度
耗電量(kW.h/月):30
能源因數 E.F. : 16.7

今晚特地去全國電子與燦坤, 但都沒看到上面這幾款, 打算明天去家樂福找找, 目前比較傾向 LG 414 公升與 Panasonic 435 公升這兩台, 因為能源因數有超過 16.

"選購效率高的電冰箱,電冰箱的效率以能源因數值(EF,ENERGY FACTOR)來表示,單位為公升/度/月,即每月消耗1度電所能使用的容積大小,EF值愈高愈省電。"

"選購冰箱可以掌握7:1:7的原則。第一個7是指家庭成員一人需要70公升容量,再來的1是指100公升的預備容量,最後的7是指70公升的冷凍空間容量。如果以一家五口的成員來說,350公升加上100公升的預備容量,還有70公升的冷凍空間,大約可以選購520公升以上的冰箱。買冰箱千萬寧大勿小,如果習慣堆積食物,常常把冰箱的滿滿的,也會影響到冰箱的使用效能。"

參考 :

冰箱購買準則- 採購絕招與E.F.節能因數值計算
電冰箱節能標章能源效率基準與標示方法

2015-12-09 補充 :

今天為了在 LG 與國際牌間抉擇, 特地對國際的 ECONAVI 調查, 原來這是有限制的, 須冷度設在 "中" 才有效 :

"eco navi要使用必須冷度在中的設定才可以, 如果調冷些就無法亮eco的綠燈. (說明書有載明,要設定在中,才會啟動Econavi)"

通常應該都是設在 "中", 所以沒差. 倒是下面這篇建議買國際, 因為它是台灣製, LG 我記得是印尼製. 目前傾向買 Panasonic NR-B486GV-DH, 公司福利社最便宜賣 22699 元, 福利金 8000 加節能補助 2000, 須自付 12699 元. 而 LG GN-M562GP 花之舞福利社賣 22800 元, 價格差不多, 但容量卻差了 71 公升 (冷凍差 2 公升, 主要差在冷藏室), 看來國際的 CP 值較高. LG 壓縮機保固十年是比較吸引我的, 國際保固則為五年, 是日系中最高的, 而且 ECONAVI 節能也是 LG 所無.

# 冰箱怎麼挑?

"如果預算只有兩三萬 那就是建議買Panasonic臺灣製的 (其他品牌或東南亞製機種通常不建議) 因為CP值 同樣價錢當然買省電的ECO NAVI省電機種 就不會去考慮其他比較耗電 容量也沒比較大的機種了"

"基本上我以Panasonic台灣製的為優先選擇, 因為日本製機種太貴, 要用省電賺回價差不知道要等多少年了... 除非有特殊需求"

2015年12月3日 星期四

Win 8.1 安裝 IIS 伺服器

今天收到資安單位來函要求將 IE 升版到 IE11, 以避免安全漏洞. 這給我出了個難題, 因為我的新版工作日誌系統還沒弄好, 而目前使用的舊系統只能在 IE9 以下跑, 升到 IE10 就會有問題 (編輯器 & 檔案上傳). 為今之計只有將舊系統改版應急才是上策. 舊系統使用 IIS+ASP+ACCESS 設計, 而我的電腦已經沒有一台有 IIS 伺服器, 只好上網搜尋安裝 IIS 的方法, 參考 :

如何在 Windows 8 安裝 IIS 8 ?
# 在 IIS 上建置傳統 ASP 網站

我的筆電是 WIN8.1, 所以就按圖索驥試試看, 安裝紀錄如下 :

首先按 Windows+Q 鍵, 在搜尋框內輸入 feature :


點選 "開啟或關閉 Windows 功能" :
勾選 Internet Information Service 以及 Web 管理工具下的項目如下 :


同時也選應用程式項下的 ASP 與 ISAPI 擴充程式 :


按確定就開始搜尋必要的檔案, 完成後就可以到 "控制台/系統管理工具", 點選 "Internet Information Services (IIS) 管理員", 點選左方 "連結" 面板中的 "站台", 可看到其預設網站繫結 :


由於我的筆電早已安裝 Apache+PHP+mySQL, HTTP 80 埠已經被 Apache 伺服器用了, 為了避免衝突, 必須將 IIS 的改為其他埠號, 例如 81. 在預設站台列上按滑鼠右鍵, 點選 "繫結" :


按編輯, 將 PORT 改為 81, 主機名稱設為 localhost :


然後點選 Default Web Site, 按滑鼠右鍵, 點選 "管理網站/啟動" 來啟動網站 :


這樣就完成 localhost 網站設定了, 打開瀏覽器連線 localhost:81 即可 :


這是 ASP 的預設站台, 如果要建立自己的網站, 先點選 "站台", 按滑鼠右鍵, 點選 "新增網站" :


在彈出選單中設定網站屬性 :


此處我將網站檔案放在 E:\myasp 下, 而且網站取名 myasp, 所以實體路徑只要填 E:\ 即可 (不要填 E:\myasp, 這樣 IIS 會以為是 E:\myasp\myasp), 我以為這樣就 OK 了, 就啟動 myasp 站台, 然後用瀏覽器連線 localhost:81/myasp 卻得到如下錯誤訊息 :

An error occurred on the server when processing the URL. Please contact the system administrator.
If you are the system administrator please click here to find out more about this error.


我在 "在IIS7中顯示ASP偵錯訊息" 這篇找到解法, 原來 IIS8 預設是關閉 ASP 的偵錯訊息的, 先點選 myasp 站台, 再點 ASP 按鈕 :


在選單的 "編譯/偵錯內容" 的 "將錯誤傳送到瀏覽器" 從 False 改為 True (同時也將伺服端與用戶端偵錯打開), 然後按右上角 "動作/套用" 即可 :


這時將 localhost:81/myasp 重新整理就會顯示錯誤訊息了 :

ADODB.Connection 錯誤 '800a0e7a'

找不到提供者。它可能未被正確安裝。

/myasp/sys_bin\access_adodb_connection_sys.asp, 行10


看起來是跟資料庫連線有關, 因為我的 myasp 架站系統採用 ACCESS 資料庫, 需使用 Microsoft.Jet.OLEDB.4.0 這個 32 位元程式來建立連線, 而 IIS 預設不執行 32 位元程式, 參考 :

ADODB.Connection 錯誤 '800a0e7a'

點選站台按滑鼠右鍵, 再點進階設定 :


將 "一般/啟用 32 位元應用程式" 改為 True 即可 :


如此這般, 再重新整理 localhost:81/myasp 就能看到 myasp 網站的畫面了 :


這個  12 年前開發的老骨董是我模仿當時很紅的 myPHPnuke 架站機用 JScript 寫的 ASP 版本, 我只是把 myPHPnuke 架好, 然後將主要的功能大略玩一遍, 了解其運作模式後就開工了, 也沒有去研究它是怎麼寫的 (還沒學 PHP, 看不懂). 那時最主要的目的是為了寫碩士論文, 因為蒐集了一堆文獻, 研讀之後需要做筆記, 為了在寫文獻回顧時搜尋方便, 就花了一個多月寫了這個 ASP 架站機, 畢業後就拿到公司用, 沒想到一用就超過十年了.

ASP 已經是很舊的技術了, 但因我對 .NET 一直無法認同, 所以也不想進階到 ASP.NET. 就算是 ASP 我也是用 Javascript 寫, 絕不用 VBScript.

其他參考 :

http://demos.telerik.com/kendo-ui/editor/index (HTML 編輯器)
網站無法執行 - 程序無法存取檔案

2015-12-04 補充 :

今天又發現一個 IIS 設定的問題, 因為 sys_bin 下的 include_programs_iis.asp 這個程式在含括應用程式檔案時會用到上層目錄 :

  case 'jlog' : {
%>       <!-- #include file="..\bin\jlog.asp" --><%
     break;}

所以進入應用程式時會出現下列錯誤 :

Active Server Pages 錯誤 'ASP 0131'
不允許的上層路徑
/myasp/sys_bin\include_programs_iis.asp, 行63
包含檔案 '..\bin\jlog.asp' 不能包含 '..' 來指出上層目錄。


這要在 ASP 中開啟上層目錄 :


注意, 在 "編譯/指令碼語言" 欄位我已將預設的 VBScript 改成 JScript, 因為我的 ASP 專案全部都是用 Javascript 寫的.

2015-12-08 (二) 補充 :

今天測試工作日誌的上傳功能時發現, IIS 8 跟以前 XP 時代的 IIS 6 不同之處是其 ASP 指令碼解譯欄位似乎只能在預設的 VBScript 與 JScript 中選一個填, 以前可以填兩個, 但現在不管填 JScript;VBScript 或 JScript, VBScript 都無法執行. 我的工作日誌全部用 JScript 寫, 唯獨檔案上傳處理程式使用了 VBScript, 這是從所買的 ASP 書裡面抄來的. 最後在下面這篇找到解法 :

Call a function written on VB from a JScript code (classic ASP)

原來只要在上傳處理程式 fupaction.asp 開頭加上下面這行即可 :

<%@ Language="VBScript" %>

此指令是強制伺服器改用 VBScript 解譯器來執行程式中的命令.