工作時做了什麼,自己最清楚

沒有留言:

以下記事,除了要記錄「做了什麼」還要寫下「為什麼這麼做」

基礎建設

wiki

最後版本由技術長架設
  • 原本用gitit,但是後來改用wikipedia,現在還是覺得用gitit好。(markdown+git)
  • 資訊透明、文件共有共編
  • 文件補齊與版本一致

git

  • 沒有版本控制,沒辦法工作
  • 脫離「人工merge地獄」的利器

git server

最後版本由技術長架設
  • 用gitWeb看code,可視化git的內容
  • 用SSH進行溝通,無須每次都打帳號密碼(visual studio只吃http)
  • 程式碼開放給公司內部所有被授權的開發者共同開發
  • 使用gitolite做ssh key權限管理

bug tracker

  • 因為bug都零散的用word檔在管理
  • 開過的bug不知道又開了一次
  • 標題的命名規則依UI選單操作進入順序,定位bug的位置

cppunit

  • 防止相同的bug再發生
  • 可定義「完成工作」的條件(尚未實現)

jenkins

  • 防止「不立即提供(編譯)最新版,是我的怠惰」的月經問題
  • 讓工程師(我自己)把時間花在coding上面 。
  • 順便進行自動化單元測試、程式碼品質度量,用某個標準量化軟體品質

程式碼品質(技術篇)

清除client的warning

  • 新人時期拿到code第一件事就是做這件事,避免無法預料的bug產生。

更改server架構

  • 後來被抓去實作新的Server - RMA, 提出全新架構(架構戰)
  • 縮小Server維護範圍,減少寫一支Msg的時間
  • 小修改無須很多code一起重編,減少測試一支Msg的時間
  • 用C++的方式解決先前的Server的問題。
    • 因if-else無法128個而使用的寫法 -> 可讀性很低
    • 三層架構區分資料庫動作還是Xml動作 -> coding太多不必要的code
    • 一支Msg一個function的設計 -> 無法區分/重複利用 Msg邏輯和資料邏輯
    • 太多通用於各個資料表的獨立function -> 要背下來才可以活用
    • 還在難以debug的MARCO -> 該使用C++的技術來取代
    • 濫用的template -> complier生成的code漲大,編譯速度超級慢
    • 太多code在用一個檔案,小修改的編譯內容太多,編譯速度慢
    • 專案檔的設置並不乾淨,不必加入KgsLib檔案

程式碼品質(管理篇)

提案、執行重構程式碼

  • 產品程式碼品質太低,邏輯前後矛盾
  • 程式定義刪除行為,沒有辦法檢查資料庫資料刪除是否乾淨。
  • 區隔Msg邏輯、資料表邏輯、畫面邏輯
  • 二次開發的架構也因此產生
  • 可完全拿掉MARCO
  • 可大量重複使用資料表的邏輯

提出「分頁Message」的觀念

  • 提高效能,效能與資料量不相依的存取方式。
  • 無需依賴WCF,可以更依賴KgsLlib

提案自動化功能測試

QA工程師撰寫
  • 快速進行「功能完整性測試」,實作後只測試整個產品的主要功能
  • 之前有人想過,但是沒有認真面對(評估)。仔細思考評估後發現是可行的。

落實前後端分工

提案、撰寫通用Query Message

  • 分工client與Server,畫面邏輯不在server做。

寫 web版 message發射器

  • 原單機版測試器,無法模擬client的送出Message情況(沒有經過IIS)
  • 遠端主機直接瀏覽器就可以進行測試(無須登入桌面)

寫 web版 xml比較器

  • 實作Xml的比較邏輯,快速的比較Xml,無須人工比對
  • 收到Message之後直接進入比較

管理建議

提案導入看板方法

  • 解決「進度到哪了」的月經問題,避免為了這問題打斷工作拉去開會。
  • 失敗原因
    • 管理者對「最小切割」的觀念錯誤,為了方便管理。
    • 分工對人不對事。
    • 面對插單時,還是要問「進度到哪了」。
    • 派工依舊整包丟
    • 管理者結果論
    • 判定此方法不適用現況(不適合於此管理者)。

用bug tracker當看板方法

  • 最小工作切割
    • Server一支Message為單位
    • Client一個畫面為單位(注意畫面之間溝通與發送Message初始化資料的時機)
  • 解決評估是否方便插單、工作進度詢問、互相Cover工作進度的問題

導入Daily Scrum

即時的反映正在「開發中+多人協作+需溝通協調」的問題
  • 每天實作上的小問題
  • 相似工作的相同問題
  • 承接前後工作的交接問題
  • 2017/01/16 開始,有繼續了,中間有一小段時間各忙不同的案子,但是卻繼續Daily Scrum

進行每週五下午的技術分享會議

  • 對於架構與技術交流
  • 進行過七場,從2016-09-30 ~ 2016-12-02(約兩個月)
  • 包含內部技術、工具運用、先備知識…的交流
  • 部門內的人全部都有分過一輪
  • 因後來大家各自忙不同的案子而淡出生活~XD

果醬的生命力

沒有留言:
其實,我也沒有很follow果醬女孩的訊息。
想說就來聽聽他的故事,覺得他對品牌的經營上,一定有一些值得我學習的吧?
剛進活動場地,看見攝影組、投影片、留言板、簽名本、拿一包紀念品。
用心的讓人感覺得出來,而且因為提早半小時到,所以看見了主辦的企劃伙伴們,一起為活動順利而禱告。

以下只是片面或零碎的活動筆記。
我參加的是這一場

活動開始

果醬女孩一開始先介紹了他一開始的樣子,從大一開始的故事。
也許,很多人覺得他很勇敢,很酷,但是真正在他的內心是害怕又非做不可。

我是誰

進入第一個主題
女孩說「知道我是誰,才可以知道何去何從」
從擺攤到百貨,從田裡工作到手上的水果,到台上的分享。

「過程除了精彩的掌聲,大部份是狼狽的樣子。」
「認識自己,定義自己的成功比追求成功還重要。」

不需要硬要做不適合自己的人,要懂得取捨,要堅持快樂!

有人常常說果醬女孩很多故事,女孩認為「只要有頭有尾,就是故事」

有一本書叫《藍,或另一種藍》中,有提到類似的觀念
「沒有對的選擇,只有把選擇做對,因為所有的選擇,都是對的」




如果忙碌的生活,讓你除了吃飯、睡覺,就找不到其它的了?
就應該要停下來,要重新尋找

不知道自己為什麼要成為專業,又何必成為專業?
所以在求學路上,做了取捨。

我們很常看自己沒有擁有的,讓自己陷入焦慮。

成功是什麼?
「就算是世界末日,也不害怕的時候。」

把握當下,好好的做喜歡的事

當喜歡的事給你的感受>不喜歡的事給你的感受時

真正重要的事就要用力的去捍衛,若品牌已經無法保留當初的初衷...就必須要重新調整方向。

果醬女孩,就是用心的把一件事做好

讓不同裁種手法的一點點的差別,也可以讓每一個懂的人都品嚐得出來。
「不需要厲害才開始,而是開始了才厲害」

為什麼要做果醬

「『簡單』才是最有力量的」

一開始

就是因為好吃,後來上分享,再來就試著賣賣看。
結果還真的有人要買!!

開始了有演講的邀請,不知道那個叫做創業
買便宜的水果,後來想起來這麼便宜真令人可怕

後來的擺攤、教課

當時,只要有曝光的機會就去。
「就算要放棄,也要有理由放棄!」

教別人做果醬的課程

讓別人也會,並且讓學生喜悅,跟我說「老師!我們做的果醬有人買耶」
讓人有力量、也讓自己開心

《18歲的成年禮:窮學生的環島豐富之旅》
你有沒有想過「這個世界是為你而創造的?我們彼此的世界並不是相同的,是為了每一個人而特別創造的」

商業化

賺錢並且要了解賺錢的目的,了解金錢流向影響了誰。
不應該不了解民生疾苦的賺著錢。




女孩的老師曾說過一句令我印象深刻的話
「要成為的一個好的廚師,就記住食材是怎麼來的,也要記住它的味道。」

最想要做的事

農夫不是只有採收才工作,而是一年四季都要工作,「果醬女孩」真正想帶給人們的是農夫們的辛勞、想讓更多的人了解農夫在做的事以及在乎的事。


什麼是影響力?

好好的對待每一個人,就是對每一個人展現影響力。
展現生命的韌性,勇敢是可以練習的,當我們可以接受意外時,就是勇敢的時刻。




犯錯、得罪別人,在人生的旅程中,都是正常的,重要的是在這過程中犯錯就要改,得罪別人就要更認識彼此(自己與別人),慢慢的更認識自己,才可以讓自己和世界和平相處。




還是有許許多多的廚師不管季節而上菜,一年無論什麼時候,餐盤上就是要放蕃茄?這不是很怪嗎?




「用我們擅長的方式改變、撼動世界」
「只要有心,就苦得起」
沒有任何一份工作,是不辛苦的。




當人沒有什麼可以失去時,就會有勇氣了
真正的創業家,應該是不管要創什麼業都是可以成功創業的。就像是真正的業務員,不管是要買鉛筆還是飛機,只要他想賣,就一定賣得出去,無論景氣如何,這都不是問題。


「果醬女孩,帶給我什麼?讓我什麼都能做」


最後要離開時

已經離開門口了。
但是女孩跑了出來並且拿了一瓶門口的玻璃瓶送給我們。

問我們說「你們今天有聽到想聽見的嗎?」
我說「有哇!面對未知的未來的來臨,無須害怕」
還問我們「是什麼樣的未來呢?」

小聊了一下,這一下下真的很厲害。
我想每一個人都很樂於和這樣的女孩當朋友吧?^^

技術文章搬家

沒有留言:
未來。
關於技術相關的文章,通通搬到新的blog https://darkblack02.blogspot.tw/
新的技術文章,會繼續在那裡出現,這裡就不再寫新的技術文章了。

關於生活的事,還是在這裡做紀錄,舊有的技術文章,依舊留在這。

野狼~使用十萬伏特~不!是「三相發電」

2 則留言:
今天車子又要進行大改造了。
這次要改造的是三相發電。

為什麼要改三相呢?
因為大燈愈來愈不亮了呀,隨著線路老化,這小小的電阻就足以讓大燈變暗了!QQ

野狼發電機,據我爬文所知,分成三種。
老狼開始~05野狼傳奇(含當時的R125): s07(4極, 磁缸較小...約82mm)
06年狼R150開始到噴狼之前: B38(8極, 約88.5mm)
噴狼之後: B8B(三相, 約93mm)
(電噴的電盤有定位凸點,要硬搞修掉也不是不行,只是平衡多少會跑掉)

參考文章

[電系] [野狼125][電系]堅持原廠,傳狼發電量增加!! 狼R發電組直上


而且我的發電機屬於s07,算是老狼+野狼傳奇派的。
狼R150的B38發電機,剛好沒有裝在我這一批車上。(還好沒有,因為會隨著B3U一起出現吧?)


而且隨著科技的發展,噴射車愈來愈多,所以料也就開始好找了起來。
除了之外,改裝文章也跟著好找了起來呢!^^

參考文章

[充電] 狼系發電終極方案
[充電] 『已解決+更新』野狼R 改三相,電盤內仁直徑一問!?
很巧的這兩篇都提到了B38的磁盤(真正的名字如下)



然後就開始偷懶了!XD
懶得自己做功課、備料(出社會了,不吃這一行就開始懶了?)
所以這次找了賣家代工。

直接說結果

換掉了...

整流器(單相全波->三相)
三相選用的是光陽的31600-LBA7-900(應該是它沒錯),雖然LBD5的名氣較大,因為它適用的全地型車是500cc的(我猜用料也比較高級或貴吧?),這顆用於光陽全地型車(參考自拍賣)
  • 2006-10 MXU 50/SR
  • 2005-10 MXU 150
  • 2003-04 MXU 250
  • 2005-10 MXU 300/R
  • 2005-10 Maxxer 300


磁缸(s07->B38)
這是原廠換原廠呀!一樣是三陽的野狼機種在使用的貨唷。

線圈(4極->12極)
(12極的照片,是借網拍的照片,我想也看不出來差別了!XDD)
重點就是要換它啦!三相的線圈。網路上的改裝,還有換上更厲害18極的。但是我很知足,12級的就夠我再戰十年了


CDI 的點火訊號產生器 (加裝一組就變成 直流 CDI)
加的那一個東西,我在網路上找到了說明

簡單的說就是
Input: (AC/DC) 6~12v, 200~450mA
Output: (DC) 80v~220v

安裝
黑線-電門
紅黑線-CDI
綠線-GND(目前接電瓶的負極)


改好發動實測

整流器輸出的有14v...電瓶有充電,在開大燈時,依然保持充電。(太棒啦!)
發動只會叫一次,會順利發動;過去是叫很多次,也是順利發動。


總共改完: 3400
你也許會說花這麼多錢?自己對岸的料買一買就好了。
沒錯!但是,我買的,是專業的服務,我相信賣家。
雖然有些補強的動作我要自己處理,但是大多數的問題,他都幫我解決了。
哪個料可以裝上去?要找哪個整流器?CDI要怎麼處理?接線的話,哪條對哪條呢?
這些要做功課,又要花很多時間了。

我得把時間花在程式語言上呀!><
所以,除了說我多花錢之外,其它的歡迎討論!^^
(之前有找到另一個賣家,開價8000)


回家再補強


上文說要補強,但是沒貼,是因為...還沒補!XD
(以下所有的照片,都是施工結束時,收尾前拍的)

施工過程,其實除了環境很熱(車庫溫室)之外,其它還好。
先來看一下施工環境照片。



直接講結果

(太熱了,加速施工...XD)

補焊上次賣家施工時,剪開的電源。

拆下賣家施工時貼的電火布(絕緣膠帶)

重新焊上纏線處


固定整流器


這裡就沒拍到了,用文字說明。

因為整流器變大了,所以原本野狼固定整流器的支架也就只能鎖一邊。但是,螺緊時,其實整流器還是會晃動,它和螺絲之間有橡膠墊,所以不會卡緊。
另一邊必須固定,否則整流器會一直打到車架。

我就拿了束帶,穿過支架與整流,目的只是不讓它一直打車架。

固定點火訊號產生器

這裡就沒拍到了,用文字說明。

(暫時叫這名稱,也許人家是供應訊號、高壓電的...)

這一顆訊號產生器,賣家施工完畢,是放在空濾進氣口的空間中,並無任何固定手法。
由於整流器的固定方式,多出了一顆螺絲,所以我就將那個螺絲拿來鎖(幸運呀!孔可以放進去),那要鎖在哪呢?

接近座墊與油箱,油箱蓋住的地方有一個孔。剛好可以鎖在那。
不過鎖不好螺絲就掉下去下面密密麻麻的線路之中了。(要小心)




以上,就是改裝三相的過程了。
騎一陣子看看吧!

燈有變亮了啦!^^

有意思的「原則」與「態度」

沒有留言:
原則,是創造生活的要素。
堅持原則,是一種生活態度,也就是說「堅持」是一種「態度」,反過來說「不堅持」並不是一種「原則」,而是一種「態度」。
ex:
「懶得做家事」,並不是一種生活原則,而是一種生活態度。
「要做家事」是一種生活原則,是不是持續的進行,是生活態度。
看了都累了。XD

買到買不到的絕版橡皮墊,座墊回春

沒有留言:
自從知道打擋桿的橡皮是可以單買的之後,就打算買到野狼所有可以更換的橡皮
拆了座墊,才發現座墊下的圓形橡皮早就離我而去了,還好方形的橡皮還在,原本想說如果買得到,就給它買個很多顆,野狼坐墊下的孔全部塞滿。

若野狼座墊的壽命,我想就是以這些橡皮為主了吧?

買料


從上週五就開始訂的一組橡皮墊。
星期一來拿→忘了訂,明天來拿。
星期二來拿→老闆拿出來,卻是油箱相關的橡皮。

一問之下才知道,座墊的橡皮,都只隨座墊出貨,不單賣的。

不死心的我,跟老闆說「我可以去找找替代料嗎?看有沒有類似的來改?」
老闆竟然說「去吧!」

(真是開心)

整個橡皮櫃都被我翻遍了的情況之下,找到了兩個。(還是在不同抽屜中找到的)
這兩個似乎有點年紀,而且抽屜的車種名稱是早就已絕版的車種了。(印象中是萬山之類的)

找到的料如照片。

因為也不知道是不是長這樣(我的座墊下的已變形。所以看不出原本的樣子了)
抱持著「應該可以上吧?」的心理買回家了。

一顆15元

施工

買回去之後,裝上去超不順利。
不知道是老化彈性不好,卡不進去?還是買的不合野狼坐墊孔?
然後,開始試著用敲的,不行。用轉的,不順,也怕扭斷就QQ了。
不過,半擠半轉的情況之下(有用眼睛確定轉的時候不會扭到頭,它會跟著轉)進去了。(暢快)

最後施工好如下圖。
座墊卡油箱的那一部份,除了如圖的那裡已用內胎取代(因為也買不到了)之外,兩邊的金屬,也用內胎圈起來(像橡皮筋這樣轉兩圈)確保座墊不會再和油箱打架。

裝上去後

OK的部份

雖然坐墊和車架已保持一直線。

不OK的部份


  1. 油箱和座墊的密合度有約一公分的帶狀空隙,我想這應該是長期沒有橡膠的情況之下,座墊海棉早就變形了。
    (應該再重包就好)
  2. 坐墊卡上油箱的情況,其實也不是這麼理想,我也不知道為什麼沒有卡合的感覺。

重新買料

把文章貼到小老婆之後
  1. 網友說「很想做柱狀膠,就去車『優力膠』」
  2. 拍賣找到「引擎吊架襯套墊」
才發現,原來我買到的東西,應該是引擎吊架襯套墊的橡膠版。
就跑去凱汰場,跟老闆問野狼傳奇的座墊。
當老闆把座墊轉過來,我才覺得情況不單純,我這十幾年來的野狼,也缺太多坐墊橡膠了吧?
所以,就用「買一個座墊」的錢買了下面的所有橡膠。
  • 三塊方形的
  • 兩塊圓形的

量測尺寸

拿到之後,就開始做一些量測。方便之後可能可以找替代料用的。(之後可能也換座墊了)
  • 方形的尺寸(長×寬×高):5.23×2×2.25 (cm)
  • 圓形的尺寸(直徑×厚度):2.4×1 (cm)








重新裝上去

就把昨天裝的重新拆下來(拆下兩秒,裝上好久),重新把正確的料件裝上去。
再補拍一張接合處都裝上內胎的樣子。

終於完工

最後來個完工照!
這十幾年來的野狼,終於把座墊恢復了。

不知道是不是那一次座墊重包,施工造成的橡膠遺失。

原本要換,變成改的右後方向燈

沒有留言:
先說現況。
我騎04年狼R,右後方向燈斷掉。
有一顆左後(或右前)方向燈的備料。
也就是現況如下
  1. 現役的斷成只能在那晃的,
  2. 躺在備料箱裡很久了,斷的可以接回去,而且是亮的,所以一直沒丟。
原本想說颱風天,沒事,來把方向燈換一換吧。
其實是,很久之前老爸跟我說「車怎麼顧成這樣?方向燈一顆是多少?車我牽去幫你修啦!」
後來被女朋友都說方向燈這樣很醜,叫我快買一顆新的,我一直很抗拒!><

想說還有備料,總有一天會換上。
先看分解圖。

壞掉的部份:反射罩和燈泡電極是靠卡筍(但是它斷了),連接到主線圖的頭也被剪斷了。
完好的部份:有燈罩、燈泡、亮亮的外表。

壞掉的部份:無燈罩,外表全黑(電鍍掛了)。
完好的部份:反射罩和燈泡連結是靠燈座(螺絲固定)、燈泡、電線完好
沒想到,兩顆的構造竟然不太相同。
仔細想一想,就把兩顆完好的部份結合起來,不就好了。

所以,就把完好的電線剪斷,穿進亮亮的外表,並且焊回去
燈座穿上亮外衣

然後,將這個部份,再重新強化,並且上一層保護
剪下的這一段(包黑色的電線),做強化。


然後,因為它是左方向燈!但是我想把它裝到右邊。
而且,燈罩是另一顆燈的。

所以....要修改一下燈外殼。
原本燈罩定位點的位置。將定位點磨掉。


經過測試沒問題,裝回車上。
就大功造成啦!


需要注意的事,其實就是記得零件都要裝好,再焊回去。
幸運的是強化保護層的長度和想像的一樣。

用javascript實作post送Xml

沒有留言:
就這樣,然後想辦法把XML字串丟進來吧!
function send() {
    var xml = '';

    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open("POST", "http://localhost/", true);
    xmlhttp.send(xml);
}
[1]
xmlhttp.open(用POST, 傳去哪個網址, true);
xmlhttp.send(XML字串); 測試頁面
<html>
<head>
    <title>test</title>
    <script type="text/javascript" src="test.js"></script>
</head>
<body>
    <button onclick=send()>Go!!</button>
</body>
</html>

參考資料

[1] How to send a specialized XML request in JavaScript

Django View 小筆記

沒有留言:

這個做法是把loading放在template,弱化了url, view的code.
算是把重心放到前端上的技巧。

在此使用的Model如下
Model
class TestObj(models.Model):
    name = models.CharField(max_length=10)
    create_datetime = models.DateTimeField()

    def __str__(self):
        return "%s, %s" % (self.name, self.create_datetime.date())


Url
url有一個變數稱為pk, pk是primay key的縮寫, 在此要填的是主key的值。
from django.conf.urls import url
from . import views


urlpatterns = [
 #...
    #test View
    url(r'^test/(?P[0-9]+)/$', views.TestObjView.as_view(), name='test'),
]

View

view有兩種,一個是取model物件的DetailView,一個是取QuerySet的ListView

ListView
template_name 預設值為<app name>/<template name>_list.html
# -*- coding: utf-8 -*-
from . import models
from django.views import generic

class TestObjView(generic.ListView):
    model = models.TestObj
 #template_name = 'testobj.html' #可自行手動指定

DetailView
template_name 預設值為<app name>/<template name>_detail.html
另一個是ListView, 顯示QuerySet的結果。
預設Query完的變數名稱: <model name>_list
# -*- coding: utf-8 -*-
class TestObjView(generic.ListView):
    model = models.TestObj
 #template_name = 'testobj.html' #可自行手動指定

TEMPLATE
依你設定的View來決定template的命名。

必須要先接list裡的物件出來
在此示範使用預設檔名 testobj_list.html
{% for testobj in testobj_list %}
 {{testobj.name}}
{% empty %}
無資訊
{% endfor %}

直接取屬性出來顯示
在此示範使用預設檔名 testobj_detail.html
{{testobj.name}}

Javascript的封裝

沒有留言:

封裝1

宣告+定義

function Female(name, age) {
    this.name = name;
    var age = age;
    this.sayAge = function() {
        if (age > 18) {
            console.log(this.name + ' is 18.');
        }
        else
        {
            console.log(this.name + ' is ' + age + '.');
        }
    };
};

呼叫執行

var mary = new Female('Mary', 16);
mary.sayAge();

var susan = new Female('Susan', 36);
susan.sayAge();

顯示

Mary is 16.
Susan is 18.

繼承2

宣告+定義

function Female(name, age) {
    this.name = name;
    var age = age;
    this.sayAge = function() {
        if (age > 18) {
            console.log(this.name + ' is 18.');
        }
        else
        {
            //sayRealAge   is a function
            //sayRealAge() is a function return value
            console.log(this.name + ' is ' + sayRealAge() + '.');
        }
    };
    
    var sayRealAge = function() {
     return age;
    };
};

呼叫執行

var mary = new Female('Mary', 16);
mary.sayAge();

var susan = new Female('Susan', 36);
susan.sayAge();

顯示

Mary is 16.
Susan is 18.

Javascript的繼承

沒有留言:

繼承1

宣告+定義

function Animal(name) {
    this.name = name;
    this.age = 18;
    this.sayName = function() {
        console.log(this.name + ' and ' + this.age);
    };
};

function Human() {
};

//繼承: Human is a Animal
Human.prototype = new Animal('bad student');

呼叫執行

var student = new Human('good student');
student.sayName();

顯示

bad student and 18

繼承2

宣告+定義

function Animal(name) {
    this.name = name;
    this.age = 18;
    this.sayName = function() {
        console.log(this.name + ' and ' + this.age);
    };
};

function Human() {
};

//繼承: Human is a Animal
Human.prototype = new Animal();

呼叫執行

var student = new Human('good student');
student.sayName();

顯示

undefined student and 18

繼承3

宣告+定義

function Animal(name) {
    this.name = name;
    this.age = 18;
    this.sayName = function() {
        console.log(this.name + ' and ' + this.age);
    };
};

function Human(name) {
    this.name = name
};

//繼承: Human is a Animal
Human.prototype = new Animal('bad student');

呼叫執行

var student = new Human('good student');
student.sayName();

顯示

good student and 18

Javascript小小入門

沒有留言:

無物件概念

文字變數

var sayHi = 'helloworld';
var sayHi = "helloworld";

數字變數

var i = 0;
var pi = 3.14;

函數

宣告+定義

var helloworld = function() {
    console.log('hello world!');
};

呼叫執行

helloworld();

顯示

hello world!

有物件概念

Javascript有一個特有的特色,稱為「原型導向」,所以在此不直接定成「物件導向」

建構式

下面兩種寫法相同。
var student = new Object();
var student = {};

建構式1

宣告+定義

function human(name) {
    this.name = name;
    this.goto = function(place) {
        console.log(this.name + ' go to ' + place);
    };
};

呼叫執行

var student = new human('good student');
student.goto("school");

顯示

good student go to school


類別加上新的 Method

function human(name) {
    this.name = name;
};

human.prototype.goto = function(place) {
    console.log(this.name + ' go to ' + place);
};

呼叫執行

var student = new human('good student');
student.goto("school");

顯示

good student go to school



建構式2

直接建構物件

var student = {
    name: 'good student',
    goto: function(place) {
        console.log(this.name + ' go to ' + place);
    }
};

呼叫執行

student.goto("school");

顯示

good student go to school


物件加上新的 Method

var student = {
    name: 'good student',
};

student.goto = function(place) {
    console.log(this.name + ' go to ' + place);
};

呼叫執行

student.goto("school");

顯示

good student go to school


python之找到區域變數們。

沒有留言:
雖然小小一篇,但是這可是讓我回想了好久呀。
python有一個小函數可以回傳當下的區域變數列表,不過如果在最外層就locals(),就是回傳全域變數們了!XDDD

locals()

javascript類似windows的messagebox

沒有留言:
javascript可以直接呼叫類似windows的messagebox的東西。
分成三種

警告視窗

alert('警告視窗, 按確定, 無回傳值');

確認視窗

confirm('確認視窗, 按確定回傳true, 按取消回傳false');

輸入視窗

prompt("輸入視窗, 回傳輸入的值", "自動載入的預設值");

python 讀 bitmap 顯示它的值

沒有留言:
原本想寫一個smooth演算法的。
但是,想不到python的前置作業還滿麻煩的。(小小的不習慣)

我準備了一張這樣的影像
顏色: 灰階
色階: 8bit/pixel (我比較喜歡叫演色性)
大小: 5 pixel ×5 pixel

原本不打算使用任何的lib進行coding,但是因為手邊並無「沒有檔頭」的影像。
準備好的影像檔,也是.bmp格式,所以就去找了一下適合的lib來解決檔頭的問題。

找到了一個叫PIL的lib,好像很厲害。
跟著這一份教學,有小小的練習了一下,如果當初研究(研究影像處理)所是用python,不知道會是怎麼樣的情況呀(遠望)

說遠了

然後,這次的實作,只有將影像讀取出來,並且顯示所有的pixel值。
from PIL import Image

bmp_image = Image.open( 'sample.bmp' )

for i_vertical in range(bmp_image.height):
    line_horizon = [bmp_image.getpixel((i_horizon, i_vertical)) for i_horizon in range(bmp_image.width) ]
    print(*line_horizon)

bmp_image.close()
effective python說用這樣比較快
from PIL import Image

bmp_image = Image.open( 'sample.bmp' )

line_horizon = (bmp_image.getpixel((i_horizon, i_vertical)) for i_vertical in range(bmp_image.height) for i_horizon in range(bmp_image.width))
for x in range(bmp_image.height):
   for y in range(bmp_image.width):
      print(next(line_horizon), ' ', end = '')
   print('')

bmp_image.close()
執行結果:
(我有手動讓它對齊)
255   0   0   0   0
255 255   0   0   0
255   0 255   0 255
  0 255   0 255   0
  0   0   0 255   0
255 255 255 255 255

postman的get, post最簡單的發送

沒有留言:
沒想到,我的網誌也開了一個Web Develop的標籤了。

最近在研究後端的技術如何使用,但是因為完全不了解前端與後端溝通的方式。所以,目前是使用測試工具進行後端code的驗證。(這個也可以避免bug 前後端互推的好工具)

進入正題


因為,想學的其實是rest的api如何設計,如何使用Django實現,所以使用postman測試時,也是使用rest的格式進行測試。

因為在此,只是為了要講postman的最簡使用方法。
所以讓Django做最簡化的coding就好。

這次功能示範用的專案目錄架構
┌mysite
│├mysite
││├setting.py
││├url.py
││├view.py
 ...
settings.py 要先註解掉CsrfViewMiddleware
注意:這只是為了測試或練習,正式架站完全不會這麼做!
MIDDLEWARE_CLASSES = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    #'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
 
urls.py
呼叫測試程式
urlpatterns = [
    url(r'^test_function/$', test),
]
views.py
寫入判斷與回傳給瀏覽器的字串。
# -*- coding: utf-8 -*-
from django.http import HttpResponse

...
def test(request):
    if 'ok' in request.GET:
        return HttpResponse('this is get')
        
    if 'ok' in request.POST:
        return HttpResponse('this is post')
        
    return HttpResponse('nothing');

GET

在網址列的後面有個Params,按下去,輸入參數,該參數會出現在網址列後面。
在Django的views.py中,如果有值,可以用request.GET['ok']取值。(此例沒有值)

POST

在網址列下面有一個Body,底下選from-data。
一樣有一個key-value的地方可以填值,將post要傳的值填上去,這些值並不會出現在網址列。
在Django的views.py中,如果有值,可以用request.POST['ok']取值。(此例沒有值)

Django之Model的CRUD操作

沒有留言:

Query

return QuerySet

<model name>.objects.all()

多重條件 邏輯and


  • 取得符合條件的物件
    <model name>.objects.get(<model attribute name>=<attribute value>, ...)
  • 取得符合條件的QuerySet
    <model name>.objects.filter(<model attribute name>=<attribute value>, ...)

slicing QuerySet

<QuerySet obj>[index_start]
<QuerySet obj>[index_start:index_end]

不支援反向索引

<QuerySet obj>[-index_start]

order by

<model name>.objects.order_by('<model attribute name>')
<model name>.objects.order_by('-<model attribute name>')

模糊查詢

<model attribute name> + <'__contains'>=<attribute value>

關係管理器

主模型.關聯模型的小寫名稱_set

CRUD

Create

<QuerySet obj> = <model name>(<model attribute name>=<attribute value>, ...)
<QuerySet obj>.save()

<QuerySet obj> = <model name>.objects.create(<model attribute name>=<attribute value>, ...)

Read

就是Query

Update

<model name>.objects.filter(<model attribute name>=<attribute value>, ...).update(<model attribute name>=<attribute value>)

Delete

<QuerySet obj>.delete()

參考資料
[1] Django筆記(5) - 模型與資料庫

Django模型: 注意事項(>1.7版)

沒有留言:

1. 建立模型[1]

用python寫好django model的class

2. 檢查資料[1]

$python manage.py check (1.7版之後限定)
看到0 errors found的通知

3. 翻譯成資料庫語言[1]

$python manage.py sqlmigrate <app name>

建立migration資料檔
建立好資料庫模型後,我們必須針對目前的模型先建立一個migration檔

建立異動紀錄[1]

$ python manage.py makemigrations <app name>
如果模型有任何異動,則會產生新的migration檔,並放置在APP底下的migration資料夾
$ python manage.py makemigrations
Django會對所有安裝好的APP做migration的檢查

4. 模型與資料庫之同步[2]

$ python manage.py syncdb

>1.7版(無須第4步)

以>1.7版的角度來複習一下剛剛的重點

參考自1.9版的官網文件
$ python manage.py makemigrations <app name>
告訴Djagno確認Model與上一版的異動
$ python manage.py sqlmigrate <app name> <vertion number>
依目前已確認的模型,生成SQL(非必要執行)
$ python manage.py migrate
把模型變成真的Table

參考資料

[1] Django筆記(5) - 模型與資料庫
[2] What should I use instead of syncdb in Django 1.9?

我的RD夢

沒有留言:
堅持RD的工作,讓我在求職時充滿信心,唯有RD才握有可以改變世界的鑰匙,發揮自己的巧思,讓公司產品可以更美好,顧客使用時的心情也愉快。
如果是PM、業務、品保,是無法直接的影響這些事。所以,一直以來堅持著一定要找RD的工作。
不過台灣的產業,對於RD的使用方式卻與此有相當大的出入

我所看見...台灣產業的RD

硬體

用來看規格,並且確定採購進來的規格相容性,與技術上的問題排解。使用自己的技術來設計與使用者無關的範圍。
在產品設計流程上,處在「細節設計」的範圍。

軟體

用來拼湊出最終結果,過程的所有設計,只是為了讓功能實現,並沒有直接與使用者相關。
就算是UI設計,使用者相關的考量,也只是陌生的領域,與RD無關。

RD就這樣成為行使高級技術的黑手工人。
在People ware這一本書中提到的「高科技幻覺」中提到,我們行使的技術,叫做「技術應用」而不是真正的技術研究&開發,在我們這樣的RD手上,並沒有真正研究或開發什麼,你會覺得你的小孩在玩樂高,是一種研究或開發嗎?

就這樣,程式設計師的技術層次被無視,硬體工程師的心思被忽略。技術層次高,被視為理所當然,是自然形成的,技術層次低,被視為領低薪理所當然,可以繼續使用的員工。
經過五年,不再抱著RD夢來找工作。

python call C++ API by Boost~初體驗

沒有留言:
原則上,是將c++編譯成dll檔。
只是這個dll檔,是要給python用的

建立專案檔

建立一個Win32 Console的dll檔專案

原本的C++程式碼

先來看看一個cpp原本的code

.h檔

#include <string>
#include <map>

class Persion
{
    std::string m_Name;
    std::string m_HomeNumber;
public:
    Persion();
    explicit Persion(const std::string &name);
    virtual ~Persion();
    void SetName(const std::string &name);
    std::string GetName() const;
    void SetHomeNumber(const std::string &number);
    std::string GetHomeNumber() const;
};

class PersionWithCell : public Persion
{
    std::string m_CellNumber;
public:
    PersionWithCell();
    explicit PersionWithCell(const std::string &name);
    void SetCellNumber(const std::string &number);
    std::string GetCellNumber() const;
};

class PhoneBook
{
    std::map<std::string, Persion*> m_PhoneBook;
public:
    int GetSize() const;
    void AddPerson(Persion *p);
    void RemovePersion(const std::string &name);
    Persion *FindPerison(const std::string &name);
};

.cpp檔

#include "phonebook.h"

Persion::Persion():
m_Name(""), m_HomeNumber("")
{}

Persion::Persion(const std::string &name):
m_Name(name), m_HomeNumber("")
{}

void Persion::SetName(const std::string &name)
{
    m_Name = name;
}

std::string Persion::GetName() const
{
    return m_Name;
}

void Persion::SetHomeNumber(const std::string &number)
{
    m_HomeNumber = number;
}

std::string Persion::GetHomeNumber() const
{
    return m_HomeNumber;
}

Persion::~Persion()
{}

int PhoneBook::GetSize() const
{
    return (int)m_PhoneBook.size();
}

void PhoneBook::AddPerson(Persion *p)
{
    m_PhoneBook[p->GetName()] = p;
}

void PhoneBook::RemovePersion(const std::string &name)
{
    m_PhoneBook.erase(name);
}

Persion *PhoneBook::FindPerison(const std::string &name)
{
    return m_PhoneBook[name];
}

void PersionWithCell::SetCellNumber(const std::string &number)
{
    m_CellNumber = number;
}

std::string PersionWithCell::GetCellNumber() const
{
    return m_CellNumber;
}

PersionWithCell::PersionWithCell():m_CellNumber(""), Persion()
{}

PersionWithCell::PersionWithCell(const std::string &name):m_CellNumber(""), Persion(name)
{}

為C++ code 建立表皮

再來我們為了這一個cpp程式,建立一份「皮」
在此可以注意的是,如果你要為屬性設定get/set,使用.add_property(),如果是只有get或只有set,就如同新增一個function一樣,用.def()
#include "phonebook.h"
#include <boost/python.hpp>

using namespace boost::python;

static std::string PrintPersion(const Persion &p)
{
    std::ostringstream stream;
    stream << p.GetName() << ": " << p.GetHomeNumber();
    return stream.str();
}

std::ostream &operator<<(std::ostream &os, const Persion &p)
{
    os << p.GetName() << ": " << p.GetHomeNumber();
    return os;
}

BOOST_PYTHON_MODULE(phonebook)
{
    class_<Persion>("Persion", init<>())
        .def(init<std::string>())
        .add_property("name", &Persion::GetName, &Persion::SetName)
        .add_property("home_number", &Persion::GetHomeNumber, &Persion::SetHomeNumber)
        .def("__str__", &PrintPersion)
        .def(self_ns::str(self))
        ;

    class_<PhoneBook>("PhoneBook")
        .def("size", &PhoneBook::GetSize)
        .def("add_persion", &PhoneBook::AddPerson)
        .def("remove_persion", &PhoneBook::RemovePersion)
        .def("find_persion", &PhoneBook::FindPerison,
            return_value_policy<reference_existing_object>())
            ;
}


編譯

編譯成.dll檔!

用python呼叫之前


  1. 將.dll改成.pyd
  2. 將.pyd檔的檔名設定成BOOST_PYTHON_MODULE()裡定義的名字
  3. 將Boost的boost_python-vc80-mt-gd-1_60.dll copy 到和.py檔同目錄
    (這一步如果有人知道怎麼不移動檔案,還麻煩請告訴我呢!)

寫python

import debug.phonebook as phonebook

book = phonebook.PhoneBook()
p = phonebook.Persion()
p.name = "Chris"
p.home_number = '(123) 456-7890'
book.add_persion(p)
p = phonebook.Persion('Mary')
#p.name = 'Mary'
p.home_number = '(123) 456-7890'
book.add_persion(p)
print('No. of contacts =', book.size())
print(book.find_persion('Mary').home_number)
print(p)
print('--------')
import debug.phonebook as phonebook
p = phonebook.Persion('Mary')
print(p)
p.home_number = '(123) 456-7890'
print(p)

def persion_str(self):
    return "Name: %s\nHome: %s" % (self.name, self.home_number)

phonebook.Persion.__str__ = persion_str
p = phonebook.Persion()
p.name = "Chris"
p.home_number = "(123) 456-7890"
print (p)

book = phonebook.PhoneBook()

class PyPersionWithCell(phonebook.Persion):
    def get_cell_number(self):
        return self.cell
    def set_cell_number(self, n):
        cell = n
    celll_number = property(get_cell_number, set_cell_number)

p = PyPersionWithCell()
p.name = 'Martin'
p.home_number = '(123) 456-7890'
p.celll_number = '(123) 097-2134'
p2 = book.find_persion('Martin')
print(p2)

執行pythony就可以看見結果啦!