2017年12月14日 星期四

Startup pm2 command for Windows Server 2012 R2


需在 windows server 重新啟動的時候,
自動執行 pm2 start someapp.js,
pm2 有 startup command 提供此機制,但不支援 windows,
以下是 worked solution


The following is my latest solution which works really well:
  • create a specific Windows user for running node scripts
  • login as that user and npm install pm2 -g
  • pm2 start all the apps I would like to have startup
  • pm2 save to save the current process list
  • create a .bat file and within it paste the following commands:
@echo off
set HOMEDRIVE=C:
set HOMEPATH=\Users\%USERNAME%
set path=C:\Users\%USERNAME%\AppData\Roaming\npm;%path%
pm2 delete all & pm2 resurrect

Use Windows Task Scheduler to create a task that:
  • runs "whether user is logged on or not"
  • is Triggered "At startup"
  • is configured to run the .bat file that we created


2017年11月7日 星期二

How to enable hardware virtualization on a MacBook?

開發環境在 Mac 上的 windows 10 Home
需要啟用 virtualization ,
可是硬體本身有支援,卻沒有啟用 virtualization,
但是該如何啟用呢?
方式如下:

How to enable virtualization in Boot Camp.
  1. holding the option key on startup, boot in to OS X. 
  2. Then go to System Preferences 
  3. Startup Disk and choose your Boot Camp partition
  4. The computer will restart and boot into Windows, with virtualization enabled.

OK! 附張成功的圖紀念一下!

2017年11月1日 星期三

Error: The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.

使用 LinqToExcel 突然發生 error,原來是安裝 windows update 後,發生的慘案
Error: The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine.

解決方案如下:

1. uninstall KB4041676 on Windows 10 and KB4041681 on Windows 7.

2. Find prior version (4.0.9801.0) of msexcl40.dll

3. Place in another directory. They suggest the application directory, but since in the next step you will modify registry to point to this older version, it can probably go anywhere.

4. Update registry key HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Jet\4.0\Engines\Excel\win32 to point to the location from step 2.

但此招是救急,可能有安全性的疑慮!

2017年10月16日 星期一

query pagination data with mongoose


目前透過 mongoose 查詢 pagination 資料覺得很麻煩,
先取得 total count 再取 page data,
目前使用的方式如下:

    user
        .find(where)
        .count()
        .then((totalCount) => {
            if (totalCount && totalCount > 0) {
                return user.find(where)
                    .select('field1 field2 field3 filed4')
                    .sort({ createdOn: -1 })
                    .skip(skip)
                    .limit(limit)
                    .exec()
                    .then((rows) => {
                        return {
                          rows:rows
                          totalCount: totalCount
                    });
            } else {
                 return res.status(200)
                        .json({
                         rows: [],
                         skip: skip,
                         limit: limit,
                         totalCount: 0
                        })
                        .end();
            }
        })
        .then((result) => {
                 return res.status(200)
                        .json({
                         rows: result.rows,
                         skip: skip,
                         limit: limit,
                         totalCount: result.totalCount
                        })
                        .end();
        })
        .catch((err) => {
            next(err);
        });

寫得落落長,太麻煩了,花了一些時間查查,有沒有什麼方便的方式
原來 mongoose 有 pagination plugin 可以用,真的是佛心來的,
使用方式如下:

Installation:
npm install mongoose-paginate

Usage:
var mongoose         = require('mongoose');
var mongoosePaginate = require('mongoose-paginate');
 
var schema = new mongoose.Schema({ /* schema definition */ });
schema.plugin(mongoosePaginate);
 
var Model = mongoose.model('Model',  schema); // Model.paginate() 

Model.paginate([query], [options], [callback])

所以上面的範例可以改成:
var where   = {};
var options = {
    select:   'field1 field2 field3 filed4',
    sort:     { createdOn: -1 },
    lean:     true,
    offset:   20, 
    limit:    10
};
user.paginate(where, options).then(function(result) {
    return res.status(200)
                        .json({
                         rows: result.docs,
                         skip: skip,
                         limit: limit,
                         totalCount: result.total
                        })
                        .end()
});

太好了,是不是簡單很多!

reference:https://www.npmjs.com/package/mongoose-paginate

Avoiding Callback Hell in Node.js - Promise


寫 nodejs 就會用到非同步的 callback
就會碰到所謂的「callback hell」的囧境
什麼是 callback hell? 如下所示:

doSomeAsyncFunc(function () {
  doSomeAsyncFunc(function () {
    doSomeAsyncFunc(function () {
      doSomeAsyncFunc(function () {
        doSomeAsyncFunc(function () {
          doSomeAsyncFunc(function () {
            doSomeAsyncFunc(function () {
              doSomeAsyncFunc(function () {
                doSomeAsyncFunc(function () {
                  // 我到底在第幾層地獄啊!?
              })
            })
          })
        })
      })
    })
  })
})



這樣光要看懂就很辛苦了,還要怎麼維護程式碼呢?

有幾種解決方式:

  1. async.waterfall
  2. promise
  3. async/await

上一篇介紹了 async.waterfall,現在來看看 Promise 如何使用

1. 先將 doSomeAsyncFunc 包裝成 promise 物件
doSomeAsyncFunc(function () {
  return new Promise(function(resolve, reject) {
    // do something, possibly async
    if (/* everythings fine */) {
      resolve(result);
    } else {
      reject(err);
    }
  });
}

2. 使用 primise.then 即可攤平 callback hell

var promise = doSomeAsyncFunc();
promise.then((result) => {
  // get result
  return '2';
}).then((result2) => {
  // get result2 ('2')
  return '3';
}).then((result3) => {
  // get result3 ('3')
}).catch((err) => {
  // error handling
});

3. 所以一開始的範例就可以改成:

var promise = doSomeAsyncFunc();
promise.then((result) => {
  // do something
  return doSomeAsyncFunc();
}).then((result) => {
  // do something
  return doSomeAsyncFunc();
}).then((result) => {
  // do something
  return doSomeAsyncFunc();
}).then((result) => {
  // do something
  return doSomeAsyncFunc();
}).then((result) => {
  // do something
  return doSomeAsyncFunc();
}).catch((err) => {
  // error handling
});

這樣就可以攤平可怕的 callback hell,回到地球表面囉!

2017年9月26日 星期二

Avoiding Callback Hell in Node.js - async.waterfall


寫 nodejs 就會用到非同步的 callback
就會碰到所謂的「callback hell」的囧境
什麼是 callback hell? 如下所示:

doSomeAsyncFunc(function () {
  doSomeAsyncFunc(function () {
    doSomeAsyncFunc(function () {
      doSomeAsyncFunc(function () {
        doSomeAsyncFunc(function () {
          doSomeAsyncFunc(function () {
            doSomeAsyncFunc(function () {
              doSomeAsyncFunc(function () {
                doSomeAsyncFunc(function () {
                  // 我到底在第幾層地獄啊!?
              })
            })
          })
        })
      })
    })
  })
})


這樣光要看懂就很辛苦了,還要怎麼維護程式碼呢?

有幾種解決方式:

  1. async.waterfall
  2. promise
  3. async/await


先來看看 async.waterfall 如何解決問題

步驟如下:

1. 先安裝 async package :   $ npm install --save async

2. import async package :   var async = require("async");

3. waterfall(tasks, callback) 的說明:

Runs the tasks array of functions in series, each passing their results to the next in the array. However, if any of the tasks pass an error to their own callback, the next function is not executed, and the main callback is immediately called with the error.

簡單來說,只要 error 的參數是 null ,就會一直往下丟 callback,
若中途呼叫 callback 且 error 參數不為 null ,則直接進入 mail callback

範例:
async.waterfall([
    function(callback) {
        callback(null, 'one', 'two');
    },
    function(arg1, arg2, callback) {
        // arg1 now equals 'one' and arg2 now equals 'two'
        callback(null, 'three');
    },
    function(arg1, callback) {
        // arg1 now equals 'three'
        callback(null, 'done');
    }
], function (err, result) {
    // result now equals 'done'
});

也就是說,一開始的 callback hell sample 可以改成:
async.waterfall([
    function(callback) {
        doSomeAsyncFunc1(function (error, result) {
            callback(error, result);
        });
    },
    function(callback) {
        doSomeAsyncFunc2(function (error, result) {
            callback(error, result);
        });
    },
    function(callback) {
        doSomeAsyncFunc3(function (error, result) {
            callback(error, result);
        });
    }
    ......
], function (err, result) {
    // main callback 
    if (err) {
        // do something
    } else if {
        // do something
    }
});

這樣就可以攤平可怕的 callback hell,回到地球表面囉!

reference: https://caolan.github.io/async/docs.html#waterfall

2017年8月9日 星期三

MySQl Error: Data too long for text column


近期站台在塞資料時,
 MySQL 拋出以下錯誤:

Error Message:
Data too long for column 'xxxx' at row 1

發現要塞 80k 資料進 text 型別的欄位失敗了!
看來是跟 MSSQL 的設計不同 ( 我是從 MSSQL 遷徙過來的 )
為了得到正確的觀念,查了一下 MySQL TEXT 欄位的定義
原來 MySQL 還有對 Text 再做細分,如下:

      Type | Maximum length
-----------+-------------------------------------
  TINYTEXT |           255 (2 8−1) bytes
      TEXT |        65,535 (216−1) bytes = 64 KiB
MEDIUMTEXT |    16,777,215 (224−1) bytes = 16 MiB
  LONGTEXT | 4,294,967,295 (232−1) bytes =  4 GiB

以後要用 TEXT 欄位,還是要多注意實際情況選擇正確的型別囉!

2017年8月8日 星期二

讀書心得:如何設計好網站


近期一直困擾著什麼樣的操作方式對 user 才是好的,

之前一直覺得好不好用應該問使用者,
請使用者提出一些意見或想法,
但使用者幾乎不可能提出什麼好的想法,
亨利福特曾說:如果當年去問顧客要什麼,他們肯定會回答我:給我一匹更快的馬

所以找看看有沒有什麼幫助的書,
找到了這本覺得不錯,分享給各位

書名:如何設計好網站:Dont Make Me Think
ISBN:9789863750086


簡單分享一下心得:

  1. 別讓 user 動腦去想
    • 這絕對也是最重要的易用性規則,不用動腦就知道怎麼用,就對了
  2. 使用者看網頁,是用掃視、矇著用的
    • 使用者上網站,大致掃一遍網頁,看到有興趣的就點進去,不會從頭到尾看完的
  3. 省略不必要的贅字
    • 作者建議一段文字,先篩選掉 1/3 後,再篩選掉 1/3,這樣就差不多了
  4. 麵包屑很重要,讓 user 知道人在何處
  5. 每頁都應該有固定的地方,可以回到首頁
    • 如:左上方的 logo,當user迷路時,可以有重新開始的機會
  6. 易用性測試
    1. 場地:二間會議室
    2. 參與人員:受測者,陪測者,觀測者
      1. 受測者,作者建議不要找相關領域,因為是不是相關領域根本不重要,
      2. 專家級的使用者,不會介意多幾個清楚的說明
    3. 週期:一個月一次
      1. 如:每月第四週星期三上午
    4. 什麼時候開始測?
      1. 開發前就可以開始測
      2. 建立簡單的雛型就可以測
      3. 沒有雛型,那就測競爭對手的網站
    5. 情境:
      1. 聘請相關或不相關領域的受測者,進行功能操作,
        會有一名陪測員說明系統及測試的任務,如:建立版型,版型發佈等等,
      2. 陪測員不能刻意引導受測者
      3. 受者測操作時,需大聲說出目前的想法,如:怎麼這麼難用!
      4. 在測試的 pc 上安裝螢幕分享軟體(含使用者的聲音、滑鼠位置等等),
        同步給另一間會議室的主管、RD相關人等觀察
      5. 觀察者在觀察時,同步記綠發現的問題,並將紀錄到的問題排列優先順序( 投票等等 ),
        ps:可能會有異想不到的發現喔!
      6. 處理的問題量及難度,要可以在下次測試前改完,不可太多
  7. 利用易用性測試,擺脫討論不完的爭論
    • 例如:在勾選某類型資料時,要使用下拉選單還是 checkbox list,
    • 這種每個人都有不同的經驗及偏好,這是爭論不完又浪費時間的;


當然還有其他細節我沒有提到,有興趣的話,可以看看這本書囉!

2017年8月2日 星期三

Gmail Error handling: 5.5.1 Authentication Required


透過 Gmail SMTP 發信,卻遇到以下錯誤訊息:

Gmail Error :The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required

原因:
因為 google 會檢查帳戶平時的使用狀態並做一些保護機制,平時登入地點是在固定地方,但若今天帳戶要設定在 VM 上,而 VM 在別的區域,那 google 會判定帳戶有風險,於是會鎖住登入的那台 server,並拋出這個 exception

解決方式:
在被鎖住的 server ,透過網頁登入 gmail,此時 gmail 會問你一些安全性問題,進行設定後,即可正常收發信件了!

reference: https://stackoverflow.com/questions/20906077/gmail-error-the-smtp-server-requires-a-secure-connection-or-the-client-was-not


2017年6月5日 星期一

IoT Platform Protocol



最近整理了一下,
各IoT平台會用到的 protocol,
看起來 MQTT 已被每個平台拿來使用,
要走 IoT 這塊,MQTT 已是必學的技術了!


Azure
  • AMQP
  • MQTT
  • HTTP
  • MQTT over WebSocket
  • AMQP over WebSocket
AWS
  • MQTT
  • WebSocket
  • HTTP
Google Cloud
  • MQTT
  • HTTP
IBM's Watson IoT Platform
  • MQTT, 
  • HTTP
中華電信智慧聯網平台
  • MQTT, 
  • WebSocket 
  •  HTTP



2017年3月3日 星期五

Renaming web site in IIS


遇到實務上的需求,
先架設測試站台 ( TestWebSite ),
確認無誤後需要轉換正式站台 ( ProdctionWebSite ),
但是.....
在 IIS 下,web site 如何更名?


在一番搜尋及實驗後,使用 appcmd 可以滿足此需求
步驟:

  1. 開啟 command 進入此路徑:
    C:\Windows\SysWOW64\inetsrv
  2. 輸入 appcmd list app :會列出目前 IIS 上的 WebSite
    appcmd list app
    
    APP "Default Web Site/" (applicationPool:DefaultAppPool)
    APP "Default Web Site/production1" (applicationPool:mypool)
    APP "Default Web Site/test1" (applicationPool:mypool)
  3. 輸入 appcmd set app [app name] -path [new name]
    appcmd set app "Default Web Site/production1" -path:/oldproduction
    appcmd set app "Default Web Site/test1" -path:/production1
  4. 輸入 appcmd list app,確認修改結果
    appcmd list app
    
    APP "Default Web Site/" (applicationPool:DefaultAppPool)
    APP "Default Web Site/oldproduction" (applicationPool:mypool)
    APP "Default Web Site/production1" (applicationPool:mypool)

參考:http://stackoverflow.com/questions/5687057/renaming-applications-in-iis-7-0


2017年1月26日 星期四

Angular2-RC4 animate error


執行 angular2 RC4 版本的 web,之前都正常,
近日突然發生以下錯誤訊息,導致網頁無法正常執行∶

EXCEPTION: Error during instantiation of AnimationDriver! (ViewUtils -> RootRenderer -> DomRootRenderer -> AnimationDriver

執行環境是 firefox ,我的版本是 50.1 (隨時在更新),
剛好同事有較舊本的 firefox ,測試正常,更新後即發生一樣的錯誤狀況,

只好請出 google 找辦法,
( 不要問我為什麼不升級 QQ )
還好有人遇到類似的問題,

將 html 引用 <script...></script> 通通放到 </body> 的上面,就解決了,過關!!

參考∶ JSPM Angular2-rc2 build animate error

visual studio code debug for nodejs + express + consign


撰寫 nodejs 在 visual studio code 進行 debug,
可以參考∶ Node.js Applications with VS Code
簡單來說會在專案根目錄新增 .vscode 資料夾,再新增 launch.js 檔
並在 configurations/program 指定起啟程式,即可進行斷點除錯,如下圖

環境說明∶
  • 關於 express server 端的程式碼皆放在「根目錄/api/」下
  • 起啟的 js 檔放在「根目錄/api/index_debug.js」
  • 其中使用 consign 指定載入順序,讓網站可正常執行,
    如∶ config file -> db -> authority -> routing -> ....... -> start server 
問題∶
在 api 資料夾直接下 command : $node index_debug.js 可正常執行,
但是直接在 visual studio code 執行 debug 卻什麼事情也沒發生,斷點也沒有反應,

































solution:
查了一下 consign 文件,verbose 設為 false 會關掉 log,導致發生什麼事都不知道,
verbose 設為 true 後,即可發現是因為路徑問題導致


只要指定好起啟目錄即可,將 cwd 設為 api 就解決囉! 如下圖



這樣就可以開心使用 visual studio code debug 功能囉!
終於讓開發能更有效率,不然班加不完啊!