2015年10月25日 星期日

程式與工作

筆者所在的連隊,前陣子在接教召,筆者和其他連數位行政,要負責近300 位召員的薪嚮跟交通費補助,筆者所在的連隊還好,只有一個排約30 位召員,其他連隊都是近90 位召員。

整個過程其實挺慘烈的,一開始就要先跟召員們收個人私章以便辦餉,要收來回交通票據還有該員的工作地或居住地證明以便核銷交通費,想當然爾大家都會忘了帶東西,補救的工作當然是我們行政要做了,各項東 西的補救方式分別是:

  • 私章:由我們行政刻一顆,刻章費用由薪餉中代扣
  • 沒帶工作地或居住地證明:請家人或同事代為傳真
  • 沒交通票據證明:我們行政代開證明
  • 沒買回程機票:我們行政代購機票,這會需要加收召員的身分證件
然後交通費資訊還要打到網路系統上,印出交通費表附在餉冊後面。

我們連因為人少,我簡單處理後兩位要刻章、兩位要代買機票,輕鬆解決;其他連跟營行政就不行了,營行政負責統籌所有印章代刻、機票證明與代購,其他連隊的行政因為人多,統計要刻誰的印章、買誰的機票、機票的時間等就花了好一段時間,統計錯誤更正也會一直出現、傳真機還會不定時嗶嗶響,送來新的住地證明,營行政就被潮水般的訊息淹沒,教召這幾天都是從早工作到晚,不斷處理進來的訊息,到機場跟刻章店處理新進的要求,回營區收召員們的證件跟歸還證件。

其實筆者自己也很懷疑,如果把我放去其他比較多人的連隊,或是讓我接營級統籌的工作,我是否能做得更好?還是會更混亂?但看著營行政做事時的樣子,我突然有種體悟,其實工作就跟程式有點類似。

實作程式時,寫code 的速度快慢其實不是重點,重點是你的程式是否切合你的問題,用錯的架構去解問題,要不碼浪費資源或是要嘛容易出錯;工作也是一樣,認真與否不是關鍵,選一套好的工作方式才是重點。

以下是我認為幾個好工作方式的要點:

  • 善用數位工具:
現代電腦其實比人類更不易犯錯,有很多枯躁的事能讓電腦代勞,同時文件在電腦上修改比手寫快得多,同時電腦還能快速搜尋、排序,如果資料量超過50筆的作業,用電腦文件來管理會比手拿一疊紙清楚得多,教召時其他連隊確認交通費金額都要去翻他們收的資料夾,一頁一頁慢慢找,我只要看一下手上電腦打好的表格,瞬間就找好了,就知道兩者有差。
工作時,時時檢視有沒有在做一些電腦可以做的事,例如手寫阿拉伯數字後也要改國字大寫數字;同一份文件對應幾十個的人名,每個人名都要產生一張有它名字的文件,這些請交給電腦,不要有工作是「如果我忘了做這步就會出錯」,這個錯誤會搞死你。
  • 做好版本控制:
請用git這次教召的營行政,用手抄的方式,把各連統計出來有證明要開、有印章要刻的名單,自己手抄到幾張紙上,之後做了什麼就從上面標記掉,問題是新的要求會一直進來,沒多久她那張紙就寫滿各種顏色的註記,要看懂它也變得益發困難。
就個人經驗來說,紙上註記兩層已經是極限了,再來就應該將註記和原稿合成一份新文件;就算要用實體紙張,多用活頁夾整理散頁,或用筆記本,避免散頁可能會被風吹散,需要花時間重排,或是更糟糕的:不同版本的散頁被吹在一起;這可以拉回強調電腦作業上,文件複製與修改的快速。
  • 確認內容正確:
這點很重要,就如我收齊個人資料,第一步是統計召員們欠缺的東西,在excel 上建一張表,這份電腦文件就變成我所謂的single source of truth,收齊的文件因為檢索速度慢,無法搜尋,基本上就是丟一邊不看了。此時,這個統計步驟就變得十分重要,這步出錯,之後的資料都會是錯的,而且,通常不會再回去檢查原始資料正確與否,檢出錯誤的時間都很晚了。
遇到這種狀況,檢查兩遍甚至三遍都不為過,所謂garbage in garbage out,如果源頭都是錯的,之後再怎麼努力都只會產出垃圾。
  • 隨時更新:
這步其實最難,當發現到現在的工作方式不足以應付工作的要求時,隨時切換自己的工作方式,就像手寫統計表浪費太多時間,花點時間先把文件打電腦裡,會讓之後的工作變得輕鬆一點,但通常大家會選擇用本來的手寫統計表。
更細部的,電腦表格有沒有整齊美觀讓人一目了然,所用系統是否對應面對的問題?幾筆資料可以用手寫表格,幾十筆可以用excel隨便做,幾百筆就需要excel 並且時時調整自己的表格了,永遠記得選一個對的工作方式比認真工作重要:working hard, after knowing you are working smart,不要低估人類犯錯的能力,高估自己的能力只是在挖洞給自己跳。

結論:

說完個人意見,回到開頭的問題,面對教召我是否會做得更好,我承認我不知道,因為我沒遇過這種等級的問題,但我相信我能避開一些其他行政遇到的問題。

要我做個總結的話,「高手」不是他們能力特別強或是覺睡得比較少,而是他們選擇好的工具跟好的工作流程,好的工作流程只能從高難度工作中鍛練,厲害的人不會一成不變,用同一套方法解決不同問題,而會因應問題變化修正工作方法;而了解面對不同難度的問題,該用什麼方法才能用最少資源,犯最少的錯誤解決問題,靠的就是經驗,能累積豐富經驗並取用自如的,就是「大師」。

附注:

啊不過說回來教召這件事,筆者面對最大的問題,其實是國軍教召網路報到跟辦餉的系統根本是一團垃圾,也就是國軍給了我們一支會炸膛的手槍上場打仗;另外像是「確認內容正確」這步,要如何讓底下的人都確實貫徹這步,讓他們別一直修改他們呈上來的要求,我想這就是另一個難題了。

大家工作上都有什麼小技巧呢,歡迎大家留言。
另外不免俗的來個:以上內容,認同請分享XDDDD

記帳兩三事

當會計,不然就是連隊預財兵(無誤),記帳都是相當重要的工作,帳本記錄當前的現金狀況,可作為未來支出收入管控的依據。。

目前我的帳本分成下面幾個項目,從左到右分別是:記帳項目資料、現金收支、各項資金、各項子科目結餘欄位,分別說明如下:

  • 記帳項目資料:記錄一筆帳的時間、帳目性質(收、支轉)、子科目代號、記帳事由。 
  • 現金收支:包含一個現金收入欄跟一個現金支出欄,視收帳或支帳在兩格中填入金額,不能一筆帳包括收帳跟支帳。 
  • 各項資金:包含現金餘額、櫃存現金餘額、銀行帳戶餘額等,現金餘額欄記錄單位有多少資產可以動用,其值應該是櫃存現金跟所有銀行帳戶餘額的總和。 
  • 各項子科目結餘欄位:專業一點的帳是不支援所謂的「大水庫理論」,各用途的帳目要分清楚,用在買食物的錢就不能用來買其他東西,這裡每格會記錄當前該子科目的餘額,全部的餘額應該和現金餘額相同 

平常記帳…呃…就是把帳寫到帳本上,包括三種:收帳、支帳跟轉帳。

收帳跟支帳就是我們收錢/花錢,看是直接動用現金或是由銀行轉帳的方式進入,在各項資金的部位填入相對的數值,並在對應的子科目欄位增加數字;再專業一點的帳會要求例如今天收入三筆錢時,如果是送入不同的子科目欄位就要登成獨立的三筆帳。

比較特別的是轉帳,像是從銀行帳戶提錢出來補充櫃現,或是由沖銷墊付的款項時,錢只是從一個科目轉到另一個科目,總金額並沒有增減,此時現金收支欄位就不用填入數字,只需要在有變動的子科目下寫入數字即可。

一個完整的登帳大概會長這個樣子:
登帳時間 子科目代碼 登帳名稱 現金收支 現金結餘 (1)
主副食費
(2)
交通費
現金收入 現金支出 現金餘額 櫃存現金 銀行帳戶餘額






6,890,000 6,090,000 22,000 2,000 20,000 12,000 10,000
10/1 (1) 支十月主副食費

12,000 10,000

8,000 0

10/2 (2) 收十月定額交通費 5,000


15,000

13,000

15,000
10/3

補充櫃現8,000





10,000 5,000




第一行是當月開帳,現金收支部分寫上今年度總支出和總收入,登帳時寫上逗號是很重要的,免得有人偷改數字;每個月底將帳本關帳,結清本月的總收支、每筆子科目的餘額,並開下個月的帳。

一般來說大家都是用現金交易,現金上的收支直接登帳即可,若有銀行帳戶的話(通常會有),就要定時到銀行去申請查帳,上面會列上該帳戶的匯入、匯出狀況,以此為附件做收支帳的登帳。


每個月,銀行會給當月的銀行對帳單,這時就可以製做當月的「銀行調節表」,因為我們登帳的時間跟銀行實際入帳的時間不同,可能出現登帳的數字不同。
此表會包含幾個項目,時間性項目包括:
  • 帳戶應收未收款:月底關帳後銀行在該月有入帳,帳戶應該收入這筆但還未登上;筆者自己遇到的例子是該月最後一天匯入了下月的定額經費,而我們還未收帳,因此出現應收未收款。 
  • 帳戶應支未支款:同樣銀行也可能自動扣款,而我們還未列入支帳,像是銀行代扣的水電費用,這個因為筆者的帳戶沒這功能,還沒遇上這問題。 
  • 銀行應收未收款:像是在途存款,錢已經在銀行但1530 當日關帳時未入帳,要到下個月才入帳,就形成應收未收 
  • 銀行應支未支款:帳戶已列支出的支票銀行未兌現,就是銀行應支未支。 
因此,我們記帳本上的餘額,加上(1),扣掉(2),應該會等於銀行帳戶餘額加上(3),扣掉(4),這個調節出來的金額就是我們帳戶本月真的剩下的金額。
就像我們帳本上有100萬元,好像很多錢,但本月銀行自動扣房貸99萬,調節後的金額只剩一萬元,這才是真的可動支的金額,瞬間發現其實帳戶快沒錢了。

另外還有狀況就是登帳錯誤,像是誤收他人匯款等,比過這種狀況相較之下不容易發生。

簡單總結調節表,手上的記帳本,是我們現在已登上的收支,這是「我們知道的」帳目;從銀行拿到的當月對帳單,上面的數字則是「我們不知道的」,會列到(1)跟(2)上;最後則是我們做了收支銀行還未處理,這是「銀行不知道的」,會列到(3)跟(4)上。
調節表其實不難,只要平時記帳記得勤,讓帳本儘量貼近銀行帳現況,不要有太多的未列帳,一般來說都很好調節出來;但若是平時不記,等到月底許多應收未收跟應支未支交錯在一起時,就很難調節出來了。

其實記帳真的不難,記好帳也能幫助控管自己的收支,不過我想也沒人沒事帳要記到這麼複雜,還要跟銀行對帳XD,這比較像法人才需要的,個人帳只要列列支出就算相當厲害了。

相關資料:

  • 關於現金調節表,這裡有相關介紹,可惜是中國網頁:
http://wiki.mbalib.com/zh-tw/%E9%93%B6%E8%A1%8C%E5%AD%98%E6%AC%BE%E4%BD%99%E9%A2%9D%E8%B0%83%E8%8A%82%E8%A1%A8
  • 台灣的頁面比較清楚的我只找到,不然大部分都是word, pdf 檔:
http://blog.xuite.net/lu833484/blog/85621204-%E9%8A%80%E8%A1%8C%E8%AA%BF%E7%AF%80%E8%A1%A8

2015年10月10日 星期六

Word 使用合併列印生成大量文件

最近筆者的部隊接教召任務,筆者的任務是幫所有的召員們辦薪餉跟交通費補助,光我一個人就點了大概28萬元的錢,事後遇到要點錢的場合都會覺得很煩,這大概是所謂的「點錢恐懼症」吧XD
事後交通費核銷需要列印每個人的憑證黏存單,上面要有每個人的姓名、要核銷的金額(大小寫都要有)、單據數量,如果一個一個檔案去改、存檔(以姓名為檔名),遇上一個連隊近百位召員一定會吃土,小小研究一下,最後用word 裡面的合併列印功能解決了這個問題。

合併列印可以讓你在文件裡插入一些變數,參照到如excel 、其他的資料庫檔案,自動把資料庫裡的一筆資料插進變數裡,每筆資料生成一份文件,例如你要寫信給100個人,你只要先把100 人的名字打好,以它為變數,word 就會產生100 份信件,最後的署名都不一樣;以這次的教召為例,我們來試用一下合併列印功能。

首先第一步當然是要先準備文件,把會變動的地方如姓名部份留白;接著準備好資料庫,以方便度來說用excel 就可以了,第一列打上項目:姓名、核銷金額、核銷金額(大寫)、單據數量,然後把該打的資料都打上去。

為了做個示範,我就只打一份表格就好,至於人名跟金額我就用一些單純的資料XD:
這是準備的word 檔,通常會比這個複雜得多
excel 的資料庫,應該也能用其他的資料庫

準備資料有幾個要點,像是我上面資料數字大寫的部分,如果你是直接選「儲存格格式」去改的話,因為它本質還是數字,參照到word 裡面還是會顯示為數字;在這裡要用
=text(B2, “[dbnum2]”)
=text(D2, “#00”)
把它轉成大寫文字,跟加上前綴的0;至於後面的format 為何是這個,老實說我也不知道去哪裡找,我真的覺得M$ 系列的產品都有這種特性,很好用但是想要進一步深入「為什麼」的時候就會碰壁。
不然也可以用「儲存格格式」去改,然後把顯示的新台幣大寫文字全部貼到word 再貼回來,讓它變成文字格式,這個方法,如果你原本的數字改掉文字不會根著改,容易出錯,個人比較不喜歡

開始連接文件:
其實這步就是選「郵件」->「啟動合併列印」->「逐步合併列印精靈」點下去,一步一步來就好了。
* 列印就選信件,使用目前打好的信件當起始文件,這部分對應到「郵件」->「選取收件者」。
* 選擇收件者其實就是選擇你打好的清單,匯入後會跳出項目選單,在這裡可以把你不要的項目挑掉,例如核銷單據張數為0的人,就不用黏存單了,那我們可以選擇「篩選」,設定「單據數量 不等於 0」,那項就消失了。

* 現在插入變數,在想要的地方,選精靈的「其他項目」或是工具列的「插入合併欄位」,選擇要插入的項目,插入的項目會有<<>>的醒目提示。
* 下一步就可以預覽信件了,一共產生了3份,自動代入了所選的欄位,每頁文件都是不同的資料項目。

* 最後可以選工具列的「完成與合併」->「編輯個別文件」選全部,把所有產生的文件都列出來,存成獨立的一份文件。

用這個方法,瞬間就能把要做的文件弄好,而且不容易出錯,這也是我認為最重要的:working hard, after knowing you are working smart,現在的電腦是很不容易出錯的,容易犯錯的都是使用者,所以挑一套不容易出錯的工作方式、工作流程,遠比認真工作更重要。

2015年9月17日 星期四

Cryptography 1:攻擊stream cipher

密碼學中,有一種極簡的密碼,就是stream cipher(流加密XD),對各式的明文,隨機產生一組和它一樣長的key並和明文xor 起來,就是一個夠好的加密,只要該密鑰是隨機產生,如同上一篇所說,密文也會夠隨機。
按:事實上我是聽課才知道這種加密,不像強者我同學曾奕恩大大,完全無師自通,看來我該讓賢了。
在實務上,通常不會用真的random密鑰,因為這會讓密鑰的長度要跟訊息一樣長,不實用,你能想像要先交換一組GB等級的密鑰嗎?我們會用pseudorandom generator,把短密鑰生成為長密鑰,來解決這個問題。

這個加密系統有一大弱點,就是密鑰是一次性的,若一把密鑰重覆使用,而密文遭人攔截,則攻擊者可以利用:
c1 ⊕ c2 = (m1 ⊕ k) ⊕ (m2 ⊕ k) = m1 ⊕ m2
若明文是以ascii 儲存,m1 ⊕ m2 已經有足夠資訊讓人猜出內容。

例如,明文常有的space,ascii 是0x20或32,它跟英文字母xor 起來的結果,大多會落在大小寫轉換的英文字母範圍內,我們用python 來試試:
uppercase = list(range(65,91))
lowercase = list(range(97,123))
msg = uppercase + lowercase
print("".join([chr(c ^ 32) for c in msg]))
print("".join(chr(c) for c in msg))

會得到:
abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

其實它X的根本就是一個對上一個,這和一般最可能發生的字母xor 字母產生的結果相差頗大,例如a xor z = 27還在不可視字元範圍內,所以如果xor 的結果落在字母內,很可能表示c1, c2中有space。
我們可以先產生一個字典,以常用ascii 和space xor的結果為鍵,以便用來反查該ascii 的值:
xorSpace = {}
for c in msg:
    xorSpace[c^32] = c

然後對各截到的密文,假設是c0, c1 … cn,c0 xor c1 中存在字典中的字元位置,就有可能是c0或c1在這裡有space,將這些位置存下來,跟c0, c2 有space 位置取交集,就能得到c0中space的位置了。
def listspace(c0, c1):
    spacepos = []
    for idx, chars in enumerate(zip(c0, c1)):
        if (chars[0] ^ chars[1]) in xorSpace:
            spacepos.append(idx)
    return spacepos

可以用
c01 = listspace(c0, c1)
c02 = listspace(c0, c2)
list(set(c01).intersection(c02))
輕鬆得到交集結果。

有了space 位置,我們就可以把攻擊對象的字元,一個一個和space 位置xor ,再用先前建的字典轉出可能的字串,例如我們隨便轉一組密文的結果:
Yolal###,##a ##rb###. #eazest xwrcy#c#n th# worl#.

亂碼(我讓它輸出#表示查不到該xor的結果)還不少,但一些字元已足夠我們去猜出明文,例如最後面的the world.;這還只是用只有一組密文的space 位置當標準,如果我們測試所有密文的space位置,結果的開頭如下,每行密文該字元表示和不同密文測試的結果,例如第一行表示第一個字元和另外三個密文測試,兩個沒找到字元,一個轉出Y:
"##Y"
"##o"
"d##dl"
"aaa"
"l"
"#e,,##,#"
"ee#"
"#"
"i,,"
"####s###"
"tt #"
"a"
" "

已經看得出明文大概是’yodalee is a’,如果再用這明文m0 = m1 xor c0 xor c1,可以試著解其它的明文,找出更多粢訊把亂碼的部分消掉,完成攻擊。
例如用下面這段簡短的python code,就可以快速測試已知答案的話,其他密文的內容:
ans0 = "xxx" print("".join([chr(ord(c) ^ c0[i] ^ c1[i]) for i, c in enumerate(ans)])

附帶一提,我加密的訊息是:
"Yodalee is a garbage. Weakest person in the world."
其實不算什麼祕密XD。

2015年9月16日 星期三

Cryptography 1:密碼學裡的隨機

小弟最近消失了好一段時間,都沒在更新文章,其實小弟是掉到陰間去了,在陰間時間變很少,都不寫code(也沒電腦Orz),也不再看相關的東西,例如rust 的文件了,因為我知道一年後出來,rust-lang 搞不好都翻了兩翻,而且看了也不能直接練習,看了等於白看。
最近把時間花在一些比較不會變的東西,像是計算理論、密碼學、數學等等的東西,請我的好友強強林寄列印的書給我,利用放島休的時間聽coursera 上stanford 的cryptography,就算在陰間還是要定期充電,不然出來都變白痴了(雖然說本來就非常弱)。

下面這是聽密碼,關於其中隨機這件事的一些體悟:

密碼學的重點,其實就在「燙」…啊不對,是在「隨機」(random) 兩字,普通的訊息加密變成隨機,讓竊聽者猜不出訊息的內容,才能達成密碼學最重要的目的。
在密碼學裡很常看到xor,就是因為xor 的特性:當你把任何東西X跟隨機的訊息Y xor 起來,出來的東西的機率分佈會跟Y 一樣隨機,因此只要準備一個夠好的Y夠隨機,一個xor 就能把X 給加密好,所以問題就出在Y到底夠不夠隨機上。
當然我們可以用硬體雜訊產生器之類的東西,製造一個真隨機的來源當作密碼,但這在密碼學上不實用,如果是真隨機,表示加、解密雙方無法重現這個密碼,就無法加、解密啦;因此我們需要pseudorandom(偽隨機),用有規則、可重現的方式製造一個很像隨機的東西。

無論是pseudorandom generator/function/permutation,都是設法設計一個夠亂的變法,並讓它們儘可能像random,並讓攻擊者在有限的運算資源限制下,分不出兩者的差異。但總歸來說,兩者還是不同的,以pseudorandom generator 為例,我們會設計很多統計上的測試,像是 0, 1 的數量不能差太多;不能有太長的0序列……讓這些測試無法分出兩者的差異。

千萬不要小看隨機這件事,小小的不隨機,都能讓攻擊者找出一絲絲突破的空間,例如Caesar cipher 隨機性不夠,用頻率攻擊法可以快速破解;enigma 只因為輸入跟輸出不會是同一個字,也能利用這點,配合電子計算機在幾十分鐘內破解;課程中有個例子是DES 有一個問題,可以用線性運算找到一個發生率小於1/2^21 不隨機事件,利用這點,就足以大幅削弱DES 的安全性,也就是說,我們發現這個pseudo-random不是真random,用這個運算預測pseudorandom下一個輸出時,可以比瞎猜好1/2^21。

----

至於random跟pseudorandom是不是一樣呢?

理論上,如果給定無限多組的統計檢定,終究可以驗出真隨機和偽隨機的差異,但同樣的在"有限的運算資源"限制下,能進行的終究只有有限組統計檢定(這個教授倒是有提到,如果P=NP的話,我們就可以……),也就是因為"有限的運算資源"限制,保護了現行的加密系統不被輕易破解。

以真實例子來看,我們可以斷言,pseudorandom不會出現全0這樣罕見的序列,但這樣的序列在random 的狀況是確確實實會發生的,所以pseudorandom 和random 真的有差,但這差異的發生率之小,除非我們能窮盡所有檢查,才能檢出這種差異。
我們在做的事情,就像往霧裡一指,說:來,這是random的產出,然後我們放出另一團pseudorandom 霧,自問:你覺得你這團pseudorandom霧和這random霧像不像?有限的檢查下,我們可能只能驗一下外觀,兩個當然一樣;但給我無限的檢查,會發現random霧裡有幾顆是硫酸、幾顆是氫氧化鈉,他們和你的霧當然不一樣,但把兩團霧混在一起,其實這根本就沒差。