2017/12/31

第十二天:從瀏覽器認識 HTTP 協定( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown # 複習 HTTP 協定 我們在[第六天:認識網站](https://ithelp.ithome.com.tw/articles/10193664),安裝了chrome瀏覽器,並且在[第九天:作一個最簡單的 Rails 網站](https://ithelp.ithome.com.tw/articles/10194359)成功架好一個 Rails 網站。 ![](https://2.bp.blogspot.com/-akKuTW81y60/WkfTXnXtzjI/AAAAAAAA_yw/BBkTCHG-HMIrnKQ8joLDynzJGGBIcREDQCLcBGAs/s1600/01.PNG) 我們可以透過 Chrome 的開發人員工具來觀察瀏覽器開啟一個網頁的過程。 # 認識 Chrome 開發人員工具 從昨天結束的地方繼續,先開啟 rails server 之後開啟 [http://localhost:3000/](http://localhost:3000/)。 ![](https://2.bp.blogspot.com/-m0w4CNehEtw/Wke_djkzhXI/AAAAAAAA_xI/C9EghQ0C_e4CqbZMRIRdH5zPBN0IBLyVACLcBGAs/s1600/2.jpg) 按下 `F12` 或 `Ctrl`+`Shift`+`I`,就可以叫出開發人員工具。 ![](https://4.bp.blogspot.com/-gVRbwZ_GC2A/Wke_P8xN5XI/AAAAAAAA_xE/ZSOAEflil8kXyF64Rj16GgLrg6vANjE5wCLcBGAs/s1600/3.jpg) 這個畫面有點複雜,總之先按這裡的`X`,把多餘的部分關掉。 ![](https://4.bp.blogspot.com/-79ljJaUuZh4/WkfAnvUVyfI/AAAAAAAA_xU/m_JVOLElBKg8O8Wn9nankchZb_FRs9OxACLcBGAs/s1600/4.jpg) 按了之後應該會看起來像這樣: ![](https://2.bp.blogspot.com/-dRGalsu0EtE/WkfBL-SPVcI/AAAAAAAA_xc/3U3JcXqCLaocOmKchKGVjxbTMBLXbrY5QCLcBGAs/s1600/5.jpg) 開發人員工具有很多的功能,我們只需要用到其中的一小部分,這裡就不一一介紹。 ![](https://3.bp.blogspot.com/-D3BgjEuQ42k/WkfCWUVoKPI/AAAAAAAA_xo/ZKLBswYCJ0Ieg4l3r0-P3kJTH8BHziCXgCLcBGAs/s1600/6.png) 請先切換到 `Network` 分頁。 ![](https://4.bp.blogspot.com/-KOj_dZDi0t4/WkfC0Z-vd1I/AAAAAAAA_xs/YaSEsn4qvlIChbzEMapNx-eQCTCc-VKcACLcBGAs/s1600/7.jpg) 一個複雜的介面,但是什麼資料都沒有顯示,那是因為開發人員工具開啟後才會開始監控數據,所以我們要重開網頁,這裡按下 `Ctrl`+`R`。 ![](https://3.bp.blogspot.com/-MjlgamEoTk0/WkfDxbrSF9I/AAAAAAAA_x8/JKIBRKmNTKIGA8sDdQo-Doz3URii2unwwCLcBGAs/s1600/8.jpg) 出現了兩筆資料,一個是 `localhost`,另一個是 `favicon.ico`,我們點 `localhost`。 ![](https://2.bp.blogspot.com/-YdP00VQvdr8/WkfF3j3fF0I/AAAAAAAA_yI/oMO9c9HcVlkgI0ZnSaRrhphBkpC7N0yfACLcBGAs/s1600/9.jpg) 我們看見這裡有四個分頁:`Headers`、`Preview`、`Response`、`Timing`,我們只需要認識 `Headers` 和 `Response`。 # Headers `Headers` 這裡的資料也很多,我們只需要認識其中的三項: ![](https://1.bp.blogspot.com/-U4jSo4i4xAY/WkfHXMxEa2I/AAAAAAAA_yU/bTUW9_VpGYsmcxfY27d9vCrBlyq0UGhOwCLcBGAs/s1600/10.jpg) - Request URL:http://localhost:3000/ - Request Method:GET - Status Code:304 Not Modified 接下來就一項一項講解。 ### Request URL 請求網址:就是你在瀏覽器上輸入的網址,因為你輸入的是 http://localhost:3000/,所以他顯示 http://localhost:3000/。 ### Request Method 請求方法:瀏覽器希望網頁伺服器做些什麼事,我們這裡是用 `GET` 是表示我們想要下載檔案。 除了 `GET` 之外,還有其他的請求方法可以使用,比方說 `POST`、`PUT`、`DELETE`,以下是各個請求方法的用途: - GET:下載檔案 - POST:上傳資料 - PUT:更新資料 - DELETE:刪除資料 舉個例:當你想在論壇發文,你把文章標題和內文填好,按下送出時,那就應該是一個 POST 請求方法。 依照目前可公開的情報,我們只需要知道 `GET` 和 `POST` 即可。 ### Status Code 狀態碼:是網頁伺服器用一個數字來表示瀏覽器提出的請求最後有沒有完成,如果沒有,為什麼沒有。其實提款機也有類似的東西,叫做[訊息代碼](http://www.bot.com.tw/services/atmmsg.htm)。 當然這個[狀態碼](https://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81)列出來會有很多,但因為我們只是要做一個聊天機器人,不需要認識全部,我們現階段只認識必須認識的那些。最主要的是你必須知道有狀態碼的存在,當你知道有狀態碼這種東西時,你需要相關資訊時就能在 Google 搜尋時輸入正確的關鍵字。 正式版說明: - 200:表示成功。 - 304:表示瀏覽器已經有一模一樣的檔案。 - 400:瀏覽器發出的請求被網頁伺服器拒收,通常是發出的請求格式不正確。 - 404:找不到網頁。 - 500:網頁伺服器掛了。 網頁伺服器擬人: - 200:網頁伺服器:「好哦~好哦~」 - 304:網頁伺服器:「你手上的檔案是最新的。」 - 400:網頁伺服器:「駁回!」 - 404:網頁伺服器:「你想找的東西不在我這。」 - 500:網頁伺服器:「阿阿我要壞掉惹。」 # Response 又稱為 Response Body(回應內容):指的是網頁伺服器回應給瀏覽器的內文部分。 ![](https://1.bp.blogspot.com/-ob-Zu2XW__s/WkfP9rbFlsI/AAAAAAAA_yk/1GGkzdLd2UAqKZQZw8JJqFj2Vv9_zcixACLcBGAs/s1600/11.jpg) 其實就是檔案內容的部分。 # HTTP 總結 - 由瀏覽器發給網頁伺服器的請求稱為 HTTP Request,HTTP Request 包含 Header 和 Body。 - 由網頁伺服器回應瀏覽器的請求稱為 HTTP Response,HTTP Response 也包含 Header 和 Body。 - Request Header 中的 Request Method 表示瀏覽器希望網頁伺服器做些什麼事。 - Response Header 中的 Status Code 表示網頁伺服器告訴瀏覽器事情辦好沒。 接下來我們從網頁伺服器的角度來觀察 HTTP Request 和 HTTP Response,但這需要寫點程式,所以我們明天會先從認識 Ruby 程式語言開始。

2017/12/30

第十一天:認識文字編輯器( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown # 前言 其實我平常不會用記事本寫程式,就像設計師不會用小畫家工作一樣。 身為一個專業的碼農,各種工具當然都要摸過。一個軟體的功能越強大,介面就會越複雜。而介面複雜的軟體本來就比較難入門,教學時當然是從最簡單的開始教起。如果我一開始就教你 Photoshop,你可能會覺得太難而不願意學習,但你已經對記事本上手之後,開始感覺到記事本的功能性不足,就會想要使用更高級的工具。現階段你已經知道記事本的侷限,我們真的需要更高級的開發環境。 我了解,在你對一個東西不感興趣之前,我怎麼認真教你,你都不會願意吸收。所以我教的每個東西都會告訴你,為什麼你需要學這個。 # 認識文字編輯器 昨天說過,電腦儲存文字的方式是透過文字編碼的方式,用一堆位元來表示一個文字。如果一個檔案是以文字編碼的形式儲存的,稱為文字檔。 在電腦裡面,檔案被分為兩大類: - 文字檔:以文字編碼的形式儲存 - 二進位檔:其他編碼形式儲存 所有能夠編輯文字檔的程式都可以稱為文字編輯器,只是有些強大到你不會這麼稱呼他。不管啦,我就要叫他們為文字編輯器。 # 常見的文字編輯器 ![](https://4.bp.blogspot.com/-cCbaE3lO5JE/WkZpUBVWltI/AAAAAAAA_so/kjrnLNzDiNId5gN5A6GXGfi8a4at226dQCLcBGAs/s1600/Notepad.png) Notepad:Windows 內建的記事本,每個人的電腦裡都應該有。 ![](https://3.bp.blogspot.com/-qv6ORcP9rz8/WkZpjJeYXmI/AAAAAAAA_ss/7hoOOhL939UsR6rjXAXx1Y9LU7Ieqo_jwCLcBGAs/s1600/Notepad%252B%252B_Logo.png) Notepad++:這是我用的第一款文字編輯器,作者是台灣人,2003年發布第一版,印象中當年中文版的文字編輯器好像沒幾個。 ![](https://2.bp.blogspot.com/-y3WQhQka9Ko/WkZ2J4xruMI/AAAAAAAA_t4/O-gFxFkCUKQlQpzFEL3pKczbsFnhJELMwCLcBGAs/s1600/Sublime_Text_3_logo.png) Sublime_Text:2008年發布第一版,因為他是英文版的文字編輯器,所以我比較晚接觸。但是他功能確實強很多,主要是他有很多外掛可以安裝。 ![](https://3.bp.blogspot.com/-c-K4J1UBGt4/WkZ2fZkIqBI/AAAAAAAA_uE/KvkbaEpfv9s9uFbooKeb5lz0RgQAiwVaQCLcBGAs/s1600/Visual_Studio_Code_0.10.1_icon.png) Visual Studio Code:2015年發布第一版,由微軟開發的文字編輯器,我最近是用這款。 ![](https://1.bp.blogspot.com/-uL3M9Y-Fd4U/WkZ2RalRqLI/AAAAAAAA_t8/59TCfrOhhhIpJhkkw7e_WASHyjqrqB2cwCLcBGAs/s1600/Vim_gloss_128.png) Vim:1991年發布第一版,聽說神人都用這款。他的特徵是純文字介面,就是跟小黑框一樣的純文字介面。為什麼神人都用這款呢?因為他的客製化可以非常高,如果文字編輯器是工程師手上的武器,那麼他就是會隨著工程師的強度進化的武器。根據神人的說法:「只要用這款,我就不用浪費時間把手從鍵盤移動到滑鼠上囉。」 這邊附上神人的超簡明 Vim 操作介紹:[https://gitbook.tw/chapters/command-line/vim-introduction.html](https://gitbook.tw/chapters/command-line/vim-introduction.html)。 ![](https://4.bp.blogspot.com/-OcUWM0YMlZc/WkZ2Ywh2V7I/AAAAAAAA_uA/_EvzogAn07Y-pERrp0q79YoZOqSUqENkACLcBGAs/s1600/Atom_icon.png) Atom:2014年發布第一版,是由 Github 開發的文字編輯器,這款好像也蠻多人推的,但我還沒用所以不清楚。 ![](https://1.bp.blogspot.com/-PO6DL3wOnNs/WkaGWdRAhmI/AAAAAAAA_wI/oMQPOJqHG_ofxXcu-lVjpCnUISigsYpvACLcBGAs/s200/CvjNepWX.png) Cloud9 IDE:這是一款被 Amazon 買走的線上的文字編輯器,如果你用 Cloud9 IDE 做網站,你的電腦可以完全不用經歷我們前幾天講過的任何安裝流程,因為你的網頁檔是放在人家的主機裡,而他已經幫你安裝好開發環境,你只需要刷信用卡。若想試用這款,但你又沒有信用卡的朋友,請到這個地方填寫表單:[https://goo.gl/forms/JiKwS1ERpC8F7Yvn2](https://goo.gl/forms/JiKwS1ERpC8F7Yvn2)。 這些專門設計給碼農用的文字編輯器,功能都差不多就那幾樣,新手應該隨便撿一款都可以用得很爽。因為我接下來的文章會以 Sublime Text 做示範,所以今天先講怎麼安裝 Sublime Text。 # 安裝 Sublime Text 首先點開 [https://www.sublimetext.com/](https://www.sublimetext.com/)。 ![](https://4.bp.blogspot.com/-lxYEtinl68E/WkZzTtk6LrI/AAAAAAAA_tM/TUIECLydxiokiyF1kMVS11A1EaT2_IXXQCLcBGAs/s1600/1.jpg) 點 `DOWNLOAD FOR WINDOWS` 下載安裝檔,下載完成後點開安裝檔。 ![](https://2.bp.blogspot.com/-KR52hdHtk-c/WkZ0qLOmADI/AAAAAAAA_tY/ZsejthWnVJYpWSOH-cHDRhWnZaVaTKjRQCLcBGAs/s1600/2.jpg) 歡迎光臨,按 `Next`。 ![](https://2.bp.blogspot.com/--jIbe-nZzs0/WkZ0005rK8I/AAAAAAAA_tc/En-kS0rrPaA0bDHtrlkSfZOQtRRV-PfgACLcBGAs/s1600/3.jpg) 選擇安裝路徑,能不改就別改吧,按 `Next`。 ![](https://1.bp.blogspot.com/-0scia_lYKiY/WkZ1BM7BndI/AAAAAAAA_tk/43YobD-ajZAkEyLKtED80Hd9QTtTMHMLgCLcBGAs/s1600/4.jpg) 要不要加到右鍵選單上?這裡要打勾再按 `Next`。 ![](https://3.bp.blogspot.com/-ww87Fb0GObg/WkZ1Mpzb96I/AAAAAAAA_ts/9yDNY6omSwQNrh8_zzrYpMS8seYSuZY-QCLcBGAs/s1600/5.jpg) 確認點餐內容,按 `Install`。 ![](https://1.bp.blogspot.com/-cFePMsP-UNA/WkZ1bipojgI/AAAAAAAA_tw/KNpZuK7y4iQOkB9Bg86WSt0C8M9Ea18AQCLcBGAs/s1600/6.jpg) 安裝完成!馬上來試用看看。 # 開啟 Sublime Text 如果你在安裝的時候沒有切換目錄的話,他會在 `C:\Program Files\Sublime Text 3`。 ![](https://3.bp.blogspot.com/-pFguEHgLrF0/WkZ3aXdR90I/AAAAAAAA_uQ/eZiGCu-urYse0BNLlGJ8Ap46fT_mid9pgCLcBGAs/s1600/7.jpg) 點兩下 `sublime_text.exe` 就能開啟他了。 ![](https://2.bp.blogspot.com/-SQMGPHz5M_Y/WkZ372esDsI/AAAAAAAA_uY/QyZ15u4_170JRHdT7Skp6rMhHCXRPgq_QCLcBGAs/s1600/8.jpg) 這是開啟之後的畫面。 除了這樣開啟他之外,你也可以對想要編輯的檔案點右鍵: ![](https://2.bp.blogspot.com/-SSW_HhPu-Hk/WkZ4nxnK7sI/AAAAAAAA_uk/E5BO7tkivlIUjOR9dRG-OPQ-TquTnzejgCLcBGAs/s1600/9.jpg) 這是檔案總管,目前所在的目錄是:`C:\Ruby24-x64\lib\ruby\gems\2.4.0\gems\railties-5.1.4\lib\rails\templates\rails\welcome`,我正準備要編輯 index.html。 選單的第二項:`Open with Sublime Text`(用 Sublime Text 開啟),點下去。 ![](https://1.bp.blogspot.com/-g6yc1C4rR0g/WkZ5VBYacaI/AAAAAAAA_us/Og2FSw3rqWMHQsyVA1kUc45g4MfGFgfCQCLcBGAs/s1600/10.jpg) 喔喔!看到亂碼啦~這是因為我們使用了錯誤的文字編碼去解讀這個檔案。 # 介紹 Sublime Text ![](https://2.bp.blogspot.com/-8ov8M3Y8rFA/WkZ51UPs6SI/AAAAAAAA_uw/aGU6o34sAD8GfhOeCnIOZlxz-ihbvPc-gCLcBGAs/s1600/11.jpg) 左下角寫著 `UTF-8`,代表目前使用的文字編碼,我們可以把他換掉。 ![](https://2.bp.blogspot.com/-AXClU9F53Z8/WkZ6iGKXmPI/AAAAAAAA_vA/mjA28-tkFjANki0d6u1hHiD-yeSZA52AACLcBGAs/s1600/12.jpg) 點左上角的 `File`(檔案),然後選 `Reload with Encoding`(用文字編碼重新載入),再選 `Chinese Traditional(BIG5)`(繁體中文(BIG5))。 ![](https://3.bp.blogspot.com/-ZyHq2cCfXms/WkZ7F3YFuTI/AAAAAAAA_vI/HkMGp9u28Xo025lPWgP_2p7zx8hSaWh-gCLcBGAs/s1600/13.jpg) 看到「只要有心,人人都可以作卡米狗」了! 但是這是BIG5編碼下的結果,我們需要的是 UTF-8 下的「只要有心,人人都可以作卡米狗」,像這樣: ![](https://3.bp.blogspot.com/-uYTxy9AYYvI/WkZ8GZV452I/AAAAAAAA_vU/0qU81J7VRQYrf887m_lA3BX5mN4DBXVawCLcBGAs/s1600/14.jpg) 只要再次調整文字編碼就可以了。 ![](https://3.bp.blogspot.com/-rrnUOys-bXQ/WkZ9z_XPqQI/AAAAAAAA_vg/Fizb4tFr_aEhAkjLLgbp8tlXJIN_6cPcgCLcBGAs/s1600/15.jpg) 在後面多打一點字: ![](https://3.bp.blogspot.com/-6WzKivjFZRg/WkZ-1Nd7-MI/AAAAAAAA_vs/q_dQfM-rLNEM0Tjr5sQTMkVPVCtB-O8nACLcBGAs/s1600/16.jpg) 讓我們再次開啟網站伺服器,來檢查看看是不是成功修改。 # 開啟網頁伺服器 先開啟檔案總管(`Windows`+`E`),移動到 `D:\只要有心,人人都可以作卡米狗\ironman` 這個資料夾下。 ![](https://4.bp.blogspot.com/-0K2p1XKIVoo/WkUSutGw2tI/AAAAAAAA_qw/1n1_hO171uMh9PZZmjXtzAPTsaVzq34MQCLcBGAs/s1600/9.jpg) 然後在網址列輸入 `cmd` 開啟小黑框。 ``` D:\只要有心,人人都可以作卡米狗\ironman> ``` 輸入 `rails s`(rails server 的簡寫),然後按 `Enter`。 ``` D:\只要有心,人人都可以作卡米狗\ironman>rails s => Booting Puma => Rails 5.1.4 application starting in development => Run `rails server -h` for more startup options *** SIGUSR2 not implemented, signal based restart unavailable! *** SIGUSR1 not implemented, signal based restart unavailable! *** SIGHUP not implemented, signal based logs reopening unavailable! Puma starting in single mode... * Version 3.11.0 (ruby 2.4.2-p198), codename: Love Song * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stop ``` # 開啟網頁 點開[http://localhost:3000/](http://localhost:3000/)。 ![](https://4.bp.blogspot.com/-EqzwC4Fiph4/WkZ_WkshacI/AAAAAAAA_v0/YkM0iW4k_AcW7VKCQpO7qQnXwI8cQ_LOwCLcBGAs/s1600/17.jpg) 大成功! # 下集預告 由於我們已經同時擁有瀏覽器以及網頁伺服器,所以我們可以開始觀察 HTTP 協定到底是什麼囉,明天我們會用 Chrome 來觀察 HTTP 協定。

2017/12/29

第十天:認識文字編碼( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 昨天我們作了一個最簡單的 Rails 網站,並且試著修改了一下網頁的顯示結果。我們是把它改爆了,再把它改成空白頁。今天我們試著在網頁輸入「只要有心,人人都可以作卡米狗」。 # 修改網頁 從昨天結束的地方開始,開檔案總管(`Windows`+`E`),在網址列上輸入`C:\Ruby24-x64\lib\ruby\gems\2.4.0\gems\railties-5.1.4\lib\rails\templates\rails\welcome`(你的路徑可能跟我的不同)。 ![](https://1.bp.blogspot.com/-ybcBeTMh6co/WkUN7yt3BkI/AAAAAAAA_p4/WBCRs5gSjd8Td4oXjLrE05K5A7ADZfcggCLcBGAs/s1600/1.jpg) 我們現在要修改的檔案是 `index.html`,而他是一個網頁檔,如果我點兩下滑鼠,就會開啟網頁。之前我們教的是先把副檔名改成 `.txt`,這樣預設開啟的程式就會是記事本,然後我們再點開來改。 今天要教你一個方法,不用修改副檔名,直接就可以用記事本打開這個檔案,先對檔案點右鍵: ![](https://4.bp.blogspot.com/-lrIIi0rhv4k/WkUPjYKpIII/AAAAAAAA_qE/k_9wmKiFA-0ZHvDN83b5rstL5AWufdemQCLcBGAs/s1600/2.jpg) 點`開啟檔案`。 ![](https://2.bp.blogspot.com/-uxErlpTkpro/WkUP2QZfTqI/AAAAAAAA_qI/QDtWM4ay5UsnfeDQlca0nymbcamnNWFCACLcBGAs/s1600/3.jpg) 因為我在這裡沒看到`記事本`,所以我點`選擇其他應用程式`,如果你有看到`記事本`的話當然就直接點`記事本`。 ![](https://3.bp.blogspot.com/-jYIALBv-JsE/WkUQYNLmtcI/AAAAAAAA_qQ/zHmJ3Pq-57kkDPgt7sJ8Wo9zmLEasMHpACLcBGAs/s1600/4.jpg) 這裡用滑鼠滾輪往下捲動,查看有無`記事本`。 ![](https://4.bp.blogspot.com/-As7eau24oiQ/WkUQieBDlCI/AAAAAAAA_qU/D_-nwG8s3hEFaNv8tWKmn-B65KMN3qLygCLcBGAs/s1600/5.jpg) 我捲到底了還是沒看到,所以我點`更多應用程式↓`,如果你有看到`記事本`的話當然就直接點`記事本`。 ![](https://2.bp.blogspot.com/-pRMmOzKHa4Q/WkUQzDDruFI/AAAAAAAA_qY/qisplbsgLhQ1E-Q-QVD7AfxneUSBAjxHwCLcBGAs/s1600/6.jpg) 終於找到`記事本`囉,選擇`記事本`然後按下`確定`。 ![](https://3.bp.blogspot.com/-ORF9MZI6TgA/WkURCHRHKyI/AAAAAAAA_qg/-lMn0nu9uGMm5JZf0Y5UBPQlfr-zFAeMACLcBGAs/s1600/7.jpg) 輸入「只要有心,人人都可以作卡米狗」後按下 `Ctrl`+`S` 存檔。 ![](https://4.bp.blogspot.com/-vjcC3iprjmA/WkURZ4vCb1I/AAAAAAAA_qk/A_ioO9RxSzgMNxxI-L6EIXL2yDA4XJqbwCLcBGAs/s1600/8.jpg) 讓我們再次開啟網站伺服器,來檢查看看是不是成功修改。 # 開啟網頁伺服器 先開啟檔案總管(`Windows`+`E`),移動到 `D:\只要有心,人人都可以作卡米狗\ironman` 這個資料夾下。 ![](https://4.bp.blogspot.com/-0K2p1XKIVoo/WkUSutGw2tI/AAAAAAAA_qw/1n1_hO171uMh9PZZmjXtzAPTsaVzq34MQCLcBGAs/s1600/9.jpg) 然後在網址列輸入 `cmd` 開啟小黑框。 ``` D:\只要有心,人人都可以作卡米狗\ironman> ``` 輸入 `rails s`(rails server 的簡寫),然後按 `Enter`。 ``` D:\只要有心,人人都可以作卡米狗\ironman>rails s => Booting Puma => Rails 5.1.4 application starting in development => Run `rails server -h` for more startup options *** SIGUSR2 not implemented, signal based restart unavailable! *** SIGUSR1 not implemented, signal based restart unavailable! *** SIGHUP not implemented, signal based logs reopening unavailable! Puma starting in single mode... * Version 3.11.0 (ruby 2.4.2-p198), codename: Love Song * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stop ``` # 開啟網頁 點開[http://localhost:3000/](http://localhost:3000/)。 ![](https://1.bp.blogspot.com/-pWetoUAK8ro/WkUTg78CRaI/AAAAAAAA_q4/S2WNozojuaYwao4fRQVRDjnnXFSSQ-vhwCLcBGAs/s1600/11.jpg) 發現網頁掛了,錯誤訊息是:「We're sorry, but something went wrong. If you are the application owner check the logs for more information.」。 「很抱歉網站掛惹,如果你是網站的擁有者,請去看一下 logs。」,所以我們回到小黑框看看。 ``` Started GET "/" for 127.0.0.1 at 2017-12-28 23:53:16 +0800 Processing by Rails::WelcomeController#index as HTML Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.1.4/lib/rails/templates/rails/welcome/index.html Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.1.4/lib/rails/templates/rails/welcome/index.html (2.0ms) Completed 500 Internal Server Error in 321ms ActionView::Template::Error (Your template was not saved as valid UTF-8. Please either specify UTF-8 as the encoding for your template in your text editor, or mark the template with its encoding by inserting the following as the first line of the template: # encoding: . The source of your template was: �u�n���ߡA�H�H���i�H�@� ``` 他說,編碼錯誤,我們的網頁檔案不是合格的 UTF-8 編碼的文字檔,所以程式遇到亂碼,掛了。你可以選擇讓文字檔調成 UTF-8 編碼,或者在你檔案裡的第一行寫這個檔案是什麼編碼。 你眉頭一皺,覺得事情並不單純。因為你記得在[第六天:認識網站](https://ithelp.ithome.com.tw/articles/10193664)的時候,用瀏覽器直接開檔案,明明還可以的呀。 你決定再開一次看看,於是你回到檔案總管點開網頁。 ![](https://1.bp.blogspot.com/-xtXrlzRoTF4/WkUkhxaMaWI/AAAAAAAA_rg/0o4J9IJhSD0WCYjKDhI94aW3b_akdeyogCLcBGAs/s1600/12.jpg) ~~鳩竟是命運的糾葛,還是...~~ 其實這是編碼問題,因為在 Windows 繁體中文版下新增純文字檔的時候預設的文字編碼為 Big5 編碼。但是 Rails Server 只吃 UTF-8 編碼,所以就掛了。 # 認識文字編碼 電腦檔案其實只能存0跟1,電腦會用許多的0跟1來組成數字,然後再定義比方說用 `1000001` 代表 `A`,用 `1000010` 代表 `B` 的方式來儲存文字。 # 認識 ASCII 編碼 ASCII 編碼是所有編碼裡面最小的一個,只有 128 個符號,所以只需要7個0或1的組合就能表達一個 ASCII 編碼,一個0或1稱為一位元(bit),所以我們可以說 ASCII 編碼是用7個位元來表達一個文字。 因為他很簡單,所以可以直接在這邊介紹,讓我們透過認識最簡單的編碼來認識文字編碼。在 ASCII 編碼裡面有一些是看得見的符號,一些是看不見的符號。看不見的符號是像換行或空白鍵這種,以下只列出看得見的部分。 ``` 用這個 來代表這個 0100001 ! 0100010 " 0100011 # 0100100 $ 0100101 % 0100110 & 0100111 ' 0101000 ( 0101001 ) 0101010 * 0101011 + 0101100 , 0101101 - 0101110 . 0101111 / 0110000 0 0110001 1 0110010 2 0110011 3 0110100 4 0110101 5 0110110 6 0110111 7 0111000 8 0111001 9 0111010 : 0111011 ; 0111100 < 0111101 = 0111110 > 0111111 ? 1000000 @ 1000001 A 1000010 B 1000011 C 1000100 D 1000101 E 1000110 F 1000111 G 1001000 H 1001001 I 1001010 J 1001011 K 1001100 L 1001101 M 1001110 N 1001111 O 1010000 P 1010001 Q 1010010 R 1010011 S 1010100 T 1010101 U 1010110 V 1010111 W 1011000 X 1011001 Y 1011010 Z 1011011 [ 1011100 \ 1011101 ] 1011110 ^ 1011111 _ 1100000 ` 1100001 a 1100010 b 1100011 c 1100100 d 1100101 e 1100110 f 1100111 g 1101000 h 1101001 i 1101010 j 1101011 k 1101100 l 1101101 m 1101110 n 1101111 o 1110000 p 1110001 q 1110010 r 1110011 s 1110100 t 1110101 u 1110110 v 1110111 w 1111000 x 1111001 y 1111010 z 1111011 { 1111100 | 1111101 } 1111110 ~ ``` 舉例來說,如果有個電腦的檔案存這個:`100101111000011101101110100111001111101111`。 當我們採用 ASCII 編碼去解讀他的時候,我們會每7個數字就切一段,像這樣:`1001011` `1100001` `1101101` `1101001` `1100111` `1101111`。 然後每一段都拿去查 ASCII 的表,看他對應的文字是什麼:`K` `a` `m` `i` `g` `o`。 最後印到螢幕上:`Kamigo`。 # 認識 Big5 節錄維基百科: > 「大五碼」(Big5)是由台灣財團法人資訊工業策進會為五大中文套裝軟體所設計的中文共通內碼,在1983年12月完成公告,隔年3月,資訊工業策進會與臺灣13家廠商簽定「16位元個人電腦套裝軟體合作開發(BIG-5)計畫(五大中文套裝軟體)」,因為此中文內碼是為臺灣自行製作開發之「五大中文套裝軟體」所設計的,所以就稱為Big5中文內碼。 簡單地說,Big5 是設計出來儲存中文用的編碼。每一種編碼使用的位元數不同,Big5 使用 16 位元去存一個文字。所以當我們採用 Big5 編碼去解讀上面那個檔案的時候,我們會每16個數字就切一段,像這樣:`1001011110000111` `0110111010011100` `1111101111`。所以當我們用了錯誤的編碼去解讀位元的時候就會導致亂碼。 有興趣看 Big5 的表可以到這個網址:[http://ash.jp/code/cn/big5tbl.htm](http://ash.jp/code/cn/big5tbl.htm) # 認識 UTF-8 UTF-8 就比較屌,他是設計出來儲存這世界上所有的文字和符號,就跟秦始皇統一度量衡一樣屌。 # 修網頁 所以我們先按照他提供的修改方法去改改看,在第一行告訴他,我們是用什麼編碼,像這樣寫:`# encoding:big5`。 ![](https://4.bp.blogspot.com/-rdPFUNyk89k/WkUz3hUnK_I/AAAAAAAA_r0/xO0kf4AQmS42KZMPEajs2ShH3xYn2VObQCLcBGAs/s1600/13.jpg) 這時再去點開[http://localhost:3000/](http://localhost:3000/)看看。 ![](https://1.bp.blogspot.com/-lnRdE8mUiS8/WkU0wOVIfRI/AAAAAAAA_sA/eTohgAy-eCQMKydZ4IJQqpdg5YmjsaoRwCLcBGAs/s1600/14.jpg) 終於~~ # 所以到底要怎麼樣才能弄出一個採用 UTF-8 編碼的文字檔呢~? 這題的答案是記事本太鳥了辦不到,請安裝其他文字編輯器。明天介紹各種文字編輯器。 # 重點 每次出錯的時候,錯誤訊息會引導你前往正確的路,記得要看。

2017/12/28

第九天:作一個最簡單的 Rails 網站( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 我們今天終於可以開始作網站了,首先我們要找一個地方放我們網站的程式碼。 # 建立一個 Rails 網站 先開啟檔案總管(`Windows`+`E`),移動到 `D:\只要有心,人人都可以作卡米狗` 這個資料夾下。 ![](https://3.bp.blogspot.com/-UeIFy3awQuA/WkPZ5L-SELI/AAAAAAAA_nY/MH_zfpTVI9cpG5qedRf2vs8fggnxT9jogCLcBGAs/s1600/1.jpg) 然後在網址列輸入 `cmd` 開啟小黑框。 ![](https://2.bp.blogspot.com/-xsgd4Tt_Ojs/WkPaAaX3k9I/AAAAAAAA_nc/kC5MplVgFn8deMI0Nxzk6mBFYrdADIUwgCLcBGAs/s1600/2.jpg) 我們要在這個資料夾建立一個名叫 `ironman` 的網站。 在小黑框輸入 `rails new ironman`。 ![](https://4.bp.blogspot.com/-eyOo7KNbPDo/WkPawYgwXVI/AAAAAAAA_nk/HM_b3jm6J3gF-HLJewT4QiorW2hLw-MCACLcBGAs/s1600/3.jpg) 然後按下 `Enter`。 ``` D:\只要有心,人人都可以作卡米狗>rails new ironman create create README.md create Rakefile create config.ru create .gitignore create Gemfile run git init from "." Initialized empty Git repository in D:/只要有心,人人都可以作卡米狗/ironman/.git/ create app create app/assets/config/manifest.js create app/assets/javascripts/application.js create app/assets/javascripts/cable.js create app/assets/stylesheets/application.css create app/channels/application_cable/channel.rb create app/channels/application_cable/connection.rb create app/controllers/application_controller.rb create app/helpers/application_helper.rb create app/jobs/application_job.rb create app/mailers/application_mailer.rb create app/models/application_record.rb create app/views/layouts/application.html.erb create app/views/layouts/mailer.html.erb create app/views/layouts/mailer.text.erb create app/assets/images/.keep create app/assets/javascripts/channels create app/assets/javascripts/channels/.keep create app/controllers/concerns/.keep create app/models/concerns/.keep create bin create bin/bundle create bin/rails create bin/rake create bin/setup create bin/update create bin/yarn create config create config/routes.rb create config/application.rb create config/environment.rb create config/secrets.yml create config/cable.yml create config/puma.rb create config/environments create config/environments/development.rb create config/environments/production.rb create config/environments/test.rb create config/initializers create config/initializers/application_controller_renderer.rb create config/initializers/assets.rb create config/initializers/backtrace_silencers.rb create config/initializers/cookies_serializer.rb create config/initializers/cors.rb create config/initializers/filter_parameter_logging.rb create config/initializers/inflections.rb create config/initializers/mime_types.rb create config/initializers/new_framework_defaults_5_1.rb create config/initializers/wrap_parameters.rb create config/locales create config/locales/en.yml create config/boot.rb create config/database.yml create db create db/seeds.rb create lib create lib/tasks create lib/tasks/.keep create lib/assets create lib/assets/.keep create log create log/.keep create public create public/404.html create public/422.html create public/500.html create public/apple-touch-icon-precomposed.png create public/apple-touch-icon.png create public/favicon.ico create public/robots.txt create test/fixtures create test/fixtures/.keep create test/fixtures/files create test/fixtures/files/.keep create test/controllers create test/controllers/.keep create test/mailers create test/mailers/.keep create test/models create test/models/.keep create test/helpers create test/helpers/.keep create test/integration create test/integration/.keep create test/test_helper.rb create test/system create test/system/.keep create test/application_system_test_case.rb create tmp create tmp/.keep create tmp/cache create tmp/cache/assets create vendor create vendor/.keep create package.json remove config/initializers/cors.rb remove config/initializers/new_framework_defaults_5_1.rb run bundle install Fetching gem metadata from https://rubygems.org/........... Fetching gem metadata from https://rubygems.org/.. Resolving dependencies..... Using rake 12.3.0 Using concurrent-ruby 1.0.5 Using i18n 0.9.1 Using minitest 5.10.3 Using thread_safe 0.3.6 Using tzinfo 1.2.4 Using activesupport 5.1.4 Using builder 3.2.3 Using erubi 1.7.0 Using mini_portile2 2.3.0 Using nokogiri 1.8.1 (x64-mingw32) Using rails-dom-testing 2.0.3 Using crass 1.0.3 Using loofah 2.1.1 Using rails-html-sanitizer 1.0.3 Using actionview 5.1.4 Using rack 2.0.3 Using rack-test 0.8.2 Using actionpack 5.1.4 Using nio4r 2.2.0 Using websocket-extensions 0.1.3 Using websocket-driver 0.6.5 Using actioncable 5.1.4 Using globalid 0.4.1 Using activejob 5.1.4 Using mini_mime 1.0.0 Using mail 2.7.0 Using actionmailer 5.1.4 Using activemodel 5.1.4 Using arel 8.0.0 Using activerecord 5.1.4 Using public_suffix 3.0.1 Using addressable 2.5.2 Using bindex 0.5.0 Using bundler 1.16.0 Using byebug 9.1.0 Using xpath 2.1.0 Using capybara 2.16.1 Using ffi 1.9.18 (x64-mingw32) Using childprocess 0.8.0 Using coffee-script-source 1.12.2 Using execjs 2.7.0 Using coffee-script 2.4.1 Using method_source 0.9.0 Using thor 0.20.0 Using railties 5.1.4 Using coffee-rails 4.2.2 Using multi_json 1.12.2 Using jbuilder 2.7.0 Using puma 3.11.0 Using sprockets 3.7.1 Using sprockets-rails 3.2.1 Using rails 5.1.4 Using rb-fsevent 0.10.2 Using rb-inotify 0.9.10 Using rubyzip 1.2.1 Using sass-listen 4.0.0 Using sass 3.5.4 Using tilt 2.0.8 Using sass-rails 5.0.7 Using selenium-webdriver 3.8.0 Using sqlite3 1.3.13 (x64-mingw32) Using turbolinks-source 5.0.3 Using turbolinks 5.0.1 Using tzinfo-data 1.2017.3 Using uglifier 4.0.2 Using web-console 3.5.1 Bundle complete! 13 Gemfile dependencies, 67 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. D:\只要有心,人人都可以作卡米狗> ``` 這邊可以先不用細讀,如果看到跟我的很像的話就是順利,不順利的人可以截圖在本文留言。 一個最簡單的網站就這樣作好了! # 看看建立的網站 先用 `dir /w` ,可以看到多了一個資料夾叫作 `ironman`。 ``` D:\只要有心,人人都可以作卡米狗>dir /w 磁碟區 D 中的磁碟是 GG 磁碟區序號: D403-9A5D D:\只要有心,人人都可以作卡米狗 的目錄 [.] [..] [ironman] 新文字文件.html 1 個檔案 37 位元組 3 個目錄 1,590,464,393,216 位元組可用 D:\只要有心,人人都可以作卡米狗> ``` 再用 `cd ironman` 移動到專案資料夾目錄下。 ``` D:\只要有心,人人都可以作卡米狗>cd ironman D:\只要有心,人人都可以作卡米狗\ironman> ``` 再用 `dir /w` 看資料夾內容。 ``` D:\只要有心,人人都可以作卡米狗\ironman>dir /w 磁碟區 D 中的磁碟是 GG 磁碟區序號: D403-9A5D D:\只要有心,人人都可以作卡米狗\ironman 的目錄 [.] [..] .gitignore [app] [bin] [config] config.ru [db] Gemfile Gemfile.lock [lib] [log] package.json [public] Rakefile README.md [test] [tmp] [vendor] 7 個檔案 7,601 位元組 12 個目錄 1,590,464,393,216 位元組可用 D:\只要有心,人人都可以作卡米狗\ironman> ``` 這就是剛剛的 `rails new ironman` 幫我們建立的檔案們。他自動生成了一個 rails 專案所需要的檔案,以及安裝相關的套件。好消息是這麼多資料夾和檔案,現階段我們都不需要認識。 # 執行網頁伺服器 我們直接用 `rails server` 執行網站伺服器。(注意:rails server 必須在專案資料夾執行才有效) ``` D:\只要有心,人人都可以作卡米狗\ironman>rails server => Booting Puma => Rails 5.1.4 application starting in development => Run `rails server -h` for more startup options *** SIGUSR2 not implemented, signal based restart unavailable! *** SIGUSR1 not implemented, signal based restart unavailable! *** SIGHUP not implemented, signal based logs reopening unavailable! Puma starting in single mode... * Version 3.11.0 (ruby 2.4.2-p198), codename: Love Song * Min threads: 5, max threads: 5 * Environment: development * Listening on tcp://0.0.0.0:3000 Use Ctrl-C to stop ``` 看到第一行 `Booting Puma` 這就是我之前說的 Puma 網頁伺服器。再看到最後面有一行 `Listening on tcp://0.0.0.0:3000` 是重點,看到這行表示 server 已經在運作了。 # 用瀏覽器連網頁伺服器 這時候你開啟這個網址:[http://127.0.0.1:3000](http://127.0.0.1:3000) 或者這個網址:[http://localhost:3000/](http://localhost:3000/) 就會看到你的網站。 網站長這樣: ![](https://1.bp.blogspot.com/-ciUbcz79xNU/WkPfvOMK8ZI/AAAAAAAA_n0/OdD3gHvS9o4gjJqJulkxHcLJtUqNscoZgCLcBGAs/s1600/4.jpg) 我可沒有要給你看我的初音主題哦。 回去看看小黑框,上面多了一些字像這樣: ``` Started GET "/" for 127.0.0.1 at 2017-12-28 01:57:53 +0800 Processing by Rails::WelcomeController#index as HTML Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.1.4/lib/rails/templates/rails/welcome/index.html.erb Rendered C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.1.4/lib/rails/templates/rails/welcome/index.html.erb (2.5ms) Completed 200 OK in 65ms (Views: 29.9ms) ``` 每當你開啟一次 [http://localhost:3000/](http://localhost:3000/),你就會看到多了一些字在小黑框上,這代表有人正在下載我們的網頁檔案。 # 網頁伺服器運作過程 這裡我們仔細讀一下看他寫些什麼,只有五行不難讀。 ``` Started GET "/" for 127.0.0.1 at 2017-12-28 01:57:53 +0800 ``` 這表示有客人在瀏覽器輸入了 [http://localhost:3000/](http://localhost:3000/) 透過網路連線過來了,他來我們拿一個檔案。 ``` Processing by Rails::WelcomeController#index as HTML ``` 我們這邊的服務生是由 `Rails::WelcomeController#index` 來作服務。 ``` Rendering C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.1.4/lib/rails/templates/rails/welcome/index.html.erb ``` 服務生決定拿 `C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.1.4/lib/rails/templates/rails/welcome/index.html.erb` 這個檔案的執行結果給客戶。 # 把網頁搞爆 為了證明這是你的網站,我們要修改一個檔案,來影響這個網站的畫面。 我們開一個新的檔案總管(`Windows`+`E`),並在網址列輸入`C:/Ruby24-x64/lib/ruby/gems/2.4.0/gems/railties-5.1.4/lib/rails/templates/rails/welcome/` (注意:你的路徑可能跟我的不同)。 ![](https://4.bp.blogspot.com/-HLi4knAuyoU/WkPi2s4m79I/AAAAAAAA_oE/IZmybl_pfXcfgmZ6gwTVnFHkRRtCT-fXQCLcBGAs/s1600/5.jpg) 嗯...為了避免初心者幼小的心靈遭受到巨大的打擊,我們千萬不要打開這個檔案。 我們先備份一下這個檔案,備份檔案的方式是新增一個資料夾叫`備份`。 ![](https://4.bp.blogspot.com/-d3r_TQzmB5k/WkPl_CeNKlI/AAAAAAAA_og/-0R41HdF-qQZfCz5ID_7jGxObLgyyF-aACLcBGAs/s1600/8.jpg) 然後把現在的這個 `index.html.erb` 用滑鼠拖曳的方式丟進`備份`資料夾裡。 ![](https://3.bp.blogspot.com/-4a3-3M4vXys/WkPmil3QRgI/AAAAAAAA_oo/K9JRWeVVLWkll78AELD0bn-YABYaQ0lVgCLcBGAs/s1600/9.jpg) 丟進去之後這裡就沒有 index.html.erb 這個檔案了。 ![](https://2.bp.blogspot.com/-IQD_r-56y5A/WkPmsAsHomI/AAAAAAAA_os/Xsu2RkyNjoQac7CZsocPuABQSt0Mqj5fACLcBGAs/s1600/10.jpg) 這時候我們再開一次網頁 [http://localhost:3000/](http://localhost:3000/)。 ![](https://1.bp.blogspot.com/-BtBVH5FCI1E/WkPnTOAWiXI/AAAAAAAA_o0/zy1ihV3kcPEFL0ru6SeRX15obU8B8rdBQCLcBGAs/s1600/11.png) 恭喜你獲得了 `第一次把網站搞爆就上手` 的成就。 因為他找不到 `index.html.erb` 這個檔案,所以就◢▆▅▄▃_崩╰(〒皿〒)╯潰_▃▄▅▆◣惹。 其實到這邊就已經證明了,[http://localhost:3000/](http://localhost:3000/) 這個網站真的是在我們的電腦上。 # 把網頁修好 這時我們要把他修好,我們在[第六天:認識網站](https://ithelp.ithome.com.tw/articles/10193664)有學過怎麼作網頁。 我們在這裡新增一個文字檔,並直接改名叫 `index.html`,再次開啟 [http://localhost:3000/](http://localhost:3000/)。 就會看到一個空白畫面。耶,我們把網站修好了。 # 關閉網頁伺服器 我們回到小黑框,按下 `Ctrl`+`C`。 ``` - Gracefully stopping, waiting for requests to finish === puma shutdown: 2017-12-28 02:48:28 +0800 === - Goodbye! Exiting 要終止批次工作嗎 (Y/N)? ``` 這邊輸入`Y`,`Enter`,網頁伺服器就被關掉了,這時候再去開網頁會看到什麼呢? [http://localhost:3000/](http://localhost:3000/) 。 ![](https://2.bp.blogspot.com/-Re-7K39CmRM/WkPrjBZkLwI/AAAAAAAA_pQ/unhp7T339V82eYoOBFNOPRftAh97trPeQCLcBGAs/s1600/14.jpg) # 結論 - 今天學會了怎麼作一個最簡單的 Rails 網站 - 今天學會執行和關閉網頁伺服器 - 還不知道為什麼 [http://localhost:3000/](http://localhost:3000/) 可以連到網站 - 還不知道為什麼在自己作的網站打中文,網站就會掛掉 如果你有偷偷研究,你會發現在我們作的網頁裡面放英文沒事,但放中文就會壞掉,明天講怎麼解決這個問題。

2017/12/27

第八天:安裝 Rails 和認識小黑框( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 今天會安裝 Rails,由於架網站需要用到大量的小黑框,所以今天主要會介紹小黑框。 # 安裝 Rails 先打開小黑框,忘記怎麼打開小黑框了嗎?按一下 `Windows`+`R` 叫出執行,並輸入 `cmd` 然後按`確定`。 ![](https://2.bp.blogspot.com/-5y8O3hv6agI/WkJqAjJngBI/AAAAAAAA_i4/ZN4LV-c_wWcaqim6t6POLdUBx8bQqxhwACLcBGAs/s1600/1.jpg) 輸入 `gem install rails` 然後按 `Enter`。 ![](https://1.bp.blogspot.com/-PUaAZMV1X14/WkJpirV0W8I/AAAAAAAA_i0/G_ttlKJHKmQd-N77iNRcH68t7MCB9a02QCLcBGAs/s1600/1.jpg) ![](https://1.bp.blogspot.com/-Ra7pn-WU1QA/WkJu7zcEnPI/AAAAAAAA_jI/JmsPjnlP39klDHJyKGfBRtci_Xv3-2ZjQCLcBGAs/s1600/2.jpg) 然後就裝好了~! 可以輸入 `rails -v` 檢查是否正確安裝 ![](https://4.bp.blogspot.com/-6kEf8gBTsCE/WkJvpXl8OWI/AAAAAAAA_jQ/9f9xxyhunpMq0iXliHDTHdlBSPDHqlBwQCLcBGAs/s1600/3.jpg) 如果你在這裡失敗的話,請在本文底下留言並附上失敗畫面。 你有注意到嗎?有時候我們安裝軟體的方式是用安裝精靈,安裝精靈就是`下一步`、`下一步`、`下一步`、`完成`的那種。但有時候安裝軟體的方法是開啟小黑框然後輸入一段文字,接下來就自動下載和安裝了。接下來我們會用到更多的小黑框,所以我想先介紹一下關於小黑框的事情。 # 認識小黑框 小黑框的正式名稱叫做命令提示字元,當我們執行 cmd.exe 時就會顯示這個。 ### 尋找小黑框 ![](https://3.bp.blogspot.com/-JFdCzUAUpZw/WkJ01zmLyYI/AAAAAAAA_jk/7cG5ujZnQlAZgMURV77vH9e4hEt-Cj_wACLcBGAs/s1600/3.jpg) 紅框框告訴你 cmd.exe 是放在哪,那我們就用檔案總管去看一下是不是真的在 `C:\WINDOWS\system32\` 資料夾下有 `cmd.exe`。 按下 `Windows`+`E` 開啟檔案總管。 ![](https://3.bp.blogspot.com/-Xr-pnmlDqaM/WkJ3BEdzJyI/AAAAAAAA_jw/jwl8XWfJmvMUsV5zTzuTnHkOfBw0CngdACLcBGAs/s1600/4.jpg) 其實檔案總管跟瀏覽器還蠻像的,都可以直接在網址列上面輸入路徑,我們先點一下網址列。 ![](https://3.bp.blogspot.com/-03A53YHKgIA/WkJ4shCVf6I/AAAAAAAA_j8/8wTezoZCFak_RGXvQ2SRNO6XghqiRmfQACLcBGAs/s1600/5.jpg) 然後輸入 `C:\WINDOWS\system32\`。 ![](https://1.bp.blogspot.com/-OeHNi5s10m8/WkJ418_BGAI/AAAAAAAA_kA/hRKPZmgDGXwmBedanWxEOwajnaYhbicZQCLcBGAs/s1600/6.jpg) 然後按下 `Enter`,就能直接抵達目標資料夾了。這裡檔案數量很多,要仔細找找。 ![](https://3.bp.blogspot.com/-gkkhxzLu8mk/WkJ49df0COI/AAAAAAAA_kE/AnSRqxzrLs0l3rPOqytjstsSPY8wBzqnwCLcBGAs/s1600/7.jpg) 找到囉!點兩下打開看看是不是真的小黑框。 ### 小黑框其實是檔案總管 ![](https://3.bp.blogspot.com/-JFdCzUAUpZw/WkJ01zmLyYI/AAAAAAAA_jk/7cG5ujZnQlAZgMURV77vH9e4hEt-Cj_wACLcBGAs/s1600/3.jpg) 現在我們來看藍框框代表什麼意思,藍框框指的是目前的所在位置。 我們用一樣的方法,從檔案總管過去看看,我們把左邊藍框框的內容(在我的電腦上是 `C:\Users\ETREX` 你的可能是別的)填到檔案總管的網址列上然後按 `Enter`。 ![](https://1.bp.blogspot.com/-vcRIKOjg7rs/WkJ8xwUBrgI/AAAAAAAA_kc/MSu2YQW696Mv9wrapY0JWMLZWCaua__gACLcBGAs/s1600/8.jpg) 我把小黑框放左邊,檔案總管放右邊,讓你看兩個有多像。 現在我們在左邊的小黑框輸入 `dir` ,`dir` 是 directory(目錄)的意思,他會列出在目前位置下的所有資料夾和檔案。 ![](https://1.bp.blogspot.com/-sJ_bEWgNWfA/WkJ9duz8T8I/AAAAAAAA_kw/XtSPUiodkacmiFGwKtxf0DL0ltB1LqfdgCLcBGAs/s1600/9.jpg) 但是他太長了,只能看到最後面。這次我們輸入 `dir /w` ,這個指令可以讓他看起來跟右邊比較像。 ![](https://2.bp.blogspot.com/-Nw4xHlKYB3o/WkJ-ESEIlNI/AAAAAAAA_k4/9Mj2kD3CbYAIHxK7ymZZRd_5frYmpxOLwCLcBGAs/s1600/10.jpg) 看起來有沒有很像!! 我們可以在檔案總管這邊新增一個資料夾叫作「只要有心,人人都可以作卡米狗」,然後再回到左邊重新輸入一次 `dir /w` ![](https://1.bp.blogspot.com/-FgiYQcJOz8Y/WkJ_GhUrPEI/AAAAAAAA_lI/du-XPzU4U50xGB6BAzVEseQPLoHT8uOVQCLcBGAs/s1600/11.jpg) 現在你可以完全理解小黑框其實就是檔案總管,小黑框的藍框框就是檔案總管的網址列,代表目前所在資料夾。 ### 切換資料夾 在小黑框不能用滑鼠,所以所有的操作都是透過指令,像我們輸入 `dir` 就會顯示目前所在資料夾下的資料夾和檔案,所以我們如果想要切換資料夾,也要輸入指令。切換資料夾的指令是 `cd`,意思是 change directory(切換目錄)。 舉例來說,我們在檔案總管想進入剛剛建立好的資料夾「只要有心,人人都可以作卡米狗」,就是點兩下滑鼠就好。那麼在小黑框則是輸入`cd 只要有心,人人都可以作卡米狗`,請注意 `cd` 和 `只要有心,人人都可以作卡米狗`的中間需要一個空白鍵。 ![](https://1.bp.blogspot.com/-7yqw_IfspEM/WkKE8z7V3vI/AAAAAAAA_lk/u6OwyIaxisU7INK36ycZ33lKz6G8puLrgCLcBGAs/s1600/13.jpg) 進入資料夾後必須重新輸入 `dir` 才能看見資料夾的內容。 ![](https://1.bp.blogspot.com/-JfgxWIjzEQk/WkKE09gTeFI/AAAAAAAA_lc/u2ttg26OZtsJmoQ93PU23y7tBd0vmBKLgCLcBGAs/s1600/14.jpg) 在這裡看見左邊有兩個資料夾,一個叫 `.`,另一個叫 `..`,但是右邊卻什麼都沒看到。其實 `.` 代表的是目前資料夾,而 `..` 代表的是上一層資料夾。意思是如果我們想回到上一層,可以輸入 `cd ..`。 ![](https://4.bp.blogspot.com/-kVwXilNfyO0/WkKF2kOpB_I/AAAAAAAA_l0/Pl5xOatsqiQBYT-GdsspO67zY4-WB6enACLcBGAs/s1600/15.jpg) ### 切換硬碟 不知為何,`cd` 指令不能拿來切換硬碟。試著輸入 `cd D:` 卻發現停留在原地。 ![](https://1.bp.blogspot.com/-y9mqoVaNmGs/WkKGXg5fNzI/AAAAAAAA_l8/3YaMxyWbfPEUA4KjSJ7zSYNSNDixZp-mACLcBGAs/s1600/16.jpg) 其實切換硬碟的方式是直接輸入 `D:` 就可以了。 ![](https://1.bp.blogspot.com/-c39Qhra7DOk/WkKHFipLuAI/AAAAAAAA_mI/RP1DQ8Nqh9IdO9ll7kKHAnabIeqv4wB8ACLcBGAs/s1600/17.jpg) ### 快速地開啟一個小黑框在指定的目錄下 其實在檔案總管的網址列輸入 cmd 也可以叫出小黑框,而且這個小黑框會直接幫你切換到和檔案總管一樣的目錄。 像這樣: ![](https://1.bp.blogspot.com/-vN3Map3pIGQ/WkKIMtNcW0I/AAAAAAAA_mU/Hugaei3gf00wWu8UaNhvBz6qAImDCCIfACLcBGAs/s1600/18.jpg) 按下 `Enter` 後就會跳出小黑框了。 ![](https://1.bp.blogspot.com/-2yWJmkKCN4o/WkKISQv9_8I/AAAAAAAA_mY/0Uo9Vfj295AwKRVdNFWTRR8qo_PCccRlQCLcBGAs/s1600/19.jpg) 今天就學到這裡,明天我們就要作網站了。

2017/12/26

第七天:認識網頁伺服器( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown # 前情提要 在之前的教學裡,我們已經了解到,瀏覽器其實是一個透過 HTTP 協定即時下載檔案並顯示在畫面上的程式。應該忘得差不多了吧?我們這邊再回顧一次關於 HTTP 協定: ![](https://4.bp.blogspot.com/-cFkpN4IAz1w/WkE6J9FMrqI/AAAAAAAA_ho/IGdVTis8A_4-as8FPkeP8tZPj8yvkQxEQCLcBGAs/s1600/1.jpg) HTTP 協定講的是瀏覽器和網頁伺服器如何進行交流,我們目前對於瀏覽器已經有足夠多的認識,但對於網頁伺服器卻還是一片空白。 你能了解瀏覽器是因為你看得見、摸得到、安裝且使用過瀏覽器。所以為了使你深入了解網頁伺服器,我應該也讓你能像玩玩具一般,玩一下網頁伺服器。 網頁伺服器跟瀏覽器一樣有非常多套軟體,我只介紹一套,而你一定要跟我同一套,要不然你看到的畫面會跟我不同,我後面會講不下去。 卡米狗是使用 Ruby 程式語言以及 Rails 網站框架作出,而 Rails 預設的網頁伺服器是用 Puma,所以我們也會用 Puma。 # 相信自己作得到 接下來的路程,會很漫長。 在出發之前,先聽一首歌:[https://www.youtube.com/watch?v=8nd8Xcs3rOw](https://www.youtube.com/watch?v=8nd8Xcs3rOw) 請你相信自己,也相信我:「只要有心,人人都可以作卡米狗」,我不會帶你走冤枉路的。 那麼,我們從安裝 Ruby 開始。 # 在不是 Windows 的系統上安裝 Ruby 請參考這篇教學:[https://railsbook.tw/chapters/02-environment-setup.html](https://railsbook.tw/chapters/02-environment-setup.html) # 在 Windows 系統上安裝 Ruby 首先打開這個網頁:[https://rubyinstaller.org/downloads/](https://rubyinstaller.org/downloads/) ![](https://2.bp.blogspot.com/-mMnlV99fmgs/WkEcSa6IB_I/AAAAAAAA_eE/ilalGaiZ5uAZGUm9OeZm_LnOs7Wmz2togCLcBGAs/s1600/0.jpg) 點擊紅色框框圈起來的部分,點完之後會獲得一個安裝檔,再點兩下安裝檔進行安裝。 ![](https://3.bp.blogspot.com/-hljKu9kZc5M/WkEfYrhekmI/AAAAAAAA_eU/vIF08oeldVIoAO-RQtddd_4On49p7r_SwCLcBGAs/s1600/1.jpg) 這邊是叫你看一下使用條款,選 `I accept the License` 然後按 `Next`。 ![](https://3.bp.blogspot.com/-SbZOujp_X08/WkEf4_u238I/AAAAAAAA_ec/cKt-vE85JdQmROf-i4zM2pdwcUMGUJbUQCLcBGAs/s1600/2.jpg) 選擇安裝路徑,這邊就直接用預設路徑,不要改。 下面有三個勾勾分別是: - 把 Ruby 資料夾加入到你的環境變數 PATH (日後會再詳細介紹) - 把副檔名 .rb 和 .rbw 預設為用 Ruby 開啟 - 使用 UTF-8 作為預設編碼 跟我勾一樣的就好。 ![](https://2.bp.blogspot.com/-Zf4XkmkX-2U/WkEhPx4fCNI/AAAAAAAA_eo/3eYvSExawNYo7UsO78AYzNvt42mOhQrJwCLcBGAs/s1600/3.jpg) 裝好了,這裡有個勾勾是問說要不要安裝得更完整一點?當然是要。 ![](https://3.bp.blogspot.com/-QWZJ3XNljMU/WkEhvUskDMI/AAAAAAAA_es/n1oMc0W2NmEvQ1b1PGzHDwz8pZJvIDJmgCLcBGAs/s1600/4.jpg) 這個小黑框叫命令提示字元,看起來就跟 BBS 有 87% 像。 他問說:「您好,請問您要單點還是套餐?」這邊我們直接按`Enter`就可以了。 ![](https://2.bp.blogspot.com/-U7d4p_9SJlc/WkEij7zXFNI/AAAAAAAA_e8/_kvNngjm7Own-Dd7Yb0tCVC7V0WabaVzACLcBGAs/s1600/5.jpg) 他說歡迎光臨,我們點`Next`。 ![](https://4.bp.blogspot.com/-K_8APP7WLyE/WkEixtSRV6I/AAAAAAAA_fA/2tLi9wEv2uwTt9CC6nCqCgV69OiZ236uwCLcBGAs/s1600/6.jpg) 請問內用還是外帶?我們點`Next`。 ![](https://2.bp.blogspot.com/-tI4TwRZSDz8/WkEjD6kh_1I/AAAAAAAA_fE/WidC6sWso3IYsVeIqTUWrW04-euWH_FNgCLcBGAs/s1600/7.jpg) `Next` ![](https://2.bp.blogspot.com/-jffydxxaJoM/WkEk9GCczjI/AAAAAAAA_fU/Ql-MSK56_3kqWpEZ6Ioed_ATbT4MV8bxACLcBGAs/s1600/8.jpg) 安裝好MSYS2 64bit 了,請問要立即執行嗎? 這裡勾勾取消掉再按`Finish`。 如果你沒有取消就按下`Finish`的話,就會多跳一個小黑框出來: ![](https://2.bp.blogspot.com/-OZT4vqsU71M/WkElZQbIEGI/AAAAAAAA_fY/Bv4IFRZi9WgAX9UGjtEk7K9bJRDubw1lQCLcBGAs/s1600/9.jpg) 我們不會用到他,所以直接點右上角的 X 關閉他就好。 而原本的小黑框會繼續跑,最後會變成這樣: ![](https://3.bp.blogspot.com/-YaprkxKxwCk/WkEl7HRiKjI/AAAAAAAA_fk/KoxhJ4UKJokyQCJCoQB8q69O-Wl5HgwkACLcBGAs/s1600/10.jpg) 他說裝好了,這邊我們按下`Enter`,結束這個回合。 讓我們來確認一下 Ruby 是不是正確安裝完成。 # 叫出小黑框 我們要先叫出一個小黑框,首先按一下 `Windows`+`R` 叫出執行,並輸入cmd。 ![](https://3.bp.blogspot.com/-bEZklORmgRo/WkEoZLPLPgI/AAAAAAAA_fw/-ZqiyAKgUl4EPal_yVBhkhpR8owBCPyUQCLcBGAs/s1600/2.jpg) 然後按`確定`。 ![](https://4.bp.blogspot.com/-sAPxrdIDLZU/WkEotpPCJVI/AAAAAAAA_f0/v8qq0cDA5bEfnyXz9sAFDqineFloDYPjwCLcBGAs/s1600/3.jpg) 這樣就可以叫出一個小黑框,其實他跟檔案總管很像,日後會再詳細介紹。 這裡輸入 `ridk version` 然後按 `Enter`。 ![](https://2.bp.blogspot.com/-rSbsLZYcIPs/WkEqZwEu4NI/AAAAAAAA_gI/p6c0KrO-KWQf1hDI54EQBHoAbe3zOtfoQCLcBGAs/s1600/4.jpg) 如果看到跟我差不多的結果,恭喜你完成了 Ruby 的安裝。 # 在安裝過程中遇到障礙了嗎? 如果在安裝過程中遇到任何障礙,請把你遇到障礙的畫面作螢幕截圖,並將圖片貼到本文底下的留言區。 # 我不會作畫面截圖,怎麼辦? 先按下 `Alt`+`Print Screen` 鍵會複製目前的畫面,再找個地方貼上(`Ctrl`+`V`),比方說小畫家,或者 Line PC版的對話框都可以。 ![](https://4.bp.blogspot.com/-lMDmHWRIcXo/WkEux-UrTXI/AAAAAAAA_gk/fcntr6x316oDxNzgS3XWILluXnTtXel7wCLcBGAs/s1600/7.jpg) 以 Line PC版來說,你可以選擇直接按貼上的快速鍵:`Ctrl`+`V`,或者在這個區域點右鍵再按`貼上`。 送出訊息之後,再按下載,就獲得畫面截圖囉。當然如果你要用手機直接對電腦螢幕拍照也行,只是畫質會比較差。 # 我找不到 Print Screen 鍵,怎麼辦? 他在這個位置: ![](https://1.bp.blogspot.com/-gLJEcnMItec/WkE0ULt9FVI/AAAAAAAA_hQ/qHLhwg-LgE061iDlN0b7KR-Rs9qbtip5ACLcBGAs/s1600/5.jpg) 你可能會看到按鍵上的字是寫 `Prnt Scrn`或`PrtSc`或`PrtSc SysRq`,而不是 `Print Screen`,不過沒關係,就是他了。 # 我不會上傳圖片,怎麼辦? 你可以使用imgur:[https://imgur.com/](https://imgur.com/) ![](https://1.bp.blogspot.com/-ny2JVk4h8XE/WkExwO7fH-I/AAAAAAAA_g0/H9WIkAkl_cAn2Fdg227LYThuCV4LsL5CACLcBGAs/s1600/8.jpg) 點一下左上角 `New post` ![](https://1.bp.blogspot.com/-m4jIP4dR26A/WkEyF64Zq5I/AAAAAAAA_g4/0ct8kCfb1PcL3t5vPrD63kBh5KcH_76mQCLcBGAs/s1600/9.jpg) 將圖片拖曳到長頸鹿那裡,或者點一下 `Browse` 按鈕,選擇你想要上傳的圖片。 ![](https://3.bp.blogspot.com/-tZ8ld5mEuLE/WkEzVS4HomI/AAAAAAAA_hE/rGO9bwv_jfMKuu9CKAJ7EUr9h4orvYFxwCLcBGAs/s1600/10.jpg) 然後按`Copy` 複製網址。 # 我沒有電腦,怎麼辦? 嗯,去買一台ㄅ 祝大家安裝 Ruby 順利,明天安裝 Rails 。

2017/12/25

第六天:認識網站( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 上一篇:第五天:認識 Line Messaging API Webhook (本系列文假設讀者沒有資訊背景,使用 windows 作業系統電腦,會使用中文輸入法。) 今天要來教大家認識網站。在介紹網站之前,我想先介紹一下瀏覽器。 # 認識瀏覽器 瀏覽器就是能讓你的電腦或手機(以下統稱電腦)顯示網頁的程式。不過科技日新月異,瀏覽器能作的事情越來越多,古代的瀏覽器只能用來開網頁。現代的瀏覽器以 Chrome 為例,除了可以用來開網頁,還可以用來看檔案和資料夾。支援各種檔案:PDF、SVG、各種圖檔、聲音檔和影片檔。 ### 常見的瀏覽器 ![](https://1.bp.blogspot.com/-NBWNnoUtxVg/Wj_ImqvZKXI/AAAAAAAA_V4/u5MnPH2e33spShJ2t1wFDwe-_sM5nYZQgCLcBGAs/s1600/223px-Internet_Explorer_10%252B11_logo.svg.png) Internet Explorer(IE):這是微軟出的瀏覽器,也是一般人買一台新電腦時就會內建的瀏覽器。對一般人來說,這就是唯一的瀏覽器。但對宅宅來說,這是用來安裝瀏覽器的瀏覽器。 ![](https://4.bp.blogspot.com/-Jb3h9RM4EZ0/Wj_K1aNN5oI/AAAAAAAA_WE/jgKuf-U7sLAHDFqNITT1AkBcWQJFaFVUACLcBGAs/s1600/200px-Firefox_Logo%252C_2017.svg.png) Mozilla Firefox(火狐):這款瀏覽器在 2004 年發布第一版,他的特色是可以安裝很多外掛,讓你可以做事更有效率。 ![](https://2.bp.blogspot.com/-1lOlOOSaSBU/Wj_K7R_s-MI/AAAAAAAA_WI/gRiJUTeHbRQriNsA9wRbGMtZByJJ_bpqQCLcBGAs/s1600/200px-Google_Chrome_icon_%2528September_2014%2529.svg.png) Google Chrome:這款是 Google 出的瀏覽器,在 2008 年發布第一版,是目前主流的瀏覽器,因為接下來的說明會使用這個瀏覽器,所以請大家安裝。 安裝 Chrome 請點連結:[https://www.google.com.tw/chrome/browser/desktop/index.html](https://www.google.com.tw/chrome/browser/desktop/index.html) 請先安裝完 Chrome 再繼續閱讀本文。 ### 認識網頁 一個網頁其實就是一個文字檔,而且你可以很容易地用記事本作出一個網頁。現在我要教你怎麼作一個網頁。 ### 認識檔案總管 先按住鍵盤上的`windows`鍵然後按一下`E`鍵,就可以叫出檔案總管。 `windows`長這樣: ![](https://3.bp.blogspot.com/-4JeQQCzMQlU/Wj_WEeYhL4I/AAAAAAAA_Wk/BSaHqO-2TI4XCa_DyhBq3ZeAck_C89qNgCLcBGAs/s1600/CtrlWindowsAlt.jpg) 就是在 `Ctrl` 跟 `Alt` 中間的那顆鍵。 成功的話就會看見檔案總管: ![](https://1.bp.blogspot.com/-UL4dKIPHSQ4/Wj_W3rckGCI/AAAAAAAA_Wo/PkO1-6eGQP8_7QMuAoYpRRtEIDSEHEg3ACLcBGAs/s1600/1.png) 先按住鍵盤的`windows`鍵然後按一下`E`鍵,我們通常會簡寫為 `windows`+`E`。像這樣透過鍵盤快速鍵叫出程式的方法,學會之後,只要在朋友面前露兩手,人家就會覺得你很厲害。 這裡教你兩招: `windows`+`D`可以顯示桌布,再按一次就會復原。 `windows`+`L`可以鎖定螢幕。 ### 新增資料夾 先點一下左側的`本機` ![](https://3.bp.blogspot.com/-Lsfuw6MEH10/Wj_bHZhhu8I/AAAAAAAA_W4/dVXqiGvMZG0lKjGJomAdOnZbaAbl23W_ACLcBGAs/s1600/2.png) 有D槽`(D:)`就點D槽,沒有D槽的點C槽`(C:)`。點進去之後捲到最下面,找到一個空白處比較多的地方,然後對著空白處點右鍵。 ![](https://2.bp.blogspot.com/-p45pNkCHe_M/Wj_ciao322I/AAAAAAAA_Xs/hM-EgXM9GzMLYwjWG7N4Wdj3scFZA5rogCLcBGAs/s1600/3.png) 然後你會看到上圖,點一下`新增(W)`,然後點`資料夾(F)`。 ![](https://3.bp.blogspot.com/-qo_OTlt-1hQ/Wj_dgyGV4lI/AAAAAAAA_X4/voffYlRjxQA287Us_FqbLKKZ-AKcC-G0wCLcBGAs/s1600/4.png) 輸入「只要有心,人人都可以作卡米狗」,然後按 `Enter`。資料夾名稱只是為了識別用,你不打也沒關係,只是我怕你到時候找不到,所以幫你想了一個很棒的資料夾名稱,就甘心耶。 ### 新增文字檔 先點進去剛作好的資料夾裡面,這次點新增文字文件。 ![](https://3.bp.blogspot.com/-J3_tbOqoFd0/Wj_fn6DktlI/AAAAAAAA_X8/3GM2HtcJEFwGGe5ZnJNG_OgdG05-2ZlxQCLcBGAs/s1600/5.png) 新增完檔案應該會看到這個樣子: ![](https://2.bp.blogspot.com/-sAavUhuSl1I/Wj_hx_itxfI/AAAAAAAA_Zw/6gajkgYkAE4RKbIamkUIvfLV0oLuN1E3QCLcBGAs/s1600/6.PNG) 請注意看這個位置: ![](https://3.bp.blogspot.com/-GECkDEIULgg/Wj_iMasDtJI/AAAAAAAA_aE/cTsnCXTS59EMkSpovt2_Z0rvAu7bkiKPQCLcBGAs/s1600/7.jpg) 如果你看不到 `.txt` 的話,代表你的系統目前是不顯示副檔名。 ### 認識副檔名 ![](https://1.bp.blogspot.com/-OkOL8UXJGds/Wj_mdBu5nAI/AAAAAAAA_a4/0Q7T2tRnZukf5FWi5iE1FDFCIxsZTp1RwCLcBGAs/s1600/8.jpg) 先點上面的 `檢視`,然後把副檔名打勾,應該就會顯示副檔名了。 一個檔案名稱最後一個 `.` 的右邊就是這個檔案的副檔名,以這個檔案為例,副檔名就是`txt`。`txt` 代表他是一個很單純的文字檔。 接著嘗試修改副檔名,修改副檔名的方法跟修改檔名的方法一樣,所以我們對檔案按右鍵選 `重新命名`,然後我們把副檔名改成 `html`。 ![](https://3.bp.blogspot.com/-zC-QwZwQaLg/Wj_pxXkZbjI/AAAAAAAA_bU/TLLiAVm-sVI6bf6AsUUU8aWihuKwMiEuQCLcBGAs/s1600/10.png) 你會看到這個警告:「如果您變更副檔名,檔案可能會變成無法使用。您確定要變更嗎?」,我們當然是選「是」。 ![](https://4.bp.blogspot.com/-f-Krlb9AqKI/Wj_qVWRon5I/AAAAAAAA_bc/8iF7ekAGKygiXOLvnG58rJeCQW90kTugwCLcBGAs/s1600/11.jpg) 改完之後,你會注意到檔案前面的圖示變成 chrome 的圖示了。那是因為 `html` 代表他是一個網頁檔,所以會用瀏覽器開啟,而我電腦的預設瀏覽器是 chrome,所以顯示圖示是 chrome 的圖示。 這表示什麼呢? - 電腦會根據副檔名來決定要怎麼解讀檔案的內容。 - 雖然他是一個空網頁!但你已經會作網頁了! 點兩下開啟檔案,是不是看到一個全白的網頁了呢? ### 修改網頁 接下來我們來作個有內容的網頁!首先把檔案的副檔名改回 `txt`,然後點兩下開啟記事本,然後輸入: ```

只要有心,人人都可以作卡米狗

``` 看起來像這樣: ![](https://3.bp.blogspot.com/-R0EfsfTDYBU/Wj_vZQyKqeI/AAAAAAAA_bs/JWJRBr5NLUI9Cfjs2G4Ai_fV69N604xaACLcBGAs/s1600/12.jpg) 你要用複製貼上的也可以,然後存檔,存檔的快捷鍵是`Ctrl`+`S`,存好檔案就按右上角的叉叉關閉記事本。 對了,我說過瀏覽器可以開啟很多種檔案,其中也包含了 `txt` 檔。這次我們用瀏覽器開啟 `txt` 檔。 ### 用瀏覽器開啟 txt 檔(純文字檔) ![](https://2.bp.blogspot.com/-iUkVEkTn7KA/Wj_wsF1x0AI/AAAAAAAA_bw/KvbxNtt79Pws_6SAS99M_Qs5iGOAXacZgCLcBGAs/s1600/13.png) 用滑鼠左鍵按住檔案。 ![](https://2.bp.blogspot.com/-_Pf6BCJa4ao/Wj_xAFruj6I/AAAAAAAA_b0/7zlBSwrMJsAEYmmAECospRNdC-IoiuiYgCLcBGAs/s1600/14.png) 拖曳滑鼠到瀏覽器。 ![](https://1.bp.blogspot.com/-EnQiRKOIiPo/Wj_xKzNXEMI/AAAAAAAA_b4/-Kg8CW5fevE-RpsMCcZJlMucgf2FXsSxwCLcBGAs/s1600/15.png) 然後放開滑鼠,就成功使用瀏覽器開啟檔案了。 當然你在網址列輸入以下文字也能夠開啟檔案: ``` file:///D:/只要有心,人人都可以作卡米狗/新文字文件.txt ``` 這時候我們看到的內容,就跟我們輸入在記事本裡的一模一樣。 ### 用瀏覽器開啟 html 檔(網頁檔) 接著把副檔名改成 `html` 然後再用瀏覽器開啟看看。 ![](https://3.bp.blogspot.com/-62fU9t9kZwM/Wj_yIh_g4BI/AAAAAAAA_b8/8l-Q5TeheQ4e_6i96X-T-C4Q8KdjxvhTwCLcBGAs/s1600/16.png) 你會看到字變大了,而且開頭的 `

` 和結尾的 `

` 消失了。 那是因為 `

` 代表接下來的內容是大標題(比較大的字),而 `

` 代表的是大標題就到這裡結束。 ### 瀏覽器的運作原理 瀏覽器就是一個用來看網頁的工具,而你可以把一個網址想像成別人硬碟裡的檔案。當你輸入一個網址時,瀏覽器會從別人的硬碟讀取網頁檔並顯示在畫面上。 ### 認識網站 網站就是一堆網頁檔,透過點超連結來切換目前正在看的網頁。你可以想成點超連結就是自動幫你在網址列輸入那個網頁路徑。 所以架網站就是弄一台開著給人家下載網頁的電腦,術語叫做網站伺服器。所以網站伺服器的電腦都是從來不關機的。 今天就先講到這裡。明天講網站伺服器。

2017/12/24

第五天:認識 Line Messaging API Webhook( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 上一篇:[第四天:認識 Webhook](http://etrex.blogspot.tw/2017/12/webhook-2018-it.html) # Line Messaging API Webhook 運作原理 不囉嗦直接上圖 ### 訂閱階段 ![](https://2.bp.blogspot.com/-kxknruACX3I/Wj6UvTo4f7I/AAAAAAAA_VA/jLWgZZdiv2UiwC5rq6GGHTfQiZrHjfgjgCLcBGAs/s1600/%25E8%25A8%2582%25E9%2596%25B1%25E9%259A%258E%25E6%25AE%25B5.jpg) 這個階段是我們在 Line developer 後台填入卡米狗的通訊地址,然後按下送出。 ### 通知階段 ![](https://3.bp.blogspot.com/-kwwT-8P30oE/Wj5yBJTV0FI/AAAAAAAA_Ss/_OwqTJ6xKzsBzLUjcAcDGjJLSKKRjO2xQCLcBGAs/s1600/%25E5%25A5%25BD%25E5%258F%258B%25E7%25BE%25A4%25E7%25B5%2584%25E6%2596%2587%25E5%25AD%2597%25E8%25A8%258A%25E6%2581%25AF.jpg) 這個階段是當有人使用 Line 傳訊息給卡米狗所在的群組,就會收到通知。Line 會把這樣的訊息傳到我們設定好的通訊地址。 ### 行動階段 ![](https://1.bp.blogspot.com/-hsv1_lfXBh4/Wj5yJKGU9BI/AAAAAAAA_Sw/q4Oo4DZ4aB4EYEK7hEd6Er1TzxYKMAmFACLcBGAs/s1600/%25E5%259B%259E%25E8%25A6%2586%25E8%25A8%258A%25E6%2581%25AF.jpg) 這個階段是卡米狗回應群組訊息,卡米狗會把訊息傳給 Line ,然後 Line 再幫我們傳到群組。 所以 Line 扮演的就只是個傳話的工具人。 以上就是一個完整的 Line Messaging API Webhook 運作原理,每一張圖都代表了一次 HTTPS 協定的傳輸(一個 HTTPS Request + 一個 HTTPS Response),在這裡你可以注意到全部的回應都是「好哦~好哦~」,這是表示簽收包裹的意思。 圖中的#01、#02表示一個代號,用來做識別用,同一個用戶會有同一個代號。就跟唐伯虎的代號叫9527一樣,在我們這裡不稱呼你為唐伯虎。「[9527就是你的終生代號,開始做事!](https://www.youtube.com/watch?v=eNfVcWJv96I)」 # Line Messaging API 的各種通知 ### 你被加好友 ![](https://3.bp.blogspot.com/-SCTVvx3ZG3E/Wj6GADhZo3I/AAAAAAAA_TA/1q3EZOV-cEYoR-0JdeZI8Tf6AayrjlEswCLcBGAs/s1600/%25E5%258A%25A0%25E5%25A5%25BD%25E5%258F%258B.jpg) ### 你被封鎖 ![](https://2.bp.blogspot.com/-lEXOW2DTVkE/Wj6GF8RlWsI/AAAAAAAA_TE/IFgHGNl2VPEIcbZ52Lsx5jAVFWGKKGy6QCLcBGAs/s1600/%25E5%25B0%2581%25E9%258E%2596.jpg) ### 你被加入群組 ![](https://3.bp.blogspot.com/-RkHc92cw_JQ/Wj6GMcDodcI/AAAAAAAA_TI/_y8U3gX9qbwoMh3Z1CB7HYuuVAiapKgLgCLcBGAs/s1600/%25E9%2580%25B2%25E5%2585%25A5%25E7%25BE%25A4%25E7%25B5%2584.jpg) ### 你被踢出群組 ![](https://4.bp.blogspot.com/-F_duK0UmLEk/Wj6GTTOSypI/AAAAAAAA_TM/qWsVSolPhLgosngF-OHl4dqLahoDcidTwCLcBGAs/s1600/%25E8%25A2%25AB%25E8%25B8%25A2%25E5%2587%25BA%25E7%25BE%25A4%25E7%25B5%2584.jpg) ### 有人加入你已經在裡面的群組 沒有,沒有這種通知,所以沒辦法在有人加入群組時讓卡米狗跟他打招呼。 因為 Line 不給的,你不能拿。 ### 在聊天室的陌生人傳送的文字訊息 ![](https://1.bp.blogspot.com/-VPc5aJNn8-E/Wj6HX5mHK0I/AAAAAAAA_Tg/c7P3q8OdBQEraR4gnF-PRhQtkN4PLXZRACLcBGAs/s1600/%25E9%259D%259E%25E5%25A5%25BD%25E5%258F%258B%25E8%2581%258A%25E5%25A4%25A9%25E5%25AE%25A4%25E6%2596%2587%25E5%25AD%2597%25E8%25A8%258A%25E6%2581%25AF.jpg) ### 在群組的陌生人傳送的文字訊息 ![](https://3.bp.blogspot.com/-NQsF_b8z6Gk/Wj6G9Jc-H1I/AAAAAAAA_TY/TG4utKjKMsUThCONug0nzMgqqrjyV-F1wCLcBGAs/s1600/%25E9%259D%259E%25E5%25A5%25BD%25E5%258F%258B%25E7%25BE%25A4%25E7%25B5%2584%25E6%2596%2587%25E5%25AD%2597%25E8%25A8%258A%25E6%2581%25AF.jpg) ### 在群組的好友傳送的文字訊息 ![](https://2.bp.blogspot.com/-q1ra7PmWvMI/Wj6H438ZbzI/AAAAAAAA_Ts/my572yCR-a8xJ4k2qdHKeOh3wrJU7Yu2wCLcBGAs/s1600/%25E5%25A5%25BD%25E5%258F%258B%25E7%25BE%25A4%25E7%25B5%2584%25E6%2596%2587%25E5%25AD%2597%25E8%25A8%258A%25E6%2581%25AF.jpg) 其實這邊的好友是聊天機器人之友。他不一定有加你好友,只要他有加任何一個 Line 聊天機器人好友,你就能知道他是誰。 ### 在私訊的文字訊息 ![](https://1.bp.blogspot.com/-Zl_yRjCWBOY/Wj6Ic5h60XI/AAAAAAAA_T0/iJB_RVwNzvs7cVWh7V_DmiSOJFIjoUwEACLcBGAs/s1600/%25E7%25A7%2581%25E8%25A8%258A.jpg) 以下就用私聊示範各種訊息類型: ### 貼圖訊息 ![](https://2.bp.blogspot.com/-uQYm035wYs8/Wj6Pvk4cFrI/AAAAAAAA_UM/hgYcvyYexqsPwukCmHmrOdOx-2pQ519IgCLcBGAs/s1600/%25E8%25B2%25BC%25E5%259C%2596%25E8%25A8%258A%25E6%2581%25AF.jpg) ### 圖片訊息 ![](https://2.bp.blogspot.com/-egx3M9aBqPc/Wj6KOJ05tOI/AAAAAAAA_T8/YfW6FIkhBPwQg9F3BwilAvSpgSmRSL8HQCLcBGAs/s1600/%25E5%259C%2596%25E7%2589%2587%25E8%25A8%258A%25E6%2581%25AF.jpg) ### 影片訊息 ![](https://1.bp.blogspot.com/-ZjKkfD6CthU/Wj6P2VwcBlI/AAAAAAAA_UQ/ZUz-u86QEJoF7FiDLoEal0lEmyWxFF3RACLcBGAs/s1600/%25E5%25BD%25B1%25E7%2589%2587%25E8%25A8%258A%25E6%2581%25AF.jpg) ### 聲音訊息 ![](https://3.bp.blogspot.com/-pRBA2q2fv4E/Wj6QQNvgwkI/AAAAAAAA_UU/cklddA3j8pwevKknSJcTa-uauuHCFbrvgCLcBGAs/s1600/%25E8%2581%25B2%25E9%259F%25B3%25E8%25A8%258A%25E6%2581%25AF.jpg) ### 檔案訊息 ![](https://1.bp.blogspot.com/-qjAJZhIhCnA/Wj6QiPT0GTI/AAAAAAAA_Uc/AEdxEOtcaAUq3f3_hm3bQatzvXIJFEiKgCLcBGAs/s1600/%25E6%25AA%2594%25E6%25A1%2588%25E8%25A8%258A%25E6%2581%25AF.jpg) ### 位置訊息 ![](https://3.bp.blogspot.com/-XzrzMCPtRDM/Wj6Q_O_nyRI/AAAAAAAA_Ug/Ml5SzH84a5A0Gj-Q3NJnxYSH6_0fLL4wACLcBGAs/s1600/%25E4%25BD%258D%25E7%25BD%25AE%25E8%25A8%258A%25E6%2581%25AF.jpg) ### Beacon 訊息 ![](https://3.bp.blogspot.com/-R-7GmGwj0i0/Wj6Rzzg1SjI/AAAAAAAA_Us/-lLy9AR-vy0-KUAwgLea5yBYPyLsUB0WQCLcBGAs/s1600/BEACON%25E8%25A8%258A%25E6%2581%25AF.jpg) Beacon 是一種感測設備,如果你的手機有開啟定位功能,接近 Beacon 時,就可以被偵測到。這技術被用來做微定位,位置訊息的誤差值很大而且在室內還有可能無法定位。若在一個室內安裝足夠多的 Beacon,就能得知這隻手機的準確位置。 ### Postback 訊息 ![](https://2.bp.blogspot.com/-f2otfYUB8a0/Wj6SfShtK3I/AAAAAAAA_U0/XdL_UhGk5AIAy8HNESJ3UTI9qH9kjWQJgCLcBGAs/s1600/Postback%25E8%25A8%258A%25E6%2581%25AF.jpg) 在你傳送含有按鈕的訊息給用戶後,若用戶點擊了按鈕,你就會收到 Postback 訊息。 以上全部的「好哦~好哦~」都只是簽收而已,還沒有回應訊息,下面才會講怎麼回應訊息。 # Line Messaging API 的各種行動 能做的事情蠻多的,詳細的以後有空再講。今天先講幾個重要的就好。 ### 關於回郵信封的使用 使用回郵信封(Reply Token)就可以不用花錢,在現實世界中是這樣運作的,在 Line Messaging API 也是如此。當你獲得一個回郵信封時,你必須在30秒之內寄出回應。因為回郵信封會在 30 秒之後失效。如果你在失效之後才寄出信, Line 就不會幫你傳話。如果你不使用回郵信封,就得買郵票。 準確地說,Line 允許你回應訊息(Reply Message),但是不允許你主動發訊息(Push Message)。如果你想要主動傳訊息就得付錢。那麼到底要付多少錢呢?他是包月制的,如果你在建立聊天機器人的時候選擇 Develop Trail (試用版),那就還是不用錢。但如果你選擇的是 Free (免費版),免費版要先升級成進階版才能用。顆顆,你每個月至少要給 Line 台幣 $3888元。 超貴 der。 ### 傳送訊息 一次最多可以傳出 5 則訊息。 ### 文字訊息 單一訊息你最多可以傳 2000 個字。 回覆訊息(Reply Message)的情況: ![](https://1.bp.blogspot.com/-iCA9fPg48Bs/Wj6Ytc_Q9FI/AAAAAAAA_Vg/eOxsV7_dPWk40h77Zez8RLK4YxWJXapnwCLcBGAs/s1600/%25E5%259B%259E%25E8%25A6%2586%25E8%25A8%258A%25E6%2581%25AF.jpg) 使用回郵信封(Reply Token)時,不需要指名傳給誰。 主動傳訊(Push Message)的情況: ![](https://4.bp.blogspot.com/-Dj_4502N3zM/Wj6Zj8jFBqI/AAAAAAAA_Vo/aMn90wFPdIs2_C6BroCITcyHqQmUukzSACLcBGAs/s1600/Push.jpg) 不使用回郵信封(Reply Token)時,就必須指定要把訊息傳送到哪裡。 ### 貼圖訊息 一個新的 Line 帳號有四套貼圖可以用。你的 Line 帳號也有這四套貼圖,就是饅頭人、熊大那些。聊天機器人只能傳送這四套貼圖裡的貼圖,不能傳其他的貼圖。所以我覺得沒什麼搞頭。 ### 取得用戶基本資料 你可以拿有加你好友的用戶代碼去查詢用戶資料,你可以獲得他的暱稱、大頭照網址、狀態。 ### 取得圖片、聲音、影片、檔案內容 你可以拿代碼再去查詢內容。你可能會問他為什麼不一開始就給你?因為這些東西比較重,而且你不一定用到,或者你家可能已經有一個一樣的東西。一切都是為了效率R~ # 講一點不是人話的東西 其實哪有這麼爽,做聊天機器人這麼容易的話,大家早就做一堆了。 上面講的全都是擬人化之後的東西,實際上是這樣: ### 前方高能注意 當有人私訊卡米狗時,Line 傳來的通知其實是長這樣: ``` { "replyToken": "nHuyWiB7yP5Zw52FIkcQobQuGDXCTA", "type": "message", "timestamp": 1462629479859, "source": { "type": "user", "userId": "U4af4980629..." }, "message": { "id": "325708", "type": "text", "text": "Hello, world" } } ``` 請保持耐心地讀完,容我簡單說明一下。 ### 認識結構化資料 因為傳遞結構化的資料,對於後續處理上來說會比較有效率,所以我們(工程師)通常這麼說話。 從 Line 傳來的訊息其實是: - 回郵信封:"nHuyWiB7yP5Zw52FIkcQobQuGDXCTA" (這是一個亂碼,請勿嘗試讀懂他。你看不懂是正常的,因為我也看不懂。) - 通知類型:這是一則訊息 - 傳送時間:1462629479859 (這是從西元19XX年到目前為止經過的總毫秒數) - 來源: - 類型:這是發生在私聊 - 用戶:"U4af4980629..." (雖然這也是亂碼,但是我有注意到一點:開頭肯定是U,應該是代表 User (用戶)的意思。) - 訊息: - 代碼:"325708" - 類型:這是一則文字訊息 - 文字:"Hello, world" 簡單一點的結構化: - 發生什麼事:有人傳私訊 - 是誰:"U4af4980629..." - 他說什麼:"Hello, world" 用人話來說: ![](https://2.bp.blogspot.com/-7JVbW0INhCg/Wj6XUkyKylI/AAAAAAAA_VM/KwmmnI22tI0eDaaJQKygzBMcDlHdDe6UQCLcBGAs/s1600/JSON.jpg) 卡米狗傳回的其實是長這樣: ``` http_status_code:200 ``` 用人話來說: ![](https://4.bp.blogspot.com/-QPQYejnFLFs/Wj6XcsHw6EI/AAAAAAAA_VQ/CwODDtRIGYsvaUnqZB5LQ92m_s4dnR9_ACLcBGAs/s1600/200OK.jpg) 因為很重要,所以說三次,這是表示簽收,不是回覆私訊。 你若有心要學作卡米狗的話,就得慢慢看懂這些東西。 雖然這些東西會越來越硬,但我會很溫柔。 # 回到訂閱階段 最一開始有提到訂閱階段,你必須要給 Line 你家地址,他才有辦法寄通知來。 但是你家是一個網站。你有發現問題嗎? 問題是你沒有家。 怎麼辦? 這表示你需要蓋一個自己的家。 明天會講架一個網站需要哪些東西。

2017/12/23

第四天:認識 Webhook( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 上一篇:[第三天:作一隻最簡單的 Line 聊天機器人](http://etrex.blogspot.tw/2017/12/line-2018-it.html) 用一句話來說明什麼是 Webhook:「Webhook 是讓一個網站能訂閱另一個網站的方法。」為了確保我們對訂閱的理解是一致的,接下來會講什麼是訂閱。 # 訂閱是事件驅動 訂閱是當某些事情發生的時候,通知者會告訴訂閱者這件事發生了。既然訂閱了,就表示收到事件後訂閱者應該會採取某些行動。 訂閱階段: ![](https://4.bp.blogspot.com/-tDH_6JW6x2M/WkE7_uJ9rDI/AAAAAAAA_h4/pGnzQcmap2YZHfo9MtNa29yBdHdTFMbegCLcBGAs/s1600/1514224595487.jpg) 通知階段: ![](https://2.bp.blogspot.com/-YG-0nOJGpus/WkE8Gb3gFcI/AAAAAAAA_h8/UqnQGqFqWXw8AO16T3xsBmiMN107dW7mwCLcBGAs/s1600/1514224605053.jpg) 下面會用生活中的例子來說明什麼是訂閱。 ### 設定鬧鐘 設定鬧鐘是一種訂閱行為。為什麼你會需要一個鬧鐘呢?因為你可能早上 9 點有事,希望能在早上 8 點起床。以這個例子來說: - 訂閱者是你 - 通知者是鬧鐘 - 事件是當早上 8 點 - 你會採取的行動是起床 當然你也許會希望通知者是你的妹妹,可是你不一定有妹妹。 ### 點餐 點餐是一種訂閱行為。首先你到櫃檯跟 NPC 點餐,點完餐之後你可能會取得一個會震動的小物,或者一根旗子,或一張紙,或者什麼都沒有,總之你會待在位置上等,直到 NPC 送餐給你,或者小物開始發出光芒並且震動,然後你帶著震動小物去找 NPC 取餐。 - 訂閱者是你 - 通知者是餐廳的 NPC - 事件是當餐點作好時 - 你會採取的行動是取得餐點 ### 你的主管交代你作事 你的主管交代你作事可能隱含著一種訂閱行為。首先你的主管找到你,然後跟你說:「這件事就交給你負責了。」你:「好哦~好哦~」 - 訂閱者是你的主管 - 通知者是你 - 事件是當你作好那件事時 - 你的主管會採取的行動是安排更多的事情給你 ### 訂閱[「只要有心,人人都可以做卡米狗」系列文](https://ithelp.ithome.com.tw/users/20107309/ironman/1253) 訂閱[「只要有心,人人都可以做卡米狗」系列文](https://ithelp.ithome.com.tw/users/20107309/ironman/1253)是一種訂閱行為。首先你會到[「只要有心,人人都可以做卡米狗」系列文](https://ithelp.ithome.com.tw/users/20107309/ironman/1253)按下「訂閱系列文」。訂閱之後,當我發新文章時,你會在 iT 邦幫忙的網頁右上角收到一個通知。(可是如果你不會時常開著 iT 邦幫忙的網頁,又為什麼要訂閱呢?_?) - 訂閱者是你 - 通知者是我 - 事件是當我寫好新文章時 - 你會採取的行動是讀我的新文章 ### 按讚[卡米狗 FB 粉絲團](https://www.facebook.com/kamigo01) 按讚[卡米狗 FB 粉絲團](https://www.facebook.com/kamigo01)是一種訂閱行為。首先你會到[卡米狗 FB 粉絲團](https://www.facebook.com/kamigo01)按下「讚」。當我在粉絲團發表貼文時,你會在 FB 網頁右上角收到一個通知。 - 訂閱者是你 - 通知者是我 - 事件是當我在粉絲團發表貼文時 - 你會採取的行動是讀我的貼文 如果你不會時常開著 iT 邦幫忙的網頁,那麼就應該訂閱一下卡米狗 FB 粉絲團。 你可能會問:「我為什麼要訂閱?」 # 為什麼要訂閱 對呀,為什麼要訂閱呢? ### 訂閱是有效率的雙向溝通方法 使用訂閱可以使你不需要去檢查事件到底發生了沒,而且可以讓你在事件發生的瞬間就立即採取行動。 ### 如果你沒有訂閱鬧鐘 你會睡得不安穩,或者睡過頭。你必須不斷的起床看時鐘(注意,時鐘跟鬧鐘不同),以確保你沒有睡過頭。 ### 如果你事情做完沒跟你主管講 你會比較爽,但是如果你的主管有看這篇文的話,他會知道你在摸魚。訂閱是一種很吃信用的機制,當通知者經常沒有盡通知責任時,訂閱功能就完全失效了,訂閱失效後就要回歸到原始的方法:單向溝通。 ### 單向溝通是沒有效率的溝通方法 假設你去早餐店點個早餐內用桌號3,在你手機滑了兩小時後,發現早餐還沒送來,於是你去問早餐店老闆:「阿我的早餐有做嗎?」老闆回:「有啦~有啦~正在做。」其實根本就忘記做,而且也差不多該吃午餐了。但如果在你手機滑十分鐘時就去跟老闆確認,也許你可以早一點拿到。 假設你是主管,你應該要跟你的員工說事情做好時跟你說一聲,明確表達你想要訂閱你員工,以確保你可以在你員工事情做完時就安排下一件事情。為了確保當通知者不盡通知責任時,你還是可以榨乾他,你要追問一個逾期時間,在時間內沒做完你就會去找他,也就是說交代工作時應該要說兩件事:「你預計什麼時候會做完」「做完的時候叫我」,如果你發現你的員工都沒有主動來找你,而是你去找他,他才跟你說「喔!我剛做好呢!」「喔!我做完忘記跟你講」那肯定就是他在摸魚。 所以不管做什麼事,還是要主動一點才好。 講到這裡,人與人之間的溝通方法,我想大家應該都完全理解。至於網站跟網站之間的溝通方法有很多種,Webhook 使用的是 HTTP 協定。 # HTTP 協定 電腦跟電腦在網路上傳遞訊息的方法其實跟郵局送掛號很像。你會作出一張明信片寄出(HTTP Request),明信片會在網路上傳遞,每個經手的郵局、郵差都能看見你寫的內容,收件人必須在收到每個明信片時進行簽收,還要立馬寄一封回信(HTTP Response),最後寄件人會收到回信,就算完成一次交流。 ![](https://4.bp.blogspot.com/-SOgkDwODskM/WkE6nmbcqZI/AAAAAAAA_hs/p00DzAZFAzg8x7BLaCW6dDiRTxmnUOvxwCLcBGAs/s1600/1514224249985.jpg) 從這張圖來看我們可以知道,你是主動方,網站是被動方。只要你不戳他,他就不會回。一個基本的網站就是這樣,只要你不做任何操作,網頁上的東西就不會變。你可能需要不斷地按下重新整理,確保你看見的畫面是最新的,舉個例:這篇文章的瀏覽量不會主動更新。 ### HTTP 協定有安全性問題 這樣的溝通方式是不安全的,只要任何一個經手的郵局、郵差是壞人,就可以偽造信件內容。有一種詐騙手法是詐騙集團會寄假的繳費單給你,如果你以為繳費單是真的,你就會去便利商店繳費。在網路上也有類似的詐騙手法。那麼要怎樣才能確保安全(Secure)呢?答案就是使用安全(Secure)的 HTTP 協定。 # HTTPS 協定 HTTPS 協定就是安全的 HTTP 協定,跟 HTTP 協定有 87% 像,不同的是它傳遞的不是明信片而是密信片,經手的郵局、郵差無法看懂內容。而且寄件者的簽名有經過認證,可以確認寄件人身分,不用擔心收到造假的信。 今天就講到這裡,明天會講 Line Webhook 實際的運作流程。

2017/12/22

第三天:作一隻最簡單的 Line 聊天機器人( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 上一篇:[第二天:認識卡米狗](http://etrex.blogspot.tw/2017/12/2018-it_21.html) 我們今天來作一個最簡單的 Line 聊天機器人,要完成這個目標,我們連一行程式都不用寫。 # 建立 Line Messaging API 帳號 ### 第一步:開啟 [Line developers 首頁](https://developers.line.me/en/) [https://developers.line.me/en/](https://developers.line.me/en/) 首頁長這樣: ![](https://1.bp.blogspot.com/-Q-FbGxIUGKA/WjvjabpyopI/AAAAAAAA_Mg/uR90xn79A6MpzFnSAnyeEfaEmCQmaZvCwCLcBGAs/s1600/1.jpg) 我們把注意力放到右上角,看到那顆 Log in 按鈕了嗎?勇敢地按下去。 他說:請輸入你正確的名字(Name)跟信箱(Email address)。 ![](https://3.bp.blogspot.com/-t-TLJYJlH6c/WjvjzL71RzI/AAAAAAAA_Mk/lTVxsUUIqngfvrbdyAu8xdLAc6cuspnOgCLcBGAs/s1600/3.jpg) 填好後就可以按下 Confirm。 ![](https://3.bp.blogspot.com/-tbDE9osdS9A/WjvkOR7CN_I/AAAAAAAA_Mo/kPTh9XENv2YWOXGQZpKOIQHUH0k_JJ3kwCLcBGAs/s1600/4.jpg) 然後他要求你再次確認你沒有亂填,當然我相信你沒有亂填,這裡直接按下右邊的 Register 就可以。 ![](https://2.bp.blogspot.com/-CE2pcGfU5zI/Wjvkh_qcuFI/AAAAAAAA_M4/slTdl1Cfr6wA4dZ-_7b46gNGECj2RZRZACLcBGAs/s1600/5.jpg) 恭喜你成為一個開發者,這邊我們直接按下 Start。 ![](https://4.bp.blogspot.com/-VFTP-xMFMVs/Wjvkvf-z7zI/AAAAAAAA_M8/-cWWsfGauO0r_Btz7WZT5-PMMuNxbIsGQCLcBGAs/s1600/6.jpg) 玩到這裡你應該會注意到一件事:如果畫面上有綠色按鈕,按下去就對了。所以這裡我們按 Create provider。 ![](https://2.bp.blogspot.com/-mwqBvzbgpGQ/WjvlKyqHD9I/AAAAAAAA_NM/L9Bh8GpaNlw9rwPCGwsNchiAhAmzI0vzgCLcBGAs/s1600/7.jpg) 如果你有開公司,這裡填公司名字。沒有開公司的話這裡就填你的名字,填完按 Confirm。 ![](https://4.bp.blogspot.com/-lHbCHW5D4Xo/Wjvlh_1IFjI/AAAAAAAA_NQ/cDnf8GYDQpo3vKUiv0sg30C_xPu7WBrWQCLcBGAs/s1600/8.jpg) 又是再次確認畫面,按綠色的 Create。 ![](https://2.bp.blogspot.com/-c-rjugY46zA/Wjvlsh_O4II/AAAAAAAA_NY/lD3mrZYdmBcSy7D5ozkDkaJk6TBE7_e2gCLcBGAs/s1600/9.jpg) 哇!這裡有三個綠色按鈕,該按哪個呢?答案是按右邊的 Messaging API。 從這裡開始,我們要填入的是聊天機器人的相關資訊。 ![](https://1.bp.blogspot.com/-5g-4FH5w5Ag/WjvmGEiIlbI/AAAAAAAA_Nk/xiHp22l-mLo0q-dnKdB7pstcuA9h7yEjwCLcBGAs/s1600/FireShot%2BCapture%2B54%2B-%2BLINE%2BDevelopers_%2B-%2Bhttps___developers.line.me_console.png) - App icon:聊天機器人的大頭照 - App name:聊天機器人的顯示名稱 - App description:聊天機器人的簡介,不過這欄隨便填就可以了,因為好像不會被任何人看見。 - Plan:Developer Trail 是試用版,Free 是免費版。當然試用版也是免費,差別在於試用版只能加 50 個好友,但是可以使用加值功能,建議選試用版。 - Category:這個隨便選 - Subcategory:這個也隨便選 - Email address:這裡填信箱 我的填完之後長這樣: ![](https://2.bp.blogspot.com/--dNYoVxXbeA/WjvoAon-89I/AAAAAAAA_Nw/ObsJqs5aZ4MIlNZjcgg08SjzY7K1Sbe9QCLcBGAs/s1600/FireShot%2BCapture%2B55%2B-%2BLINE%2BDevelopers_%2B-%2Bhttps___developers.line.me_console.png) 填好就可以按 Confirm。 ![](https://3.bp.blogspot.com/-p7UF3UsyPv0/WjvoVnbXKDI/AAAAAAAA_N0/x7W1IT9XHvkZJUegzqSg1oobD3i6EaN1ACLcBGAs/s1600/FireShot%2BCapture%2B56%2B-%2BLINE%2BDevelopers_%2B-%2Bhttps___developers.line.me_console.png) 不曉得為什麼, Line 很愛再次確認,這裡有兩個勾勾要打,先打勾再按 Create。 ![](https://1.bp.blogspot.com/-ZagOJ7nAP-U/WjvooSgKCrI/AAAAAAAA_N8/ek7ZMoudFnsdjKqhb-WV3KlSB1JhzijKQCLcBGAs/s1600/FireShot%2BCapture%2B57%2B-%2BLINE%2BDevelopers_%2B-%2Bhttps___developers.line.me_console_.png) 終於創好聊天機器人囉!點進去看看,這裡當然就不是點綠色按鈕了。 ![](https://3.bp.blogspot.com/-qsoDpFcQPgg/WjvpEFlvhOI/AAAAAAAA_OE/b6QQb-P_Ki0kZVSUHd2uAhfTMfiUXP4nACLcBGAs/s1600/FireShot%2BCapture%2B58%2B-%2BLINE%2BDevelopers%2B-%2Bhttps___developers.line.me_console_channel_1553191554_basic_.png) 訊息量很大,不過我們直接看到最後面有個 QR code of your bot。 # 加入聊天機器人為好友 拿起你的手機,作行動條碼掃描。 ![](https://4.bp.blogspot.com/-LiYmU1LxKB8/WjvqSWsu1EI/AAAAAAAA_OY/lVprNpBloJo8k-DKhCNqbCpn7408zp90QCLcBGAs/s1600/2017-12-22%2B00.52.31.png) 點綠色的加入。 # 傳訊息給這個聊天機器人 點進私聊畫面後會看到他傳了一個訊息給你: ![](https://2.bp.blogspot.com/-xmrpZ2rh_qk/Wjvra1zog1I/AAAAAAAA_O0/5YNRvId7_ygkhROxN-B3m82oedjckU9FQCLcBGAs/s1600/2017-12-22%2B01.09.06.png) 這是歡迎訊息(Greeting messages),隨便跟他說句話先。 你應該會注意到沒地方可以打字,這裡要先按左下角的鍵盤按鈕,然後再打字。 ![](https://3.bp.blogspot.com/-QXd0XPX_K_g/WjvraujGsLI/AAAAAAAA_Ow/eddpF62ohHQ4xuW2YYmSbpGDpmMfXLyyQCLcBGAs/s1600/2017-12-22%2B01.11.03.png) 這是自動回覆訊息(Auto-reply messages)。 最簡單的聊天機器人到此完成!!!! 但是要怎麼控制他呢? # 登入後台修改歡迎訊息 從這個網址可以找到剛剛創好的聊天機器人。 [https://developers.line.me/console/](https://developers.line.me/console/) 跟剛剛一樣,先點進去,最下面的 QR code of your bot 再往上一點: ![](https://2.bp.blogspot.com/-SvSwq297FOs/Wjvuf3yMMhI/AAAAAAAA_PU/PpgjOLDuLo0qfuriCGmBet6O3aMD3yepQCLcBGAs/s1600/1513877097033.jpg) 這裡可以修改歡迎訊息和自動回覆訊息,這裡我們先點下面的 Set message。 你有可能會看見要求登入的畫面: ![](https://2.bp.blogspot.com/-0YCapXyudU8/WjvvqSQSdHI/AAAAAAAA_Pg/kdhfFxWyzk0j_igOEHKJml-W6iEFDNh8ACLcBGAs/s1600/1513877366762.jpg) 或者直接進入招呼語設定頁: ![](https://4.bp.blogspot.com/-bhMw9mmLjFw/Wjvv-dGVuaI/AAAAAAAA_Pk/9ubyRV7LpcAIHA4iVlLBdCMmJRGcXEtJgCLcBGAs/s1600/1513877331470.jpg) 這裡是全中文的,是因為這裡已經是 Line@ 的後台,而不是 Line developer 的後台。Line developer 的後台目前還沒有作中文版。也就是說,我們剛創好的聊天機器人帳號,其實是一個啟用了 Line Messaging API 的 Line@ 帳號。 ![](https://3.bp.blogspot.com/-CiYWkeD94d0/WjvxONLSEEI/AAAAAAAA_Pw/sP9xaVbGPtIqDerrDeAN_GMVVlWCL1BWgCLcBGAs/s1600/1513877784112.jpg) 稍微改一下字之後按儲存。這裡我們需要測試一下剛剛的設定有沒有正確運作。 測試的方法是先封鎖聊天機器人。 ![](https://3.bp.blogspot.com/-9oOk19pT9DQ/Wjvx0jr5npI/AAAAAAAA_P8/ccrA91tXnPg1HyF_Y_WiiRRJcj2wN5FnwCLcBGAs/s1600/111.png) 再解除封鎖。 ![](https://2.bp.blogspot.com/-8N9_qFnxxZM/WjvyE1VdGYI/AAAAAAAA_QA/UP2a2pPYM20k2_Ja75wXPvDSiDSlK0GhQCLcBGAs/s1600/112.png) 成功! # 修改自動回應 我們不用回到 Line Developer 後台,直接點左邊的自動回應作設定就可以。 ![](https://4.bp.blogspot.com/-dZk9bU07X6Y/WjvypLqIdaI/AAAAAAAA_QM/KbssBe7elJMLrQ3q4VoQA0EsUSPSdqNeQCLcBGAs/s1600/113.jpg) 點擊後會看到這個畫面。 ![](https://1.bp.blogspot.com/-c22oU5bqMMM/WjvzwOlPyiI/AAAAAAAA_QY/UuqXDPaQHnUhPoNZqtnu65bz_WMufxfbgCLcBGAs/s1600/1513878410265.jpg) 接著一樣點紅色箭頭的部分,修改預設值。 ![](https://2.bp.blogspot.com/-NjA-FEh0LAA/Wjv0XfrDeFI/AAAAAAAA_Qg/7lW13HD4Amw8Pn1ezlrGL8SiSAJVp1rywCLcBGAs/s1600/114.jpg) 這裡就隨便填入一個幹話。 ![](https://1.bp.blogspot.com/-CyCtD4zwzqI/Wjv0fSbvrOI/AAAAAAAA_Qk/PWalxIqVEyQpwB3LRiWS57hWxgHfv4IAACLcBGAs/s1600/115.jpg) 按儲存,然後試用一下。 ![](https://2.bp.blogspot.com/-v52Xg1VvXzQ/Wjv0twIfpvI/AAAAAAAA_Qo/Sy7H0smfKiwrxT8ZVuuQ36yjSo9HFXQoACLcBGAs/s1600/116.png) 馬上就變成幹話機器人。 # 新增關鍵字回應 如果你都有仔細看,應該會發現左邊有一個叫作是關鍵字回應訊息的,剛剛應該很想點進去看吧?現在可以點了,點進去長這樣: ![](https://3.bp.blogspot.com/-UvK3PKef-1M/Wjv1wV5MQNI/AAAAAAAA_Q0/b5b_e6g88lQhX1kO6MYiHLz2NtjMtmLEACLcBGAs/s1600/1513878951876.jpg) 我們點綠色的建立關鍵字按紐。 ![](https://1.bp.blogspot.com/-lFjkm66bo8I/Wjv2frAUukI/AAAAAAAA_Q8/KXuu8gh0v50L8Pm8YqbGrusvGCw6dB80gCLcBGAs/s1600/118.jpg) 在代表關鍵字我們填入「QQ」,然後在下面一堆按紐的地方點一下文字按紐,接著在文字區塊填入「我難過」。 ![](https://2.bp.blogspot.com/-FQDQINaPQds/Wjv2fjRiDEI/AAAAAAAA_RA/uk-MtTtrsB8c0C2HqD4kYTGxc8ep7xZzACLcBGAs/s1600/119.jpg) 然後按下儲存。 ![](https://3.bp.blogspot.com/-uFjH3J9MB1w/Wjv1Ih0vk_I/AAAAAAAA_Qs/tCDW7Q2RgBUv3stUPKTit3dG1q7Csg-9wCLcBGAs/s1600/1513878791635.jpg) 測試一下結果: ![](https://2.bp.blogspot.com/-8939jW2bM0A/Wjv3ebP7VjI/AAAAAAAA_RM/XIGVeLEzpX0erp1mwrNx-YVeWgO1ixKTACLcBGAs/s1600/117.png) 所以關鍵字回應其實 Line@ 平台已經作好了。 對的,只有作者能教的卡米狗這樣就完成了,你還能自行切換大頭照跟顯示名稱。 # 怎麼讓聊天機器人能加入群組? 其實就在剛剛的 Line Developer 後台,再往上看一點。 ![](https://1.bp.blogspot.com/-vrIlFMKlmkg/Wjv4-_inP-I/AAAAAAAA_RY/jmkMdNYuVL0DNtoePmZ2XVcgCwmw7IL_ACLcBGAs/s1600/120.jpg) Allow bot to join group chats (允許機器人加入群聊) 預設值是 Disabled,我們按一下右邊那個鉛筆按鈕,改成另一個選項,再按 Update 就好了。 # 怎麼讓其他人也能加關鍵字回應? 要像卡米狗那樣讓大家都能夠透過對話新增關鍵字回應的話,我們需要使用 Line Messaging API 中的 Webhook 功能。 明天會介紹 Webhook 的運作原理。

2017/12/21

第二天:認識卡米狗 ( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 上一篇:[第一天:認識聊天機器人](http://etrex.blogspot.tw/2017/12/2018-it.html) 下一篇:[第三天:作一隻最簡單的 Line 聊天機器人](http://etrex.blogspot.tw/2017/12/line-2018-it.html) # 認識卡米狗 其實卡米狗也很想認識你們,趕快來加我好友RRRRR FB粉絲團:[https://www.facebook.com/kamigo01/](https://www.facebook.com/kamigo01/) Line:[https://line.me/R/ti/p/%40aab8659n](https://line.me/R/ti/p/%40aab8659n) Line行動條碼: ![](https://4.bp.blogspot.com/-OmUZp94T_Dc/WjqUoWoKToI/AAAAAAAA_HE/vqhd7iGMhwA47d-4WZUdpl9fyma1O82KwCLcBGAs/s1600/QRCODE.png) 官網:[https://www.kamigo.tw/](https://www.kamigo.tw/) # 卡米狗的誕生 去年9月時,聽說 Line 終於開放了讓聊天機器人可以進入群組的功能,於是我興沖沖的做了一個 Line 聊天機器人,取名叫卡米狗,並且放上一張幾年前我隨便畫的狗圖。 一開始本來打算要做的功能是資料科學相關的,比方說下列功能: - 發言次數排行榜 - 誰跟誰最常聊天 - 某個人的出沒時間(星期幾的幾點到幾點會出現)(誰出現了誰就跟著出現) - 某個人的口頭禪 - 誰是句點王 但當時卻發現 Line 並不會告訴你在群組中講話的人是誰,於是乎上面提到的所有功能都做不出來,不過既然程式都寫好了,那就隨便加功能吧。 哦對了,過了一年之後 Line 終於想通了,現在可以做這些功能了,但我還沒做。 # 卡米狗的各種功能 ### 影片支援 最早期的卡米狗只有一個功能,就是當他看到「我難過」就回應「[https://youtu.be/T0LfHEwEXXw?t=1m13s](https://youtu.be/T0LfHEwEXXw?t=1m13s)」,此時尚未引起什麼風波。至今已經因為無法輸入網址而失效了。 ### 跟風(推齊) 當時加入的第一個講幹話的功能是跟風(推齊)功能,也就是當看到有兩次以上有人說出相同的句子,那麼就跟著說的功能。當時在這種情況下,卡米狗會說的話並不多,但是已經造成群組某部分人的反感。主因是人類受到聊天機器人的影響,為了使聊天機器人講話,某一群人就故意複製前面的人講過的話。 ![](https://2.bp.blogspot.com/-OoYDqDRs6hY/Wjqfyng8nKI/AAAAAAAA_Ks/Bf0t-cn-ueU_7UgkVkeWJoWgbD3B5qM_ACLcBGAs/s1600/%25E6%258E%25A8%25E9%25BD%258A.PNG) 當時有人說「跟機器人講話很有趣嗎?一直洗版吵死了,這完全是在浪費時間。」我說「在機器人出現之前,群組裡面一堆人也是這樣推齊,當時你怎麼不講他們呢~?」結果他一氣之下就怒離群組了。0.0 其實卡米狗被討厭,他心理壓力也是很大呢。 ### 學說話以及關鍵字回應 因為影片支援功能只支援「我難過」,群友們就在問說可不可以加入「分手快樂」「柯南」「遊戲王」「棋靈王」...。我想「哇,如果全都是我來加,那我不就很累?」所以我就想到,如果能讓大家直接教卡米狗,那他們就可以不用跟我說,直接就教卡米狗了!這是一個很單純的功能,所以很快地就完成了。 這個指令是這樣的:當有人說「卡米狗學說話;姆咪姆咪;心動動~」卡米狗會根據分隔符號「;」得知當有人說「姆咪姆咪」時就要回應「心動動~」 ![](https://3.bp.blogspot.com/-M5XNPkq4rGU/WjqVRfNWIOI/AAAAAAAA_HU/p7SGb6J-im0nml-Q2eIOivAirmgLFTwTACLcBGAs/s1600/%25E5%25AD%25B8%25E8%25AA%25AA%25E8%25A9%25B1.PNG) 當輸入的指令語法正確時,卡米狗就會說出「好哦~好哦~」 我沒有想到的是,在這個功能完成之後,大家開始教他吹捧某些人、講髒話、亂嗆人,在此同時也開始加他好友,一邊在私聊教卡米狗說話,一邊在群組講關鍵字去觸發卡米狗。卡米狗在這個時期獲得大量的擴張,在一週之內使用人數就破萬。 不過後來學習的內容含有網址引起太多的負面問題,我最後還是移除了所有包含/的關鍵字,同時也禁止/符號的學習。 這個指令是有各種縮寫的,比方說「卡米狗學說話」可以簡寫為「學說話」、「學」,分隔符號除了;之外還有另外三種,分別是全形空白、半形空白、全形分號、半形分號。 ![](https://1.bp.blogspot.com/-QEzuaZQij5g/WjqYkY65MaI/AAAAAAAA_Ig/QvDA_qSHrmIYVHYgdn7SyynVzGFd9W2aQCLcBGAs/s1600/%25E5%25AD%25B8%25E8%25AA%25AA%25E8%25A9%25B12.PNG) ### 見人說人話,見鬼說鬼話 考慮到多個群組都教了相同的關鍵字時,卡米狗應該在每個群組做出不同的回應,這樣才不會被討厭,於是就加入了這樣的功能。當有人說「姆咪姆咪」時,卡米狗會先檢查這個群組有沒有人教過看到「姆咪姆咪」要回應,如果教過多次,就回應最後一次學過的內容,如果都沒學過,那麼就再檢查其他群組有沒有學過「姆咪姆咪」。 ### 說話模式 卡米狗在幾天之內就學壞了,講的話越來越討人厭。為了使卡米狗不那麼討人厭,加入了「卡米狗 不可以說別人教你的話」的功能,這樣在群組內就可以全權控制卡米狗只講那些在這個群組學到的話。 ![](https://3.bp.blogspot.com/-weVIgwGny7w/WjqVn3ZRmxI/AAAAAAAA_HY/tIsjbTZjM4Ucw50JKgunGB0JM-nE9NxQQCLcBGAs/s1600/%25E8%25AA%25AA%25E8%25A9%25B1%25E6%25A8%25A1%25E5%25BC%258F.PNG) ### 目前狀態 當有人在講正經事的時候,卡米狗並不會很識相地自動閉嘴,於是卡米狗就會被踢出群組。為了避免卡米狗被踢出群組,我加入了「卡米狗安靜」指令,使卡米狗可以不講話地待在群組。為了不被討厭,卡米狗真的付出了很大的努力呢。 ![](https://4.bp.blogspot.com/-bC8glCzrx_s/WjqWMiIXdjI/AAAAAAAA_Hw/JMOTPvNW9_s796HKiF5AgX-4xDI8xN6VQCLcBGAs/s1600/%25E7%259B%25AE%25E5%2589%258D%25E7%258B%2580%25E6%2585%258B.PNG) ### 卡米狗 用的人真的越來越多了,而且後來才用的人根本就以為卡米狗會自動學講話,他們完全不知道其實卡米狗會說的話都是其他群組的人教他的。而且隨著指令越加越多,沒有人能夠記得到底指令要輸入什麼文字才是正確的,甚至連作者自己也不記得(我本來就記憶力超差)。所以需要一個功能讓卡米狗自己說出怎麼下指令控制卡米狗。 只要說「卡米狗」卡米狗就會告訴你他目前的狀態,以及相關的指令。 這是在 Line PC 版會看到的畫面: ![](https://1.bp.blogspot.com/-HxD1G6oydQ8/WjqWnO9tPOI/AAAAAAAA_H0/DL6Vv07tSFIsCO1LM4NIwzIqCjMo5bDDwCLcBGAs/s1600/%25E5%258D%25A1%25E7%25B1%25B3%25E7%258B%25971.PNG) 這是在 Line 手機板會看到的畫面: ![](https://2.bp.blogspot.com/-d7iCo9CM-zQ/Wjqjq19BGTI/AAAAAAAA_LA/QF6SUSO0wnQANXw7kvimPno_0UzLIYNegCLcBGAs/s1600/%25E5%258D%25A1%25E7%25B1%25B3%25E7%258B%2597.jpg) ### 你會說什麼 說真的,沒人記得到底教過卡米狗什麼內容,唯一記得的人(?)就只剩下卡米狗了。讓卡米狗自己說出學過什麼的指令就是:「卡米狗 你會說什麼」 ![](https://1.bp.blogspot.com/-_7WeJ08lpPQ/WjqXb5f8D7I/AAAAAAAA_IQ/diWWCEuqVWo6V6Y4web9fjerXKI9yZWjwCLcBGAs/s1600/%25E4%25BD%25A0%25E6%259C%2583%25E8%25AA%25AA%25E4%25BB%2580%25E9%25BA%25BC.PNG) ### 抽籤 朋友問我說,可不可以讓卡米狗抽塔羅牌?我覺得可以,於是就做了抽籤功能,當然這個抽籤功能也是設計成要由大家下指令(而不是作者下指令)才能使用。使用方法是在原本的關鍵字前面加入「卡米狗」三個字,那麼就會從原本的關鍵字回應轉變為抽籤模式。關鍵字回應是會回應最後一筆學過的內容,而抽籤回應則是隨機挑選一筆。 使用方法: 先教卡米狗對相同的關鍵字兩筆以上的回應 ![](https://2.bp.blogspot.com/-WGb314K8o5k/WjqZllo6egI/AAAAAAAA_Iw/uWcOR78vQN0I6xjt07Fk98Cg1vdCoa2WgCLcBGAs/s1600/%25E6%258A%25BD%25E7%25B1%25A41.PNG) 在觸發關鍵字時,在關鍵字的前面加入「卡米狗」他就有機會講出不一樣的內容 ![](https://4.bp.blogspot.com/-pf7DyBNU4yA/WjqZu5qwRKI/AAAAAAAA_I0/z4YxW3RnoGEIVtWDTD5mBNAKITiDkgBbQCLcBGAs/s1600/%25E6%258A%25BD%25E7%25B1%25A42.PNG) 如果沒加「卡米狗」的話就會變成這樣: ![](https://2.bp.blogspot.com/-DVPu0G7QOUw/WjqZ5JTIVYI/AAAAAAAA_I4/uBVUXymOVMwxeRRHBZ72f_BONBmgQJDCgCLcBGAs/s1600/%25E6%258A%25BD%25E7%25B1%25A43.PNG) ### 大量學習 由於抽籤功能需要重複輸入很多次相同的關鍵字和不同的回應,這樣的話,需要教大量內容的時候就太麻煩了,於是就做了這樣的指令: ![](https://2.bp.blogspot.com/-H_NOjG4oRW0/WjqaTvm9yGI/AAAAAAAA_JA/c1eeVMgMvaMjON3FCYzBq6YdPhgM2HPYgCLcBGAs/s1600/%25E5%25A4%25A7%25E9%2587%258F%25E5%25AD%25B8%25E7%25BF%2592.PNG) ### 忘記 由於抽籤功能會使得所有教過的內容都有可能出現,所以你就不能用教新的內容去覆蓋舊的內容了,以前教過的一些垃圾回應就又跑出來,所以就需要刪除教學紀錄的功能,使用方法如下: ![](https://1.bp.blogspot.com/-1HzGNwWGR2E/WjqaicByGkI/AAAAAAAA_JE/GdzJCWAEnnk7zzWh-xjXKVXTzHGA2cpfwCLcBGAs/s1600/%25E5%25BF%2598%25E8%25A8%2598.PNG) ### 壞壞 也是為了讓卡米狗不被討厭,卡米狗最有趣的地方就是他會講一些別人教的內容,但這也是另人討厭的地方,因為這些內容你不一定會喜歡。「卡米狗忘記」指令無法刪除別人教的內容,所以需要一個封鎖別人教過的內容的指令。當卡米狗講出了一些傷人的話時,你可以說「卡米狗壞壞」,那麼卡米狗就會將那筆教學紀錄標記為封鎖,下次不會再講。 ![](https://1.bp.blogspot.com/-v1EtWxg22p0/Wjqa4SfndnI/AAAAAAAA_JQ/20gaKFb99ms1B4V_D_zNRBFQOWF55sCfgCLcBGAs/s1600/%25E5%25A3%259E%25E5%25A3%259E.PNG) ### 查天氣 這是卡米狗開始往智能助理發展的第一步。輸入「天氣」開頭的句子,卡米狗就會去查中央氣象局目前最新的雷達回波圖來給你。 ![](https://1.bp.blogspot.com/-KYt8026gg98/WjqbLTgj1OI/AAAAAAAA_JY/g1iqR6XtwIodumboFiZ3b39JmdxSSdN4gCLcBGAs/s1600/%25E5%25A4%25A9%25E6%25B0%25A3.PNG) ### 查 PIXNET 美食 這也是身為一個智能助理應該要具備的功能,輸入「想吃牛排」,就查詢 PIXNET 上和「牛排」相關的食記。 ![](https://1.bp.blogspot.com/-ymPPeUv6_vU/Wjqj0fIGaRI/AAAAAAAA_LE/li7GI0mHjdUeyznUauJH0jKrzttKsBoQACLcBGAs/s1600/%25E6%2583%25B3%25E5%2590%2583%25E7%2589%259B%25E6%258E%2592.jpg) ### PIXNET 文章閱讀器 一個好的聊天機器人最好能讓大家在群組就做完所有想做的事情。當有人貼 PIXNET 文章超連結時,卡米狗就會幫你把文章內容抓下來一段一段地貼給你。 ![](https://3.bp.blogspot.com/-lpu5zrBJtz4/Wjqj9wTgbeI/AAAAAAAA_LM/yeTaITBXDDQtbC1IhAcSu-0qiaHvEOLFgCLcBGAs/s1600/%25E9%2596%25B1%25E8%25AE%2580%25E5%2599%25A81.jpg) ![](https://1.bp.blogspot.com/-B7P85zCVbFQ/WjqkEGbx9dI/AAAAAAAA_LQ/rMHWLRAIJZA5Q2-hcMTOnDS0_v8dSwXvACLcBGAs/s1600/%25E9%2596%25B1%25E8%25AE%2580%25E5%2599%25A82.jpg) ### 今天的 這功能跟抽籤有點像,但又稍微不一樣,抽籤是在關鍵字前面加上「卡米狗」,今天的功能則是在關鍵字前面加上「今天的」。卡米狗就會說出所有今天學過這個關鍵字的回應。因為有幾隻Line聊天機器人做了懶人包或抓重點功能,我覺得很棒,所以我也提供了差不多的功能。 ![](https://2.bp.blogspot.com/-IR9oDquN8sY/Wjqc3p7VyuI/AAAAAAAA_KA/L1PjcnSOHgA1SKPPh3d-gs_kXWjvCF74QCLcBGAs/s1600/%25E4%25BB%258A%25E5%25A4%25A9%25E7%259A%2584.PNG) 既然做了「今天的」那有沒有「昨天的」?有的,其實有這麼多: - 今天 - 昨天 - 前天 - 本周 - 本月 - 今年 - 所有 而且那個「的」要打不打都可以。 ### [卡米狗貼圖](https://store.line.me/stickershop/product/1500785/?ref=Desktop) 卡米狗也有出[貼圖](https://store.line.me/stickershop/product/1500785/?ref=Desktop),而且[卡米狗貼圖](https://store.line.me/stickershop/product/1500785/?ref=Desktop)可以用來控制卡米狗!如果你喜歡卡米狗的話,請以購買代替領養,謝謝你的支持~ 每張[貼圖](https://store.line.me/stickershop/product/1500785/?ref=Desktop)都相當於輸入「卡米狗」加上[貼圖](https://store.line.me/stickershop/product/1500785/?ref=Desktop)上的字 ![](https://1.bp.blogspot.com/-QZVg1c6-9-A/WjqdWT-SPaI/AAAAAAAA_KI/qzrdkV1Ks_s75L6R6yJaTm1nxB-pHDC8QCLcBGAs/s1600/%25E8%25B2%25BC%25E5%259C%2596.PNG) 以[貼圖](https://store.line.me/stickershop/product/1500785/?ref=Desktop)控制卡米狗的範例 ![](https://3.bp.blogspot.com/-Vdli-gcPiHk/WjqduSULohI/AAAAAAAA_KM/27-GP0nCA0MXt8tplZMoDM94UWtpNZ0IACLcBGAs/s1600/%25E8%25B2%25BC%25E5%259C%25962.PNG) ![](https://4.bp.blogspot.com/-aDIylTX3dW0/WjqebIDjF8I/AAAAAAAA_KY/tG5Jb53xwxM_s93_oepgLBjvtILNmpqAwCLcBGAs/s1600/%25E8%25B2%25BC%25E5%259C%25963.PNG) 這麼棒的[貼圖](https://store.line.me/stickershop/product/1500785/?ref=Desktop)不買嗎? # 卡米狗可以翻群或防翻群嗎? 不能。 目前市面上的翻群機器人和防翻群機器人都不是正統的聊天機器人帳號,而是使用一般人的 Line 帳號加上外掛程式去做成的,Line 在使用條款中有提到禁止這種行為,所以製作這種聊天機器人會受到 Line 的封鎖而導致無法使用。 一個正統的 Line 聊天機器人帳號是會有盾牌的帳號(在PC版好像看不到盾牌),目前一個群組只能加入一隻正統聊天機器人。 卡米狗的盾牌是灰色的。 ![](https://1.bp.blogspot.com/-2dpFwVmlliQ/WjqkNUuk6RI/AAAAAAAA_LY/Tq_KtfN1ehc6Yr7zCFn5iJo1r59CCXU0gCLcBGAs/s1600/%25E7%2581%25B0%25E7%259B%25BE%25E7%2589%258C.jpg) 接下來會講解怎麼做一隻最簡單的卡米狗。

2017/12/20

第一天:認識聊天機器人 ( 2018 iT邦幫忙鐵人賽-只要有心,人人都可以作卡米狗 )

markdown 下一篇:[第二天:認識卡米狗](http://etrex.blogspot.tw/2017/12/2018-it_21.html) # 什麼是聊天機器人(chatbot) 聊天機器人就像[卡米狗](https://www.kamigo.tw),他可能是一個在通訊軟體上的帳號,或官方帳號,或粉絲團或者其他形式,只要你可以跟他互傳訊息,而他不是真人,那麼他就是聊天機器人。 # 聊天機器人是未來趨勢嗎? 聊天機器人是未來趨勢嗎?是的。 在智慧型手機還沒出現的時代,大部分的服務都是網站的形式存在,但是在智慧型手機普及之後,大家使用電腦的時間變短了,所以服務開始轉移到手機 App 上。近幾年發現雖然人們經常使用手機,但在手機上最常使用的 App 就是 Facebook、Line、Telegram...等等通訊軟體,已經越來越少人願意安裝新 App。安裝 App 要等下載、吃流量、吃手機空間,對大家來說都是困擾。 如果服務能以聊天機器人的形式存在,那麼大家就不需要安裝新的 App,只要加好友,就能馬上使用。若是聊天機器人在群組中,那麼一個人邀請進入群組,所有人同時可以使用,對服務商來說,這是一個會自動擴散的行銷模式。 除了通訊軟體之外,很多大型服務都有提供私訊或公開訊息的功能。舉例來說,在淘寶、露天拍賣、YAHOO拍賣等等的各大電商,你都可以跟店家私訊。因為一個服務如果不做私訊,很難滿足雙方的溝通需求。也就是說,私訊功能在大型服務上是必要的,而只要有私訊的地方,就有機會可以做聊天機器人。 做聊天機器人可以多一個接觸客戶的管道。如果你的霸氣老闆說過「大家都有做 App ,那我們也要做 App,不管做得好不好,氣勢上不能輸!」那霸氣老闆一定也會說「大家都有做聊天機器人,我們也要做,不管做得好不好,氣勢上不能輸!」。 # 聊天機器人能做什麼? 從理論上來說,聊天機器人可以做到大部分網站和 App 能做到的事情,只是透過不一樣的呈現和互動方式,以下列出一些可能性。 ## 網路客服 現代的人對於長篇文章的接受度越來越低,以 FB 小編為例,常常有人問一些明明就寫在 FAQ(常見問答)裡面的問題,但你身為小編,你能嗆他為什麼不看 FAQ 嗎?你不能。你會複製 FAQ 裡面的重點,然後採用有禮貌的語氣回答。機器人最有耐心了,所以這種事情就很適合交給聊天機器人。如果存在一個系統,他可以讓你匯入 FAQ ,當有人問到 FAQ 裡有提到的問題時,就幫你自動回應,那不是很好嗎? ## 搜尋引擎 你可以想像聊天機器人其實是一個搜尋引擎,他是一個在你輸入關鍵字之後,只會顯示一筆短文的搜尋引擎。當然你要顯示多筆結果也不是不行,只是這樣的使用情境比較不像一個聊天機器人該做的事。 ## 訂閱訊息 當你加入某個聊天機器人為好友,就代表你同意他傳訊息給你。取得有效的客戶連絡方式是在做行銷時很重要的一環,現在的人不會每秒都在收 email,但是對於 Line 傳來的訊息卻可以秒讀,這就是最有效的聯絡方式。目前常見的服務是鬧鐘、天氣或股票相關的資訊提供型聊天機器人。 ## 角色模擬 現代的人很寂寞,也時常感到無聊,對他們來說,找樂子是一件很重要的事情。我有看過一個聊天機器人,他是酒店小姐,當你加他好友之後,他就會一直傳訊息給你,要約你去酒店消費,即使你不做任何回應,他也有辦法一直講。他有一個寫好的劇本,每天就照劇本跟你聊天培養感情,如果哪天你回應了,就會有真人跟你傳訊息約你出來。 ## 陪聊天 像[卡米狗](https://www.kamigo.tw)這種聊天機器人,除了平時在群組講講幹話,同時也會講笑話、唱歌、占卜算命等等的聊天機器人也是受歡迎的一種類型。 ## 純文字遊戲 在古代有一種遊戲叫做 [MUD](https://zh.wikipedia.org/wiki/MUD),他是在圖形化人機介面還沒成熟時的遊戲。遊戲會用文字描述玩家現在的處境,然後給玩家一些選項,而玩家可以用打字的方式選擇,比方說「在你面前出現了一個很大的湖,請問要把斧頭丟進湖裡嗎?(yes/no)」此時透過輸入「yes」或「no」來影響遊戲走向。 ## 網頁遊戲 facebook 的聊天機器人支援顯示內嵌網頁在對話框,也就是說你可以在 facebook messenger 上面作一個開心農場。跟原版開心農場不一樣的地方是,原版開心農場在有人偷你菜的時候會給你一個 facebook 通知,但是在 facebook messenger 上的開心農場可以直接私訊你「熊孩子又來偷你菜了,要偷回去嗎?(yes/no)」這時候你可以透過私訊的方式去操作這個遊戲,而不用真正開啟這個遊戲畫面,對於上班族來說不用開啟遊戲就能玩遊戲是一件多麼棒的事情。 ## 線上桌遊 聊天機器人可以透過私訊傳遞機密情報,而在群組傳遞公開情報。舉例來說,你可以做一個聊天機器人,讓他在群組建立遊戲和讓其他玩家加入遊戲,而在私訊進行遊戲。一個邏輯正確的聊天機器人應該要透過私訊告訴你目前的手牌是什麼,而不是在群組。 ## 放置 PLAY 型線上遊戲 傳說中的 RO 外掛可以做到脫機外掛,也就是不執行主程式,只開一個黑黑的畫面(終端機),然後透過純文字的方式告訴你目前發生了什麼事。比方說「你攻擊了波利,造成了5點傷害。」,把這樣的訊息從終端機改成用聊天機器人發送訊息的形式也是可能的。像那個功德無量放生系統,我就覺得很適合做成聊天機器人。 ## 訂餐、訂位 雖然還沒有看到任何一家賣雞排的或賣手搖飲料的店做,但我覺得應該很快就會有結合 POS 機的聊天機器人,只要在 Line 上面傳訊息說「兩片雞排要辣」就自動把訂單打出來給店家的聊天機器人。 ## 賣東西 Line 上的聊天機器人可以傳送 Template 和 Carousel 這些類型的訊息,他看起來是像這樣的: ![](https://4.bp.blogspot.com/-2tg_4pzQKl0/WjlFfBW-WAI/AAAAAAAA_AE/4pKzluuCKVcN5DRL6xc2qgkAhhIj3l8YQCKgBGAs/s1600/IMG_6820.PNG) 這很適合作為商品選單,或者說他其實是設計出來專門讓你賣東西用的功能。關於在 Line 上要怎麼付款這件事,有一個保證可行的方案是你跟聊天機器人對話的過程中建立訂單,然後再開啟一個結帳網頁。雖然現在 Line 有些事情還不能做,但既然他是趨勢,就表示通訊平台未來會設計出更多樣式的訊息和功能提供給大家使用,最值得期待的我會認為是 Line Pay 的整合。哦對了,聽說 Facebook 上的聊天機器人是有做完整金流的,所以如果做在 Facebook 上就不用另外開網頁囉。 ## 智能助理 像是 Siri 這類型的聊天機器人,他可以同時提供許多種上述服務,那他就會被稱為智能助理。 # 聽說做聊天機器人需要會人工智慧、機器學習等這些很潮的技術才做得起來? 沒有這回事,[卡米狗](https://www.kamigo.tw)就是一個完全沒有用到這些技術的聊天機器人。 目前的聊天機器人從訊息的解讀方式來看的話,可以分為三大類:使用規則、使用按鈕、和使用語意分析。 [卡米狗](https://www.kamigo.tw)是使用規則來解讀訊息的聊天機器人,舉例來說「[卡米狗](https://www.kamigo.tw)學;你好嗎;我很好」這並不是一個正常人類會自然講出來的話,而是一種指令。對[卡米狗](https://www.kamigo.tw)來說,只要你打錯字,不符合規則,他就不會理你了。因為打錯字就無法使用,會讓大家造成很大的挫折感,所以[卡米狗](https://www.kamigo.tw)也有使用按鈕。 當你說「[卡米狗](https://www.kamigo.tw)」時,他會用純文字描述目前狀態,然後給出一個包含兩個按鈕的選單,接下來所有的操作你只需要點擊按鈕,因為沒有輸入文字的階段了,所以就不會有打錯字的問題。而一個好的語意分析能夠讓你在打錯字或者用不同的說法,都能猜到你要的是什麼。 ![](https://3.bp.blogspot.com/-XkUzjViLgdw/WjlKrRBUW0I/AAAAAAAA_EY/PvxFyk6w9EUK2Yca4GP3jNdFhuP65nNgQCKgBGAs/s1600/IMG_6821.PNG) ![](https://1.bp.blogspot.com/-2L8En0_gWhk/WjlK2ESm5xI/AAAAAAAA_Ec/cv5ekbYZjQwEKBDUT6K2zsjVcXXOsG-AACKgBGAs/s1600/IMG_6822.PNG) 目前語意分析做得最好的方法是使用深度學習技術加上大量良好的資料輸入。當然如果你有深度學習技術和相關的資料,你可以做得更好。但在成本考量下,做一個簡單的聊天機器人其實也可以做得不錯。 # 有可能在 PTT 上面做一個聊天機器人嗎? 是的,廣義的聊天機器人是可以在透過任何文字交流的平台上發布或回應訊息。差別只在於 PTT 並沒有做 API (應用程式介面) 方便我們去串接,所以我們只能透過類似外掛程式的方式去控制網頁發布或回應訊息。

2017/11/29

Ruby - 使用多態關聯

markdown ## 使用 [多態關聯 Polymorphic Associations](http://guides.rubyonrails.org/association_basics.html#polymorphic-associations) 目的:在一個表格可能被多個表格參考時,不使用多個 references 去儲存參考,而是使用一個 reference + 一個 type 欄位去儲存。 建立: ``` class CreatePictures < ActiveRecord::Migration[5.0] def change create_table :pictures do |t| t.string :name t.references :imageable, polymorphic: true, index: true t.timestamps end end end ``` ``` class Picture < ApplicationRecord belongs_to :imageable, polymorphic: true end class Employee < ApplicationRecord has_many :pictures, as: :imageable end class Product < ApplicationRecord has_many :pictures, as: :imageable end ``` 使用: ``` Product.last.pictures Employee.last.pictures ```

Ruby - 使用 Devise confirmable

markdown ## Devise confirmable 當你想要認證註冊者的信箱時可以使用 confirmable 安裝方式請參考:[https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users](https://github.com/plataformatec/devise/wiki/How-To:-Add-:confirmable-to-Users) 以下說明一些實務上的可能會遇到的細節調整方式。 ## 什麼時候會寄出信? ### 建立 user 時 在建立 user 時,會在呼叫 user.save 後寄信給 user。 ``` user = User.create user.save ``` ### user email 更新時 在編輯 user 時,若 email 有修改,會在呼叫 user.save 後寄信給 user。 ``` user = User.find(params[:id]) user.email = 'QQ@QQ' user.save ``` 此時寫入的 email 會被保存到 unconfirmed_email,而原先的 email 欄位在 user 完成認證之前不會改變。 ## 開發時測試寄信的方法 在開發時可能會希望不要真的寄出信件,此時可以使用 letter_opener,他會在需要寄信時,只將信件內容印在 console log 上。 設定方法是在 `config/environments/development.rb` 加入以下程式碼: ``` config.action_mailer.delivery_method = :letter_opener config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } ``` ## confirmable 自動測試 加入了 confirmable 之後可能會導致 test fail,因為 devise 嘗試 send mail 但是 test 環境下可能無法正確寄信。 #### 避免寄出信件的方法 如果你希望在測試時不要寄信,如果你使用 FactoryBot 這個套件來生成 user,以下是跳過 email 驗證的方法: ``` FactoryBot.define do factory :user do after(:build) { |u| u.skip_confirmation! } end end ``` 在不使用 FactoryBot 的情況下,跳過 email 驗證的方法: ``` user = User.new user.skip_confirmation! user.save ``` #### 成功寄出信件的方法 如果你希望寄信,但是你沒有設定 host 值,那麼你會看見這個: ``` ActionView::Template::Error: Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true ``` 此時你需要加入以下內容至 `config/environments/test.rb`: ``` config.action_mailer.delivery_method = :test config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } ``` ### 測試寄件內容 使用 ActionMailer::Base.deliveries.last 可以取得最後一次寄出的信件內容: ``` user = User.new user.save mail = ActionMailer::Base.deliveries.last mail.from mail.to mail.subject mail.body.to_s ``` 因此可以對信件內容做測試。 ### 模擬使用者完成認證 用 code 完成認證的方法 ``` user = User.find(params[:id]) user.confirm ``` ## 同一個認證連結被點擊第二次會發生什麼事? 當 user 點擊第二次認證信連結時,預設是會顯示「 Email was already confirmed, please try signing in. 」字樣。可以透過自訂 controller 去修改預設行為 ## 怎麼修改認證信內容? 改 template 改 template 路徑 ## 自定義寄信路徑 ``` class DeviseMailer < Devise::Mailer helper :application # gives access to all helpers defined within `application_helper`. include Devise::Controllers::UrlHelpers # Optional. eg. `confirmation_url` def headers_for(action, opts) super.merge!({template_path: '/users/mailer'}) # this moves the Devise template path from /views/devise/mailer to /views/users/mailer end # def confirmation_instructions(record, token, opts={}) # headers["Custom-header"] = "Bar" # opts[:from] = 'my_custom_from@domain.com' # opts[:reply_to] = 'my_custom_from@domain.com' # super # end end ``` ## 參考資料: 測試寄信的方法 [http://guides.rubyonrails.org/testing.html#testing-your-mailers](http://guides.rubyonrails.org/testing.html#testing-your-mailers) 阻止修改mail時的認證:[https://coderwall.com/p/7_yh8q/skip-devise-email-confirmation-on-update](https://coderwall.com/p/7_yh8q/skip-devise-email-confirmation-on-update)

2017/11/28

Ruby - 使用 Pundit

markdown Pundit 是一個用來做身分驗證的工具。對於每一個 Model 來說,目前登入者能不能對這個 Model 進行某種操作,可以被定義在 Policy 上。 Pundit 並不是一個複雜的 gem,但仍然很多人使用,我認為他存在的價值跟 rails 一樣,都是在提出一個收納的概念,教你如何存放你的 code 到正確的位置。 Pundit:我認為所有跟登入者權限相關的東西都應該被儲存在同一個 class(Policy),同一個資料夾下(Policy),我創造了一個架構,使得所有按照我架構的寫法的 code 可以少寫一些字,並且讓專案的 code 看起來更乾淨。 如果你想要檢查登入者(user) 有沒有辦法對資料(record) 進行某種操作 (update?),可以這樣寫: ``` class PostPolicy < ApplicationPolicy def update? user.admin? or not record.published? end end ``` 下面的 code 跟 上面的 code 是等價的 ``` class PostPolicy attr_reader :user, :post def initialize(user, post) @user = user @post = post end def update? user.admin? or not post.published? end end ``` 當你在 Controller 的 action 裡面寫到 authorize model 時,Pundit 會幫你看有沒有跟 action 同名的 Policy。透過 current_user 跟 model 這兩個值去做檢查。 注意:Devise 剛好會生成一個方法叫做是 current_user。 舉例來說,這個 action: ``` def update @post = Post.find(params[:id]) authorize @post if @post.update(post_params) redirect_to @post else render :edit end end ``` 執行 authorize @post 時,等於去執行以下程式: ``` unless PostPolicy.new(current_user, @post).update? raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}" end ``` 你也可以自己指定要執行的 policy 方法名稱 ``` authorize @post :update? ``` 如果 policy 不需要 record 變數就可以做,則 record 可以不傳,改傳 record 的 Class ``` # in controller def admin_list authorize Post # we don't have a particular post to authorize # Rest of controller action end # in policy class PostPolicy < ApplicationPolicy def admin_list? user.admin? end end ``` authorize 會回傳傳入的參數,所以可以在 authorize 的時候一邊指定要儲存到哪個變數。 ``` # in controller def show @user = authorize User.find(params[:id]) end ``` policy method 可以讓你取得 policy 物件 ``` policy(@post) ``` 等於 ``` PostPolicy.new(current_user, @post) ``` Pundit 不只對 model 可以加 policy,也可以對 symbol 加 policy。 ``` # in policy class DashboardPolicy < Struct.new(:user, :dashboard) # ... end #in controller authorize :dashboard, :show? # In views <% if policy(:dashboard).show? %> ``` Pundit 對於 Scope 也有處理: ``` class PostPolicy < ApplicationPolicy class Scope attr_reader :user, :scope def initialize(user, scope) @user = user @scope = scope end def resolve if user.admin? scope.all else scope.where(published: true) end end end def update? user.admin? or not post.published? end end ``` 可以簡寫為 ``` class PostPolicy < ApplicationPolicy class Scope < Scope def resolve if user.admin? scope.all else scope.where(published: true) end end end def update? user.admin? or not post.published? end end ``` 當你定義好 scope 之後,可以這樣去使用它: ``` def index @posts = policy_scope(Post) end ``` policy_scope 傳入的參數會是一個可以下 query 的物件,然後會執行相當於以下程式: ``` def index @posts = PostPolicy::Scope.new(current_user, Post).resolve end ``` 如果你不想忘記寫 authorize,那你可以在 ApplicationController 加入下面的程式: ``` after_action :verify_authorized, except: :index after_action :verify_policy_scoped, only: :index ``` 這樣的話就會在 controller action 中沒有呼叫 authorize 或 policy_scope 的時候跳出錯誤。 如果真的不需要驗證,那你可以在 action 中寫入 skip_authorization。 ``` def show record = Record.find_by(attribute: "value") if record.present? authorize record else skip_authorization end end ``` 你可以指定 Model 對應的 Policy 名稱 ``` class Post def self.policy_class PostablePolicy end end ``` pundit 也有提供 generator ``` # in bash: rails g pundit:policy post ``` 你可以做一個 ApplicationPolicy ,讓他被繼承到每一個 Policy, 使得所有的 Policy 都會去檢查是否使用者有登入 ``` class ApplicationPolicy def initialize(user, record) raise Pundit::NotAuthorizedError, "must be logged in" unless user @user = user @record = record end end ``` 然後你就可以在 ApplicationController 用 rescue_from 去接他。 ``` class ApplicationController < ActionController::Base protect_from_forgery include Pundit rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized private def user_not_authorized flash[:alert] = "You are not authorized to perform this action." redirect_to(request.referrer || root_path) end end ``` 或者在你的 config/application.rb 去接他 config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden pundit 也可以用來處理 params ``` # in policy class PostPolicy < ApplicationPolicy def permitted_attributes if user.admin? || user.owner_of?(post) [:title, :body, :tag_list] else [:tag_list] end end end # in controller def update @post = Post.find(params[:id]) if @post.update_attributes(permitted_attributes(@post)) redirect_to @post else render :edit end end ``` 你可以針對每個不同的 action 提供不同的 permitted_attributes ``` class PostPolicy < ApplicationPolicy def permitted_attributes_for_create [:title, :body] end def permitted_attributes_for_edit [:body] end end ```

2017/11/21

mac - 關閉 chrome 的兩指滑動換頁功能

markdown 在 mac 上的 chrome 有一個功能是使用兩指向右滑動可以回到上一頁,可是幹,我只是想看左邊的東西欸,所以我找到怎麼把這個功能關閉的方法。 在 bash 下輸入以下指令: ``` defaults write com.google.Chrome AppleEnableMouseSwipeNavigateWithScrolls -bool false defaults write com.google.Chrome AppleEnableSwipeNavigateWithScrolls -bool false ``` 然後重開 chrome

2017/11/8

rails - encode & decode

markdown HTML encode ``` require 'cgi' CGI.escapeHTML('<') # "&lt;" ``` HTML decode ``` require 'cgi' CGI.unescapeHTML('&lt;') # "<" ```

mac - 移除所有 ANSI escape code

markdown 當你用 rspec 跑測試並且生成結果檔案時,檔案的內容可能會包含 [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) 所表示的顏色。 舉例來說,如果你用以下程式跑測試: ``` rspec --format documentation --out result.txt ``` 你可以使用 cat 去讀他 ``` cat result.txt ``` 結果看起來像這樣:
但是打開 result.txt 時,你會看到這樣的東西: ``` ... Finished in 1.76 seconds (files took 6.55 seconds to load) [32m1 example, 0 failures [0m Randomized with seed 1 ``` [32m [0m 代表的就是顏色,這被稱為 [ANSI escape code](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors)。 但是我希望讓他消失,在請教大大之後得到一個不錯的解法,有人用 node.js 做了一個簡單的指令[strip-ansi](https://github.com/chalk/strip-ansi-cli)。 安裝方法(如果你有node.js) ``` # 這裡是 bash npm install --global strip-ansi-cli ``` 使用方法 ``` # 基本用法 strip-ansi 字串 # 透過 | cat 輸入檔案路徑 | strip-ansi > 輸出檔案路徑 ```

2017/11/6

Ruby - warning: toplevel constant B referenced by A::B

markdown ##問題 warning: toplevel constant B referenced by A::B ##成因 當 A 是一個 class 且 A::B 還沒有被定義時,ruby 找不到 A::B 時,若 B 有定義,就先使用 B, 而不是拋出 Module#const_missing。 ``` class A end A::String #warning: toplevel constant String referenced by A::String ``` 但 rails 的 autoload 是透過修改 Module#const_missing 而完成的。也就是說,rails 還來不及 autoload 就已經被 toplevel constant 攔截了。 ##解法一 在使用到 A::B 的檔案前面都加 require_dependency 'a/b' ##解法二 在使用到 B 的檔案後面加 require_dependency 'a/b' 確保 rails 不可能會有知道 B 的存在但不知道 A::B 的存在的可能發生。 參考文件 [http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html](http://stem.ps/rails/2015/01/25/ruby-gotcha-toplevel-constant-referenced-by.html) [https://stackoverflow.com/questions/18515100/warning-toplevel-constant-referenced](https://stackoverflow.com/questions/18515100/warning-toplevel-constant-referenced)

2017/10/30

Python - numpy 的使用方法

markdown [NumPy Reference](https://docs.scipy.org/doc/numpy-1.13.0/reference/index.html) 數列生成 ``` >>> np.zeros(5) #array([ 0., 0., 0., 0., 0.]) >>> np.ones(5) #array([ 1., 1., 1., 1., 1.]) >>> np.arange(5) #array([0, 1, 2, 3, 4]) ``` [更多的數列生成](https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.array-creation.html) 數列變形 ``` >>> np.arange(12) #array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) >>> np.arange(12).reshape(2,6) #array([[ 0, 1, 2, 3, 4, 5], # [ 6, 7, 8, 9, 10, 11]]) >>> np.arange(12).reshape(3,4) #array([[ 0, 1, 2, 3], # [ 4, 5, 6, 7], # [ 8, 9, 10, 11]]) >>> np.arange(12).reshape(4,3) #array([[ 0, 1, 2], # [ 3, 4, 5], # [ 6, 7, 8], # [ 9, 10, 11]]) >>> np.arange(12).reshape(6,2) #array([[ 0, 1], # [ 2, 3], # [ 4, 5], # [ 6, 7], # [ 8, 9], # [10, 11]]) >>> np.arange(12).reshape(12,1).flatten() #array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]) ``` 查看數列形狀 ``` >>> np.arange(12).reshape(1,2,3,2) #array([[[[ 0, 1], # [ 2, 3], # [ 4, 5]], # # [[ 6, 7], # [ 8, 9], # [10, 11]]]]) >>> np.arange(12).reshape(1,2,3,2).shape #(1, 2, 3, 2) ``` [更多的數列操作](https://docs.scipy.org/doc/numpy-1.13.0/reference/routines.array-manipulation.html)

2017/10/26

Rails - Apartment 的使用方法

markdown #簡介 Apartment : [https://github.com/influitive/apartment](https://github.com/influitive/apartment) 這個套件的功能是讓你在 rails 可以透過切換 db schema,來存取不同的資料。 在 postgresql 中,預設的 schema 名稱為 public ,而所有的 table 都在 schema 'public' 下。 你可以簡單地把 schema 看成 namespace,在 apartment 中,這被稱為是 tenant。 #安裝步驟 請參考 : [https://github.com/influitive/apartment](https://github.com/influitive/apartment) #使用方法 ## 在 rails c 環境下 新增 tenant ``` Apartment::Tenant.create('abc') ``` 這個指令會在 schema 'abc' 下複製 public 上的所有表格。所以 tenant 就是具有相同表格的 schema。 在以下的示範,看到 abc 的地方,代表的是要填入你的 schema name。 顯示目前所在的 tenant ``` Apartment::Tenant.current # "public" ``` 切換 tenant ``` Apartment::Tenant.switch!('abc') Apartment::Tenant.current # "abc" Apartment::Tenant.switch!('public') Apartment::Tenant.current # "public" Apartment::Tenant.switch('abc') do Apartment::Tenant.current # "abc" end Apartment::Tenant.current # "public" ``` 有暫時切換跟永久切換兩種 ## 在 rails db 環境下 列出所有 schema ``` \dn # List of schemas # Name | Owner #--------+---------- # public | postgres # abc | etrex # (2 rows) ``` 顯示目前所在的 schema ``` SHOW search_path; # search_path #----------------- # "$user", public # (1 row) ``` 切換 schema ``` SET search_path TO abc; # SET SET search_path TO 'abc'; # SET ``` 字串要不要加引號都可以,當 search_path 的值不在 schema 的列表上時不會跳 error,可以想像成連接到一個空的 schema,而這樣並不代表新增了一個 schema。 在 select 的當下使用 schema ``` SELECT * FROM schema_name.table_name; ``` ## 關於 excluded_models 在 apartment 提供的功能中有一個功能,這個功能是可以設定在切換 schema 的時候,讓某些表格不要被切換,也就是做成全域的表格。 舉例來說,假設我有兩個 table,是使用以下 code 所生成。 ``` # 這裡是 bash rails g model a rails g model b a:references rails db:migrate ``` 然後我將 B 做成全域的表格 ``` # 這裡是 /config/initializers/apartment.rb 約 18 行的位置 config.excluded_models = %w{ B } ``` 然後建立一個 tenant 'abc' 並且切換過去,在這個環境下做測試 ``` # 這裡是 rails c 環境下 Apartment::Tenant.create('abc') Apartment::Tenant.switch!('abc') ``` 對 A 做一些事情 ``` A.count # (3.8ms) SELECT COUNT(*) FROM "as" # => 0 ``` 對 B 也做一些事情 ``` B.count # (0.5ms) SELECT COUNT(*) FROM "public"."bs" # => 0 ``` 在這裡可以看到,當你對 B 進行操作時,其實是會強制加上 "public" 的,也就是說,對於 B ,不管在哪一個 tenant 下,都只會去存取 schema 'public' 下的表格,所以其他的 schema 的表格 bs 應該會都是空的。 嘗試在 tenant 'abc' 下新增資料 ``` a = A.create() # (0.2ms) BEGIN # SQL (0.4ms) INSERT INTO "as" ("created_at", "updated_at") VALUES ($1, $2) RETURNING "id" [["created_at", "2017-10-25 17:16:22.084365"], ["updated_at", "2017-10-25 17:16:22.084365"]] b = B.create(a:a) # (0.2ms) BEGIN # SQL (1.5ms) INSERT INTO "public"."bs" ("a_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" [["a_id", 3], ["created_at", "2017-10-25 17:16:24.957753"], ["updated_at", "2017-10-25 17:16:24.957753"]] # (0.2ms) ROLLBACK #ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR: insert or update on table "bs" violates foreign #key constraint "fk_rails_ddf8c0c4b5" #DETAIL: Key (a_id)=(3) is not present in table "as". #: INSERT INTO "public"."bs" ("a_id", "created_at", "updated_at") VALUES ($1, $2, $3) RETURNING "id" # from (irb):31 ``` 這時候出大問題了,因為 A 建立在 abc 下,但是 B 建立在 public 下。而 public.bs 有一個外來鍵限制是 a_id 必須要在 public.as 中有出現。 使用 [pgAdmin](https://www.pgadmin.org/) 連進去看,對 db_name/Schemas/public/Tables/bs/Constraints/fk_rails_ddf8c04b5 按右鍵選 CREATE Script: 。
會看到生成的 script 內容為: ``` -- Constraint: fk_rails_ddf8c0c4b5 -- ALTER TABLE public.bs DROP CONSTRAINT fk_rails_ddf8c0c4b5; ALTER TABLE public.bs ADD CONSTRAINT fk_rails_ddf8c0c4b5 FOREIGN KEY (a_id) REFERENCES public."as" (id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION; ``` 在這裡明確地指出跟 public.bs 有關係的表格是 public.as ,而不是其他 schema 下的 as,但是 Apartment 不處理,所以會出問題。

2017/10/19

Network debug 方法

markdown ## linux 環境下 查詢所有 process ``` ps ``` 輸出 ``` PID TTY TIME CMD 21968 ttys000 0:00.16 -bash ``` 查詢 port 3000 被誰占用 ``` lsof -i :3000 ``` 輸出 ``` COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME ruby 20308 etrex 25u IPv4 0xd000000000000 0t0 TCP *:hbci (LISTEN) ``` 刪除某個 process ``` kill 20308 ``` 強制刪除某個 process ``` kill -9 20308 ``` ## 參考文件 kill process:[https://blog.gtwang.org/linux/linux-kill-killall-xkill/](https://blog.gtwang.org/linux/linux-kill-killall-xkill/)

Ruby - RSpec 的使用方法

markdown ## RSpec 簡介 RSpec 在執行的時候不保證執行順序,每個測試產生的資料不會自動被清除。 新增測試的generator語法: ``` rails generate rspec:model user ``` 這樣寫會建立一個檔案在 spec/models/user_spec.rb 執行測試的指令是在 rails 專案目錄下輸入以下指令: ``` # 這裡是 bash # 執行所有測試 rspec # 執行某個資料夾下的所有測試 rspec ./spec/models # 執行某個檔案裡的所有測試 rspec ./spec/models/user_spec.rb # 執行某個檔案裡的某個測試 rspec ./spec/models/user_spec.rb:8 ``` 簡單的範例 ``` require 'rails_helper' RSpec.describe "規格說明" do describe "處於某個狀態下" do # 設定狀態變數 let(:a) { 1 } it "should be 1" do puts "should be 1" expect(a).to eq(1) end end end ``` let 在每次測試裡,第一次存取變數時就會執行對應的程式 ``` require 'rails_helper' RSpec.describe "規格說明" do describe "處於某個狀態下" do let(:a) { puts "let a"; 1 } it "1" do puts "1" puts "a=#{a}" end it "2" do puts "2" puts "a=#{a}" puts "a=#{a}" puts "a=#{a}" end end end ``` 輸出 ``` 1 let a a=1 .2 let a a=1 a=1 a=1 . ``` before 和 after 會在所有測試的執行前後做事 ``` RSpec.describe "規格說明" do describe "處於某個狀態下" do before { puts "before" } after { puts "after" } it "1" do puts "1" end it "2" do puts "2" end end end ``` 執行結果 ``` before 1 after .before 2 after . ``` 因為測試對資料庫的操作會互相影響,如果想要確保每個測試都是在資料庫乾淨的狀態下,可以使用 [database_cleaner](https://github.com/DatabaseCleaner/database_cleaner)。 ``` require 'database_cleaner' ... RSpec.configure do |config| ... config.before(:suite) do DatabaseCleaner.strategy = :transaction DatabaseCleaner.clean_with(:truncation) end config.around(:each) do |example| DatabaseCleaner.cleaning do example.run end end ... end ``` 其中的 before、around 可以參考官網說明文件:[https://relishapp.com/rspec/rspec-core/v/2-13/docs/hooks/before-and-after-hooks#before/after-blocks-defined-in-config-are-run-in-order](https://relishapp.com/rspec/rspec-core/v/2-13/docs/hooks/before-and-after-hooks#before/after-blocks-defined-in-config-are-run-in-order) 如果想要控制 rspec 執行每一個 test 的順序,可以這樣寫: ``` # 這裡是 bash rspec --order defined rspec --seed 1 ``` 詳細的介紹可以參考 [https://relishapp.com/rspec/rspec-core/docs/command-line/order](https://relishapp.com/rspec/rspec-core/docs/command-line/order) 如果想要把結果輸出到檔案,可以這樣寫: ``` # 這裡是 bash rspec --out result.txt rspec --format documentation --out result.txt ``` 上面兩行會使檔案內容不同,詳細的介紹可以參考 [https://relishapp.com/rspec/rspec-core/v/2-4/docs/command-line/format-option](https://relishapp.com/rspec/rspec-core/v/2-4/docs/command-line/format-option)

Ruby - debug 方法

markdown ## 查詢繼承關係 ``` File.ancestors # [File, IO, File::Constants, Enumerable, Object, Kernel, BasicObject] ``` ## 從物件找方法 ``` # 查 File 的類別方法 File.methods # 查 File 的實體方法 File.instance_methods # 查 File 的實體方法 File.new('/').methods # 取得繼承樹上所有的方法 File.methods(true) # 只取得屬於 File 的方法 File.methods(false) ``` ## 從方法找定義 ``` File.method(:read) # #Method: File(IO).read IO.method(:read) # #Method: IO.read IO.method(:read).source_location # nil ``` 因為 IO.read 的定義是寫在 c 語言,所以就不顯示了。 ## 參考文件 為什麼File.method(:read)是nil:[https://ja.stackoverflow.com/questions/5755/ruby-file-read-%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AE%E8%AA%AC%E6%98%8E%E3%82%92api%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%81%A7%E8%AA%BF%E3%81%B9%E3%81%9F%E3%81%84](https://ja.stackoverflow.com/questions/5755/ruby-file-read-%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%81%AE%E8%AA%AC%E6%98%8E%E3%82%92api%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88%E3%81%A7%E8%AA%BF%E3%81%B9%E3%81%9F%E3%81%84)

Python - 電腦字體數字辨識

markdown 續前篇:[Python - draw text on image and image to numpy array](http://etrex.blogspot.tw/2017/10/python-draw-text-on-image-and-image-to.html) ## 目標 嘗試建立一個簡單的類神經網路,只針對電腦字體數字 0~9 共 10 張圖片作訓練,訓練資料就是測試資料,在 40 次左右的訓練後正確度可達到 100%。 ## 本文包含 * keras 的使用 * keras Model 輸出成圖片 ## 程式碼 ``` import numpy as np from PIL import Image from PIL import ImageFont from PIL import ImageDraw image_size = (8,13) font_size = 10 x_train = np.array([]) y_train = np.array([]) for i in range(10): # 空白圖片生成 image = Image.new('L', image_size, 0) # 取得繪圖器 draw = ImageDraw.Draw(image) # 字型設定 # font = ImageFont.truetype("C:/Windows/Fonts/cour.ttf", font_size) font = ImageFont.truetype("C:/Windows/Fonts/msjh.ttc", font_size) # 關閉反鋸齒 draw.fontmode = '1' # 測量文字尺寸 text_size = draw.textsize(str(i),font) # print('text_size:', text_size) # 文字置中 text_position = ((image_size[0]-text_size[0])//2,(image_size[1]-text_size[1])//2) # print('text_position:', text_position) # 畫上文字 draw.text(text_position, str(i), 255, font) # 存檔 image.save(str(i)+'.bmp') # 轉成 numpy array na = np.array(image.getdata()).reshape(image.size[1], image.size[0]) # 加入訓練資料 x_train = np.append(x_train,na) y_train = np.append(y_train,i) import keras from keras.models import Sequential from keras.layers import Dense from keras.optimizers import RMSprop # 每次更新時所採用的資料筆數 batch_size = 1 # 總共有幾種數字 num_classes = 10 # 要更新幾次 epochs = 100 # 把資料轉成 model 需要的格式 x_train = x_train.reshape(10, 104) x_train = x_train.astype('float32') x_train /= 255 print(x_train.shape[0], 'train samples') y_train = keras.utils.to_categorical(y_train, num_classes) # 建立 model model = Sequential() # 一層 + softmax model.add(Dense(num_classes, input_shape=(104,), activation='softmax')) # ?? model.summary() # 選擇 loss function 和 optimizer model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) # 開始訓練 history = model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_train, y_train)) # 計算分數 score = model.evaluate(x_train, y_train, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1]) # 儲存 model 至圖片 from keras.utils import plot_model plot_model(model, to_file='model.png') ``` ## 輸出 ``` Using TensorFlow backend. 10 train samples _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= dense_1 (Dense) (None, 10) 1050 ================================================================= Total params: 1,050 Trainable params: 1,050 Non-trainable params: 0 _________________________________________________________________ Train on 10 samples, validate on 10 samples Epoch 1/100 10/10 [==============================] - ETA: 0s - loss: 2.5473 - acc: 0.0000e+00 - val_loss: 2.4555 - val_acc: 0.1000 Epoch 2/100 10/10 [==============================] - ETA: 0s - loss: 2.4563 - acc: 0.1000 - val_loss: 2.3924 - val_acc: 0.1000 Epoch 3/100 10/10 [==============================] - ETA: 0s - loss: 2.3926 - acc: 0.1000 - val_loss: 2.3334 - val_acc: 0.2000 Epoch 4/100 10/10 [==============================] - ETA: 0s - loss: 2.3336 - acc: 0.2000 - val_loss: 2.2760 - val_acc: 0.2000 Epoch 5/100 10/10 [==============================] - ETA: 0s - loss: 2.2766 - acc: 0.2000 - val_loss: 2.2196 - val_acc: 0.2000 Epoch 6/100 10/10 [==============================] - ETA: 0s - loss: 2.2203 - acc: 0.2000 - val_loss: 2.1636 - val_acc: 0.4000 Epoch 7/100 10/10 [==============================] - ETA: 0s - loss: 2.1640 - acc: 0.4000 - val_loss: 2.1090 - val_acc: 0.5000 Epoch 8/100 10/10 [==============================] - ETA: 0s - loss: 2.1096 - acc: 0.4000 - val_loss: 2.0545 - val_acc: 0.5000 Epoch 9/100 10/10 [==============================] - ETA: 0s - loss: 2.0556 - acc: 0.5000 - val_loss: 2.0013 - val_acc: 0.5000 Epoch 10/100 10/10 [==============================] - ETA: 0s - loss: 2.0023 - acc: 0.5000 - val_loss: 1.9484 - val_acc: 0.5000 Epoch 11/100 10/10 [==============================] - ETA: 0s - loss: 1.9493 - acc: 0.5000 - val_loss: 1.8971 - val_acc: 0.5000 Epoch 12/100 10/10 [==============================] - ETA: 0s - loss: 1.8985 - acc: 0.5000 - val_loss: 1.8453 - val_acc: 0.5000 Epoch 13/100 10/10 [==============================] - ETA: 0s - loss: 1.8464 - acc: 0.5000 - val_loss: 1.7949 - val_acc: 0.5000 Epoch 14/100 10/10 [==============================] - ETA: 0s - loss: 1.7962 - acc: 0.5000 - val_loss: 1.7448 - val_acc: 0.5000 Epoch 15/100 10/10 [==============================] - ETA: 0s - loss: 1.7464 - acc: 0.5000 - val_loss: 1.6958 - val_acc: 0.5000 Epoch 16/100 10/10 [==============================] - ETA: 0s - loss: 1.6971 - acc: 0.5000 - val_loss: 1.6471 - val_acc: 0.5000 Epoch 17/100 10/10 [==============================] - ETA: 0s - loss: 1.6486 - acc: 0.5000 - val_loss: 1.5994 - val_acc: 0.5000 Epoch 18/100 10/10 [==============================] - ETA: 0s - loss: 1.6007 - acc: 0.5000 - val_loss: 1.5520 - val_acc: 0.7000 Epoch 19/100 10/10 [==============================] - ETA: 0s - loss: 1.5538 - acc: 0.7000 - val_loss: 1.5064 - val_acc: 0.7000 Epoch 20/100 10/10 [==============================] - ETA: 0s - loss: 1.5078 - acc: 0.7000 - val_loss: 1.4612 - val_acc: 0.7000 Epoch 21/100 10/10 [==============================] - ETA: 0s - loss: 1.4629 - acc: 0.7000 - val_loss: 1.4168 - val_acc: 0.7000 Epoch 22/100 10/10 [==============================] - ETA: 0s - loss: 1.4190 - acc: 0.7000 - val_loss: 1.3736 - val_acc: 0.7000 Epoch 23/100 10/10 [==============================] - ETA: 0s - loss: 1.3758 - acc: 0.7000 - val_loss: 1.3311 - val_acc: 0.8000 Epoch 24/100 10/10 [==============================] - ETA: 0s - loss: 1.3331 - acc: 0.8000 - val_loss: 1.2891 - val_acc: 0.8000 Epoch 25/100 10/10 [==============================] - ETA: 0s - loss: 1.2913 - acc: 0.8000 - val_loss: 1.2488 - val_acc: 0.9000 Epoch 26/100 10/10 [==============================] - ETA: 0s - loss: 1.2513 - acc: 0.9000 - val_loss: 1.2091 - val_acc: 0.9000 Epoch 27/100 10/10 [==============================] - ETA: 0s - loss: 1.2114 - acc: 0.9000 - val_loss: 1.1701 - val_acc: 0.9000 Epoch 28/100 10/10 [==============================] - ETA: 0s - loss: 1.1721 - acc: 0.9000 - val_loss: 1.1324 - val_acc: 0.9000 Epoch 29/100 10/10 [==============================] - ETA: 0s - loss: 1.1349 - acc: 0.9000 - val_loss: 1.0957 - val_acc: 0.9000 Epoch 30/100 10/10 [==============================] - ETA: 0s - loss: 1.0984 - acc: 0.9000 - val_loss: 1.0596 - val_acc: 0.9000 Epoch 31/100 10/10 [==============================] - ETA: 0s - loss: 1.0620 - acc: 0.9000 - val_loss: 1.0243 - val_acc: 0.9000 Epoch 32/100 10/10 [==============================] - ETA: 0s - loss: 1.0269 - acc: 0.9000 - val_loss: 0.9905 - val_acc: 1.0000 Epoch 33/100 10/10 [==============================] - ETA: 0s - loss: 0.9932 - acc: 1.0000 - val_loss: 0.9571 - val_acc: 1.0000 Epoch 34/100 10/10 [==============================] - ETA: 0s - loss: 0.9597 - acc: 1.0000 - val_loss: 0.9247 - val_acc: 1.0000 Epoch 35/100 10/10 [==============================] - ETA: 0s - loss: 0.9276 - acc: 1.0000 - val_loss: 0.8934 - val_acc: 1.0000 Epoch 36/100 10/10 [==============================] - ETA: 0s - loss: 0.8962 - acc: 1.0000 - val_loss: 0.8629 - val_acc: 1.0000 Epoch 37/100 10/10 [==============================] - ETA: 0s - loss: 0.8655 - acc: 1.0000 - val_loss: 0.8330 - val_acc: 1.0000 Epoch 38/100 10/10 [==============================] - ETA: 0s - loss: 0.8359 - acc: 1.0000 - val_loss: 0.8047 - val_acc: 1.0000 Epoch 39/100 10/10 [==============================] - ETA: 0s - loss: 0.8077 - acc: 1.0000 - val_loss: 0.7766 - val_acc: 1.0000 Epoch 40/100 10/10 [==============================] - ETA: 0s - loss: 0.7797 - acc: 1.0000 - val_loss: 0.7501 - val_acc: 1.0000 Epoch 41/100 10/10 [==============================] - ETA: 0s - loss: 0.7529 - acc: 1.0000 - val_loss: 0.7239 - val_acc: 1.0000 Epoch 42/100 10/10 [==============================] - ETA: 0s - loss: 0.7270 - acc: 1.0000 - val_loss: 0.6988 - val_acc: 1.0000 Epoch 43/100 10/10 [==============================] - ETA: 0s - loss: 0.7018 - acc: 1.0000 - val_loss: 0.6744 - val_acc: 1.0000 Epoch 44/100 10/10 [==============================] - ETA: 0s - loss: 0.6773 - acc: 1.0000 - val_loss: 0.6511 - val_acc: 1.0000 Epoch 45/100 10/10 [==============================] - ETA: 0s - loss: 0.6542 - acc: 1.0000 - val_loss: 0.6283 - val_acc: 1.0000 Epoch 46/100 10/10 [==============================] - ETA: 0s - loss: 0.6312 - acc: 1.0000 - val_loss: 0.6065 - val_acc: 1.0000 Epoch 47/100 10/10 [==============================] - ETA: 0s - loss: 0.6097 - acc: 1.0000 - val_loss: 0.5852 - val_acc: 1.0000 Epoch 48/100 10/10 [==============================] - ETA: 0s - loss: 0.5882 - acc: 1.0000 - val_loss: 0.5647 - val_acc: 1.0000 Epoch 49/100 10/10 [==============================] - ETA: 0s - loss: 0.5677 - acc: 1.0000 - val_loss: 0.5451 - val_acc: 1.0000 Epoch 50/100 10/10 [==============================] - ETA: 0s - loss: 0.5482 - acc: 1.0000 - val_loss: 0.5261 - val_acc: 1.0000 Epoch 51/100 10/10 [==============================] - ETA: 0s - loss: 0.5291 - acc: 1.0000 - val_loss: 0.5078 - val_acc: 1.0000 Epoch 52/100 10/10 [==============================] - ETA: 0s - loss: 0.5108 - acc: 1.0000 - val_loss: 0.4900 - val_acc: 1.0000 Epoch 53/100 10/10 [==============================] - ETA: 0s - loss: 0.4928 - acc: 1.0000 - val_loss: 0.4729 - val_acc: 1.0000 Epoch 54/100 10/10 [==============================] - ETA: 0s - loss: 0.4759 - acc: 1.0000 - val_loss: 0.4567 - val_acc: 1.0000 Epoch 55/100 10/10 [==============================] - ETA: 0s - loss: 0.4596 - acc: 1.0000 - val_loss: 0.4409 - val_acc: 1.0000 Epoch 56/100 10/10 [==============================] - ETA: 0s - loss: 0.4440 - acc: 1.0000 - val_loss: 0.4258 - val_acc: 1.0000 Epoch 57/100 10/10 [==============================] - ETA: 0s - loss: 0.4286 - acc: 1.0000 - val_loss: 0.4113 - val_acc: 1.0000 Epoch 58/100 10/10 [==============================] - ETA: 0s - loss: 0.4143 - acc: 1.0000 - val_loss: 0.3971 - val_acc: 1.0000 Epoch 59/100 10/10 [==============================] - ETA: 0s - loss: 0.4001 - acc: 1.0000 - val_loss: 0.3835 - val_acc: 1.0000 Epoch 60/100 10/10 [==============================] - ETA: 0s - loss: 0.3864 - acc: 1.0000 - val_loss: 0.3706 - val_acc: 1.0000 Epoch 61/100 10/10 [==============================] - ETA: 0s - loss: 0.3735 - acc: 1.0000 - val_loss: 0.3580 - val_acc: 1.0000 Epoch 62/100 10/10 [==============================] - ETA: 0s - loss: 0.3611 - acc: 1.0000 - val_loss: 0.3459 - val_acc: 1.0000 Epoch 63/100 10/10 [==============================] - ETA: 0s - loss: 0.3487 - acc: 1.0000 - val_loss: 0.3343 - val_acc: 1.0000 Epoch 64/100 10/10 [==============================] - ETA: 0s - loss: 0.3370 - acc: 1.0000 - val_loss: 0.3232 - val_acc: 1.0000 Epoch 65/100 10/10 [==============================] - ETA: 0s - loss: 0.3261 - acc: 1.0000 - val_loss: 0.3125 - val_acc: 1.0000 Epoch 66/100 10/10 [==============================] - ETA: 0s - loss: 0.3152 - acc: 1.0000 - val_loss: 0.3023 - val_acc: 1.0000 Epoch 67/100 10/10 [==============================] - ETA: 0s - loss: 0.3049 - acc: 1.0000 - val_loss: 0.2925 - val_acc: 1.0000 Epoch 68/100 10/10 [==============================] - ETA: 0s - loss: 0.2953 - acc: 1.0000 - val_loss: 0.2828 - val_acc: 1.0000 Epoch 69/100 10/10 [==============================] - ETA: 0s - loss: 0.2854 - acc: 1.0000 - val_loss: 0.2736 - val_acc: 1.0000 Epoch 70/100 10/10 [==============================] - ETA: 0s - loss: 0.2762 - acc: 1.0000 - val_loss: 0.2648 - val_acc: 1.0000 Epoch 71/100 10/10 [==============================] - ETA: 0s - loss: 0.2675 - acc: 1.0000 - val_loss: 0.2563 - val_acc: 1.0000 Epoch 72/100 10/10 [==============================] - ETA: 0s - loss: 0.2588 - acc: 1.0000 - val_loss: 0.2481 - val_acc: 1.0000 Epoch 73/100 10/10 [==============================] - ETA: 0s - loss: 0.2506 - acc: 1.0000 - val_loss: 0.2403 - val_acc: 1.0000 Epoch 74/100 10/10 [==============================] - ETA: 0s - loss: 0.2429 - acc: 1.0000 - val_loss: 0.2327 - val_acc: 1.0000 Epoch 75/100 10/10 [==============================] - ETA: 0s - loss: 0.2351 - acc: 1.0000 - val_loss: 0.2254 - val_acc: 1.0000 Epoch 76/100 10/10 [==============================] - ETA: 0s - loss: 0.2279 - acc: 1.0000 - val_loss: 0.2184 - val_acc: 1.0000 Epoch 77/100 10/10 [==============================] - ETA: 0s - loss: 0.2209 - acc: 1.0000 - val_loss: 0.2117 - val_acc: 1.0000 Epoch 78/100 10/10 [==============================] - ETA: 0s - loss: 0.2140 - acc: 1.0000 - val_loss: 0.2053 - val_acc: 1.0000 Epoch 79/100 10/10 [==============================] - ETA: 0s - loss: 0.2078 - acc: 1.0000 - val_loss: 0.1989 - val_acc: 1.0000 Epoch 80/100 10/10 [==============================] - ETA: 0s - loss: 0.2011 - acc: 1.0000 - val_loss: 0.1929 - val_acc: 1.0000 Epoch 81/100 10/10 [==============================] - ETA: 0s - loss: 0.1954 - acc: 1.0000 - val_loss: 0.1872 - val_acc: 1.0000 Epoch 82/100 10/10 [==============================] - ETA: 0s - loss: 0.1894 - acc: 1.0000 - val_loss: 0.1817 - val_acc: 1.0000 Epoch 83/100 10/10 [==============================] - ETA: 0s - loss: 0.1841 - acc: 1.0000 - val_loss: 0.1763 - val_acc: 1.0000 Epoch 84/100 10/10 [==============================] - ETA: 0s - loss: 0.1784 - acc: 1.0000 - val_loss: 0.1711 - val_acc: 1.0000 Epoch 85/100 10/10 [==============================] - ETA: 0s - loss: 0.1732 - acc: 1.0000 - val_loss: 0.1662 - val_acc: 1.0000 Epoch 86/100 10/10 [==============================] - ETA: 0s - loss: 0.1684 - acc: 1.0000 - val_loss: 0.1614 - val_acc: 1.0000 Epoch 87/100 10/10 [==============================] - ETA: 0s - loss: 0.1636 - acc: 1.0000 - val_loss: 0.1568 - val_acc: 1.0000 Epoch 88/100 10/10 [==============================] - ETA: 0s - loss: 0.1590 - acc: 1.0000 - val_loss: 0.1523 - val_acc: 1.0000 Epoch 89/100 10/10 [==============================] - ETA: 0s - loss: 0.1542 - acc: 1.0000 - val_loss: 0.1480 - val_acc: 1.0000 Epoch 90/100 10/10 [==============================] - ETA: 0s - loss: 0.1501 - acc: 1.0000 - val_loss: 0.1438 - val_acc: 1.0000 Epoch 91/100 10/10 [==============================] - ETA: 0s - loss: 0.1457 - acc: 1.0000 - val_loss: 0.1399 - val_acc: 1.0000 Epoch 92/100 10/10 [==============================] - ETA: 0s - loss: 0.1418 - acc: 1.0000 - val_loss: 0.1360 - val_acc: 1.0000 Epoch 93/100 10/10 [==============================] - ETA: 0s - loss: 0.1379 - acc: 1.0000 - val_loss: 0.1323 - val_acc: 1.0000 Epoch 94/100 10/10 [==============================] - ETA: 0s - loss: 0.1343 - acc: 1.0000 - val_loss: 0.1287 - val_acc: 1.0000 Epoch 95/100 10/10 [==============================] - ETA: 0s - loss: 0.1306 - acc: 1.0000 - val_loss: 0.1252 - val_acc: 1.0000 Epoch 96/100 10/10 [==============================] - ETA: 0s - loss: 0.1271 - acc: 1.0000 - val_loss: 0.1218 - val_acc: 1.0000 Epoch 97/100 10/10 [==============================] - ETA: 0s - loss: 0.1237 - acc: 1.0000 - val_loss: 0.1185 - val_acc: 1.0000 Epoch 98/100 10/10 [==============================] - ETA: 0s - loss: 0.1204 - acc: 1.0000 - val_loss: 0.1154 - val_acc: 1.0000 Epoch 99/100 10/10 [==============================] - ETA: 0s - loss: 0.1172 - acc: 1.0000 - val_loss: 0.1124 - val_acc: 1.0000 Epoch 100/100 10/10 [==============================] - ETA: 0s - loss: 0.1141 - acc: 1.0000 - val_loss: 0.1095 - val_acc: 1.0000 Test loss: 0.109465420246 Test accuracy: 1.0 ``` ## 輸出的圖片 plot_model 的執行,需要安裝 pydot 和 graphviz ``` pip3 install pydot ``` ## plot_model 的環境安裝 在 windows 上,graphviz 必須手動安裝,安裝檔可以到他們官網下載。 [http://www.graphviz.org/Download_windows.php](http://www.graphviz.org/Download_windows.php) 安裝好之後必須在環境變數 path 加上 C:\Program Files (x86)\Graphviz2.30\bin 才能使用。 cmd 下輸入指令: ``` dot -version ``` 若顯示以下訊息,表示正確安裝。 ``` dot - graphviz version 2.30.1 (20130214.1330) libdir = "C:\Program Files (x86)\Graphviz2.30\bin" Activated plugin library: gvplugin_pango.dll Using textlayout: textlayout:cairo Activated plugin library: gvplugin_dot_layout.dll Using layout: dot:dot_layout Activated plugin library: gvplugin_core.dll Using render: dot:core Using device: dot:dot:core The plugin configuration file: C:\Program Files (x86)\Graphviz2.30\bin\config6 was successfully loaded. render : cairo dot fig gd gdiplus map pic pov ps svg tk vml vrml xdot layout : circo dot fdp neato nop nop1 nop2 osage patchwork sfdp twopi textlayout : textlayout device : bmp canon cmap cmapx cmapx_np dot emf emfplus eps fig gd gd2 gif gv imap imap_np ismap jpe jpeg jpg metafile pdf p ic plain plain-ext png pov ps ps2 svg svgz tif tiff tk vml vmlz vrml wbmp xdot loadimage : (lib) bmp eps gd gd2 gif jpe jpeg jpg png ps svg ``` ## 參考文件 plot_model 在 windows 上的環境建立:[https://zhuanlan.zhihu.com/p/28158957](https://zhuanlan.zhihu.com/p/28158957) graphviz 的使用:[https://www.openfoundry.org/tw/foss-programs/8820-graphviz-](https://www.openfoundry.org/tw/foss-programs/8820-graphviz-)