2019年1月30日 星期三

错误(opfparser):E20006

错误(opfparser):E20006: 有不止一个标题定义在opf的元数据。
但是没有一个标题将 "title-type" 重新定义为 "main" 标题。
欲了解更多信息,请参考
http://idpf.org/epub/30/spec/epub30-publications.html#sec-opf-dctitle

最近在轉電子書時,遇到上述錯誤
我猜大部份都是發生在書名有副標的情況

看了一下 content.opf 內容
應該是 dc:title 有 2 個 node 的緣故
可以移除一個

但正解應該是如下,我們以藤井樹的《這城市─B棟11樓第二部》此書為例

<dc:title id="t1">這城市</dc:title>
<meta refines="#t1" property="title-type">main</meta>

<dc:title id="t2">B棟11樓第二部</dc:title>
<meta refines="#t2" property="title-type">subtitle</meta>

2019年1月29日 星期二

ES7 Async performance 陷阱

在有了 Async / Await 的語法糖加持之後
感覺 Node.js 的世界突然美好了起來

終於可以用比較直覺的角度去寫程式
特別是那些習慣寫 C, Java, Python 等的人

但是在方便之餘
還是要特別小心 await 的使用情境
以避免造成效能上的問題

在下列例子中
testAsync1 會比 testAsync2 有更好的效能

因為在 testAsync1 中
我們會先用一個變數 promise2 去承接 Promise
此時,這個 Promise 裡面的操作有機會先執行
等到 await promise1 時,promise2 就差不多執行完畢 (秒數一樣)
故在 await promise2 時,promise2 應該就是一個 ready 的狀態 (ok or failed)

而在 testAsync2 中
因為我們少了那個中間變數
故在 await 時,至少一定要等待 3 秒

這就因此造成了 2 者間的差異

function getPromise() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            resolve('ok');
        }, 3000);
    });
}

async function testAsync1() {
    var date1 = new Date();

    var promise1 = getPromise();
    var promise2 = getPromise();

    var res;
    res = await promise1;
    res = await promise2;

    console.log(res, new Date() - date1);
    return Promise.resolve();
};

async function testAsync2() {
    var date1 = new Date();

    var res;
    res = await getPromise();
    res = await getPromise();

    console.log(res, new Date() - date1);
    return Promise.resolve();
};

testAsync1();
testAsync2();

執行結果如下

ok 3002
ok 6001

2019年1月28日 星期一

電子書硬體個人心得

這 2 個月以來
我在 Youtube 觀看的都是電子書相關的影片

即使已經拿到 Kindle Oasis2
我還是會不自覺的觀看相關開箱文

目前個人想像中的使用方式是
1. Kindle Oasis2 → Amazon.com 的英文書 (程式相關的)
2. Kindle Paperwhite3 → Amazon.cn 的簡體書
3. Onyx Boox Note Lite → 手上有的 PDF 文件 (程式相關的)

雖然很想購買 Onyx Boox Note Lite
但在冷靜思考後便覺得會浪費錢
(後記:後來還是敵不過心中的小惡魔買了)

先不提這台是否是目前最好的 Android 電子紙選擇

人的時間有限
即使下班後都在看書
這 3 台硬體能分配到的時間也是不多

重點是人在看書時只能 single thread

故用 2 台以上的硬體看書真的不是一個好主意

雖然不討厭 Kindle Oasis2
但我最喜歡的還是 Kindle Paperwhite3 拿在手上的感覺

如果可以重新選擇
我會選擇購買 Onyx Boox Note Lite 或是根本都不買

畢竟 Kindle Paperwhite3 上的書都還沒看完

google-auth-library:DEP007 解決方式

使用 nodemailer 只要幾行 code 就可以發送 email

不過如果是使用 gmail 當寄件者
你只有 2 個選擇

1. 降低 gmail security policy (有風險)
2. 使用 OAuth2

為了安全起見
我這裡是使用第 2 種方式

可參考 Nick Noarch 的 Sending Emails with Node.js Using SMTP, Gmail, and OAuth2

雖然照他的方式可以順利的寄發 email

但 googleapis 這個 module 在 refresh token 時會有以下警告

google-auth-library:DEP007
The `refreshAccessToken` method has been deprecated, and will be removed
in the 3.0 release of google-auth-library. Please use the `getRequestHeaders`
method instead.


試了一下應該這樣可以解決了

const oauth2Client = new OAuth2(clientID, clientSecret, redirectURL);
oauth2Client.setCredentials({refresh_token: refresh_token});

// old way
oauth2Client.refreshAccessToken().then((tokens) => {
    var token1 = tokens.credentials.access_token;  
});

// new way
oauth2Client.getRequestHeaders().then(header => {
    var patten = 'Bearer ';
    var token2 = header.Authorization.substring(patten.length);
});

自動發送電子書 email 到亞馬遜

亞馬遜有一個很棒的功能,你可以透過 email 將有支援的檔案寄到亞馬遜帳號﹝個人設置﹞,便可以在個人文檔中看到此電子書,理論上是跟 Amazon Drive 共用容量﹝5 GB﹞,但大陸亞馬遜似乎沒有連動?

底下是有支援的檔案格式:
Kindle格式(.MOBI、.AZW)
Microsoft Word(.DOC、.DOCX)
HTML(.HTML、.HTM)
RTF (.RTF)
文本(.TXT)
JPEG(.JPEG、.JPG)
GIF (.GIF)
PNG (.PNG)
BMP (.BMP)
PDF (.PDF)

既然身為一個程式設計師,寫程式自動發 email 應該是一件很合理的事。

個人用的是 Node.js﹝nodemailer﹞,這幾天在傳送時都一直遇到下列錯誤,"您发送至Kindle的邮件未附任何文件附件"。

原本以為是類似編碼等設定沒有設定好,但在下載了郵件原始檔後也看不出任何異狀。

後來靈機一動,想說會不會是沒有郵件本文的原因,就隨便插了一段空白區塊,果然就成功了。注意不能是空字串,之前就是用空字串才有問題。

底下是我目前的設定,提供給有需要的人參考。

var user = config.gmail.user;
var clientID = config.gmail.clientID;
var clientSecret = config.gmail.clientSecret;
var redirectURL = config.gmail.redirectURL;
var refresh_token = config.gmail.refresh_token;

var amazonEmail = config.amazonEmail;

const smtpTransport = nodemailer.createTransport({
    service: "gmail",
    auth: {
        type: "OAuth2",
        user: user,
        clientId: clientID,
        clientSecret: clientSecret,
        refreshToken: refresh_token,
        accessToken: accessToken
    }
});

const mailOptions = {
    from: user,
    to: amazonEmail,
    subject: "Convert",
    attachments: attachments,
    generateTextFromHTML: true,
    html: "<div></div>"
};

smtpTransport.sendMail(mailOptions, (error, response) => {
    if (error) return reject(error);
    smtpTransport.close();

    resolve(response);
});

2019年1月25日 星期五

grep 小技巧

目前因為測試
故手上有好幾千筆的開機資料

正常情況下只要 parse 一次即可
故時間還可以接受

但是如果要測試 Server 的功能時
這幾千筆的資料便會拖慢測試速度

grep 有一個參數可以方便我們擷取前幾筆的資料
這樣一來就可以產生出可供人工使用的測試資料了
輸出控制:
  -m, --max-count=NUM       在達到 NUM 符合項目後停止

Usage:
grep ".*" --text -m 30000 Reboot.log > test.log

2019年1月22日 星期二

樂天電子書使用 kindlegen 轉檔

有些直排的電子書經過 calibre 轉換後會變成橫排,網路上說是因為 calibre 會去修改 css 樣式,故較好的方式是使用 Kindle 的 kindlegen command line tool 轉換。

據實測的結果,真的可以順利呈現直排中文。

不過樂天的電子書似乎在 XHTML 檔有些問題﹝只試過一本﹞,可以使用以下步驟修正。

1. 取得 DRM-Free 後的 epub 檔案,請參考其他網路文章。
2. 改副檔名為 zip 並解壓縮。
3. 修改 OEBPS\*.xhtml ,手動在檔案前面加上下列文字。

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html>

2019/05/30 更新
有些書轉完後在 Kindle 看會變亂碼,經實測也是加入上面 2 行就可以恢復正常。

2019年1月18日 星期五

AI 3 要素

大數據,演算法,計算力

相關運用
大數據:資料收集,資料庫 (SQL, NoSQL)
演算法:現成框架、模型 (Tensorflow, Caffe, CNTK, PaddlePaddle)
計算力:CPU, GPU, TPU, FPGA


2019年1月11日 星期五

八陣圖

功蓋三分國,名成八陣圖
江流石不轉,遺恨失吞吳



2019年1月10日 星期四

電子書比價

今天心血來潮想要比較一下之前買的書在 3 家的售價
居然 Google 是最便宜的
果然是家大業大

之前是為了測試讀墨才在讀墨購買
故還需要另外申請帳號
(理論上應該也可以用 Google 但是他沒放在註冊頁面)

看來以後直接以 Google 為主好了

樂天可以用 Google 帳號綁定,不用申請帳號
其他網站也有使用類似的技術

真心覺得 Google 應該要針對帳號收月費
不然哪天 Google 倒了就不能用了
拜託再撐個 20 年就好

反正等我老了我應該也不想用電腦
但是 Kindle 看書還是一定要的呀

人生只需要 2 個帳號
Google and Amazon