<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by 陳雁智 (Marat Y. C. Chen) on Medium]]></title>
        <description><![CDATA[Stories by 陳雁智 (Marat Y. C. Chen) on Medium]]></description>
        <link>https://medium.com/@yenzhit?source=rss-97e61a6f9cb7------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*AhC8bz5brFCzRP82bomX8w@2x.jpeg</url>
            <title>Stories by 陳雁智 (Marat Y. C. Chen) on Medium</title>
            <link>https://medium.com/@yenzhit?source=rss-97e61a6f9cb7------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 23 May 2026 06:46:42 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@yenzhit/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[AWS Associate Certificate 攻略]]></title>
            <link>https://medium.com/manjeaneer/aws-associate-certificate-%E6%94%BB%E7%95%A5-5e0b2e2e35ee?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/5e0b2e2e35ee</guid>
            <category><![CDATA[cloud]]></category>
            <category><![CDATA[aws]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Sun, 18 Feb 2018 10:11:45 GMT</pubDate>
            <atom:updated>2018-02-18T10:11:45.919Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p>因為工作需求，入手三張 AWS Associate Level 證照，把準備過程跟心得整理一下，供需要的朋友參考</p><p><strong>TL;DR</strong></p><ul><li>不確定程度，先看 a cloud guru 的課程, Udemy 購買後寫信轉 account 到 a cloud guru 看討論版跟心得，LinuxAcademy 的 SAA 課程更詳細，預算夠可以搭配使用</li><li>有實務經驗，直接做 Whizlab diagnostic test，combo code 買下去不貴，掃題都有 80% PASS 就可以考</li><li>白皮書跟 FAQ 很營養，投資報酬率低，有實務經驗後拿來修練比較有</li><li>三張重疊的部分其實不少，SAA 考完再熟 DynamoDB 大概 DOA 也差不多，SOA 倒是很強調細節跟服務本身的行為</li></ul><p>要把考試講得很複雜我不太會，以下簡單介紹三張證照筆者還有印象的部分</p><h3>AWS Solution Architect Associate (SAA)</h3><p>對 AWS 服務不熟就從這張開始，必考 VPC, EC2, EBS, ELB, RDS S3, StorageGateWay, IAM, SQS, SNS，主要重點在認識大部分 AWS 的服務差異跟各主適合的使用情境，比如典型的 3 Tier Web Application 會在 VPC public subnets 內放置 ELB 並分流到 EC2 ，並且把 RDS instances 放在 private subnets 內</p><p>幾個重點服務至少要掌握的基本：</p><ul><li>VPC 實做要熟到能從零自建到一個有 Network ACL 跟 NAT Gateway/Instance 並且用 ELB 分流的程度，知道無法 ssh 進 instance 或 HTTP 不通可能是什麼原因，Network ACL 跟 Security Group 差異在那裡 (stateless 跟 stateful ) ，NAT Gateway 跟 private subnets 的關係，建 NAT instance 後 source designation check 要關才能順利運作，VPC 不充許 transitive peering，Direct connect 跟 VPN 差在那裡，如何互補</li><li>EC2 的 instance type 有那幾種，各自適合什麼樣的用途，租用的種類有那些 (on-demand, reserved, spot)，tendency 差別是什麼，placement group 有什麼好處，EBS-backed 跟 instance store-backed 的差異，EBS 種類，EBS snapshot 存在那裡，Auto-Scaling 如何運作</li><li>RDS 支援 MySQL, Aurora, PostgreSQL, MariaDB, Oracle, SQL Server 這六種，那些支援 Multi-AZ 跟 read replica ，這兩個 feature 在 replication 差異在那，RDS instance 的 security group 至少要有什麼設定</li><li>S3 Storage class 有那些，IAM Policy 跟 Bucket Policy 的差異跟各自的用途，什麼時候用 IA, RSS, 跟 Glacier，encryption 方式有那些，S3 bucket 的 URL 格式如何，S3 如何建置 static website，CORS 設定主要針對什麼情況，什麼時候需要用到 Multi-upload，單一 Object 最大容量，3 種 Storage Gateway 的差別為何跟對應的情境</li><li>IAM 的 root account, user, group, role, policy 各自是什麼，role 跟 STS 的關係，federation 是怎麼做的，deny, explicit allow 跟 explicit deny 在 policy 內如何評估 (evaluate)</li><li>SQS, SNS, SWF 差異為何跟各自對應的情境</li></ul><p>看完 a cloud guru 的 video 應該就有一半的基本認識，細節部分再參考 LInuxAcademy 的課程做得相對詳細，裡面的 Orion paper 把服務間的關係整理得很清楚，多掃幾次 Whizlab 的考題，整理自己不熟的服務跟差異點後再回顧，練習題順到 40 分鐘內可以掃完通過考試不是問題，想投機掃 Whizlab 硬考雖然可以，只是往後上手還是要再來一次，不如好好準備一次</p><p>另外 a cloud guru SAA 裡的 mega test 難度太難了，跟 SAA 實際考題差太多，可以挑戰但以 Whizlab 為主</p><h3>AWS Developer Associate (DOA)</h3><ul><li>有準備過 SAA 的話這張應該算最簡單，跟 SAA 重覆的部分很多，當時看到 a cloud guru 一堆 90%+ 以為怎麼大家都這麼強，考過後覺得這張最簡單，廣度沒有 SAA 寬，對幾個服務的基本細節，像是 API 或 CLI 需要深入認識，但不必全部都懂，課程練習題跟 whizlab 有提過的留下印象就好</li><li>DynamoDB， 必考，需要多花一點時間瞭解跟實作，像是 table, attribute, primary key, partition key, sort key, hash key, range key, global index, local index, 各自的關係跟差異，read 跟 write capacity 的計算一定考</li><li>CloudFormation 也是重點，stack template 包含那些，resource 一定要有，intrinsic function 跟 pseudo variable 有那幾個，跟 OpsWorks 還有 ElasticBeanStalk 的差別在那裡，stack 建立失敗的行為</li><li>S3 的 API call, CLI, policy 也是熱門考點，比如自建 encryption key 要帶那些 header 進 request, versioning 建立跟刪除的行為，API 回傳的 status code 可能是什麼原因</li><li>SQS 跟 SNS 的 API 跟相關實作，whizlab 考過檢討會了就足夠</li><li>各個服務的預設限制，像 DynamoDB table 上限，S3 bucket 上限，SQS message 會留多少這類，建議把 Whizlab 練習題考過的都整理起來</li></ul><h3>AWS Sysops Administrator (SOA)</h3><p>考題難度最難最細，主要範圍有 Auto-Scaling, ELB, CloudWatch, RDS, S3 bucket Policy, IAM policy 跟 Billing，以情境題為主，裡面蠻多題目在實務上也會碰到，主要方向是各個服務在不同情況下的行為</p><ul><li>CloudWatch 如何自定 metric，送 GET 跟 POST 的限制各別是什麼，那些 metrics 需要自定，相關的參數，CloudWatch 跟 Auto-scaling 如何搭配，那些服務有 detailed monitoring，ELB 跟 Auto-scaling 的 detailed monitoring 不另外收費，alarm 如何測試，billing alarm 如何設定</li><li>Auto-scaling 各項行為，minimum, desired, maximum capacity 的關係，如何在 CLI 更新設定，suspend 的時候如果 policy 條件被觸發會如何，redistribution 可能會發什麼情況，支援那些 notification 跟可以執行什麼動作，跟 ELB 的搭配，health check EC2 instance 跟 ELB 的差別</li><li>ELB sticky session, draining connection, health check 各自要解決什麼問題</li><li>RDS automatic backup 跟 manual backup 差別為何，在 console 可以看到那些 log，Disaster Recovery 要怎麼做，Multi-AZ 如何實行，有 update 時 Master 跟 Slave 如何被 update，跟 read replica 在 replication 的差異</li><li>ElastiCache 裡 memcache 跟 redis 各自有那些重點指標需要看，eviction 太高該如何解決</li><li>IAM policy 解讀，如何限制 IP 的 condition ，跟 identity provider 怎麼搭配</li></ul><p>原本以為 SAA 跟 DOA 準備過後這張也會很順，做完 whizlab diagnositc test 後發現一塌糊塗後才回來把考題針對的服務的細節跟行為重新整理跟實驗，過程中也弄清楚沒想過那些情況跟服務對應的行為</p><h3>總結</h3><p>筆者從開始準備到三張都拿到大概三個半月，前兩個月是待業狀態，投入的時間相對多，一開始 SAA 先把 a cloud guru 用 1.25X-1.5X 看完，不熟的部分再 1.5X-2X 複習，做了 mega test 後發現不太夠又趁 LinuxAcademy 特價入手，再把不熟的部分再 1.5X 或跳段看，接著掃 Whizlab 考題配 FAQ 看完，SAA 6 個 mockup test 平均大概 80% 就預約考試，DOA 跟 SOA 以 LinuxAcademy 跟 Whizlab 搭配，平圴也是 1.25X-1.75X 的速度看教學跟練實作，SAA 重覆的部分直接跳過，Whizlab 邊掃題邊檢討跟看 FAQ，以 Whizlab 答題率 80% 當做準備完成的門檻</p><p>以上整理得不盡完善但希望可以幫忙一樣準備證照的朋友們探索一點方向，總結一下個人對三張證照的解讀</p><ul><li>SAA: 各項 AWS 服務功能認識及不同情境下各個服務如何搭配</li><li>DOA: 對 CLI 跟 API 有基本認識</li><li>SOA: AWS 服務在不同情境下的行為，認識 security 及 disaster recovery 的基本做法</li></ul><p>現在回顧覺得證照本身價值並不高，準備過程學習 AWS 各個服務特性跟應用情境，提昇閱讀文件跟 spec 都順暢度帶來的收穫更有價值</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5e0b2e2e35ee" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/aws-associate-certificate-%E6%94%BB%E7%95%A5-5e0b2e2e35ee">AWS Associate Certificate 攻略</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[2017 CS50 problem set 總回顧 + GCP 上建置 Cloud9 及 Jupyter Notebook]]></title>
            <link>https://medium.com/manjeaneer/cs50-problem-set-%E7%B8%BD%E5%9B%9E%E9%A1%A7-gcp-%E4%B8%8A%E5%BB%BA%E7%BD%AE-cloud9-%E5%8F%8A-jupyter-notebook-d0b295eca12b?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/d0b295eca12b</guid>
            <category><![CDATA[maratchen]]></category>
            <category><![CDATA[cloud9]]></category>
            <category><![CDATA[cloud]]></category>
            <category><![CDATA[cs50]]></category>
            <category><![CDATA[jupyter-notebook]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Mon, 13 Nov 2017 21:01:03 GMT</pubDate>
            <atom:updated>2018-02-17T11:44:39.565Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p>系列最後一篇了，首先謝謝你願意進來閱讀，一系列回顧僅希望能夠在作業以外也輕輕推一把卡住的朋友們，無論 2017 或未來 2018 的 cs50 過程中有所助益，以下提供綱要讓第一次閱讀的朋友能快速找到感興趣的內容：</p><p>1. <a href="https://medium.com/manjeaneer/cs50-problem-set-2-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-459fe685af9e">pset 2 crack</a>, 使用 crypt 時會回傳相同指標可能導致邏輯正確但結果錯誤，不清楚指標或程式碼給出預期外結果的朋友可以參考</p><p>2. <a href="https://medium.com/manjeaneer/cs50-problem-set-2-3-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-5c57e91cce1f">pset 2+3 crack</a>, binary search, crack 使用遞迴方式的 pseudo code 及使用遞迴實作 binary search 未將回傳值做為參數時，即使搜尋成功後回到 base case 後最終結果可能是失敗</p><p>3. <a href="https://medium.com/manjeaneer/cs50-problem-set-4-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-8882b3c980de">pset 4 resize</a>, 作業細節澄清；使用二維陣列時需要將陣列大小一起帶入函式； recover 實作與 check50 驗證使用的檔案並不相同，需要考慮一般情況的寫法</p><p>4. <a href="https://medium.com/manjeaneer/cs50-problem-set-5-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-2c4cd00cbc3b">pset 5 speller</a> 跟著演算法、圖與程式碼追蹤 tries 加入單字時的圖解說明</p><p>5. <a href="https://medium.com/manjeaneer/cs50-problem-set-6-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-ffebacb5230f">pset 6 sentiment</a> Python 主程式中, Flask 跟 Jinja 間的關係，request 解讀與 jinja 中 safe 使用與否的結果</p><p>6. <a href="https://medium.com/manjeaneer/cs50-problem-set-7%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-e843b9606d4c">pset 7 cs50 finance</a> 使用 html 在 index 實作交易範例與 SQLAlchemy 使用注意要點</p><p>7. <a href="https://medium.com/manjeaneer/cs50-problem-set-8-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-c83e9e2b3388">pset 8 mashup</a> 聚焦 script.js 的分析、JavaScript 跟 C, python 在變數呼叫與範圍差異比較</p><p>心得己經夠多就不廢話，接下來分享 cs50.io 不給力時，可以參考以下步驟在 GCP 自置 Cloud9，跟 Python 寫作者很愛的 JupyterNotebook ，以下先以 macos 作範例，windows 之後補上</p><h3>tl;dr</h3><ol><li>啟用 Google Cloud Platform 帳號，建立一個 VM instance，並使用 Startup script 預先執行套件安裝</li><li>加入兩個防火牆規則分別給 Cloud9 及 Jupyter Notebook</li><li>安裝 Cloud9 並使用 openssl 產生 key 及 crt 後設定為 HTTPS 連線</li><li>安裝 Anaconda 並使用 openssl 再產生 pem 後設定為 HTTPS 連線</li></ol><h3>Cloud9</h3><p>1. 首先申請一個 Google 帳號，並到 Google Cloud Platform 申請免費試用，2017 年仍有 12 個月 300 USD 的額度，參考 <a href="https://jerrynest.io/gcp-server/">Jerry 的教學文</a> 申請</p><p>2. 開啟一個 Compute Engine Instance ，以 cs50 的需求，開最小的資源 f1-micro 除了安裝較久外，效能其實夠用，有高運算需求可以選擇更大的資源，區域(zone)建議選擇臺灣機房 (asia-east1) ，享受低延遲高頻寬</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*vdh9MxN108nslEWN1LjR4g.png" /><figcaption>Project Page of Google Cloud Platform</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WCDzhUpiqIQZWtC_HvhkMQ.png" /><figcaption>Navigate to create an instance</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/944/1*qZ8wD_brWykRsGsg0iyhAQ.png" /><figcaption>Zone: asia-east1-a (Taiwan), Instance type: f1-micro</figcaption></figure><p>這邊以 Debian (stretch) 為例，若選擇 Ubuntu 系列 (補充： Ubuntu 安裝較快) 或其它 Linux 發行版也沒問題，主要差別是之後套件管理可能是 apt-get 或 yum ，建議 http/http 防火牆可以先打開供之後連線使用</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/970/1*IOjVAa9UKZdSi_iOrk9jJQ.png" /><figcaption>Debian (apt-get) and add HTTP/HTTPS traffic</figcaption></figure><p>4. Compute Engine 可以讓 instance 啟動後自動執行套件安裝，點開 Management, disks, networks, SSH Key，將以下的 script 貼到 <strong>Management</strong> 裡 Automation 的 Startup script 內</p><pre>#!/bin/bash<br>apt-get update -y<br>apt-get -y install git <br>apt-get -y install build-essential <br>curl -sL <a href="https://deb.nodesource.com/setup_8.x">https://deb.nodesource.com/setup_8.x</a> | sudo -E bash -<br>apt-get -y install nodejs<br>apt-get -y install openssl<br>apt-get -y install wget</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/455/1*o0WjYS6GiqgNwOqUvuehvw.png" /><figcaption>Startup script</figcaption></figure><p>若發行版的套件管理工具為 yum，置換 apt-get 為 yum， apt-get -y install build-essential 置換為 yum groupinstall &#39;Development Tools&#39; 即可，主要目的為安裝 gcc 與 make 供 cloud9 安裝用</p><p>4. <strong>使用 ssh key </strong>的方式連到<strong> </strong>GCP compute engine，開啟 macos terminal (application)移到 .ssh 目錄 cd ~/.ssh或自建新目錄放 ssh key ，再來產生 ssh key ssh-keygen -t rsa ，順手輸入一組 passpharse 保護一下，執行 ssh-add key_name (這裡命名為 gcp_ide) 將 key 加入授權 (authentication agent)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*6-FiwPGQ7pd0o8ZgB3JSJw.png" /><figcaption>Generate a ssh key pair</figcaption></figure><p>再回到 Create an instance 介面點到 SSH Keys</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/916/1*L22dsi7H3jMUYmzy3Knivg.png" /><figcaption>Copy and paste the public key to SSH Keys</figcaption></figure><p>確認以下三點後，按下 Create 創造我們需要的 instance</p><ul><li>HTTP/HTTPS traffic 是否已勾選</li><li>SSH Keys 己貼上</li><li>Automation script 己貼上</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/325/1*gxbzG3wt1E5v2xNM-MYnCA.png" /><figcaption>Compute Engine Instance startup</figcaption></figure><p>instance 啟動等候 5–10 分鐘，差不多就完成套件更新，可以看到 CPU 飆高後降下來，再來以 ssh 連到 instance，先在 VM instance 頁面找到剛啟動 instance 的外部 ip (external IP)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/707/1*XFuc53g2QvS-Z1a7we5C7g.png" /><figcaption>external IP of a VM instance</figcaption></figure><p>再來 ssh xx.xx.xx.xx (external IP) 就可進到該 VM instnace 的 shell</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/549/1*ePSKrqPZg4n47t0OFFcm8w.png" /><figcaption>Commandl line of the launched VM instance</figcaption></figure><p>5. ssh 進入 shell 後再來參考<a href="https://www.aliangliang.top/setup-cloud9-with-own-host/">阿良良的日常筆記教學</a>將 cloud9 設置起來，安裝過程大概五分鐘</p><pre>git clone git://github.com/c9/core.git c9sdk<br>sh c9sdk/scripts/install-sdk.sh # This takes about 5 minutes</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/820/1*clrlt-SmEZRlzSRQJ_sqcQ.png" /><figcaption>cloud9 installation compelted</figcaption></figure><p>6. 完成後執行 node ~/c9sdk/server.js --listen 0.0.0.0 -p 9999 -a username:password listen 參數設為 0.0.0.0 允許所有 ip 連線，若有固定 ip 也可以只監聽來自己 ip 的連線， p 參數為監聽埠口，這裡以 9999 為例，-a 參數則是 username:password 的方式要求連線後鍵入登入帳密</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/735/1*rHh4ZF2B_Xg1IFQfMc8UTQ.png" /><figcaption>Cloud9 IDE server launched successfully</figcaption></figure><p>再來就按熟悉的方式打開瀏覽器 (safari, chrome, firefox, and etc.) 鍵入 http://instance_ip:9999/後連線</p><p>7. 噹噹～ 連不到，意料之中，在使用雲端服務常常會忘了開<strong>防火牆</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*i5eLIUqHETt-odAyFOIRkg.png" /><figcaption>Connection timed out in Firefox due to the blockage of firewalls</figcaption></figure><p>8. 若防火牆還沒打開，到 VPC — firewall rules將需要用到的 port 9999 開起來用，設定好 network tag 後再到 VM instance 內加入，需要使用 jupyter notebook 的朋友可以多建一個規則 (jupyternotebook, port9998) 稍後使用</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/503/1*zCAVrta7VL9uPpKG5XxoPw.png" /><figcaption>Create a fire wall rule for tcp 9999 to allow cloud9 connection</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/465/1*HtQJHlNFixIPVjFknBUSQQ.png" /><figcaption>Add the created tag in the launched VM instance</figcaption></figure><p>9. 設定好後再試一下，嘩啦～ 熟悉的 cloud9 IDE 就出現了</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/379/1*1qDxmE4klRE5mtlKWx_Szw.png" /><figcaption>IP:port (xx.xx.xx.xx:9999) in browser</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*d_INuoGJM5i8swQfrb1V6Q.png" /><figcaption>Cloud9 Standalone version</figcaption></figure><p>10. 不過這裡使用 HTTP 連線，基於安全顧慮，最好將它改成 <strong>HTTPS</strong> 連線，這裡參考 <a href="https://www.digitalocean.com/community/tutorials/openssl-essentials-working-with-ssl-certificates-private-keys-and-csrs">digitocean openssl</a> 產生自用的 SSL certificate (openssl 在 Startup script 裡己預先安裝)，cloud9 的設定一樣參考阿良良的教學，不熟悉 vim 用法可以參考 <a href="https://www.slideshare.net/c9s/vim-hacks">c9s 的 vim </a>投影片或 <a href="https://www.youtube.com/watch?v=0DD_H-xE6PQ">youtube影片</a></p><pre><br>## 產生自用的 key 跟 crt <br>openssl req -newkey rsa:2048 -nodes -keyout ~/.ssh/gcp-ide.key -x509 -days 365 -out ~/.ssh/gcp-ide.crt</pre><pre>## 使用 vim 編輯 `c9sdk/config/standalon.js` 內 `packagePath: “connect-architect/connect` 的物件<br>vim ~/c9sdk/configs/standalone.js</pre><pre>## 將 config.secure 以 // 註解掉，加入<br>    {<br>        key: require(&quot;fs&quot;).readFileSync(&#39;/path/to/gcp-ide.key&#39;),<br>        cert: require(&quot;fs&quot;).readFileSync(&#39;/path/to/gcp-ide.crt&#39;)<br>    }<br>## /path/to 置換為存放 key 及 crt 的位置，以 ls /path/to/key.pem 確認</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/983/1*pboSLapcdPi5xWKZkzJG0g.png" /><figcaption>Generate key for Cloud9 HTTPS connection</figcaption></figure><p>11. 加入設定後，按步驟 6 再啟動 cloud9 IDE 一次 (node ~/c9sdk/server.js --listen 0.0.0.0 -p 9999 -a username:password)，在瀏覽器網址列前的 http 置換為 https (https://xx.xx.xx.xx:9999/) 登入後即可，由於 openssl 產生的 crt 未經過外部驗證，沒有在瀏覽器信任名單之中，可能會跑出以下警示，將加入例外，再重新連線一次即可</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/878/1*z5VCXL68GFXPc6OV3XTv-A.png" /><figcaption>Warning due to self-generated certificates not trusted by the browser</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/519/1*aRmhPV3lwyaIiQnYp4dWjg.png" /><figcaption>Log in Cloud9</figcaption></figure><h3>Jupyter Notebook</h3><ol><li>按以下方式在 shell 下載 <a href="https://anaconda.org/anaconda/python">Anaconda</a> 執行安裝程式，成功跑起來看到很多 installing 噴起來後可以去刷個牙跟 FB，蠻多套件需要安裝，大概 5–10 分鐘左右完成</li></ol><pre>wget <a href="https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh">https://repo.continuum.io/archive/Anaconda3-5.0.1-Linux-x86_64.sh</a><br>bash Anaconda3-5.0.1-Linux-x86_64.sh -b -p $HOME/Anaconda3 &amp;&amp; export PATH=&quot;$HOME/Anaconda3/bin:$PATH&quot;</pre><p>2. 在 bashrc 中將 Anaconda 加入 PATH，方便每次登入都能直接使用</p><pre>echo &#39;export PATH=&quot;$HOME/Anaconda3/bin:$PATH&quot;&#39; &gt;&gt; ~/.bashrc</pre><p>4. 安裝 cloud9 時若還沒為 Jupyter Notebook 建立防火牆規則，一樣到 VPC -&gt; firewall rules 裡加一個規則， port 除了系統預設像是 22, 80, 443 等避免使用外，可以自定喜歡的數字，以 tcp:9998 為例，再將該 tag 附到已經建立的 VM instance (gcp-ide)</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/284/1*c7hq9qWxa6gI5wIcxNeMyA.png" /><figcaption>VPC — Firewall rules — CREATE FIREWALL RULES (tag: jupyternotebook)</figcaption></figure><p>5. 接著參考<a href="https://jupyter-notebook.readthedocs.io/en/stable/public_server.html">官方文件</a> 來建立 https 的連線</p><pre>## 先產生 jupyter notebook 的 config 檔 <br>jupyter-notebook --generate-config</pre><pre>## 使用在 cloud9 己經建立的 key 跟 crt 產生一組 pem <br>openssl x509 -in ~/.ssh/gcp-ide.crt -out ~/.ssh/gcp-ide.pem -outform PEM</pre><p>7. 建議設定 JupyterNotebook 的密碼以免被來路不明怪客誤用，更新 ~/.jupyter/jupyter_notebook_config.py 裡面的以下設定</p><pre># 產生一組 Jupyter Notebook 的登入密碼<br>jupyter notebook password</pre><pre># 一樣用 vim 來編輯<br>vim ~/.jupyter/jupyter_notebook_config.py</pre><pre># Set options for certfile, ip, password, and toggle off<br># browser auto-opening</pre><pre>c.NotebookApp.open_browser = False</pre><pre>c.NotebookApp.certfile = u&#39;/absolute/path/to/your/certificate/mycert.pem&#39;<br>c.NotebookApp.keyfile = u&#39;/absolute/path/to/your/certificate/mykey.key&#39;<br># Set ip to &#39;*&#39; to bind on all interfaces (ips) for the public server<br>c.NotebookApp.ip = &#39;*&#39;</pre><pre># It is a good idea to set a known, fixed port for server access<br>c.NotebookApp.port = 9998</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/650/1*x-knWJTWkh-8xiTQ_G3g1Q.png" /><figcaption>Configuration update in ~/.jupyter/jupyter_notebook_config.py</figcaption></figure><p>9. 再來一樣 https 連到接著 port 9998 就嘩啦～ （第一次還是會碰到警告頁面，一樣加入例外即可），再來迎接 jupiter notebook 的頁面，輸入之前建立的密碼後開始使用自己的 Jupyter Notebook</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/662/1*pACm9YQA2CE28YtcRkmOcA.png" /><figcaption>Jupyter Notebook login page</figcaption></figure><p>第一次建立中間可能會碰到一些錯誤，可以確認是否為以下問題：</p><ol><li>VPC — Firewalls rules 有沒有增加對應的 tcp port ，並將 network tag 加到了執行程式的 instance 上，使用的 tag 名稱是否正確 (希望 GCP 可以加上自動提示)</li><li>Startup script 是否於 instance 啟動前附上並執行完成 (檢查 CPU 使用率)</li><li>SSL key/crt/pem 檔的位置是否正確並使用絕對路徑 home/user/.ssh/your_key.key</li><li>shell 內的程式執行後，瀏覽器端網址前面改為 https 如 https://IP:port 的格式連線</li></ol><p>雖然 AWS 仍是主流，小眾市場還是值得一點關照，GCP 在 UI 設計上還不錯，所有的 VM instances 都在同一個頁面上這點很方便，但 tag 不能自動 prompt 這點有點不人性，不正確的 tag 也不提示這點也很麻煩，以上結束了 2017 cs50 回顧，任意建議都歡迎留言提出</p><p><strong>後記</strong></p><p>AWS 已於 2016 年購入 Cloud9, 並在 2017 年將 Cloud9 做為一個 AWS 服務推出，申請好 AWS 帳號後開啟 Cloud9 服務並按照指示設定完成，就可以有自己的 Cloud9 IDE 了，目前還沒有提供給所有 region 使用，離臺灣最近的是新加坡，實際使用起來其實速度可接受，另外也能設定閒置一定時間後自動將 host Cloud9 IDE 的機器關起來節省費用這點蠻貼心的</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d0b295eca12b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/cs50-problem-set-%E7%B8%BD%E5%9B%9E%E9%A1%A7-gcp-%E4%B8%8A%E5%BB%BA%E7%BD%AE-cloud9-%E5%8F%8A-jupyter-notebook-d0b295eca12b">2017 CS50 problem set 總回顧 + GCP 上建置 Cloud9 及 Jupyter Notebook</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CS50 problem set 8 作業回顧]]></title>
            <link>https://medium.com/manjeaneer/cs50-problem-set-8-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-c83e9e2b3388?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/c83e9e2b3388</guid>
            <category><![CDATA[web-programming]]></category>
            <category><![CDATA[maratchen]]></category>
            <category><![CDATA[cs50]]></category>
            <category><![CDATA[computer-science]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Sat, 11 Nov 2017 21:01:06 GMT</pubDate>
            <atom:updated>2017-11-11T21:01:34.638Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p>cs50 最後一個作業把 Python Flask, Database, JavaScript, jQuery, Ajax 都用上了，完成一個將地圖與新聞結合 (mashup) 的 web application，若對 pset 7 還有印象的話，第十週的課程內容特別提及了 JavaScript 讓瀏覽器不必刷新整個頁面而更新部分結果，也就是說 pset 7 作業實際只要一個 html 檔，其餘都可以用 JavaScript 讓使用者保持在同一頁面操作</p><p>pset8 要求如下：<br>1. 查詢必須提示城市、州、或郵遞區號<br>2. 附近區域的城市一併顯示<br>3. 按擊城市後顯示該城市相關新聞</p><p>一開始有點難想像如何完成這個複雜需求，幸虧 cs50 團隊己經將大致架構完成，也推薦了套件跟相關文件，重點仍然擺在完成 JavaScript — Flask — Database 彼此的互動，這次經驗三個較耗費時間的點：<br>1. JavaScript 中的 callback 跟 ajax 行為與語法熟悉度較低<br>2. Google API 參數較多，需要時間找到符合需要的參數<br>3. JavaScript 變數範圍及除錯與 C 或 Python 完全不同</p><p>第一點與第二相對好解決，反覆參數課堂範例、作業既有的程式碼或查資料就可以解決，在第三點上面吃了很大的虧，耗費蠻多時間以為是語法錯誤而實際上是因為對 JavaScript不夠了解造成一直用不適合的思維寫，稍後再做細部說明</p><p>實作時，可以多花一點時間反覆讀作業關於架構及各支程式的介紹，會增加不少對撰寫 web application 的熟悉度</p><p>讀了幾次程式碼跟作業介紹後，這次簡圖聚焦於 JavaScript ，也就是 client side 的程式，與 Python Flask，server side 的程式間的關係：</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FCF7l7SINwMsQMOplVkbxg.png" /><figcaption>Scheme for 2017 cs50 pset 8 (mashup)</figcaption></figure><p>很明顯看得出來 Javascript 的部分比例相對大，時常寫到函式間相互呼叫的情況就迷路，畫一次圖就對函式間的關係清楚多了，script.js 主要有四個部分<br>1. Google Map 初始化，地圖相關的設定<br>2. configure() 加上了google.maps.event.addListener(map,&quot;dragend&quot;,function())<br>跟 google.maps.event.addListener(map,&quot;zoom_changed&quot;,function()) 這兩個 listener 讓 JavascriptS 碰到拖拉 drag 或縮放 zoom時就呼叫 update() 將城市點 (marker) 加入地圖<br>3. 搜尋框內鍵入文字時，不斷將參數 (q=…) 送給 Flask.url_for(&#39;search&#39;) 查詢 database 內是否有類似記錄<br>4. addMark(place) 內也加上了一個 listener 監聽點擊事件，觸發時就呼叫 Flask.url_for(&#39;article&#39;) 並組合出相對應的 html 回傳到 client 端</p><p>寫 JavaScript 中，持續記得<strong>執行順序</strong>是<strong>從上而下</strong>，有時為了讓程式簡單會想抽離函式獨立寫出來，導致順序或變數可能要重新安排，是寫 anonymous function 反而不太會出錯，需要再深入了解 JavaScript 比較能善用它的設計</p><h3><strong>變數呼叫與變數範圍比較 C, Python, JavaScript</strong></h3><p>寫 javascript 時，沿用 c 或 python 對變數的操作吃了蠻多虧，檢討起來是對變數範圍差異不甚清楚，以下比較：</p><h4><strong>C 語言</strong></h4><p><strong>變數呼叫</strong><br> call by value 或 call by reference (指標)，若是 call by value, 使用該變數的函數會複製一份而不影響原值，在 wk4 介紹指標時己經強調了差異。</p><p><strong>變數範圍</strong><br> local 或 global，內層的區塊 (block) 可以取用外層的變數，例如:</p><pre>int a = 2;<br>    for (int i = 0 ; i &lt; 5 ; i++) <br>    {<br>        printf(“%i\t”, a*i); // output 0, 2, 4, 6, 8<br>    }<br>    <br>    //below causes error during compilation<br>    printf(“%i\n”,i);</pre><p>在外層宣告的 a 在迴圈內可以被呼叫，而嘗試使用內層宣告的 int i 若在外層區塊則會導致編繹失敗</p><h4>Python</h4><p><strong>變數呼叫</strong><br>所有變數在 Python 中都視為一個物件，在呼叫時其實是 call by object，引用 Jeff Knupp 的一篇 <a href="https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/">blog</a> 為例:</p><pre> <br>some_guy = ‘Fred’</pre><pre>first_names = []<br>first_names.append(some_guy)</pre><pre>another_list_of_names = first_names<br>another_list_of_names.append(‘George’)<br>some_guy = ‘Bill’</pre><pre>print (some_guy, first_names, another_list_of_names)<br></pre><p>在 Python 中，assignment (=) 的行為實際上是將一個名字 (name) 跟一個物件 (object) 綑 (bind) 在一起的操作，在上面的例子的第六行 another_list_of_names = first_names 創造了新的名字(name) another_list_of_names 並指向同一個物件，所以 appned(&#39;Geroge&#39;) 對該物件加上一個元素 (‘George’) 後 first_name 跟 another_list_of_names 會印出相同結果</p><p><strong>變數範圍</strong><br>改寫 C 的範例:</p><pre>a = 2</pre><pre>for i in range(0,5):<br>    print(a*i) # output 0, 2, 4, 6, 8</pre><pre>print(i) # output 4</pre><p>不同於 c 裡宣告的 i 在區塊外無法被呼叫，此時的 i (name) 己經指向在迴圈中產生的整數 4, 所以在迴圈外仍然可以呼叫</p><h4>JavaScript</h4><p><strong>呼叫方式與變數範圍</strong><br>call by sharing，傻了，字面上完全看不出來，更亂的是連 <a href="https://en.wikipedia.org/wiki/Evaluation_strategy#Call_by_sharing">Wikipedia</a> 上也寫 Python 也使用這個方式，好在 stack overflow 上有相當不錯的<a href="https://stackoverflow.com/a/3638034">討論串</a>可以參考，寫作業需要訣竅的話，一言以蔽之</p><blockquote>不要輕易嘗試修改函數範圍外的變數，除非知道自己在做什麼</blockquote><p>將同樣例子改寫成 JavaScript</p><pre>function test() {<br>    var a = 2;<br>    function test2(a) {<br>        for (var i = 0; i &lt; 5 ; i++)<br>        {<br>            console.log(a*i); // output 0,2,4,6,8<br>        }<br>        a = 4;<br>        console.log(a); // output 4<br>        console.log(i); / output 5<br>     }<br>     test2(a); // output 2<br>     console.log(a); // output 2<br>};<br>test();</pre><p>從執行結果可以看到：<br>1. test2 呼叫的 a 做的操作 a=4 在外層沒有影響，類似 call by value 的效果<br>2. 然而迴圈初始化的 i 又能在迴圈外層呼叫，與 c 的行為不同</p><p>同時撰寫 Flask 跟 JavaScript 時，在不熟悉兩者差別的情況下，蠻容易誤用 Python 變數呼叫及範圍的特性到 JavaScript 的程式碼，耗費相當多時間在除錯上</p><p>完成作業期間還卡在一個無奈的點，當時 cs50.io 有些不明問題導致 Degraded Performance，查看修改時常碰到 connection timeout 的狀況，慘到寫不下去就去 Google Cloud Platform 自己設置一個環境開發了，作法記錄在下次的回顧</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*T35bjIeuB6vp_UUDinkyug.png" /><figcaption>cs50.io Degraded Performance</figcaption></figure><p>完成最後一個作業的成就感還好，比對三個月前的自己，對記憶體、檔案格式、演算法、資料結構、網路有更完整的了解，收穫最多是在 Web Programming 部分，一直以來對 JavaScript 抱持著敬畏的心情，整個課程完成後，雖然還是怕怕的，但在閱讀相關材料時吸收的程度加強了不少，也確定自己沒有喜歡寫前端的部分，意外的收穫。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c83e9e2b3388" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/cs50-problem-set-8-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-c83e9e2b3388">CS50 problem set 8 作業回顧</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CS50 problem set 7作業回顧]]></title>
            <link>https://medium.com/manjeaneer/cs50-problem-set-7%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-e843b9606d4c?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/e843b9606d4c</guid>
            <category><![CDATA[web-programming]]></category>
            <category><![CDATA[cs50]]></category>
            <category><![CDATA[maratchen]]></category>
            <category><![CDATA[orm]]></category>
            <category><![CDATA[computer-science]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Wed, 08 Nov 2017 21:01:03 GMT</pubDate>
            <atom:updated>2017-11-08T21:01:03.033Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p>pset 6 認識 python 及 flask 後， pset7 加入 CSS 及資料庫 (database) 操作，完成類似股票交易平台的網址，基本要求有以下功能：</p><ol><li>註冊/登錄</li><li>根據股票代碼查詢股價並執行買賣</li><li>呈現交易記錄及目前股票組成</li></ol><p>完成作業基本要求倒不難，跟 pset 6 的難度相近，多了讀取或寫入 database ，將幾個主要函式、對應的 html、 及 database 的操作劃出來就可以感受到 資料庫幾乎是這類系統的中心，也突顯出 SQL injection 的危害程度</p><p>另外，CSS 的好處在這裡突顯，sytle.css 幾乎控制所有頁面元素的屬性，如顏色、線條粗細、間距等，需要修改風格時只需要更動單一檔案既可套用到所有頁面</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yU_D51OzhRdTmlbSvGJDkA.png" /><figcaption>Scheme of 2017 cs50 pset 7 “cs50 finance”</figcaption></figure><p>cs50 團隊避免過早提及 javaSciprt, 所以 cs50 finance 架構中，幾乎每個 route 都對應到 render 出一個 html ，也就是每個操作完成都需要重新讀取頁面，但也埋下一個小問題</p><p>除了基本要求外，還需要額外完成以下其中一項：</p><ol><li>更改密碼</li><li>充許增加現金 (預設登錄為 $10,000)</li><li>能在股票組成頁面 (index) 執行買賣，不需要鍵入股票代碼</li></ol><p>很好，看起來第三個最難，選它，於是實作就卡在主要兩個部分：</p><ol><li>為了達成第三點，如何將代入目前頁面資訊做為 request 內容一起帶入 request 到 server 端 ( 不使用 javaScript )</li><li>課程提供 cs50 方便操作 database，實務上可能還是用 ORM 或其它方式，花了一點時間將 database 相關的操作都用 SQLAlchemy 重新寫過</li></ol><p>關於第一點，筆者的作法是新增股數輸入框，買與賣兩個按鈕，將它們都包入同一個 form，及新增一條 trade route 處理，大致上如以下 pseudo code:</p><pre>&lt;form action=&quot;{{ url_for(&#39;<strong>trade</strong>&#39;) }}&quot; method=&quot;post&quot;&gt;<br>                        ...(skip)...</pre><pre>    &lt;td&gt;{{ <strong>jinja_variable_for_symbol</strong> }}&lt;<strong>input</strong> type=&quot;<strong>hidden</strong>&quot; name=&quot;<strong>symbol</strong>&quot; value=&quot;{{ jinja_variable_for_symbol }}&quot; /&gt;&lt;/td&gt;<br>    // an hidden put field whose value is replaced by jinja variable<br>    <br>    &lt;td&gt;&lt;input name=&quot;shares&quot; type=&quot;number&quot;/&gt;&lt;/td&gt;<br>    // an input field for fill in the shares to be sold or bought<br>    <br>    &lt;td&gt;&lt;span&gt;&lt;button type=&quot;submit&quot; name=&quot;<strong>operation</strong>&quot; value=&quot;<strong>buy</strong>&quot;&gt;Buy&lt;/button&gt;&lt;/span&gt;&lt;/td&gt;<br>    // operation as the parameter name whose value is <strong>buy</strong><br>    <br>    &lt;td&gt;&lt;span&gt;&lt;button type=&quot;submit&quot; name=&quot;<strong>operation</strong>&quot; value=&quot;<strong>sell</strong>&quot;&gt;Sell&lt;/button&gt;&lt;/span&gt;&lt;/td&gt;<br>    // operation as the parameter name whose value is <strong>sell</strong></pre><pre>                        ...(skip)...<br>&lt;/form&gt;</pre><p>為了代入既有的股票代碼 (symbol) 到表格 (form) 遞交 (submit) 的 POST request，這次使用的方式是將股票代碼欄位也設定成 input 、值為 symbol 、但屬性為 hidden，在處理的 trade route 裡再透過 request.form.get 取出各個值 (symbol, share, operation(buy/sell)) 做交易處理完成</p><p><strong>SQLAlchemy 心得</strong></p><p>目前歸納下來不會寫壞掉的幾個方式：</p><ol><li>db = SQLALchemy(app) 先做，將 db 這個物件建出來，再做 db.create_all() 或 db.session.query()操作，或是設計新的類別 (class)</li><li>各個表格依 schema 都需要一個對應的 class，表格 (table)名稱用 table_name 設定，要注意的是 SQLAlchemy 要求至少一個 <strong>primary key</strong> ，沒有設定的話無論是建立表格或查詢 (query) 都會失敗</li></ol><pre>class User(db.Model):<br>    __tablename__ = &#39;users&#39; <br>    // tablename for queries in database<br>    <br>    id = db.Column(db.Integer, primary_key=True, autoincrement=True)  <br>    // key value of the table<br>   <br>    username = db.Column(db.String(80), unique=True, nullable=False)<br>    hash = db.Column(db.String(120), unique=True, nullable=False)<br>    cash = db.Column(db.Float, nullable=False, default=10000)</pre><pre>def __repr__(self):<br>        return &#39;&lt;User %r&gt;&#39; % self.username</pre><pre>new_User = User(username=&quot;abc&quot;, hash=pwd_context.hash(&quot;password&quot;))<br>db.session.add(new_User)<br>db.session.commit()</pre><p>2. db.session.add(new_User) 還不會把資料寫進資料庫，只是先註冊 (register) 這個操作，要到 db.session.commit() 成功完成才能算是操作成功，若一直沒有看到資料被寫入或更新，最好先檢查是否有做 commit</p><p>3. User.query() 可以執行查詢，這個方式限制的方法還蠻多，大部分還是使用 db.session.query(User) 執行，在加上 filter_by 或 order_by 的操作通常不會出錯</p><p>4. asc 或 desc 的操作需要先以 from sqlalchemy.sql import func 方式引入 func: db.session.query(User.name).orderby(User.id.desc())</p><p>5. count 的操作: db.session.query(User.username).count()</p><p>6. limit 的操作: db.session.query(User.username).limit(&quot;number&quot;)</p><p>將 SQL 相關的部分重寫來熟悉 ORM 是個還不錯的練習，畢竟實務上手刻 SQL statement 出錯機會還蠻高，加上檢查的成本，不太經濟，況且基本防止 SQL injection 的保護也會做好，但實務上遇到調校 query 的時候還是得仰賴專業 DBA 的協助，必要時還是得手刻，不過機率相對小就是</p><p>接下來就是最後一個 web programming 的作業，加上 javascript, jQuery, 跟 ajax，讓學員對熟悉前後端的基本結構，在 javaScript 上踩了不少雷，下期一起補充一下 C, Python, javascript 對變數範圍及引用的基本差異</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=e843b9606d4c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/cs50-problem-set-7%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-e843b9606d4c">CS50 problem set 7作業回顧</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CS50 problem set 6 作業回顧]]></title>
            <link>https://medium.com/manjeaneer/cs50-problem-set-6-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-ffebacb5230f?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/ffebacb5230f</guid>
            <category><![CDATA[cs50]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[c]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[maratchen]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Sun, 05 Nov 2017 21:01:00 GMT</pubDate>
            <atom:updated>2017-11-05T21:01:00.605Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p>2017 cs50 下半場專注於 web programming ，從透過 telnet 對網站送出 GET/POST 的 request ，解讀 response 重點欄位，http 協定，到 python flask 微框架 (micro-framework)，後續將 css, javascript, jQuery, ajax 建構上去</p><p>和之前作業一樣，pset 6–8 已經設計好程式架構並將未完成的重點功能留給學員，過程中探索各個模組如何互動與物件方法使用，pset 6 要求使用 python 重新實作 pset 1–2 的部分程式 (crack, credit, mario) 進而熟悉 python 語法，另一個 sentiments 裡，先讀懂在 python flask 的框架下程式的全貌，大部分著重完成主程式引用的 analyzer 模組中的物件方法。</p><p>Python 在語法上相對於 c 是平易近人許多，完前第一部分後對 python 語法熟悉後，應該感覺作業難度相對容易（註： 2016 cs50 的 <a href="http://cdn.cs50.net/2015/fall/psets/6/pset6/pset6.html">pset6</a> 是用 c 完成實作 http server )，較花時間的部分可能是了解 flask 本身的使用方法與 jinja 的互動，還有整體結構。</p><p>程式本身相對單純，這次回顧著重在互動的細節，也就是當 flask run 執行後, 使用的過程在 server side 如何處理送進來的 request，首先，預設的根目錄 “/” 在 application.py 被定義了以下的函式</p><pre><a href="http://twitter.com/app">@app</a>.route(&quot;/&quot;)<br>def index():<br>    return render_template(&quot;index.html&quot;) // 回傳 jinja 處後的 index.html </pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pkycsfZsEwWE37_RTnPuww.png" /></figure><p>將瀏覽器的開發者工具打開 network 頁面，確實也看到送出了一個 GET / 的 request，server 即回傳相對應的 html，如以下的簡圖所示，收到了 route 到 “/” 路徑，執行 index() 然後將 layout.html 套入 index.html 後回傳</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Ov8Rmhz37YZd_2uxF5XNgA.png" /><figcaption>Scheme of sentiment ( 2017 cs50 pset 6 )</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SS50-WnlAQPFxFJ9NUVKhQ.png" /><figcaption>search_name for cs50</figcaption></figure><p>接著將 cs50 鍵入搜尋列後送出，可以觀察到這次 search 後面加上了 ?screen_name=cs50 做為參數，相對應的程式前半段則檢查了是否有 screen_name:</p><pre><a href="http://twitter.com/app">@app</a>.route(&quot;/search&quot;)<br>def search():</pre><pre># validate screen_name<br>    screen_name = <strong>request.args.get(&quot;screen_name&quot;, &quot;&quot;)</strong><br>    <strong>if not screen_name</strong>:<br>        return redirect(url_for(&quot;index&quot;))</pre><p>若無則回到 index</p><p>回到簡圖中，送出 request 到接收到 response 的過程呼叫了 search 執行：</p><ol><li>讀入 positive-words.txt 及 negative-words.txt</li><li>用 1. 所建立兩個物件 positives 及 negatives 建立 analyzer 物件</li><li>呼叫 helper.py 的 get_user_timeline 代入 screen_name 取得推特文</li><li>逐行讀取 3. 取出的 tweets 並送入 analyzer 的 analyze_tweet 做分析 (each line in tweets)</li><li>呼叫 helper.py 的 chart ，並代入情緒分析後的推文數目 (counts((positive, negative, neutral)) 產出圖表</li><li>代入 chart 及 screen_name 將 search.html 產生回覆 (response)</li></ol><p>以上將這次作業的兩個流程及相對應的物件做一個大概介紹，可能會在內文注意到<strong>物件</strong>持續出現，不同於 c 語言，python 設計本身是物件導向 (Object-oriented) 語言，幾乎所有東西都是物件， a = 1 裡的 a 也是一個物件，而可以單純到只有一個變數或複雜到一個包含其它物件的結構像是 analyzer。</p><p>除此之外，python 物件會通常伴隨相對應的操作方法，像是作業內 analyzer是用正負情緒單字產生的物件，而它提供了一個 analyze_tweets 方法來分析一段文字中正負情緒並傳出總和分數。</p><p>Python 成為當下流行的語言原因之一就是開發者們開源各式各樣的模組 (module) 甚至框架 (framework) 讓其它開發者能夠專注實踐自己的想法上，很多時候需要某個功能只要 google 或到 github 上查詢關鍵字就能下載並導入 (import) 進自己的程式使用。</p><p><strong>關於資訊安全</strong></p><p>最後有一點值得注意的是在 template 裡的 search.html 使用到 jinja 裡的 <strong>safe</strong></p><pre>...(skip)...</pre><pre>{% block body %}<br>{{ chart | <strong>safe</strong> }} // with safe<br>&lt;h1&gt; Chart without safe &lt;/h1&gt;<br>{{ chart }} // without safe<br>{% endblock %}</pre><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EpJbKaF5vlV4N-oRkfRVTQ.png" /><figcaption>Comparison: <strong>top</strong> {{ chart | safe }} <strong>bottom </strong>{{ chart }}</figcaption></figure><p>根據文件 <a href="http://jinja.pocoo.org/docs/2.9/templates/">safe in jinja</a> 裡的說明，jinja 預設會跳脫 (escape) 所有字元，也就是任何 html 的語法標籤都會被跳脫掉，左圖下半部示範了沒有加上 safe 時，反而顯示一段 html ，進而檢視原始碼會看到所有語法相關的符號像是 &quot; &amp; &gt; 等被用 &amp;#34 &amp;amp &amp;lt被替換掉，瀏覽器就把這些字元當一般字元顯示而非 html 處理</p><p>原因是 jinja 為了防範 <a href="https://www.owasp.org/index.php/DOM_based_XSS_Prevention_Cheat_Sheet">XSS</a> (Cross-site Scripting) DOM 類型攻擊，避免攻擊者注射 (inject) 惡意程式碼，更全面的介紹可以參考 <a href="https://www.slideshare.net/yftzeng/2013-0413-jstwsecurityforfrontendengineeringprequel">ant 對資安防範</a>的簡報。</p><p><strong>題外 — 關於簡單架構圖</strong></p><p>就以往工作經驗的體會，系統由於過於複雜及牽連較廣的技術層面，提高了團隊成員對整體架構了解的門檻，導致各個成員只關注負責的部分，在溝通上淪為各踢皮球，解決問題時不找出根因 (root cause)，往後耗費更多時間在修正不徹底的解決方案，過程反覆後造就出一個恐怖平衡的怪物，若能有一張成員都能有共識的架構圖，相信對團隊溝通與解決問題會有相當幫忙。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ffebacb5230f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/cs50-problem-set-6-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-ffebacb5230f">CS50 problem set 6 作業回顧</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CS50 problem set 5 作業回顧]]></title>
            <link>https://medium.com/manjeaneer/cs50-problem-set-5-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-2c4cd00cbc3b?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/2c4cd00cbc3b</guid>
            <category><![CDATA[maratchen]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[c]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[cs50]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Fri, 03 Nov 2017 06:43:41 GMT</pubDate>
            <atom:updated>2017-11-03T06:58:51.155Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p>第五週 cs50 介紹了幾種基本資料結構，像是 linked list, stack, queue, hash table, 跟 tries，想當然作業範圍就包括實作其中一個資料結構<br>經歷過前四週 C 語言的 problem set ，個人覺得 2017 cs50 課程最難的作業是 pset 5 ， 用 c 寫出一支拼字檢查程式，讀取一個字典文字檔與使用其中的單字比對文章中單字是否不在字典內，實作過程中自己卡在兩個點比較久：</p><ol><li>設計資料結構該有的元素跟對應的操作: 例如， tries 裡每一個 node 至少有一個 node 指標的陣列跟變數儲存是否為最後一個節點，在增加或刪除節點時需要考慮什麼條件</li><li>程式有 memory leak: 剛開始不依賴外部資料挑戰用遞迴實作的結果雖然正確，valgrind 不帶參數跑也沒有症狀，check50 反而抓到memory，用了 valgrind \- v (-verbose) 也給出一樣的錯誤診斷，但在遞迴的過程還沒找到好的方式解決，最後參考 <a href="http://www.techiedelight.com/trie-implementation-insert-search-delete/">tech delight</a> 上的方式用迴圈的方式重頭寫過一次</li></ol><p>對 tries 比較陌生，就透過實作認識它，以下以作業為例介紹程式的一部分來介紹在 tries 中加入一個單字 cat 的執行過程：</p><p>主要目標是檢查拼字，但在 spec 要求考慮 ‘ 可能是單字一部分，於是設計的 tries 中的 node 結構包含：<br>1. 大小為 27 個 node 指標 (node*) 陣列 (a-z+’) : 記錄下一個 node 的位置<br>2. 一個 bool 變數 (Last_char) : 記錄是否這個 node 為結尾</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/700/1*IisWPjpcZO2FrFCGKz5g3A.png" /><figcaption>Tries node 結構</figcaption></figure><p><strong>A tries node</strong></p><pre>struct dic_tries<br>{<br> struct dic_tries* next_node[27]; // node* pointer array<br> bool last_char; // bool variable<br>};</pre><p>當一個 cat 單字被加入時，有以下幾個步驟：<br>1. 先建立一個 tracker 去追蹤資料結構，初始化時指向ries 的入口點<br>2. 讀第一個字元 c ，檢查從進入點 (Dictionary Entry) 開始查指標陣列 (next_node) 中指向 c 是否為 NULL <br>3. 由於是第一個加入的單字，所有指標陣列的值都是 NULL，於是執行初始化一個 node 的過程，若值不為 NULL 則前進到該單字的 node<br>4. 將新產生的 node 的位址 (0x0001) 指派進 Dictionary Entry 裡指標陣列指向 c 的元素<br>5. 將 1. 中建立的 node 移到新建立的 node (0x0001)，繼續讀下一個字元，回到步驟 2. 繼續<br>6. 當讀到字串結尾 ‘\0’ 時，就跳出追磫資料結構的迴圈，將當下 node 的 Last_char 設為 True 表示這個 node 是某個單字的結尾，完成添加該單字的過程</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/1*G5JulEgqhYf7dnfRnN12SQ.png" /><figcaption>Dictionary Entry 中指標陣列 C 的元素指到新增的 node 並將 node tracker 移過去</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/1*UywywR-3IYLx2q6h-Coxfg.png" /><figcaption>在 c 字元node 的指標陣列中，將代表 a 的元素指到新增的 node 並移動 Node tracker 過去</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/880/1*8d_hGeV4pxe3A6UHuJBoSg.png" /><figcaption>加入最後一個字完 t 後，將該 node 的 Last_char 設為 true，代表 cat 單字的結尾</figcaption></figure><p><strong>Add a word into an tries</strong></p><pre> <br>bool add_word(dic_node* entry_node, char* word)<br>{<br>    bool add_success = false ;<br>    dic_node* node = entry_node; // initailize a node tracker variable<br>    if ( node != NULL &amp;&amp; word != NULL)<br>    {<br>        while(*word != ‘\0’) //exit loop when the string reaches the end<br>        {<br>            int index = encode_char(word);<br>            if ( node-&gt;next_node[index] == NULL ) // add a new node if the pointer is NULL<br>            {<br>                node-&gt;next_node[index] = add_dic_node();<br>            }<br>            node = node-&gt;next_node[index]; // move the node tracker            to the newly added or next node<br>            word++; // ready for the next character<br>        }<br>        node-&gt;last_char = true;<br>        return add_success = true;<br>    }<br>    return add_success;<br>}</pre><p>以上三張圖描繪了在一個 tries 加入一個單字 cat 的過程跟其中 node 間的關聯； 做完後有感受到設計作業的用心，由於學員的程度不一致，cs50 團隊一開始就準備好基本架構，函數原型的宣告，讓學員直接專注在實作資料結構本身與操作方法。<br>在這個過程中，實際體會到開發協作方式之一就是預先定義好主架構與溝通界面，團隊成員實作與測試符合要求的程式，快速在短時間內開發其反覆迭代測試。<br>做 debug 時也常用到 debugger 設定 breakpoint 檢查當下變數的值或 node 的位置，對追蹤與解決邏輯錯誤幫助很大，不必再一行一行去插入 printf 印出來找。<br>完成這週後，有兩週的課堂不需要寫作業，一週介紹基本網路觀念，另一週介紹機器學習，再來就是 web programming，pset6, 使用 python 跟 flask 分析 twitter 內容與結果呈現。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=2c4cd00cbc3b" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/cs50-problem-set-5-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-2c4cd00cbc3b">CS50 problem set 5 作業回顧</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CS50 problem set 4 作業回顧]]></title>
            <link>https://medium.com/manjeaneer/cs50-problem-set-4-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-8882b3c980de?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/8882b3c980de</guid>
            <category><![CDATA[c]]></category>
            <category><![CDATA[maratchen]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[cs50]]></category>
            <category><![CDATA[computer-science]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Mon, 23 Oct 2017 11:48:59 GMT</pubDate>
            <atom:updated>2017-10-23T23:00:43.430Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p><strong>resize</strong><br>當時寫 pset4 的 resize 時，看完作業需求其實沒有很清楚要寫出什麼樣的 resize，找了一個很厲害的 reference <a href="http://www.davdata.nl/math/bmresize.html">bmpresize</a>, 就開始抱頭下去燒一整週結果沒什麼成果，再去 reddit 上的課程討論區發現以下這一段</p><iframe src="https://cdn.embedly.com/widgets/media.html?type=text%2Fhtml&amp;key=a19fcc184b9711e1b4764040d3dc5c07&amp;schema=reddit&amp;url=https%3A//www.reddit.com/r/cs50/comments/6sj8n2/pset4_resize_what_does_it_mean_to_resize_a/&amp;image=https%3A//i.embed.ly/1/image%3Furl%3Dhttps%253A%252F%252Fwww.redditstatic.com%252Ficon.png%26key%3Da19fcc184b9711e1b4764040d3dc5c07" width="600" height="400" frameborder="0" scrolling="no"><a href="https://medium.com/media/2543dea6656f82a7c469d5f5274900a7/href">https://medium.com/media/2543dea6656f82a7c469d5f5274900a7/href</a></iframe><blockquote>Think of it as you go pixel by pixel. If your ratio is .5, you’ll skip the first pixel, write the second. If the ratio is .25, you skip the first, second, third, and write the fourth.</blockquote><blockquote>Try to think of an algorithm to represent this. But at the same time, if your ratio is .4, you’ll skip the first pixel, the second pixel, but write the third. Then you’ll skip the fourth pixel, but write the fifth (4/10 = 2/5 for every 5 pixels in the out file you’ll write 2 pixels) So you’ll need to think of a way to do this.</blockquote><p>英文很多，用圖來表示比較快</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YaXWuCN7HQ7zk9nRxMDwdg.png" /><figcaption>(左) 原圖 (中) 我以為的 resize (75%) (右) 作業預期的 resize (75%)</figcaption></figure><p>…原來只要按比例撿 pixel 就可以了，不用考慮 resize 後的細節變化，卡關途中撿了一個陣列在 C 裡需要注意的點： 陣列在 C 裡是以<strong>指標方式做開頭 </strong>(其實 Lecture 有強調)，在呼叫時最好把大小一起帶入，比如以下兩種方式</p><pre>void function(int m, n int array[m][n])</pre><p>或建一個結構帶陣列大小，然後用指標取值</p><pre>struct two_dimensional_array{<br>    int m;<br>    int n;<br>    array[m][n]<br>}<br>two_dimensional_array *ptr = NULL<br>ptr = malloc(sizeof(two_dimensional_array))<br>void function(struct* ptr, array[(ptr)-&gt;m][(ptr)-&gt;n]</pre><p>另外，特別要注意的是，<strong>建立變數</strong>時一定要<strong>初始化</strong> (給零值或 NULL)<strong>，</strong>在 debug 的時候可以少花很多時間，程式可能是對的，但沒有初始化變數而導致結果錯誤的時候，通常會先以為寫錯然後繞很遠的路</p><p><strong>recover</strong></p><p>寫 cs50 作業真的不能取巧，在這一題就遇到作業給的 card.raw 跟 check50 檢查用的檔不一樣，在寫的時候把 50 張檔案當成迴圈結尾，即使成功還原，在 check50 時會失敗在最後一個檔 (15.jpg)</p><p>一個方式是以當讀檔結束當跳出迴圈的條件，pseudo code:</p><pre>While(1)<br>{<br>    if (fread(讀card.raw進一個512 byte (FAT基本block) array))<br>    {<br>        //失敗就跳出loop<br>    }<br>    jf (array[0,1,2] = 0xffd8ff ) //找到jpg header<br>    {<br>        //開新檔，建pointer準備寫入<br>    }<br>    if (output_file_ptr) // 開檔跟pointer建起來<br>    {<br>        if(fwrite(..output_file) != 1)<br>        {<br>            //寫入失敗，關掉 output_file<br>        }<br>    }<br>}</pre><p>寫 pset4 過程中卡蠻久，但解開不懂的問題時還蠻有收穫，像是實際去算一張 resize 後的圖大小應該變多少，為何要加padding (memory alignment)，拿 bmp 的 header 檔跟 xxd 倒出來的實際資料相互驗證，重覆練習使用 fopen, fseek, fclose 這些檔案與指標操作，從中體會實際程式在讀取資料的大致過程，畢竟，寫作業如果只為了拿一個虛虛的 100% 而浪費了中間的過程就太可惜了。</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8882b3c980de" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/cs50-problem-set-4-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-8882b3c980de">CS50 problem set 4 作業回顧</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CS50 problem set 2+3 作業回顧]]></title>
            <link>https://medium.com/manjeaneer/cs50-problem-set-2-3-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-5c57e91cce1f?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/5c57e91cce1f</guid>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[cs50]]></category>
            <category><![CDATA[maratchen]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[c]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Fri, 20 Oct 2017 12:05:02 GMT</pubDate>
            <atom:updated>2017-11-05T05:21:53.494Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p>迴圈 (loop) 與遞回 (recursion)</p><p>pset2 作業 crack 本質上就是實作暴力解長度最多為 4 個字元的密碼，直覺上最快是直寫四個迴圈不斷產生a, b … z, aa, ab … 的字串做完 hash 後用 strcmp 比對 crypt 出的 hash 值，peusdo code：</p><pre>for (int i = &#39;A&#39; ; i &lt;= &#39;z&#39; ; i++ )<br>    {<br>        if (isalpha(i))  // 不懂資料結構前的寫法，畢竟中間不是英文的字不多<br>        比對 crypt(i, salt=&quot;50&quot;) 出來的值是否跟目標相同<br>        for (int j= &#39;A&#39; ; i &lt;= &#39;z&#39; ; i++ )<br>        {<br>             ... 開始不動大腦重覆刻迴圈 ...<br>        }<br>    }</pre><p>雖然直覺但應該有更簡潔的寫法，於是在 python 上實作一版遞迴</p><pre>def alphabet_generator(plain_text, input_hash):<br>    先做一個可能字元的 list<br>    if 字串長度到最大值 (4個字元) 就回傳作完 Null (<strong>Base Case</strong>)<br>    elif 字串長度為零，base case<br>        把 list 每一個字元出來作 crypt 跟比較<br>    else 開始進遞回<br>        從 list 裡再撈一個字元跟進來的 plain_text 加在一起做 crypt 比較<br>        alphabet_generator(plain_text+j) 進遞迴繼續找 (<strong>Recursive Case</strong>)</pre><p>目前對寫出一個有限遞迴的心得大概兩點：</p><ol><li>Base case 要確保遞迴可以被結束</li><li>進遞迴的參數要想清楚，可以產生預想的組合</li></ol><p>pset3 其中一題是實作二分搜尋，在還不熟悉遞回寫法時，可能會寫出以下無效的方式</p><pre>Bool Binary_search(int value, int values[], int start, int end);<br>Binary_search(…) {<br>…<br>Bool Found = Binary_search(int value, int values[], int start, int end); // recursion case<br>…<br>Return True; // found<br>…<br>Return False; // not found<br>}</pre><p>遞迴函式沒有把回傳值放進去往下遞迴，在途中搜尋到也不會回值搜㝷成功，修改成下面的方式將回傳值代入即可：</p><pre>Bool Binary_search(int value, int values[], int start, int end, bool found);</pre><p>這樣一但搜尋成功就會一路將 True值傳上去。</p><p>下次寫卡很慘的 pset4 ，誤解作業要求卡五天最後發現其實不用作到太複雜</p><p><strong>Reference</strong></p><p>Recursive function: <a href="https://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/recursion2.html">https://www.cs.umd.edu/class/fall2002/cmsc214/Tutorial/recursion2.html</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=5c57e91cce1f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/cs50-problem-set-2-3-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-5c57e91cce1f">CS50 problem set 2+3 作業回顧</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[CS50 problem set 2 作業回顧]]></title>
            <link>https://medium.com/manjeaneer/cs50-problem-set-2-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-459fe685af9e?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/459fe685af9e</guid>
            <category><![CDATA[cs50]]></category>
            <category><![CDATA[computer-science]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[c]]></category>
            <category><![CDATA[maratchen]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Tue, 17 Oct 2017 12:27:00 GMT</pubDate>
            <atom:updated>2017-10-17T12:27:00.576Z</atom:updated>
            <cc:license>https://creativecommons.org/publicdomain/mark/1.0/</cc:license>
            <content:encoded><![CDATA[<p>起初看到 ptt 有人徵 cs50 讀書會起了好奇心，又逛到 <a href="http://huli.logdown.com/posts/687027-cs50-programming-course-like-ocean">Huli 的介紹文</a>，就進 edX 報名了這堂課，大學時自學過兩週的 Matlab 跟一點 C++加上資料結構，對整體的認識實在不夠完整，趁這次再一次認識一下電腦科學 (Computer Science) 這門學問建立起連結零碎知識片段。</p><p>課程內容在 google 上己經有查不完的內容了，這次選擇寫2017的作業 (problem sets) 卡住的一些雷</p><p><strong>pset 2 crypt</strong></p><p>作業已經提示要使用 crypt 這個函式，但此時還沒有指標觀念，一開始想把 crypt 產生出 hashed 值這段用函式包起來傳出 CS50 函式庫定義的 string，如以下的 pseudo code:</p><pre>for key in [a..ZZZZ]<br>    hashed_to_be_tested = generated_hashed(key)</pre><pre>string generated_hashed(key):<br>    return crypt(key, salt)</pre><p>若整支程式只用<strong>一次</strong> crypt 倒沒問題，若在其它區塊再次用了 crypt 產生值，則可能產生額外行為而不符合原先設想的邏輯，一直到除錯時才發現變數值不合預期而注意變數的指標沒變才發現 crypt 的行為: <strong>crypt 回傳的指標 (char*) 都是固定的</strong>，</p><p>對指標稍熟後再次驗證確實沒錯，如以下程式</p><pre>#define _XOPEN_SOURCE<br>#include &lt;unistd.h&gt;<br>#include &lt;stdio.h&gt;<br>#include &lt;string.h&gt;<br>#include &lt;stdlib.h&gt;</pre><pre>int main(void)<br>{<br>    // initilize two pointers with the returned values from crypt<br>    char* hashed_1 = crypt(&quot;abc&quot;, &quot;50&quot;);<br>    char* hashed_2 = crypt(&quot;def&quot;, &quot;50&quot;);<br>    // initailize two new pointers with memory allocation<br>    char* hashed_3 = NULL;<br>    hashed_3 = malloc(sizeof(char)*14);<br>    strcpy(hashed_3,crypt(&quot;abc&quot;, &quot;50&quot;));<br>    char* hashed_4 = NULL;<br>    hashed_4 = malloc(sizeof(char)*14);<br>    strcpy(hashed_4,crypt(&quot;def&quot;, &quot;50&quot;));<br>    <br>    printf(&quot;1st key: %p, value: %s\n&quot;, hashed_1, hashed_1);<br>    printf(&quot;2nd key: %p, value: %s\n&quot;, hashed_2, hashed_2);<br>    printf(&quot;3rd key: %p, value: %s\n&quot;, hashed_3, hashed_3);<br>    printf(&quot;4th key: %p, value: %s\n&quot;, hashed_4, hashed_4);<br>    <br>}</pre><pre>// clang -ggdb3 -O0 -std=c11 -Wall -Werror -Wshadow crypt.c -lcrypt -lm -o crypt</pre><p>結果：第一跟第二個變數被賦給了相同的指標值而印出時產生一樣的結果，而第三跟第四個變數在先配置記憶體後得到的指標值剛好差了 0x20: 也就是32bytes，這裡發現有趣的東西，研究一下再來分享</p><pre>1st key: 0x7fbc8dcc21c0, value: 501slZ9s3gdss<br>2nd key: 0x7fbc8dcc21c0, value: 501slZ9s3gdss<br>3rd key: 0x22a7420, value: 50PaJ4.RO0YUo<br>4th key: 0x22a7440, value: 501slZ9s3gdss</pre><p>下回寫遞迴實作二分搜尋時自己犯的新手錯誤，過程中不斷體會 ptt 程設版常看到的簽名檔，實在沒錯</p><p>“遞迴只應天上有，凡人該當用迴圈”</p><p>“To iterate is human, to recurse, divine”</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=459fe685af9e" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/cs50-problem-set-2-%E4%BD%9C%E6%A5%AD%E5%9B%9E%E9%A1%A7-459fe685af9e">CS50 problem set 2 作業回顧</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Top in Linux]]></title>
            <link>https://medium.com/manjeaneer/top-in-linux-1076bf5ffbf5?source=rss-97e61a6f9cb7------2</link>
            <guid isPermaLink="false">https://medium.com/p/1076bf5ffbf5</guid>
            <category><![CDATA[linux]]></category>
            <category><![CDATA[administration]]></category>
            <category><![CDATA[monitoring]]></category>
            <category><![CDATA[operating-systems]]></category>
            <category><![CDATA[maratchen]]></category>
            <dc:creator><![CDATA[陳雁智 (Marat Y. C. Chen)]]></dc:creator>
            <pubDate>Tue, 15 Aug 2017 09:00:57 GMT</pubDate>
            <atom:updated>2017-08-15T09:02:46.007Z</atom:updated>
            <cc:license>https://creativecommons.org/licenses/by-nc-sa/4.0/</cc:license>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*UEr7LfeF5SmZMYUwYuh6_w.png" /><figcaption>Top in Linux</figcaption></figure><p>Linux 的 Top 通常是效能檢查第一步，google也有不少使用教學，對於各項參數的細節探討則相對少，本篇以 Centos 7.x 版 top 前五行為例做整理</p><h4>第一行 up, users, load average</h4><ol><li>top — 07:21:34 up 1:00 前面是目前時間， up 後面則是自最近開機以來的時間</li><li>1 user 目前總共有幾個 user 連入，即使是同一個使用者建立複數連線也會加入計算</li><li>load average: 0.00, 0.01, 0.05 過去1, 5, 及15分鐘的平均系統負荷，系統負荷把三種 process 列入計算：CPU 執行中、等待 CPU 資源、及不可中斷但在睡眠狀態（等待磁碟操作），但處於 idle 的 process 則不列入</li></ol><h4>第二行 Tasks</h4><ol><li>total 後面四種狀態的 task (預設)或 thread (大寫 H 切換) 的總和；進入記憶體待執行的程式都算一個 task ，通常可以將 task 數當成已經存在於記憶體內的 process 數；而一個 process 可能有一個或複數個 threads (multi-thread) ，取決於程式內容；Linux 內對 process 有特定的資料結構 (task_struct) ，細節可參考 <a href="http://www.tldp.org/LDP/tlk/kernel/processes.html">http://www.tldp.org/LDP/tlk/kernel/processes.html</a></li><li>running 正在執行或等待執行的 process 數</li><li>sleeping 等於事件 (event) 或資源 (resource) 的 process 數； 若一個 process 需要存取大量的磁碟資料，則它很有可能進入 sleeping 的狀態</li><li>stopped 收到終止指令的 process 數，在 Linux 中包含 SIGSTOP, SIGTSTP, SIGTTIN, 和 SIGTTOU 等</li><li>zombie 當一個子程序 (child process) 己經結束執行進入 exit 的狀態，但母程序 (parent process) 尚未執行 wait 的系統指令，導致這個子程序仍然存在於 process table 上而無法釋放資源，使用 kill 也無法終止該子程序；需要注意的是 orphan 跟 zombie 並不相同， orphan 子程序通常是母程序己結束但該子程序仍在執行中</li></ol><h4>第三行 %Cpu(s)</h4><p>top 預設的統計時間為 1.5 秒 Delay time，這一行統計了下列類型程序佔 CPU 的時間比例</p><ol><li>0.0us 執行沒有被設定 nice 參數的使用者程序 (user process)</li><li>0.0sy 執行核心 (kernel) 程序</li><li>0.0ni 執行被設定 nice 參數的使用者程序；在 Linux 中，nice 值的範圍從 -20 到 19, 越低的值表示該程序有更高的優先執行順序</li><li>100.0id 執行 kernel idle handler</li><li>0.0wa 等待 I/O 完成，此時 CPU 可以視為不工作的狀態</li><li>0.0hi 處理硬體中斷 (hardware interrupts)，比如硬碟需要讀取一塊磁區或網路需要處理剛抵達的封包，這類中斷會直接中斷 CPU 執行而觸發相對應的 kernel 程序</li><li>0.0si 處理軟體中斷 (software interrupts)，類似硬體中斷，不同之處在於它只能從執行中的程序發出中斷需求 (interrupt request, IRQ)，這類中斷不會直接中斷CPU，而是由 kernel 排程處理</li><li>0.0st 被 hypervisor 偷走的 CPU 時間； 在虛擬機 (VM) 中，hypervisor 可能會因為特定原因取走該虛擬機的 CPU ，這段時間就被列入 st 內</li></ol><h4>第四行 KiB Mem (KiB: KiloByte, 1024 Byte)</h4><ol><li>602832 total 總共可用的實際記憶體 (Physical memory) 大小，因為 Linux kernel會佔用一部分，值會比實際硬體略小一些，等於 free + used + buff/cache</li><li>236892 free 尚未使用</li><li>135532 used 應用程序正在使用</li><li>230408 buff/cache Linux kernel 2.4後buffer跟cache的功能基本上相同，做為暫存資料／檔案用，cache為page cache在實際記憶體裡的一部分，page cache另一部分為swap cache，mem cache很容易就到數十GB以加速 Linux 對 I/O 的操作；buffer則是存放不在page cache內的非檔案資料，通常大小在幾十MB內</li></ol><h4>第五行 Swap (KiB: KiloByte, 1024 Byte)</h4><p>swap實際存放於磁碟 (disk) 上，Linux將一部分的磁區做為實際記憶體不夠用時的暫存</p><ol><li>0 total 功能同 mem total</li><li>0 free 功能同 mem free</li><li>0 used 功能同 mem use</li><li>345228 avail Mem 可用的 swap memory 大小</li></ol><h4>第六行 PID USER PR NI VIRT RES SHR S %CPU %MEM Time+ COMMMAND</h4><ol><li>PID task (process) 的獨特序號，常搭配 kill 強制停止該 task</li><li>USER 執行該 task 的使用者</li><li>PR task 的優先權(priority)，有些 task 以 rt (real time) 表示該 task 需要被即時執行，不過在 Linux kernel 2.6 後，rt 的 task 充許被中斷 (preemptible) 的，也就是這類 task 不總是被排最高的優先次序</li><li>NI nice 值，越低者表示該 task 有較高的優先順序，充許範圍為 -20 至 19, 預設的一般 task 通常是零，可用 nice -n -20 ... 來指派某程式的 nice 值</li><li>VIRT 使用的虛擬記憶體 (virtual memory) 大小，在 Linux 中的記憶體管理是以分頁 (page, 大小為4KB) 為單位，為讓更有效運用實體記憶體 (physical memory) ，在虛擬記憶體中會有一張 page table 記載虛擬記憶體與實體記憶體之間地址 (address) 的對應關係</li><li>RES 使用的實體記憶體大小 (resident size)，記載的值會反映到%MEM裡去，將該欄位總合起來可能大於總記憶量，因為單一 page 可能會被多個 process 使用而重複計算</li><li>SHR 共享記憶體大小 (sharable memory)，task 在執行時可能會將某個函式庫 (library) 讀取進來，但實際不一定要用到整個函式庫，這時讀取進的函式庫大小會被記算進 VIRT 及 SHR，而實際使用的函式 (function) 大小則計入 RES</li><li>S task 狀態，可能會有以下幾種<br> D = uninterruptible sleep （不可被中斷的等待）<br> R = running (執行中）<br> S = sleeping (等待中)<br> T = stopped by job control signal (被控制中斷)<br> t = stopped by debugger during trace (被debugger中斷)<br> Z = zombie (子程序己結束但母程序尚未執 wait）</li><li>%CPU task 使用的 CPU 時間比例，若是 multi-process 的 task 有可能超過 100%，也就是使用超過一個 core</li><li>%MEM task 使用的記憶體大小，parent process (主程序) 的大小為其子程序的總和</li><li>TIME+ 己執行的時間</li><li>COMMAND 實際執行指令</li></ol><p>以上大概介紹top中預設的欄位，在top執行時可鍵入F 看到所有的欄位並選擇加入及指定排序的欄位，除此之後，top 也充許使用者對 task 做操作，例如指定 nice 值等。</p><h3>後記</h3><p>寫作過程中對各個名詞做搜尋及閱讀時不斷會發現 Linux 更底層的設計，一層一層下去應該都能寫成論文了，像是記憶體管理，CPU 的資源調度都是很大的題目，不太能在這個短篇做進一步介紹，以下列出寫作時的參考資料供有興趣的讀者做進一步深入</p><ul><li>hardware/software interrupts 討論串： <a href="https://unix.stackexchange.com/questions/17998/what-are-software-and-hardware-interrupts-and-how-are-they-processed">https://unix.stackexchange.com/questions/17998/what-are-software-and-hardware-interrupts-and-how-are-they-processed</a></li><li>steal 討論串: <a href="https://serverfault.com/questions/230495/what-does-st-mean-in-top">https://serverfault.com/questions/230495/what-does-st-mean-in-top</a></li><li>memory 討論串： <a href="https://serverfault.com/questions/85470/meaning-of-the-buffers-cache-line-in-the-output-of-free">https://serverfault.com/questions/85470/meaning-of-the-buffers-cache-line-in-the-output-of-free</a></li><li>buffer / cache 討論串： <a href="https://www.quora.com/What-is-the-difference-between-Buffers-and-Cached-columns-in-proc-meminfo-output">https://www.quora.com/What-is-the-difference-between-Buffers-and-Cached-columns-in-proc-meminfo-output</a></li><li>virtual memory 介紹： <a href="https://www.logicmonitor.com/blog/what-is-virtual-memory-anyway/">https://www.logicmonitor.com/blog/what-is-virtual-memory-anyway/</a></li><li>page and swapping 介紹： <a href="http://www.linux-tutorial.info/modules.php?name=MContent&amp;obj=page&amp;pageid=89">http://www.linux-tutorial.info/modules.php?name=MContent&amp;obj=page&amp;pageid=89</a></li><li>page fault/swap-in(out) 介紹： <a href="http://blog.scoutapp.com/articles/2015/04/10/understanding-page-faults-and-memory-swap-in-outs-when-should-you-worry">http://blog.scoutapp.com/articles/2015/04/10/understanding-page-faults-and-memory-swap-in-outs-when-should-you-worry</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1076bf5ffbf5" width="1" height="1" alt=""><hr><p><a href="https://medium.com/manjeaneer/top-in-linux-1076bf5ffbf5">Top in Linux</a> was originally published in <a href="https://medium.com/manjeaneer">Manjeaneer</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>