2022年6月8日 星期三

樊登說書

圖:樊登說書 實體勳章 非同凡響

約莫 2021 春天起入坑,接著靠運動時期清書,應該沒八個月規律地刷完一遍,不到四百本書,正在進行複習第二遍,未來就進入每週聽一本書,然後沒啥 podcast 想聽時,繼續挑有興趣的來複習。

從樊登說書的熱門書籍清起,可以很清楚地看到 TA 已經是親子學習為主、商業工具書為輔,但無論如何,都仍是人性議題,帶團隊跟養小孩都還是相互呼應的,稱不上衝突。例如如何鼓勵員工往前邁進,等同於鼓勵小孩如何進步一樣。

我以前也覺得網路上有很多文料,舉凡工作技術文、親子、科普等,認為不需要翻書了,直到被大學室友提醒:片段的文章,跟從頭到尾的書籍,還是有很大的不一樣。現代人的習性也慢慢被切割成只能閱讀零碎的片段。

樊登說書其實厲害的就樊登一人,自己打通任督二脈,以論語中庸當內力,在吸取中內外的書籍,的確如他所言,這個事業搞起來後,自己受益最大,也開始慢跑健身少吃麵食,也持續享受著看書、講書的興趣,推掉不必要聚會,並精實的呼應著讓人一年讀 52本書,另外,也朝向不吃光用戶眼光跟時間,吸收完知識後,關掉 app 去做正經事。其實看一個人功力強不強,就像看廚師炒飯一樣,一本經典書籍內容那麼充沛,有幾位網紅可以好好用 30 分鐘介紹一本書?又有幾位網紅可以串起各類書籍,並且前後呼應而不是自相矛盾?

回顧起 2021 年接觸的 app ,應當就這 app 受益最大。從商務工具書,提醒自己溝通時要著重事實的呈述而非情緒,親子相處時,要多留點時間給小孩,不只陪伴,還包括等待小孩成長。我想,我還是會繼續複習完成二刷吧


樊登說書 熱門書籍 Top 100 清單(說書時間、書名):

2017-03-18 正面管教

2016-07-30 非暴力沟通

2017-04-08 亲密关系

2018-04-28 终身成长

2019-03-30 逆商

2018-12-15 父母的语言

2016-11-19 刻意练习

2015-10-24 关键对话

2017-12-09 可复制的领导力

2017-10-07 高效能人士的七个习惯

2017-01-07 如何让你爱的人爱上你

2018-06-09 即兴演讲

2017-05-20 自卑与超越

2016-01-01 如何培养孩子的社会能力

2019-03-02 应对焦虑

2018-10-27 活好

2013-12-03 你就是孩子最好的玩具

2019-06-01 不管教的勇气

2019-07-20 掌控习惯

2016-12-10 不吼不叫

2016-07-16 如何说孩子才会听,怎么听孩子才肯说

2019-01-12 感受爱

2015-09-18 幸福的婚姻

2018-11-03 认知天性

2020-04-18 陪孩子终身成长

2016-10-15 销售就是要玩转情商

2019-10-12 不妥协的谈判

2019-03-16 列奥纳多·达·芬奇传

2020-01-04 我们都曾受过伤,却有了更好的人生

2019-04-06 能力陷阱

2021-07-10 人生只有一件事

2019-06-15 自尊

2019-08-03 事实

2019-11-09 被忽视的孩子

2018-03-03 他人的力量

2019-04-27 低风险创业

2019-06-08 高效休息法

2020-02-29 思维的囚徒

2019-02-16 用事实说话

2019-05-04 坚毅

2020-09-19 自驱型成长

2020-09-26 活出心花怒放的人生

2018-12-08 思辨与立场

2013-11-25 幸福的方法

2016-02-04 我的情绪为何总被他人左右

2020-09-12 洞见

2018-01-06 反脆弱

2019-05-11 原生家庭

2018-07-07 活法

2019-08-31 解码青春期

2014-01-04 第3选择

2020-02-08 爱、金钱和孩子

2020-04-11 意志力

2018-10-13 掌控谈话

2018-10-06 运动改造大脑

2019-08-17 顾客为什么购买

2021-09-11 心态

2019-11-23 孔子传

2017-11-18 思考,快与慢

2019-04-20 世界观

2020-05-23 斯坦福高效睡眠法

2016-03-26 干法

2016-06-25 你要如何衡量你的人生

2018-08-11 热锅上的家庭

2015-07-03 次第花开

2021-05-22 解惑:心智模式决定你的一生

2018-09-22 一平方米的静心

2020-08-08 陌生人效应

2019-07-13 学会吃饭

2020-09-05 曾国藩的正面与侧面

2019-08-10 身为职场女性

2020-06-20 与内心的恐惧对话

2017-08-05 少有人走的路

2019-12-14 幸福的陷阱

2019-03-23 欲罢不能

2016-12-03 销售洗脑

2019-07-27 道德经说什么

2018-12-01 苏东坡传

2019-03-09 你要的是幸福,还是对错

2019-04-13 掌控

2021-04-17 你好,小孩

2020-11-28 内在动机:自主掌控人生的力量

2018-11-10 扫除道

2015-02-06 叛逆不是孩子的错

2021-05-15 考试脑科学

2018-01-27 深度工作

2018-03-24 心流

2021-04-24 如何克服社交焦虑

2019-02-23 高能量姿势

2019-09-07 分手后,成为更好的自己

2014-03-14 管理十诫

2021-03-20 幸福关系的7段旅程

2016-05-06 养育女孩

2020-07-25 学习的格局

2015-12-12 瞬变

2019-11-16 你为什么不道歉

2017-12-02 恰如其分的自尊

2017-01-21 王阳明哲学

2020-03-28 弹性

2019-05-18 有限与无限的游戏

2022年5月30日 星期一

Go 開發筆記 - 使用 Regular Expression / Regex / Re

網路上還滿多教學以及文件,其中官方文件 pkg.go.dev/regexp 滿清楚的。也有看到一篇許多人推的 github.com/StefanSchroeder/Golang-Regex-Tutorial ,有中英文。

在此把一些語法筆記一下,方便自己未來快速回憶。

使用筆記:
  • 有兩種 Regular Expression 實現方式 ,其中有 POSIX 關鍵字是 POSIX ERE (egrep) 語法跟效果。
  • 初始化有 Compile 跟 MustCompile (對應的是 CompilePOSIX 和 MustCompilePOSIX) ,其中有 Must 字眼是驗證語法錯誤時,會進入 panics 狀態
使用範例:

% cat main.go
package main

// https://pkg.go.dev/regexp
// https://pkg.go.dev/regexp/syntax

import (
    "fmt"
    "regexp"
)

func main() {
    input := `
<html>
    <head>
        <title>study golang</title>
    </head>
    <body>
        <ul>
            <li>changyy.org</li>
            <li>1234567890</li>
            <li>abcdefg</li>
            <li>abcdefgABCDEFG</li>
            <li>abcdef1234567890gABCDEFG</li>
        </ul>
    </body>
</html>`

    // Style 1: regexp.Match
    {
        matched, err := regexp.Match(`<[A-Za-z]+>(.*?)</[A-Za-z]+>`, []byte(input))
        if err != nil {
            fmt.Println("Style 1 - regexp.Match error:", err)
        } else {
            fmt.Println("Style 1 - regexp.Match: ", matched)
        }
    }

    // Style 2: regexp.Compile + obj.MatchString
    // https://pkg.go.dev/regexp#Regexp.MatchString
    {
        obj, err := regexp.Compile(`<[A-Za-z]+>(.*?)</[A-Za-z]+>`)
        if err != nil {
            fmt.Println("regexp.Compile error:", err)
        } else {
            fmt.Println("Style 2 - case 1: ", obj.MatchString(`<title>Hello World</title>`))
            fmt.Println("Style 2 - case 2: ", obj.MatchString(input))
        }
    }

    // Style 3: regexp.MustCompile + obj.MatchString
    // https://pkg.go.dev/regexp#Regexp.MatchString
    {
        pattern := `<[A-Za-z]+>(.*?)</[A-Za-z]+>`
        obj := regexp.MustCompile(pattern)
        fmt.Println("Style 3 - case 1: ", obj.MatchString(`<title>Hello World</title>`))
        fmt.Println("Style 3 - case 2: ", obj.MatchString(input))
    }

    // Style 4: obj.FindString
    // https://pkg.go.dev/regexp#Regexp.FindString
    {
        pattern := `<[A-Za-z]+>(.*?)</[A-Za-z]+>`
        obj := regexp.MustCompile(pattern)
        fmt.Println("Style 4 - case 1: ", obj.FindString(`<title>Hello World</title>`))
        fmt.Println("Style 4 - case 2: ", obj.FindString(input))
    }

    // Style 5: obj.FindAllString , obj.FindAllStringIndex
    // https://pkg.go.dev/regexp#Regexp.FindAllString
    // https://pkg.go.dev/regexp#Regexp.FindAllStringIndex
    {
        pattern := `<[A-Za-z]+>(.*?)</[A-Za-z]+>`
        obj := regexp.MustCompile(pattern)
        fmt.Println("Style 5 - case 1: ", obj.FindAllString(`<title>Hello World</title>`, -1))
        fmt.Println("Style 5 - case 2: ", obj.FindAllString(input, -1))
        fmt.Println("Style 5 - case 3: ", obj.FindAllStringIndex(`<title>Hello World</title>`, -1))
        fmt.Println("Style 5 - case 4: ", obj.FindAllStringIndex(input, -1))
    }

    // Style 6: obj.FindStringSubmatch , obj.FindStringSubmatchIndex
    // https://pkg.go.dev/regexp#Regexp.FindStringSubmatch
    // https://pkg.go.dev/regexp#Regexp.FindStringSubmatchIndex
    {
        pattern := `<[A-Za-z]+>(.*?)</[A-Za-z]+>`
        obj := regexp.MustCompile(pattern)
        fmt.Println("Style 6 - case 1: ", obj.FindStringSubmatch(`<title>Hello World</title>`))
        fmt.Println("Style 6 - case 2: ", obj.FindStringSubmatch(input))
        fmt.Println("Style 6 - case 3: ", obj.FindStringSubmatchIndex(`<title>Hello World</title>`))
        fmt.Println("Style 6 - case 4: ", obj.FindStringSubmatchIndex(input))
    }

    // Style 7: obj.ReplaceAllString
    // https://pkg.go.dev/regexp#Regexp.ReplaceAllString
    {
        pattern := `<[A-Za-z]+>(.*?)</[A-Za-z]+>`
        obj := regexp.MustCompile(pattern)
        fmt.Println("Style 7 - case 1: ", obj.ReplaceAllString(`<title>Hello World</title>`, "A"))
        fmt.Println("Style 7 - case 2: ", obj.ReplaceAllString(input, "B"))
    }

    // Style 8: obj.Split
    // https://pkg.go.dev/regexp#Regexp.Split
    {
        pattern := `<[A-Za-z]+>(.*?)</[A-Za-z]+>`
        obj := regexp.MustCompile(pattern)
        fmt.Println("Style 8 - case 1: ", len(obj.Split(`<title>Hello World</title>`, -1)))
        fmt.Println("Style 8 - case 2: ", len(obj.Split(input, -1)))
    }

    // Style 9: obj.Longest()
    // https://pkg.go.dev/regexp#Regexp.FindString
    // https://pkg.go.dev/regexp#Regexp.Longest
    {
        pattern := `a(|b)`
        obj := regexp.MustCompile(pattern)
        fmt.Println("Style 9 - case 1: ", obj.FindString(`abb`))
        obj.Longest()
        fmt.Println("Style 9 - case 2: ", obj.FindString(`abb`))
    }
}

% go run main.go 
Style 1 - regexp.Match:  true
Style 2 - case 1:  true
Style 2 - case 2:  true
Style 3 - case 1:  true
Style 3 - case 2:  true
Style 4 - case 1:  <title>Hello World</title>
Style 4 - case 2:  <title>study golang</title>
Style 5 - case 1:  [<title>Hello World</title>]
Style 5 - case 2:  [<title>study golang</title> <li>changyy.org</li> <li>1234567890</li> <li>abcdefg</li> <li>abcdefgABCDEFG</li> <li>abcdef1234567890gABCDEFG</li>]
Style 5 - case 3:  [[0 26]]
Style 5 - case 4:  [[27 54] [103 123] [136 155] [168 184] [197 220] [233 266]]
Style 6 - case 1:  [<title>Hello World</title> Hello World]
Style 6 - case 2:  [<title>study golang</title> study golang]
Style 6 - case 3:  [0 26 7 18]
Style 6 - case 4:  [27 54 34 46]
Style 7 - case 1:  A
Style 7 - case 2:  
<html>
    <head>
        B
    </head>
    <body>
        <ul>
            B
            B
            B
            B
            B
        </ul>
    </body>
</html>
Style 8 - case 1:  2
Style 8 - case 2:  7
Style 9 - case 1:  a
Style 9 - case 2:  ab

2022年5月26日 星期四

Go 開發筆記 - 使用 database/sql 通用介面存取資料庫,以 SQLite3 為例

在 Golang 的世界,有定義資料庫存取的通用介面 database/sql ,但貌似官方沒有提供實作而是讓廣大的鄉民開發,並且標記哪些套件是有通過 go-sql-test 驗證的,因此,大部分就是挑哪些有標記的,或是直接看 github 有多熱門也行。

相關文件:
以下就連續動作,筆記一下。

程式碼:

package main

import (
    "log"
    "database/sql"
    _ "github.com/mattn/go-sqlite3"
)

func main() {
    db, err := sql.Open("sqlite3", "/tmp/sqlite3.db")
    if err != nil {
        log.Fatalln(err)
    }
    defer db.Close()

    //
    // http://go-database-sql.org/modifying.html
    //
    // via db.Exec with checking the error message only
    if _, err := db.Exec(`
        CREATE TABLE IF NOT EXISTS account (
            uid INTEGER PRIMARY KEY AUTOINCREMENT,
            username VARCHAR(64) NULL
        );
    `); err != nil {
        log.Println(err)
    }

    // Insert via db.Prepare
    if stmt, err := db.Prepare("INSERT INTO account(username) VALUES(?)"); err == nil {
        if res, err := stmt.Exec("changyy.org"); err != nil {
            log.Println("Insert Exec Error:", err)
        } else if lastId, err := res.LastInsertId() ; err != nil {
            log.Println("Get LastInsertId Error:", err)
        } else if rowCount, err := res.RowsAffected() ; err != nil {
            log.Println("Get RowsAffected Error:", err)
        } else {
            log.Println("Insert Done, Last Insert Id:", lastId, ", RowsAffected: ", rowCount)

            // Update via db.Prepare
            if stmt, err := db.Prepare("UPDATE account SET username = ? WHERE uid = ?"); err != nil {
                log.Println("Update Prepqre Error:", err)
            } else if res, err := stmt.Exec("blog.changyy.org", lastId); err != nil {
                log.Println("Update Exec Error:", err)
            } else if rowCount, err := res.RowsAffected() ; err != nil {
                log.Println("Get RowsAffected Error:", err)
            } else {
                log.Println("Update RowsAffected: ", rowCount)
            }
        }
    } else {
        log.Println("Prepqre Insert Error:", err)
    }

    //
    // http://go-database-sql.org/retrieving.html
    // https://pkg.go.dev/database/sql#DB.Query
    //
    // via db.Query with sql.Rows and error mesasge
    rows, err := db.Query("SELECT * FROM account")
    if err != nil {
        log.Println(err)
    } else {
        defer rows.Close()
        log.Println("Result:")
        for rows.Next() {
            var id int
            var username string
            if err := rows.Scan(&id, &username) ; err == nil {
                log.Println(id, username)
            } else {
                log.Println(err)
            }
        }
        if err := rows.Err() ; err != nil {
            log.Println(err)
        }
    }
}

執行:

% go run main.go    
2022/05/25 20:44:26 Insert Done, Last Insert Id: 1 , RowsAffected:  1
2022/05/25 20:44:26 Update RowsAffected:  1
2022/05/25 20:44:26 Result:
2022/05/25 20:44:26 1 blog.changyy.org

% file /tmp/sqlite3.db
/tmp/sqlite3.db: SQLite 3.x database, last written using SQLite version 3038005, file counter 3, database pages 3, cookie 0x1, schema 4, UTF-8, version-valid-for 3

% sqlite3 /tmp/sqlite3.db .schema
CREATE TABLE account (
            uid INTEGER PRIMARY KEY AUTOINCREMENT,
            username VARCHAR(64) NULL
        );
CREATE TABLE sqlite_sequence(name,seq);

2022年5月22日 星期日

Go 開發筆記 - 使用 golang.org/x/oauth2 與 Facebook 登入 / Google OAuth 串接

最近評估網站是否從 PHP 翻到 Golang ,研究了一下關於串接 OAuth2 相關部分。早年在串 FB 登入時,都是直接使用 Facebook PHP SDK ,雖然都知道底層還是 OAuth2 ,但不免還是擔心要串時很麻煩(主要是很懶再刻一份)。稍微研究了一下,原來有 golang.org/x/oauth2 套件可以用,裡頭有支援了各式各家的登入機制,非常方便。

接著反而開始複習起來 Facebook 登入 該怎樣處理,過程:
  • 建立一個 FB 應用程式 developers.facebook.com/apps/
  • 設定 FB 登入相關事宜,包括應用程式網域(添加 localhost)、FB 登入用戶端 OAuth 設定,如 有效的 OAuth 重新導向 URI
  • 處理相關雜事
結果處理相關雜事反而耗掉最多時間,包括:
  • FB應用程式要儲存時,還得弄個 隱私政策網址 跟 用戶資料刪除 網頁
  • FB登入相關,要求都走 https 溝通,變成要研究 golang gin 如何跑 https web server 出來、憑證該怎樣產生等
  • 寫完程式後,體驗流程後,想弄個 github 筆記一下且降低程式碼變動,開始規劃如何靠 YAML 檔案來抽換設定檔
大概就是如此,花了不少時間。最後的效果純粹驗證支援 FB 登入是可行的,收工 XD

2022年5月21日 星期六

Switch 防塵 防塵箱 / 防塵套 / 防塵布

圖:不到60元的小箱子,尺寸 325x167x155mm

前陣子因為信用卡回饋折扣,敗了台 Switch ,順便當作防疫包升級。恰好這後疫情時代,Switch跟健身環不再是難買的,以及本身也不打算拿著 Switch 小螢幕玩,就買了大概 8500 的舊機(因折扣平台限制,不能挑其他便宜的地方),下一刻就是再買原廠手把、健身環大冒險,以及下載 "遊戲盒子" 隨時關注想收藏的數位版遊戲,整個入坑太深,當初信用卡折扣早已用光 XD

回過頭來,在想是不是要買個防塵的東西,結果找了下有人專門在做壓克力板也算精美,價格大概三四百。由於我多買了充電的設備,size若要的話,已經需要訂製才行。

此外,我覺得還是要留意散熱,不太適合一直罩住的。單純買個蓋子避免灰塵即可!原本想買一些硬塑膠板自己製作,結果室友神指示,就買了不錯的小籃子頂替。推敲了一下,最適合的此寸高度是 15cm 的,寬(深)也 15cm,剩下長 30cm就夠用,就是找 15x15x30 的小籃子,網路上就隨便找一個不用百元的,搞定!

其中買了三款箱子,尺寸分別是:

  • 325x167x155mm (商品編號 P5-0255)
    • 非常剛好,但缺點是全密封
  • 169x283x130mm (商品編號 KGB-201)
    • 原本期待這個是最佳的,非密封可散熱,但發現13cm不夠高,推論還是switch稍微撐著它
  • 168x281x119mm (商品編號 KGB-102)
    • 順手測一下,最後也不適用,當作收納籃使用