2017年9月13日 星期三

[python] 用 requests 出現 InsecureRequestWarning,自己加上認證檔

在換到 requests 之後,因為他使用 urllib3,就會對 https 的網址出現以下警告:

InsecureRequestWarning: Unverified HTTPS request is being made. Adding certificate verification is strongly advised. See: https://urllib3.readthedocs.io/en/latest/advanced-usage.html#ssl-warnings

通常找到的解決方法是關閉這個警告,如下:

import requests.packages.urllib3
requests.packages.urllib3.disable_warnings()

在官網上提供另一個方法就是加上認證,但是,認證檔要去哪兒找?

這真的要感謝 stackoverflow 的網友以及 certifiio 網站提供可用的認證檔。

所以先到 http://certifiio.readthedocs.io/en/latest/ 下載 Raw CA Bundle,放在你知道的地方。
然後在使用 requests 的時候,verify 參數後面接那個檔案的路徑。問題解決!

[超譯] 微服務怎麼溝通?

# 微服務怎麼溝通?

我們在工作上做過一些分散式的開發與服務間的溝通。有些是透過開放 HTTP 服務。對於系統間的非同步訊息傳送,我公司使用 FubuMVC 與它的 .Net Core 取代物 "Jasper" 做為 service bus (translate "Jasper" to "MassTransit" or "NServiceBus" when you read this). 此格文是給我們團隊的架構的建議的草案,讓我們團隊為產品選擇何者做為微服務架構的一部份時有個參考。如果我同事看到這篇而有不同意的話,不用擔心。這份文件是活的,總是能討論的。

微服務通常需要傳送訊息給別人或處理別人的訊息,也許是微服務或客戶端。因此,為服務間通訊好好思考是值得的。

我們通常使用 HTTP 或 Jasper/FubuMVC service bus 做為服務間溝通。在思考如何選擇服務間溝通的工具之前,先要想想你的訊息的要求是什麼。服務間溝通約略是以下幾個分類:

1. Publish/Subscribe 非同步廣播一個訊息到所有的訂閱者,不預期一個立即的回應。它與「射後不理」的差異是隱含「保證送達」,也就是訊息會持續保留,直到它被發布出去。Jasper/FubuMVC service bus 有做到「保證送達」,它透過在 LightingQueue 的持續式 "store and forward" 機制,而且最後我們把 RabbitMQ 放進 Docker'ized hosting。

2. Request/Reply 呼叫另一個服務且期待一個回應。從 web service 查詢資料是一個例子。透過 service bus 送訊息且期待一個回應也是一個例子。query handler 就是 request/reply 的範例。

3. Fire and Forget 送出一個 request,然後不管任何回應,不在乎回應是否有來。這種模式多用在效能優先且訊息不是很要緊的情況。Jasper/FubuMVC 使用在 node 內通訊,用以協調訂閱與健康檢查,這是透過 LightningQueue 在 "fire and forget" 的模式來做。

## 以下情況使用 HTTP Service:
* 你的服務要開放 API 給外部使用者。
* 你的服務要給網頁瀏覽器使用。
* 你要開放查詢端點( query endpoint) 給其他服務,它們需要拿到資料馬上使用的方式。
* 你不需要「保證送達」。
* 你在前期不清楚未來你的服務的客戶端會是什麼其他的機制。目前 HTTP 普通存在於所有平台。
* 你需要開放你的服務給「非.Net」客戶端。用現存其他平台的 service bus 是完全可能的,但在這個情況,用 HTTP 端點會比較少阻力。

## 以下情況使用 Service Bus:
* 你需要耐用的 publish/subscribe 的模式。如果你的服務不需要等待下家系統的回應,你需要的可能是 publish/subscribe。
* 如果你會同一個訊息給不同的訂閱者。
* 如果你需要支援「動態訂閱」。也就是讓其他服務可以到你的服務註冊,然後從你的服務接收訊息。
* 如果你要「射後不理」的訊息方式,使用 service bus 在 LightningQueue 的 non-persistent mode。(參考 ZeroMQ)
* 你也許需要 Jasper/FubuMVC 裡的 "delayed message" 的好處。
* 你需要實作長命服務,例如 saga workflow
* 雖然可利用限縮 HTTP request 來控制,但透過 servcie bus 後面的 message queue 來處理大量負載會更簡單有效。
* 如果 message 處理順序很重要,你需要在 servcie bus 排隊。

## 灰色地帶
比較 HTTP 與 service bus 不是完全黑與白的選擇。service bus 也支援 request/reply 模式,你也可以用 HTTP 來做射而不理。兩個招數可以與我們現存的技術堆疊水平擴展。Jasper 最終會支援 HTTP 傳輸以及更有效率的 request/reply,這讓情況更混亂。如果你感覺不是很清楚哪個方向才對,那你的團隊所熟悉的方法會是較可接受的選擇。很可能,這意謂著,使用常見的 ASP.NET Core 堆疊給 HTTP Service 使用,而不是我們今天定做的 service bus 技術。

## 避免以下整合的方式
因為外部客戶端的關係,我們會必須使用下列的方式。但是非常強烈建議不要這麼做:
* publish 檔案到檔案系統及監控目錄
* publish 檔案到 FTP server
* 使用共享資料庫。關聯式資料庫的排隊機制不是很有效率,而且我們也不想要服務之間藉著共享資料庫而有太硬的耦合。
不同意嗎?還有什麼要加的?不用客氣,請幫我讓這個列表更圓滿,可以在下方留言。
原文連結:https://jeremydmiller.com/2017/05/24/how-should-microservices-communicate/

[windows] python 幫忙打開檔名太長限制

不知道你是否有遇到,在windows複製/移動檔案的時候發生路徑太長以致於無法複製/移動的情況?

我大概每年發生個四、五次,在備份自己的電腦檔案時就一定會發生。然後就有些檔案就無法備份或是要改短名字,搬完再改回來。有次發現用 node.js 寫程式複製檔案可以不被限制,後來就自己寫個程式來複製。

今天在裝 python3.6.2 的時候發現它的安裝程式會好心問你要不要關閉這個選項,若是要的話,它會用 winreg 幫你改個 registry。

import winreg; winreg.SetValueEx(winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, r'SYSTEM\CurrentControlSet\Control\FileSystem'), 'LongPathsEnabled', None, winreg.REG_DWORD, 1)

如果有需要的話,也有 python 的話,執行這句就有同樣效果。
當筆記。

[python] 徒手把自己的程式從 py2 改成 py3

# 1
想親身體會一下從 py2 升到 py3 會有多痛苦,決定把自己來一遍。遇到以下的事情,其實感覺還好。

# 2
我最常遇到的是 print 後面要加括號,用手動改久了真的很想用 regexp 之類的直接取代

# 3
urllib 被拆成幾個部份,我有用到的:

urllib.urlencode ---> urllib.parse.urlencode
urllib.urlopen ---> urllib.request.urlopen

# 4
文字編碼的問題會在幾個地方遇到

在檔案讀寫,改用 codecs 的 open 並指定 encoding。
urlopen,得到的內容要 decode(encoding)
csv.reader 改用 codecs 的 open 並指定 encoding。

# 5
dict1.keys() 回傳的東西不是單純的 list,所以沒辦法做到 dict1.keys().sort()。解決方法是 sorted(dict1.keys())

從這樣:
dict1.keys().sort()
變這樣:
sorted(dict1.keys())

# 6
sort 原先有 cmp function 的,現在只能 key function,兩者概念相差甚大。現在 py3 提供 wrapper 從 cmp function 轉成 key function。

從這樣:
sorted(cursor,key=cmpbyyear, reverse=True)
變這樣:
sorted(cursor,key=functools.cmp_to_key(cmpbyyear), reverse=True)

# 7
dict1.has_key('skey') 現在不能用,改成 'skey' in dict1

從這樣:
dict1.has_key('skey')
變這樣:
'skey' in dict1
# 8
map 現在回傳是個 map 物件,是一種 iter,如果沒有執行 iter 動作的話,就不會真的開動。最簡單的方法就是包一層 list。

從這樣:
map(func, seq)
變這樣:
list(map(func, seq))

2017年9月10日 星期日

[electron] 入 jQuery 之類的問題。

Electron (atom.io) 引入 jQuery 之類的問題。

在使用 electron (.atom.io) 的時候,如果是在 render process 的 js 裡面要使用 jquery,是另外一回事。如果是像我一樣,把原來是網頁程式改成 electron,在 html 裡面要引入 jquery 一樣會有符號問題,因為 electron 有去修改 DOM 裡面的變數。所以得要修正回來才行。
在網頁程式裡的最前面加入修正:
<head>
<script>
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
<script type="text/javascript" src="jquery.js">
</script>
</head>

在 main process 的 nodeIntegration 不關掉好像也沒有關係。現在我還沒有遇到問題。
參考:
https://electron.atom.io/docs/faq/…

2017.09.11 更新:
還有另外一種做法,我也比較喜歡。我就是不想去動原來網頁程式的內容的情況下,在 main.js (有寫的人應該知道這是什麼)裡面,createWindow 的地方,創建新的 BrowserWindow 時,加入新的選項 nodeIntegration: false,如下:

function createWindow () {
  // Create the browser window.
  win = new BrowserWindow(
{width: 800, height: 600,
webPreferences: { //https://electron.atom.io/docs/faq/#i-can-not-use-jqueryrequirejsmeteorangularjs-in-electron
nodeIntegration: false
}
})
  // and load the index.html of the app. 
  win.loadURL('http://127.0.0.1:10001/')
  // Open the DevTools.
  ////win.webContents.openDevTools()
  // Emitted when the window is closed.
  win.on('closed', () => {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    win = null
  })
}

這樣原來網頁程式就不用動了。

2017年4月26日 星期三

[超譯] LinuxKit 為容器而生的操作系統

超譯

https://gianarb.it/blog/linuxkit-operating-system-build-for-containers

超譯目的:
linuxkit 是什麼?從這篇來了解 linuxkit 是什麼。

內容:

Linuxkit 是 Docker 在 DockerCon 2017 呈現的的新專案。在 GitHub 的專案描述為:

一個安全,可攜、玲瓏的操作系統,為了容器而打造。

我已非常興奮,在 Justin Cormack 與其他貢獻者在其為私人庫的時候,我已經在觀察這專案。我也被邀請以 ci-wg 團隊的角色進入 CNCF,從第一天開始我就喜愛這專案。

你可想像,linuxkit 是個建立者,建立基於容器的 Linux 操作系統的所有東西。

這專案可以留在持續整合系統(CI system),讓我們可測試不同的核心版本與散佈。你可用小核心帶著你所需的所有服務,你可以利用 Docker 或 QEMU 建立不同的可執行服務在雲端上,例如谷歌雲平台。

持續交付,新模式

我對谷歌雲平台沒很大信心,我想用 AWS 為服務供應者來做些數學。假設我已經有最一般的持續整合系統,一個大盒子持續執行已設定好的工作,支援你所有的專案。或是你已經有可用的容器,擁有獨立分開的環境。

假設你的 jenkins 已經準備好在 m3.xlarge:

m3.xlarge 每月吃到吐會花掉 $194.72。

來做夢一下,你有一個非常小的伺服器,它只是個前端程式,讓你的 CI 與所有工作執行在不同的實體上,如同 t2.small 這麼小。

t2.small 使用一個小時要付 $0.72。

我算一個小時是因為付錢的最小單位為小時,我希望你的 CI job 可以跑低於一小時。簡單算一下要付多少錢,就像你以前付錢一樣。

194.72 / 0.72 ~ 270 大約是每月 270 個 build。

如果你一個月跑少於 270 個 build 的話,你可以省下一些錢。但你可以有其他的益處:

  1. 更多的 job,更多的實體。非常容易擴展。對 Jenkins master/slave 等更容易些。
  2. 有多少時間是假日,你的 Jenkins 仍然開啟但沒事可做?這些日子你仍然要為那前端付錢。

你的持續交付的不同設計,會有這些不同的益處。

LinuxKit CI 實作

這裡有個目錄叫 ./test 它包含一些 linuxkit 的使用例。我會解釋實務上 linuxkit 如何被測試。因為它自己用自己,超酷的!

首先你需要下載並編譯 linuxkit:

git clone github.com:linuxkit/linuxkit $GOPATH/src/github.com/linuxkit/linuxkit
make
./bin/moby

你可以把它搬到你的 $PATH (使用 make install)。

$ moby
Please specify a command.

USAGE: moby [options] COMMAND

Commands:
  build       Build a Moby image from a YAML file
  run         Run a Moby image on a local hypervisor or remote cloud
  version     Print version information
  help        Print this message

Run 'moby COMMAND --help' for more information on the command

Options:
  -q    Quiet execution
  -v    Verbose execution

在這時間點,CLI 還是很簡單,最重要的指令是建立與執行。linuxkit 是建基於 YAML 檔,它可以描述你的核心,需要什麼應用與服務。我們從 linuxkit/test/test.yml 開始。

kernel:
  image: "mobylinux/kernel:4.9.x"
  cmdline: "console=ttyS0"
init:
  - mobylinux/init:8375addb923b8b88b2209740309c92aa5f2a4f9d
  - mobylinux/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
  - mobylinux/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
  - mobylinux/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935
onboot:
  - name: dhcpcd
    image: "mobylinux/dhcpcd:0d4012269cb142972fed8542fbdc3ff5a7b695cd"
    binds:
     - /var:/var
     - /tmp:/etc
    capabilities:
     - CAP_NET_ADMIN
     - CAP_NET_BIND_SERVICE
     - CAP_NET_RAW
    net: host
    command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
  - name: check
    image: "mobylinux/check:c9e41ab96b3ea6a3ced97634751e20d12a5bf52f"
    pid: host
    capabilities:
     - CAP_SYS_BOOT
    readonly: true
outputs:
  - format: kernel+initrd
  - format: iso-bios
  - format: iso-efi
  - format: gcp-img

linuxkit 會建立所有的東西在一個容器裡面,這表示你不需要一堆相依,它非常容易使用。它產生不同的 output,在這例子有 kernel+initrdiso-biosiso-efigcp-img,它相依於你想要執行的核心的平台。

我多解釋一下這 YAML 如何工作的。你可以看到有不同的主要區段:kernelinitonbootservice與其他。

幾乎每個都有個關鍵字 image,就如我之前所說,因為每個東西都用在容器上,在這例子都存在 hub.docker.com/u/mobylinux/ 裡。

基礎的核心是 mobylinux/kernel:4.9.xREADME.md說:

  • kernel 指定 Docker image 的核心,包含核心與檔案系統的 tarball,eg 包含 modules。這例子的核心是從 kernel/ 所建立。
  • init 是 Docker image 基礎的 init 行程,這是由基礎系統所取出來的,包含 initcontainerdrunc與一些其他工具。其由 pkg/init/ 所建立。
  • onboot 是系統容器,按順序執行,他們應該做完事就馬上結束。
  • services 是系統服務,它們會在系統開啟之後一直執行。
  • files 是額外加入 image 的檔案。
  • outputs 是描述哪些要建立的東西,像是 ISO 之類的。

到此,我們可以試,如果你在 MacOS 上,你不需要安裝任何東西,只要一個被 linuxkit 支援的 hyperkit 就可以了。

./test 包含不同的測試,但現在我們先專注在 ./test/check 的目錄。這包含一組檢定,確認這核心怎麼被 LinuxKit 建立。舉例來說,它們是 smoke test,在每次新的 pull request 被建在庫時被執行。

就如我之前說,每個東西都在容器內執行,如果你看 check 目錄,那裡有個 makefilie,它會建立一個 mobylinux/check image,在 test.yml 裡面是這樣:

onboot:
  - name: check
    image: "mobylinux/check:c9e41ab96b3ea6a3ced97634751e20d12a5bf52f"
    pid: host
    capabilities:
     - CAP_SYS_BOOT
    readonly: true

你可以用這 check 目錄的 Makefile 來建立一個新版的 check,只要使用這指令 make

當你有正確版本的測試,我們可以用 moby 來建立 image:

cd $GOPATH/src/github.com/linuxkit/linuxkit
moby build test/test.yml

它的部份輸出:

Create outputs:
  test-bzImage test-initrd.img test-cmdline
  test.iso
  test-efi.iso
  test.img.tar.gz

這目錄裡面,你會看到有許多根目錄下所有的檔案,這些檔案可用 qemu 執行,可用谷歌雲平台執行,可用 hyperkit 執行…等。

moby run test

在 MacOS 用 LinuxKit 這指令是使用 hyperkit 去啟動一個 VM,我無法把所有的輸出都貼出來,但你可以看 hypervisor 的記錄:

virtio-net-vpnkit: initialising, opts="path=/Users/gianlucaarbezzano/Library/Containers/com.docker.docker/Data/s50"
virtio-net-vpnkit: magic=VMN3T version=1 commit=0123456789012345678901234567890123456789
Connection established with MAC=02:50:00:00:00:04 and MTU 1500
early console in extract_kernel
input_data: 0x0000000001f2c3b4
input_len: 0x000000000067b1e5
output: 0x0000000001000000
output_len: 0x0000000001595280
kernel_total_size: 0x000000000118a000
booted via startup_32()
Physical KASLR using RDRAND RDTSC...
Virtual KASLR using RDRAND RDTSC...

Decompressing Linux... Parsing ELF... Performing relocations... done.
Booting the kernel.
[    0.000000] Linux version 4.9.21-moby (root@84baa8e89c00) (gcc version 6.2.1 20160822 (Alpine 6.2.1) ) #1 SMP Sun Apr 9 22:21:32 UTC 2017
[    0.000000] Command line: earlyprintk=serial console=ttyS0
[    0.000000] x86/fpu: Supporting XSAVE feature 0x001: 'x87 floating point registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x002: 'SSE registers'
[    0.000000] x86/fpu: Supporting XSAVE feature 0x004: 'AVX registers'
[    0.000000] x86/fpu: xstate_offset[2]:  576, xstate_sizes[2]:  256
[    0.000000] x86/fpu: Enabled xstate features 0x7, context size is 832 bytes, using 'standard' format.
[    0.000000] x86/fpu: Using 'eager' FPU context switches.
[    0.000000] e820: BIOS-provided physical RAM map:
[    0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
[    0.000000] BIOS-e820: [mem 0x0000000000100000-0x000000003fffffff] usable

當 VM 準備好,LinuxKit 會啟動所有的 initonboot,這些記錄非常好懂,像 test.yml 啟動 containerdrunc

init:
  - mobylinux/init:8375addb923b8b88b2209740309c92aa5f2a4f9d
  - mobylinux/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
  - mobylinux/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
  - mobylinux/ca-certificates:eabc5a6e59f05aa91529d80e9a595b85b046f935
onboot:
  - name: dhcpcd
    image: "mobylinux/dhcpcd:0d4012269cb142972fed8542fbdc3ff5a7b695cd"
    binds:
     - /var:/var
     - /tmp:/etc
    capabilities:
     - CAP_NET_ADMIN
     - CAP_NET_BIND_SERVICE
     - CAP_NET_RAW
    net: host
    command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
  - name: check
    image: "mobylinux/check:c9e41ab96b3ea6a3ced97634751e20d12a5bf52f"
    pid: host
    capabilities:
     - CAP_SYS_BOOT
    readonly: true
Welcome to LinuxKit

            ##         .
          ## ## ##        ==
           ## ## ## ## ##    ===
       /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
       \______ o           __/
         \    \         __/
          \____\_______/


/ # INFO[0000] starting containerd boot...                   module=containerd
INFO[0000] starting debug API...                         debug="/run/containerd/debug.sock" module=containerd
INFO[0000] loading monitor plugin "cgroups"...           module=containerd
INFO[0000] loading runtime plugin "linux"...             module=containerd
INFO[0000] loading snapshot plugin "snapshot-overlay"...  module=containerd
INFO[0000] loading grpc service plugin "healthcheck-grpc"...  module=containerd
INFO[0000] loading grpc service plugin "images-grpc"...  module=containerd
INFO[0000] loading grpc service plugin "metrics-grpc"...  module=containerd

最後一步是 check,它執行真正的測試套裝:

kernel config test succeeded!
info: reading kernel config from /proc/config.gz ...

Generally Necessary:
- cgroup hierarchy: properly mounted [/sys/fs/cgroup]
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: enabled

........
.......

Moby test suite PASSED

            ##         .
          ## ## ##        ==
           ## ## ## ## ##    ===
       /"""""""""""""""""\___/ ===
      ~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ /  ===- ~~~
       \______ o           __/
         \    \         __/
          \____\_______/

[    3.578681] ACPI: Preparing to enter system sleep state S5
[    3.579063] reboot: Power down

最後的記錄是 check-kernel-config.sh 的產出。

如果你使用 linux,你可以用相同的指令,但預設你是使用 qemu,它是一個開源機器模擬器。

sudo apt-get install qemu

我的 Asus Zenbook 是裝 Ubuntu,我在它上面測試,當我執行 moby run,它會用 qemu 來執行其指令:

/usr/bin/qemu-system-x86_64 -device virtio-rng-pci -smp 1 -m 1024 -enable-kvm
    -machine q35,accel=kvm:tcg -kernel test-bzImage -initrd test-initrd.img -append
    console=ttyS0 -nographic

預設是在 x86_64 上測試,但 qemu 支援其他的架構與裝置。與例來說,你可以模擬一個 arm 與樹莓派。在這時點,LinuxKit 還沒準備好支援其他架構。但這是此專案的主要範圍。這只是時間問題,應該很快!

偵測一個 build 是否成功可能不如你所想的簡單。這 VM 內的狀態不是你從筆電內取得的那一個。在這時候要了解你的 PR 內的程式碼好或不好,我們是這樣解析輸出的:

define check_test_log
    @cat $1 |grep -q 'Moby test suite PASSED'
endef

./linuxkit/Makefile

現在解釋 linuxkit 自我測試是如何工作的,正是解釋它本身如何工作的最好方法。這正好是拼圖的一片,如果你看過 every pr 它有個 GitHub 狀態,裡面指到一個網站,它有一些特殊 build 的記錄。那些不在 linuxkit 的管理之內,因為它只是一個 builder 用來建立環境的。其餘是被 datakit 所管。我會在另一個貼文談到。

結論

runc、docker、containerd、rkt,還有 Prometheus、InfluxDB、Telegraf 很多專案支援不同的架構,它們需要用不同的設定與能力在不同的核心上執行。它們需要在你的筆電上跑,在你的 IBM 伺服器跑,在樹莓派上跑。

這專案還在早期階段,但我了解為何 Docker 需要類似的東西,如我所言,其他專案需要這種東西以獲得一些益處。讓它開源,是非常好的,而且我很榮幸成為此驚艷專案的其中一員。我做了一些最終測試並嘗試了解它如何設計與工作。這是我測試的結果。我希望這篇文章能對給予正確觀念上幫上一些忙。

我計畫是建立一組設定來測試 InfluxDB 且用 qemu 讓它在不同架構與裝置測試。敬請期待新的貼文。

一些連結:

審閱者: Justin Cormack

2017年4月23日 星期日

[mathjax]math formula generated by stackedit published to blogger

之前在 在 blogspot / blogger 網誌裡顯示 latex 裡面用的方法,適用於直接在 blogger 編輯的時候,輸入 latex 語法。然而,若使用 stackedit 直接發佈(publish)的文章,就看不見。

原因是,stackedit 轉成 html 的時候,把數學公式轉過,已經不是 latex 語法。而是變成這樣:

<script type="math/tex; mode=display" id="MathJax-Element-85"> e^\varphi = 1 + \varphi + \varphi^2/2! + \varphi^3/3! + \dotso </script>

那麼,之前在 head 加入的程式就要改變為:

<script src='https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML' type='text/javascript'/>

經過測試,直接輸入 latex 語法與經 stackedit 轉換後的兩種做法可以共存。真是謝天謝地。

參考:

http://map-testing.blogspot.tw/2016/08/hello_23.html