2019年3月11日 星期一

Web技術相關好文&重點整理

JS:

1.我知道你懂 hoisting,可是你了解到多深?
https://github.com/aszx87410/blog/issues/34

此文章從ECMAScript的規格去剖析hoisting的原理,非常不錯。以下節錄結論:
當我們在進入一個 EC 的時候(你可以把它想成就是在執行 function 後,但還沒開始跑 function 內部的程式碼以前),會按照順序做以下三件事:
1. 把參數放到 VO 裡面並設定好值,傳什麼進來就是什麼,沒有值的設成 undefined
2. 把 function 宣告放到 VO 裡,如果已經有同名的就覆蓋
3. 把變數宣告放到 VO 裡,如果已經有同名的則忽略

2. Microtasks/Macrotasks and their relations to Promises/Event
https://javascript.info/microtask-queue

這也是一篇很有趣的文章,網站整體的內容也很充實。重點在認識V8對於Promise和Event的處理順序,對於理解Node非同步很有幫助。可以幫助釐清promise chain中的非同步處理的順序。ex: 不同then裡面若各自有非同步的呼叫,並無法保證前一個then中的會先執行完,也就是說Promise chain在使用上,要注意then裡頭若是有非同步呼叫,(很有)可能會在這個then block結束後才完成,因此下一個then block不能相依於此then block的非同步處理結果

System Design:

1.搶購系統設計
https://codertw.com/程式語言/573527/

此文章深入探討搶票/搶購系統的架構設計,內容含括前/後端業務邏輯,也提出許多解決方案,值得參考。

ES6 features:

1. import/export Modules:
https://stackoverflow.com/questions/36795819/when-should-i-use-curly-braces-for-es6-import/36796281#36796281

扼要回答了ES6 Module的使用方式,也解釋了export default(預設導出/入)和 { A as B } ( named export renaming)的意涵。

React:

Life Cycle demo:
https://codesandbox.io/s/8k9k5zm060

一個簡單的demo,可以了解元件的生命週期,和state update的一些呼叫順序。

2019年1月29日 星期二

MongoDB document schema 設計思維入門

本文摘要自Thinking in Documents: Part 2.

此文章將介紹MongoDB的Document schema設計思維,包含如何用embedding及referencing來整理相關資料,也會介紹一點索引及MongoDB的transaction model。

定義你自己的Document Schema

首先,最重要的是你的app查詢資料的模式,也別忘記善用document model的彈性,意即其embedding和豐富的BSON based資料結構支援。

app資料存取的模式首要在以下幾點:

1. 資料庫的讀寫比(R/W ratio)
2. 資料庫所做的查詢指令及資料更新的類型(type of queries and updates)
3. 資料的生命週期以及document的成長速度

若你有關聯式資料庫的背景,可以先想像以下兩點:

1. 你會如何使用關聯式DB來實作這些操作。
2. 在MongoDB要怎麼實作。

另外也可以透過RDBMS的日誌來分析最常使用的查詢指令或是最常被共同查詢的資料,作為是否合併在單一document下的考量。

使用Embedding或Referencing來建立關聯

直接embed或是對其他collection的document做reference的時機並無絕對,但是還是有一些準則可供參考。

Embedding

對於一對一(one-to-one)或是一對多(one-to-many)的對應關係,很適合使用embedding模式,因為這些資料很可能本身就是依存在parent document之下的一種特性或是資訊。此時parent document就像是data owner或是container一樣。可以想像當parent document消滅,若該document將會失去意義的話,就是屬於這種類型。

若是需要被一起更動(update atomically)的資料,也應該使用此模式,詳細可參照下面關於Transaction model的說明。

然而,並不是所有的一對一或是一對多對應關係都適合embedding。舉例來說,以下的時機適合使用referencing:

1. 當一個document很頻繁被讀取,但是其內的embedded document卻幾乎不會被存取到。舉例來說,一個顧客紀錄document之中的年度總報告。由於年度總報告並不會被經常使用,嵌入它只會增加該collection消耗的記憶體。
2. 某一document其中一部分很頻繁被更新且不斷成長,但是剩下的部份卻相對沒有變動。
3. document size超過MongoDB目前的 16 MB限制。

Referencing

Referencing讓資料正規化(data normalization)變得可能,也比embedding有彈性。但是MongoDB伺服器卻需要追加查詢來解析關聯,因此會需要多次讀取動作,消耗較多時間。

實作上通常是在一個document中儲存另一個document的_id field當作參照,接著再由app執行查詢來取得參照的資料。

Referencing應該被用在:

1. 當使用embedding會造成資料冗餘(data duplication),無法期待效能向上時。
2. 物件從各種不同來源被關聯時。
3. 多對多(many-to-many)關係時。
4. 大型、階層式的資料集時。

不同的設計目標

從以上觀察我們可以發現RDBMS和document model的根本上差異:

1. RDBMS對資料的處理是以儲存空間效率來考量(因為早期儲存空間是系統中成本最高的元件)。
2. MongoDB的document model則是以app存取資料的效率為考量(因為開發者的時間和上線速度現在比儲存空間還要受重視)。

MongoDB Transaction Model

MongoDB提供了如關聯式DB的document-level ACID compliance,包含可以atomically update embedded arrays以及sub-document,且無須付出如RDBMS的耗時ACID operation,以及在不同table之間維護關聯完整性(referential integrity)。

Document-level ACID compliance保證在document改動時的隔離性(isolation),任何錯誤都會讓資料還原到操作前的樣貌,且用戶端也會收到原本的document view。

NOTE:在 MongoDB 4.0之後,加入了 multi-document ACID transactions來確保replica sets之間的資料是一致的,並確保任何執行都是「有或全無(all-or-nothing)」來維護資料完整性。在4.0版本之前,您還是可以透過findandmodify或是two-phase commit來達到一樣的目的。

如何找出我的資料?

MongoDB使用B-tree indexes,並原生支援secondary indexes。因此,SQL背景的人很快就能上手。不過索引也還是一樣會在寫入及資源使用上增加負擔,如同所有的資料庫。預設MongoDB會在document的 _id欄位建立索引,其他user-defined indexes都是secondary indexes。
任何欄位都能當作secondary index,包含在arrays中的欄位。在MongoDB中的索引有:

1. Compound Indexes
2. Geospatial Indexes
3. Text Search Indexes
4. Unique Indexes
5. Array Indexes
6. TTL Indexes
7. Sparse Indexes
8. Hash Indexes

另外,MongoDB也支援index intersection以使用多個索引做查詢。

2019年1月17日 星期四

How to clone an object in Javascript with Object.defineProperties?

TL;DR

Sometimes we want to clone an object in JS, we will use something like:


const obj = {foo:'bar'};
const newobj = {};
for (const key in obj){
    newobj[key] = obj[key];
}

This will work fine under most circumstances, since you might never adjust the property flags of the object. Also, when we create an object property, theare default to true, so everything is "default normal." And you might even not know there are such flags. Property flags, in brief, are metadata for the property in the object. They define the configuration of the property such as if the property is writable/enumerable/configurable.

Here are some simple explanation about the flags:

Writable: can reassign value or not.
Enumerable: can enumerate it with for...in loop or not.
Configurable: can change the flags shown above and this flag or not.

Okay, the problem with the above cloning code is that when someone changes the flags to non-default values, and you unconsciously clone the object without knowing those property flags. In a nutshell, if you want to clone an object along with the flags, please do as following:


let newobj = Object.defineProperties({}, Object.getOwnPropertyDescriptors(obj));

Here we use Object.defineProperties(object, descriptors) and Object.getOwnPropertyDescriptors(object) to accomplish this. The former will define properties for the objects in the first argument ( here is an empty object literal. ) with the property descriptors in the second argument ( here is the latter function getOwnPropertyDescriptors. ). However, although the code is cleaner, this method should be employed only when you really need to clone the property descriptors since it is slower and not straight-forward enough.

For more on Property flags and descriptors:

2018年6月9日 星期六

Kivy PongGame adaption

markdown Lately I try to do some side projects and I found an app might be great. So I start to look for some Python libraries as a GUI solution. I compared Tkinter, PyQt, WxPython,  Kivy. I want it free, modern, and have good API reference. Tkinter looks old, PyQt is not free and API of PySide is somewhat difficult for me to read. WxPython is good, but I like the UI of Kivy more. Therefore I have gone through the tutorials and Development guide, and also the PongGame one. Following the steps is really easy and it did not take much time to complete. As the author said, the app was the bare minimum to understand the application development in Kivy, so I made some improvements, mostly to make it more naturally, and I think share it would be interesting. Here are the improvements I did: 1. Instead of Touch event( hard to play by PC users), I try to read the API and use Window.KeyBoard class. 2. Moving the paddle was not smooth and it can stuck when you change direction promptly. Here it is: #pong.kv ``` #:kivy 1.0.9 #step2 : size_x:self.size_x size_y:self.size_y size: self.size_x, self.size_y canvas: Ellipse: pos: self.pos size: self.size : size: 25, 200 canvas: Rectangle: pos:self.pos size:self.size : #ball id here ball: pong_ball p1: player_left p2: player_right canvas: Rectangle: pos: self.center_x - 5, 0 size: 5, self.height Label: font_size: 70 center_x: root.width / 4 top: root.top - 5 text: str(root.p1.score) Label: font_size: 70 center_x: root.width * 3 / 4 top: root.top - 5 text: str(root.p2.score) PongBall: id: pong_ball center: self.parent.center PongPaddle: id: player_left x: root.x center_y: root.center_y PongPaddle: id: player_right x: root.width - self.width center_y: root.center_y ``` #PongGame.py ``` #Original by the author of Kivy- inclement, Adapted by iamlockon on 2018-06-09 #More PongGame information from the author: #https://kivy.org/docs/tutorials/pong.html from kivy.app import App from kivy.uix.widget import Widget from kivy.properties import NumericProperty, ReferenceListProperty, ObjectProperty from kivy.vector import Vector from kivy.clock import Clock from kivy.core.window import Window class PongPaddle(Widget): score = NumericProperty(0) #setting paddle speed vel_paddle_y = NumericProperty(0) #track the key states with mask key_mask = NumericProperty(0) def bounce_ball(self, ball): if self.collide_widget(ball): vx, vy = ball.velocity offset = (ball.center_y - self.center_y) / (self.height / 2) bounced = Vector(-1 * vx, vy) vel = bounced *1.1 ball.velocity = vel.x, vel.y + offset def move(self): #12,3: both pressed ; 0: both unpressed --> stop if self.key_mask in (12, 3, 0): self.vel_paddle_y = 0 #8,2: pressing up if self.key_mask in (8, 2): self.vel_paddle_y = 8 #4,1: pressing down if self.key_mask in (4, 1): self.vel_paddle_y = -8 self.center_y = self.vel_paddle_y + self.center_y #step2 class PongBall(Widget): size_x = NumericProperty(50) size_y = NumericProperty(50) velocity_x = NumericProperty(0) velocity_y = NumericProperty(0) velocity = ReferenceListProperty(velocity_x, velocity_y) def move(self): self.pos = Vector(*self.velocity) + self.pos class PongGame(Widget): ball = ObjectProperty(None) p1 = ObjectProperty(None) p2 = ObjectProperty(None) def __init__(self, **kwargs): super(PongGame, self).__init__(**kwargs) #Get a keyboard instance self._keyboard = Window.request_keyboard( self._keyboard_closed, self, 'text') if self._keyboard.widget: pass #Binding key events to keyboard self._keyboard.bind(on_key_down=self._on_keyboard_down) self._keyboard.bind(on_key_up=self._on_keyboard_up) def _keyboard_closed(self): print('My kb has been closed!') def _on_keyboard_down(self, keyboard, keycode, *args): ''' Setting the key_mask of paddles(players) respectively. You might need some bitwise operation knowledge to understand this. 'c' for player 1 up, 'v' for player 1 down. 'n' for player 2 up, 'm' for player 2 down. bit: 4 3 2 1 key: c v n m ex: 0 1 0 0 -> 4, player 1 goes down ex: 1 1 0 1 -> 13, player 1 stops, player 2 moves down ''' if keycode[1] == 'c': self.p1.key_mask = self.p1.key_mask | 8 return True if keycode[1] == 'v': self.p1.key_mask = self.p1.key_mask | 4 return True if keycode[1] == 'n': self.p2.key_mask = self.p2.key_mask | 2 return True if keycode[1] == 'm': self.p2.key_mask = self.p2.key_mask | 1 return True def _on_keyboard_up(self, keyboard, keycode): if keycode[1] == 'c': self.p1.key_mask = self.p1.key_mask & 7 return True if keycode[1] == 'v': self.p1.key_mask = self.p1.key_mask & 11 return True if keycode[1] == 'n': self.p2.key_mask = self.p2.key_mask & 13 return True if keycode[1] == 'm': self.p2.key_mask = self.p2.key_mask & 14 return True def serve_ball(self, vel=(4, 0)): self.ball.center = self.center self.ball.velocity = vel def update(self, dt): self.ball.move() #go outside the fringes, pull it back 2 pixels to make sure it can still move. if self.p1.top > self.top: self.p1.top = self.top-2 if self.p1.pos[1] < self.x: self.p1.pos[1] = self.x+2 self.p1.move() if self.p2.top > self.top: self.p2.top = self.top-2 if self.p2.pos[1] < self.x: self.p2.pos[1] = self.x+2 self.p2.move() self.p1.bounce_ball(self.ball) self.p2.bounce_ball(self.ball) if (self.ball.y < self.y) or (self.ball.top > self.top): self.ball.velocity_y *= -1 if self.ball.x < self.x: self.p2.score += 1 self.serve_ball(vel=(4,0)) if self.ball.x > self.width: self.p1.score += 1 self.serve_ball(vel=(-4,0)) class PongApp(App): def build(self): game = PongGame() game.serve_ball() Clock.schedule_interval(game.update, 1.0 / 60.0) return game if __name__ == "__main__": PongApp().run() ```

2018年5月13日 星期日

Python筆記:資料處理

Python3字串

Python3字串是Unicode字元字串,不再是byte陣列字串。

unicodedata模組

1. unicodedata.lookup(case-insensitive name)會回傳一個Unicode字元。
2. unicodedata.name(Unicode character)會回傳一個大寫的字元名稱(name)。

編碼與解碼

和外界交換資料時,我們必須知道以下兩件事:
  •  把Unicode字元字串編碼為byte的方式
  • 把byte解碼為Unicode字元字串的方式
1. 由於UTF-8是Python, Linux, HTML的標準編碼格式,因此在許多方面都建議使用該格式為字串進行編碼。

格式字串(string formatting)

和C/C++很相似的,%s,%x可以用來在字串中加入值,以下列出常用的代號:

%s :字串
%d:十進位整數
%x:十六進位整數
%o:八進位整數
%f:十進位浮點數
%e:指數浮點數
%g:十進位或指數浮點數
%%:印出"%"

使用的方式是 " %s " % 值,用括號包起字串後加上百分符號,然後再加上值(如果有複數的話則用tuple):

>>> "The dog %s is %f year-old." % ("Jim", 10)
The dog Jim is 10 year-old.

如果需要把欄位寬度設為某個值,只要在"%"和類型指定符之間加上數值就可以了,預設正數會向右對齊(左邊以空格填充),負數會向左對齊(右邊填充空格)。如果要設定字元寬度的話,則是再加上小數點後加上數值:

>>> "%10.5d %10.3f %10.4s" % (1041, 91.14141, "Goodddd")
'     01041     91.141       Good'
>>> "%10.3d %10.3f %10.4s" % (1041, 91.14141, "Goodddd")
'      1041     91.141       Good'

從以上第二個指令結果來看,當字元寬度限制被加在整數上,似乎會無效。
我們甚至可以搭配" * "來傳入設定欄位寬度和字元寬度的值,以彈性變更:

>>> "%*.*d %*.*f" % (10, 4,4452, 3,6, 234.2115514)
'      4452 234.211551'

要注意的是,使用%來格式化字串的方式是舊有的方式,如果以Python3撰寫程式的話,建議使用以下介紹的新方式來操作。

使用{}與format做格式字串

廢話不多說,上例子:

>>> '{2} {0} {1}'.format("First", "Second", "Third")
'Third First Second'

大括號中的數字會參考到tuple中相對應index的值。我們也可以在format的引數加上關鍵字參數或是字典:

>>> "{n} {f} {s}".format(n='12', f=2134, s='\u2603')
'12 2134 ☃'

 >>> "{0[n]} {0[f]} {0[s]} {1}".format({'n':53, 'f':3.33, 's':'rwer'}, 'hey')
'53 3.33 rwer hey'


注意到字典範例中的"0"嗎?它代表format中的第一個項目(字典),然後我們再對該參數(視"0"為一個字典類型的變數)取值。

 新方法也可以使用舊方法的一些格式參數:

>>> "{0:<10d} {1:>10.2f} {2:^s}".format(42, 6.231, 'straw')
'42               6.23 straw'

藍色字體的是表示對齊方向,"<"表示向左對齊,"^"表示置中。要注意整數在此就不適用小數點後的字元寬度設定,直譯器會明確地指出錯誤。

>>> "{0:<10.2d} {1:>10.2f} {2:^s}".format(42, 6.231, 'straw')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Precision not allowed in integer format specifier

我們還可以用空格以外的字元來填充欄位空白,只要在":"的後面加上該符和對齊字元(必須)就行了:

>>> "{0:@^25.11s}".format("Hello")
'@@@@@@@@@@Hello@@@@@@@@@@'

二進位資料

二進位的資料在處理上會遇到位元組順序(Big-endian, little-endian)以及整數符號位元(最大位元, most significant bit)的問題,讓我們繼續看下去。

1. byte類型的物件是不可變的,就像byte類型的tuple。
2. 另一種表示二位元資料的類型是可變的,稱作bytearray,就像byte的list一樣。
3. struct模組的unpack(), pack()函式可以用來在byte序列和Python資料之間轉換:

>>> data[1]
80
>>> data[:1]
b'\x89'
>>> data =b'\x89PNG\x00\x35\xff\x02\x51\x41sqty'
>>> data
b'\x89PNG\x005\xff\x02QAsqty'
>>> data[0]
137
>>> data[1]
80
>>> st.unpack('>b',data[:1])
(-119,)
>>> st.unpack('>B',data[:1])
(137,)
>>> st.unpack('>bb',data[:2])
(-119, 80)
>>> st.unpack('>BB',data[:2])
(137, 80)
>>> st.unpack('>L',data[2:6])
(1313275957,)
>>> st.unpack('>L',data[2:7])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
struct.error: unpack requires a bytes object of length 4
>>> st.unpack('>b',data[:1])
(-119,)
>>> st.unpack('<b',data[:1])
(-119,)
>>> st.unpack('<L',data[:4])
(1196314761,)
>>> st.unpack('>L',data[:4])
(2303741511,)

unpack, pack的第一個參數都是用來指示如何解釋第二個參數的模式,">"代表Big endian,也就是我們要指定原本的位元組順序為「以最高位元開頭」,注意到這裡很容易混淆的是endian代表的字義並不是「結尾」的意思,而是「端」的意思。所以Big endian才會是「以最大的那端做開頭」的作法。可以觀察如下範例:

>>> st.pack('>L',154)
b'\x00\x00\x00\x9a'
>>> st.pack('<L',154)
b'\x9a\x00\x00\x00'

基本上網路資料傳輸都是Big endian,這樣的表示法也會和十六位元的讀取順序一致(由左至右)。至於Endian模式之後的"b", "L"則是對資料的格式做限定,"b"代表有號(signed)的單個byte,"L"代表無號(unsigned)的4-bytes長整數(long)。其他的資料格式代號可以參考這裡

4. 內建的binascii模組可以用來在二進位資料與各式各樣的字串格式做轉換,例如base 16, base 64, uuencode等:

>>> import binascii as ba
>>> va = b'909090234234'
>>> va
b'909090234234'
>>> ba.unhexlify(va)
b'\x90\x90\x90#B4'

但如官網文件所述,這是一個比較低階的模組,通常不會直接使用它,而是使用如uu, base64, 或binhex這些模組來處理。





2018年4月29日 星期日

TCP學習筆記


ARQ

在傳輸層以下的底層通道可能會造成封包位元錯誤(由於封包傳輸,傳播,暫存在網路中的實體元件)的時候,我們可以和接電話一樣想像如何確保資訊正確:

使用肯定/否定確認(Positive Acknowledge),以此建立具重送機制的自動重複請求(Automatic Repeat Request, ARQ)協定。
因為這種機制的關係,ARQ協定需要三種額外的功能:

1.錯誤偵測:檢查位元錯誤(ex:UDP checksum欄位)。
2.接收端回饋:ACK, NAK,通常僅需要一個位元(ex: 0 for NAK, 1 for ACK)。
3.重送:經過以上的偵測後如果有問題,就要有重送的功能。

可靠連線

序號(sequence number)欄位可以用來編號封包,除了可以解決ACK/NAK封包可能損毀的問題,也讓協定的接收端可以確定封包是否為重送。

接收端送出重複的ACK(duplicate ACK)可以用來代替送出NAK,讓傳送端知道該ACK標註的封包序號之後的封包並未被接收到(P3-26, rdt2.2)。

計時器可以處理封包的逾時並重送。主要觸發條件可能是封包遺失,也可能是傳輸延遲過長。

TCP連線

連線狀態存在於終端系統上,而不會在中介網路元件(路由器, L2 switch..)上。
這種連線是一種點到點(point-to-point)的全雙工服務(full-duplex service)。

TCP連線管理

假設用戶端應用程式行程想跟伺服端上的某筆行程建立連線,以下為步驟:
  1. 用戶端TCP會先傳送一筆不含應用層資料的TCP區段,其SYN bit會被設為1,因此這種特殊區段又被稱作SYN區段。同時用戶端會隨機選擇一個初始序號(client_isn)並放入SYN區段的序號欄位。
  2. 當包含此區段的IP資料報抵達伺服端主機,伺服端就會取出SYN區段,配置TCP緩衝區與變數給這筆連線,然後送出一筆也不包含應用層資料的SYNACK區段,其標頭有3項重要資訊:

    • SYN bit被設為1
    • 確認欄位被設為client_isn+1
    • 序號欄位會設為伺服端自己的初始序號(server_isn)
    • 其意義為:「我已經收到要求開啟連線的SYN封包,其序號為client_isn。我同意建立此連線,並且決定我的初始序號為server_isn。
  3.  當用戶端收到SYNACK封包,也會配置TCP緩衝區與變數,並送出具以下標頭的確認區段:
  • SYN bit被設為0(因為連線已經建立)
  • 確認欄位被設為server_isn+1
  • 在此區段中可能就會有給伺服端的資料
在以上三步驟完成之後,未來所有的區段的SYN bit都會設為0。由於會互相傳送三份封包來建立連線,此程序又被稱為三向交握(three-way handshake)。





Python筆記:物件與類別

類別

__init__(self)是在Python中的類別建構子(class constructor,就像C++中和類別同名的成員函式),其中self參數代表正在被建構的物件本身。此方法並非必要

繼承

在Python中,父類別又稱為parent, superclass, base class,子類別又稱為child, subclass, derived class。以下範例可以看到Yugo繼承Car,及複寫Car的成員方法。

當我們想要在子類別中呼叫父類別的函式時,我們可以在函式名稱前加上super()。如果子類別需要定義新的作法,但是又需要父類別的作法時,使用super()可以確保子類別沒有重複的程式碼,且當父類別定義被更動時,我們不需要更改子類別就能反應其改變。

特性(property)

特性可以作為用來裝飾物件屬性(attibute)的介面,有兩種方式可以使用它:
1. 先定義getter, setter之後,把property(getter, [setter])指派給該屬性。
2. 用裝飾器,@property放在getter之前,@attibute.setter放在setter之前。
如果沒有藉由特性的以上兩個方法來指定setter給某屬性的話,就無法直接改變該屬性,這對於唯讀的屬性來說很方便。注意到getter是必要的,如果沒有getter的話會無法編譯程式。

用__attibuteName來隱藏屬性

在屬性前面加上雙底線可以建立"表面上"只有類別定義域內可以存取的屬性(因為如果我們用該屬性名稱或是加了雙底限的屬性名稱去存取會找不到該屬性),但如果真的要從外部存取的話,可以用_ClassName__attibuteName。

方法類型

除了實例方法(在方法的第一個參數使用self的方法)之外,還有類別方法(在方法的第一個參數使用cls),並且在方法宣告前一行要加上@classmethod。類別方法會共通於所有的實例。通常會用來紀錄關於類型的資訊(類型各物件的數量、類型的狀態等等)。另外還有靜態方法,以@staticmethod開頭,這種方法是唯一不需要帶入任何參數的方法,通常用來處理屬於該類別相當一般化的工作。由於其靜態的特性,呼叫它甚至不需要建立物件。

重載運算子(Operator overloading)

Python中,如果我們的自定義類別需要重載運算子,可以定義以下函數(僅列出部份):
__eq__(self, other)    self == other
__ne__(self, other)    self != other
__lt__(self, other)      self < other
__gt__(self, other)     self > other
__le__(self, other)     self <= other
__ge__(self, other)    self >= other
__add__(self, other) self + other
__str__(self)   print(str())
__repr__(self)   object


Python筆記:模組、套件與程式

匯入模組(module)

整個檔案匯入可以用import filename或是局部匯入可以用from filename import function_name

我們也可以為匯入的模組取個別名(alias),例如把上圖的第二行加上 as ex,這樣就可以使用叫簡短的ex來使用該模組。第七行的匯入也可以依樣畫葫蘆。

模組搜尋路徑

Python會在sys標準模組的path此一變數中定義要去哪裡找尋匯入的檔案,其中第一行的字串代表當前目錄。我們可以印出該變數內容來看(上方3行是用來印出變數的程式):
同時我們也要注意因為自定義模組和標準模組名字衝突而造成標準模組函式無法正常使用。

套件(package)

透過在程式的目錄下新增一個名為__init__.py的檔案(無論有無內容),此目錄就會被視為一個套件。例如我們可以在主程式的目錄下新增一個src目錄,並在裡頭放一些模組檔案,還有__init__.py,這樣一來src目錄就會被Python視為一個套件(多個模組檔案的集合)。

通用模組介紹

1. setdefault(ele, default)的用途是在指定字典中某鍵"ele"的值時,如果該鍵值不存在則設定為"default"。
2. defaultdict(func)則是建立一個預設值為某種類型或內容的字典。func可能是int(), dict()等等,也可能是自定義的任何內容。例如,defaultdict(int)用來建立計數器相當方便,因為該字典內的元素的預設值為0。
3. collections套件中的Counter(list)則是內建的計數器,呼叫它會回傳一個Counter物件。該物件有一些方法如most_common()可以降冪回傳結果,或是用"&", "+","-"來對多個物件計算。
4. collections套件中還有OrderedDict()可以協助我們建立記得項目順序的字典。
5 collections套件還有deque(一種雙頭的序列資料結構,同時具有stack和sequence的功能)可以使用。

2018年4月28日 星期六

Python筆記:程式結構

迴圈

在Python中有個While/For迴圈搭配else的奇特用法(至少我沒有印象在Java, C/C++有看過),主要是在迴圈正常結束(沒有因為break而提早結束)時,進入到else的區塊中執行程式碼:

>>>pos = 1
>>>while pos < 5:
            if pos == 7:
                   break
            pos++
       else:
               #do nothing

以上展示了一個一定會進入else區塊的範例,因為pos永遠不會等於7,所以一定不會提早結束迴圈。else內可以放入只有迴圈正常結束才會執行的code。在for迴圈的使用方式也是一樣。

 迭代

1. zip()函式可以協助我們並行地迭代多個序列:

>>> animals = ['Dog', 'Cat', 'Elephant']
>>> colors = ['Blue', 'Yellow', 'Black']
>>> for animal, color in zip(animals, colors):
                 print( 'animal: ', animal, 'is in', color )
zip()回傳的是一個可迭代(iterable)的合併值,我們可以直接把此值轉換為list, dict...
2. range(start, stop, step)可以用來產生[start, stop)範圍的整數,並且每次數值會變動step的量。

生成式

1. list生成式:[ 運算式 for 項目 in 可迭代項目 ]

>>> mlist = [ num-1 for num in range(4,8) if num not 5 ]
>>> mlist
[3, 4, 6]

>>> a = range(2, 5)
>>> b = range(5,8)
>>> c = [(d,e) for d in a for e in b]
>>> c
(2, 5)
(2, 6)
(2, 7)
(3, 5)
(3, 6)
(3, 7)
(4, 5)
(4, 6)
(4, 7)

2. dict生成式:{鍵運算式 :值運算式 for 運算式 in 可迭代項目}

>>> word = 'letters'
>>> letter_counts = {letter: word.count(letter) for letter in set(word)}
>>> letter_counts
{'l': 1, 'e': 2, 't': 2, 'r': 1, 's': 1}

3. set生成式:{運算式 for 運算式 in 可迭代項目}

幾乎和list生成式一樣,只是換成了大括號。

4. 產生器生成式:(運算式 for 項目 in 可迭代項目)

注意到並沒有tuple生成式,上面的公式會回傳一種類型為generator的物件。這種產生器物件很特別,一旦被執行(例如用list()對它進行迭代)就無法再次使用。

函式(function)

1. 函式可以有任意數量及類型的參數(parameter),也可以回傳任意數量及類型的值,如果函式沒有使用return,呼叫函式之後會得到None:

>>> print(no_return())
None

None在Python中是一個特殊的值,它與False不一樣,雖然在布林運算中它屬於false。我們可以用is運算子來分辨遺漏值(missing value)與空值(empty value, 例如 ''、[]、(,)、{}、set())。

2. 函式的參數定義中可以有預設值,但是我們如果指定可變的值(串列、字典等)當作預設參數,該參數會被保留在函數的域(scope)當中,下一次呼叫該函式時,該預設參數的值會是上一次呼叫結束時的值。

3. 在函式呼叫時也有位置參數(照位置順序)及關鍵字參數(照參數定義)兩種方式。且位置參數及關鍵字參數可以混合使用。但是要注意混合使用時位置參數必須都在前面。

4. 用" * "來收集位置參數,例如foo(arg1, arg2, *args),args在此是tuple類型;用" ** "來收集關鍵字參數,例如bar(**kwargs),kwargs在此是dict類型。args和kwargs都是可隨意定義的參數名稱。

5. 文件字串是用來在函式定義的開頭加入一些說明用的,可以用'docstring'或'''docstring'''的方式加入,並使用help()來印出格式化的文件字串,echo.__doc__則是印出原始的文件字串。

閉包(Closure)

這其實就是一種內部函式,只要理解到所有函式本身所包含的區塊都是一個scope,在那個區塊當中的任何物件都認識彼此,因此當我們把這個內部函式用某種方式(例如當作回傳值)帶到更外部的scope時,我們就能把該scope的相關變數也帶過去。

>>> def foo(high):
             def inner():
                   return high
             return inner
>>> a = foo('Good')
>>> a()
'Good'
>>>type(a)
<class 'function'>

產生器(Generator)

產生器是一種序列(sequence)建立物件,可以用來迭代很大的序列,而不需在記憶體中儲存整個序列。通常產生器會是迭代器的資料來源。特別的是,每次迭代產生器時,它都會記得之前的呼叫(但其實類型還是一般的函式,除了把return改為yield之外並沒有什麼特殊的)中回傳的值到了哪裡。我們可以自己寫產生器函式:

>>> def giveMagicNumber(end):
               val = 1
               while val < end:
                       yield val * 9487
                       val++
>>> type(giveMagicNumber)
<class 'function'>
>>> a = giveMagicNumber(484)
>>> type(a)
<class 'generator'>

裝飾器(Decorator)

裝飾器可以拿來修飾原有的函式,例如加入除錯的log或是稍微在函式原有的執行流程上加入一些處理。我們可以直接呼叫裝飾器:


在以上的例子中,deco是裝飾器,add是原函式,可以看到在第10行我直接呼叫該裝飾器且加上參數,當然我們也可以先myNewFunc = deco(add)建立一個被裝飾過的函式後再呼叫也可以。Python中也可以直接把裝飾器加在函式定義上一行,告訴直譯器我們要直接裝飾原函式:

如果有多個裝飾器,會先執行最靠近函式的那個,再依序往上執行。







2018年4月23日 星期一

Python筆記:串列(list)、Tuple、字典(dictionary)、集合(set)

List&Tuple

1. 與字串不同,tuple與list的元素可以是不同的類型,且可以是任何Python物件
2. list可以用[Object A, ObjectB, ...]的方式建立。
3. list()可以用來建立empty list。也可以用來轉換其他資料結構為list:


>>>list('meow')
['m', 'e', 'o', 'w']

或是把tuple轉換為list:

>>> tup = ('a', 'b', 'c')
>>>list(tup)
['a', 'b', 'c']

4. 我們可以用[ : : -1]來把list內的元素倒置。

串列操作

假設mlist = [ 'a', 'b', 'c'] ; mlist2 = [ 'd', 'e', 'f']。
1. mlist.extend(mlist2)可以把串列無縫合併為 [ 'a', 'b', 'c', 'd', 'e', 'f']。
2. mlist += mlist2也是一樣的效果。
3. mlist.append(mlist2)則是把mlist2當成一個新元素加入mlist。
4. 用insert( pos, el ) 可以把el加到pos,超出pos的話會和append()一樣,加入結尾。
5. 用del mlist[pos]可以把位在pos的元素移除,注意到del是一種Python陳述式而非函式。
   這種特殊的陳述式是賦值( = )的反向操作。
6. 用mlist.remove(el)可以把el給移除。
7. mlist.pop(pos)會把位在pos的元素移出,預設是取出結尾的元素,相當於pos = -1。

從以上的操作之中,我們可以實作出LIFO(Last In First Out)或FIFO(First In First Out)資料結構。LIFO相當於堆疊(stack),可以用pop()和append()完成 ; FIFO相當於佇列(queue),可以用pop(0)和append()完成。

8. 用mlist.index(el)來找出某個元素的index,夠直白吧。
9. 用in來檢查list是否存在某值:

>>> mlist3 = [ 'bird', 'min', 'ham' ]
>>> 'min' in mlist3
True
>>> 'B' in mlist3
False

10. 如果要排序元素,可以使用sort()來就地(sort in place)排序,回傳list本身。如果要回傳副本的話可以使用sorted()。數字的排序預設是升冪,但我們可以用sort(reverse=true)來改為降冪排列。

Tuple

1. 因為其不可變的性質,我們可以說Tuple是constant list。
2. 我們可以用()來建立空tuple,也可以直接用mtuple = 'a', 'b', 'c'的方式建立tuple。
3. tuple unpacking指的是把一個tuple指派給多個變數,像是a, b, c = mtuple。
4. tuple可以用來交換變數的值,像是a, b = b, a這樣,就可以把a,b 各自所含的值給交換。

Dictionary

1. 字典又稱為associative array, hash, hashmap,其中的元素為鍵值對(key-value pair),鍵可以是任何不可變的Python類型:Boolean, Integer, Floating point, tuple, string....但是字典通常是可變的,這代表字典的元素可以被新增、刪除、改變。
2. 用{}來建立空字典。
3. 用dict(Object)來建立字典,其中Object可以是任何含有鍵值對的序列,包含類似'ab', ['a', 'b'], ('a', 'b')這樣的雙項目,都會被視為一組鍵值對 'a' : 'b'。
4. 用dict1.update(dict2)的方式來合併字典。
5. 用del dict1[key]的方式來刪除某個元素。
6. 用dict1.clear()來清除字典。
7. 用in來找字典是否有某個鍵。
8. 用dict2.keys()來取得包含所有鍵的一個可迭代(iterable)的dict_keys物件,這種物件因為不會像Python2回傳的list一樣佔用那麼多記憶體及消耗時間。
9. 用dict2.values()來取得所有的值,用dict2.items()取得所有的鍵值對。

Set

1. 集合就像是從鍵值對去掉值的字典。
2. 用set()來建立空集合,用大括號建立一般的集合。
3. 因為{}會被解譯器優先解譯為空字典,所以不能用{}建立空集合。
4. 用set(Object)來轉換其他類型的物件為集合。
5. 經常會用in來檢查集合內容或是設定迴圈變數值:

>>> alphabet = { 'a' : {'x', 'y', 'z'}, 'b' : {'y', 'z'}, 'c' : {x} }
for key, value in alphabet.items():
      if  'y' in value:
             print(key)

6. 用'&'或是intersection()來取得交集,或是用'|'或union()來取得聯集,或是用'-'或difference()來取得差集
7. 用'<='或issubset()來檢查子集合。用'<'來檢查真子集合(proper subset, 代表兩集合不一樣)。也可以用'>='或ussuperset()來檢查超集合(superset),用'>'來檢查真超集合(proper superset)。

2018年4月22日 星期日

Python筆記:數字、字串與變數

變數、名稱與物件

1.在Python中,所有的東西都是物件,物件會有一個類型(type),類型決定物件的特性。類別(class)則是物件的定義。在Python中兩者幾乎是同樣的意義。
2.Python是一種強類型(strong typing)的語言,意味著物件的類型無法變更
3.我們可以使用type(Object)來取得物件的類型:
>>>type(67)
<class 'int'>

數字

"/ "是浮點數除法運算子,"//"是整數的除法運算子:
>>>9 / 5 
1.8
>>>9 // 5
1
divmod(a, b)可以用來同時取得商和餘數:
>>>divmod(9, 5)
(1, 4)

基數

整數預設都是十進位,但是可以用0b/0B(二進位),0o/0O(八進位),0x/0X(十六進位)來表達其他基數的整數。

類型轉換

int(literal)可以把合法的literal轉換為整數。

字串

1. Python 3支援Unicode標準,這種處理標準的能力是Python2所不具備的。
2. 在Python中,我們可以用雙引號或單引號來包字串。也可以使用三個單/雙引號來建立多行字串
>>poem = '''This is a purposely created
multi-lined string.''''
這樣的方式產生的字串會包含所有內含的跳脫字元以及空格。
3. print()會自動把多個參數合在一起並在其間加上空格,並在結尾加上換行符號。
4. str()可以用來把其他資料類型轉為字串。
5. "*"可以用來複製字串。ex: 'A' *4。
注意:Python中的字串是不可變的。

Slice: [開啟:結束:間隔]

Slice可以用來擷取子字串:
  • [:]會擷取整個字串
  • [start:]會從start擷取到結束
  • [:end]會從開始擷取到end-1
  • [start:end:step]會從start以step個間隔擷取到end
其他函式:
1. string.split('delimiter')可以用來以特定字元分割字串。
2. 'delimiter'.join(sequence)可以用來結合序列。


2017年10月25日 星期三

Linux指令筆記-刪除package時,如何也刪除不再需要的package dependencies

在Debian Linux中移除不需要的package(包含所有相依套件(dependency)

當我們使用apt-get install安裝了軟體之後,發現裝錯或是不再需要,如果只使用


apt-get remove {套件名稱}

那麼剩餘的相依套件以及組態檔都將會留下,讓系統浪費不需要的空間。如果改用

apt-get purge  {套件名稱}

則會把相關的組態檔或紀錄檔一併刪除,但相依套件仍然會留下。如果要完全把相關的檔案

及相依套件都刪除的話,可以使用apt-get purge先移除除了相依套件之外的東西,然後再使

用以下指令

apt-get autoremove  

就可以把所有不再被任何package參考的相依套件給刪除掉。

2016年3月21日 星期一

交換生錦囊Info For Exchange Students to Japan-在日本辦手機號碼Having your cell phone number or cheap SIM card in Japan

大家好,好久不見。說好的手機文要來了。

概說(Introduction)

自從2015年5月1日日本總務省發布了規範SIM卡綁定的相關條例的解除(SIMロック解除の義務化)之後,從2010年就開始的手機自由化可以算是走到了一個新段落。話說從頭的話,就是日本的通信業者由於在手機販賣上各家削價競爭的緣故,這些便宜的方案到頭來其實還是要消費者長期的契約來達到回本的效果。因此,為了防止消費者跳槽,日本的4大業者都採用了SIM卡綁定的方式(不像台灣是違約金)來確保成本能夠回收。不過也不要覺得日本很奇怪,根據維基百科,美國的4大通信業者也有3間都採用同樣的手法。總之,隨著此項風氣的散去,近日日本的電信方案可以說是百花齊放、眾家爭鳴,想當然爾,對於消費者而言,適合自己的選擇也能變多。不管是家族一起的方案,或是學生方案,或是不想要綁約的留學生方案(我是這麼叫它啦...),現在都有很多選項可供考慮了。(因此,我來到日本之前特地為了手機研究了一陣子....)

(English Translation:
Since 2015.05.01 the Ministry of Internal Affairs and Communications of Japan asked domestic service providers to unleash the SIM lock regulations, the progress of cell phone liberalization has been coming to a new era. Long story short, because Japan mobile service providers compete strongly against each other, they have to redeem their lost during price down by constraining their customers with long-term contracts which came with a provider-based mobile phone model design. And that modification limited the compatibility of Japan mobile phones. But don't blame Japan too soon, because as Wikipedia said, in the US, 3 out of 4 of major service providers in the US employs this kind of approach to do the same thing. Anyhow, for customers like us, it turns out that we could have more cheap plans than we did before, so let's think in a more positive way lol.)

以下開始介紹我所知道的資訊,我會從現有的方案開始介紹,然後再介紹概括的使用流程,因為不才如我也只用過其中一家,對於其他同類的廉價SIM卡廠家的方式如果有出入還請指正^一^
(English Translation:
I will introduce you to the information I have known from the basics to application procedures needed, but my knowledge is limited, so please correct me if I am wrong.)

首先來個概略的介紹的話,就是

1.廉價SIM卡跟斯斯一樣分為三種,主要有純上網用(データ通信SIM)和可以發簡訊(SMS対応SIM)和可以打電話又可以上網(音声SIM)的三種。每個月繳的費用由前往後增加。仔細想想不需要緊急聯絡或是做大事業的人其實前面兩者就可以了。要用LINE或其他會發驗證碼到手機的網路服務的人必須要用可以對應SMS的SIM卡,因為純上網的SIM卡是沒有獨立電話號碼的。

2.通常需要一張信用卡(誰的都可以)來當作每個月付款的手段。(非常重要!!)

3.有的要綁約,有的不用。(我使用中的OCN就不用綁約,熱門的b-mobile就有限制使用5個月以上。)

4.在確定要使用之前請先確定自己的手機是"動作確認端末",否則到時候都買來了不能用。

5.像是我用的OCN mobile ONE有提供可以撥接電話的純上網SIM卡,方法是利用IP電話的概念(像是SKYPE一樣),要撥接都得開行動網路才行(我就是用這種,搭配的就是050開頭的號碼,有點像是半殘的電話號碼。有一些號碼無法撥通,包含一些免費撥接電話和緊急電話110.119等。詳細點此) 。

(English Translation:

First of all, the basics :

1. Kakuyasu sim card can be classified into 3 kinds in large, Data-only(データ通信SIM) and Data + Text Message(SMS対応SIM) and Data+ Text Message + Phone calls(音声SIM). The monthly fee will increase as the functions are included. If you need to use LINE or other online services that require cell phone verification or the like, please select SMS対応SIM since the Data only ones come without phone number.

2. You need a valid credit card(you can use anyone's card.) to achieve monthly payments.(Important!!)

3. Some plans have minimum contract period, some don't.( the provider I'm using doesn't require that, but some also popular ones require 5 months or more )

4. Make sure your device is compatible.

5. The one I'm using (OCN mobile ONE) provides Data-only sim card with IP telephony service combination, and they also have discount for that. Details in English

日本語が分かる冒険者へ(For those who read Japanese)

傳送點我(Compare plans)
上面的連結是我找了許久才找到的總結網站,裡面有當今日本絕大多數的留學生適合的方案可供參考,但是從價位上來說,對於長期居住的人也是非常適合的。不過要注意的是,大多數的公司都是用4大通信業者的線路來提供服務,所以在挑選的時候,該業者使用的線路也是一個重點。

(English Translation:
The link above will direct you to a summary website that tells you everything about Kakuyasu sim card, and hopefully you will be able to find one that fits you the best. Since these plans are provided by minor companies using major service provider's networks, when you compare among them, you may want to pay attention to the  service provider they use.)

有幾個主要業者提供每個月改變方案內容的服務,例如一個月3G太少不夠用,下個月提升到5G,而且只要在手機上的業者提供的APP動動手指就可以完成申請;或是提供高速開關的服務,如果想要節省流量使用的話,可以平時把高速開關關上,這樣就只會用低速上網(但是對於LINE或是FB文字瀏覽其實是足夠的),就不會用到流量了。

(English Translation:
There are some companies provide you with monthly adjustment service, for instance, if you want to lift the capacity from 3G/month to 5G/month just on your phone with their APP; or you want high speed switch that help you with using your capacity economically.)

講這麼多,其實看得懂日文的點進去上頭的網站看一看就都會懂啦。


(English Translation:

Sorry to be verbose, if you will, you can just click on the link above and check for yourself.)


主要流程(Procedures)


因為我不想要再繼續幫我使用的公司打廣告了(同時也因為我懶了XD),所以我只概括介紹一下大致上的申請流程
(English Translation:
Because I don't feel like advertising the service I am using( also since I am a bit tired lol), I will concisely summarize the procedures you might be interested to know. )

1.確定自己的手機是動作確認端末之一,然後訂購和自己手機的SIM卡SIZE一樣的SIM卡包。可以從Axxzon.jp或Rxxxten買到,也可以去找實體店鋪,不過因為展店通常不多,可能網購比較方便。

2.取得該公司的SIM卡包(通常會含有SIM卡和申請流程所需的SIM卡資訊)。

3.照著SIM卡包的提示進行登錄手續,這時候你會需要信用卡、現住地址的資訊在你手邊,也有可能會需要一個朋友的日本手機號碼(不能是050開頭)來接收驗證碼(就跟LINE的驗證碼一樣的東西)。

4.結束。

(English Translation:
1.Make sure your cell phone is compatible, and order the SIM card pack corresponding with your cell phone's SIM card Size(there are nano, micro, standard...). Usually you can get one from Amaxxx.jp or Rakuxxx, or pay a visit to their shops, however, net purchase is often faster.

2.Getting your SIM card pack.(Usually comes with the SIM card and manual with registration info.)

3. Follow the instructions to complete registration procedures, this is the time you will need a credit card and your residence address beside you. Also you might need a valid cell phone number in Japan(cannot be 050 numbers.) to receive verification password( like the one LINE ask you to type sometimes when you login in a new device)

4. Done.

看在我熬夜從12點敲鍵盤到3點的份上,別太苛責我說明得不夠有條理吧XD
算是我去年9月的記憶的剩餘部分和使用後的經驗,祝各位辦手機順利囉~

Given that I wrote these words down from 0 A.M to 3 A.M, please don't blame me too much for being verbose and illogical lol. Last but not least, best wishes for all you coming to JP!

2015年11月1日 星期日

日本東京外國語大學(TUFS)交換心得-從準備到來日本

因為各種原因,現在冷冰冰的手指不知道要從哪些片段開始談起。
這篇文章主要是想分享透過台大的交換學生計畫來日本交換留學後的生活,
前面會講一些交換申請的經驗,雖然會很簡短但是應該都是重點。

申請前

依照重要性排序的話:

1.顧好全學年的GPA,想大四出去就顧好大二成績,想大五出去就顧好大三成績。
2.語言檢定,日語組最好拿個N2或N1,但這只是一塊必要的敲門磚,事實上,GPA幾乎代表一切。
3.做一些讓別人感覺你有想去認識這個國家,這個文化的事情,例如某些社團。台大的話就是台灣日本學生交流會為大宗,裏頭有許多學生都會有跟你共同的喜好,也出產很多歷屆交換生。

申請中

主要就是撰寫自傳和讀書計畫,有機會記得找優秀前輩的範本看看(我分數頗低,都只有3.7,還是別伸手了XD),然後自傳的話其實個人認為跟成績評分的重複性滿高的,除非你的優秀不到拿書卷獎的地步。因為如果有書卷獎的話寫進自傳我就不相信評審會無視(我是沒得寫啦),關於這一點我是覺得滿可惜的。事實上就是你的GPA幾乎決定你會去哪兒。

讀書計畫就是找一間你比較會寫的,有興趣的去寫就行了,這不多說。

然後資料上傳好(包含成績證明,名次證明,身分證,學生證等等)之後,就等交換名次出爐。
我記得我看到我在日語組成績的時候一瞬間眼前黑了一片,因為真的超級後面(印象中總成績是3.600,GPA部分是3.533,自傳和讀書計畫都是3.700)。接著就第一次志願選填,上了就看滿不滿意,不滿意就放棄,可以參加第二次志願選填(但是要是第二次沒有上....XD)

錄取後


我個人是在第二階段才錄取東京外國語大學的,算是相當幸運。雖然身為機械系的一員我覺得自己應該真的要到一間具備工程學科課程的大學去,但是想想我已經垂垂老矣的大五交換生活,現在這樣應該比去到任何一間大學讓我繼續讀機械專業還要好得多(不諱言,我對純機械系研究的東西真的沒什麼興趣,而且我希望來日本主要的目的是學語言和玩耍)。

錄取後需要做的事情就是提出一些對方學校要求的文件,例如東外大會要JASSO essay(格式是英文,印象中約200字。對方學校要幫你申請日本政府的獎學金用的,盡量寫好一點),還有健康檢查證明,其他都不太重要就不提了。健康檢查證明主要是去任何一家醫院,拿著東外大給的格式的檢查項目單,一一檢查完就可以了,東外大的項目不多,很快就能結束,但是有個胸部X光的項目,所以要等幾天才能拿結果。

接著就等對方傳來We are glad you are a recipient now的好消息,這代表你/妳已經成為正式的交換生了。在這個時間點之後再開始辦一些出國手續比較穩當。東外大是在5/8通知我這件事情的。然後再等JASSO的消息,我是在7/15收到消息。

至於出國手續的部分,最重要的是護照和簽證,護照的有效期要涵蓋交換期,簽證要等對方學校寄在留資格證明書給你才能去位在慶城街的日本交流協會辦。另外還有旅遊平安險,學校是說如果沒保的話有權終止交換生的交換權利。還有一張機票,我個人是買幾乎跟來回一樣貴的單程日本航空經濟艙,因為來回年票更貴,而且我中間並沒有計畫要返台。


出發前

呼,終於來到出發前了。

建議大家可以善用各家航空公司的線上報到(online check-in)服務,這樣當天到機場就可以享有幾乎是商務艙旅客的優先掛行李資格,看著長長的經濟艙人龍慢慢排。線上報到服務就是先確認你/妳的航班所有資訊,包含你/妳這個人的所有資訊,完成之後就可以取得登機證(搭乗券),拿著它和護照基本上就可以上飛機了。如此一來,到機場之後就可以直接去掛行李的優先櫃台,不用擠一般櫃台。

想在日本打工的人,記得準備好紙本的資格外活動許可申請書,說明網站連結在此


至於行李的部分,我個人建議是帶一些在日本第一天就必須用到的物品,例如衣服,錢(至少帶個10万円比較安全,如果想要盡快把一切物品買齊又不想被收手續費,無論是海外刷卡或是領錢),盥洗用品,文具用品,鞋子(洗澡時穿的和室內穿的,可以帶兩雙),電鍋。個人覺得電鍋可以用寄的,但是可能要付出幾乎要四分之一或是整個電鍋的錢去寄它。然後信用卡我覺得是必備的,不管是在辦手機或是Amazon.jp或是在缺乏現金且金額較大的消費時。我會另寫一篇文章介紹關於日本辦手機的情報,因為這很重要(如果想要省點錢)也很不容易完全弄懂。

從這裡開始就會比較偏向針對有志到外大的留學生的介紹。

抵達後

抵達之後,在入境關卡那邊,如果有想要打工的人記得出示預先準備好的資格外活動許可申請書。入境審查官隨後會給你/妳背面有蓋資格外活動許可章的在留卡。入境之後,外大應該會有志工在機場等大家(如果有申請),只要在出境大廳附近注意一下拿牌子的人就可以了。我是在成田機場降落,因此我先搭了利木津巴士到吉祥寺(利木津巴士可以寄放2箱行李在車上,所以注意別帶太多行李,像我帶3大包1筆電就有點吃力),在吉祥寺也會有人迎接,這時候就搭JR中央線到武藏境之後,轉搭小田急多摩川線到達多磨站(注意是多磨站不是多摩站,雖然應該不太會搭錯),從多磨站再拖著行李走大約15分鐘(沒行李大概10分鐘)就會穿越東京外國語大學,抵達國際交流會館。接著就可以正式進入宿舍。

宿舍概況(Dormitory Condition)

我想幾張照片勝過千言萬語。




























我住在2號館(I live in Dorm 2),和1號館的差異就是沒有獨立衛浴(no bath-unit),但是空間大很多(Much larger space)。但!!是!!獨立衛浴帶來的舒適會讓你每個月多2000日圓以上的水電費。
而且洗澡還要先開熱水器等10~20分鐘。2號館的公共衛浴不但不用錢,而且還需要刷卡才能進去,裡面有洗衣機和烘衣機還有電熨斗,基本上設施精良。兩棟的月租費(monthly pay)都是21000 yen,不含水電費(without electricity/water bill)。

1號館的公共設施有食物販賣機,健身器材,桌球桌,球具,談話室,音樂室,圖書室,電腦室(可以掃描,列印,影印,都不用錢)還有設備充足的廚房,5樓還有電動遊戲室(還沒去過)。

2號館以上通通都沒有,但別傷心,1和2號館是相連的。

除此之外兩棟的各樓層都有微波爐和烤箱(微波爐只有2F以上有),還有公共的飲食區(有桌椅)。

除了沒有飲水機之外(學校幾乎都沒有公用飲水機),這棟宿舍非常的棒。不但房間很大(2號館優勢),而且設備完整,又在學校裡面(Inside the campus),上課走路到教室絕對不超過10分鐘。 唯一的外部缺點就是旁邊一邊是校內操場兼棒球場兼美式足球場,一邊是足球場。常常白天會很熱鬧,因此可能希望天天睡到12點的同學們會很想要撞牆。

另外一個缺點就是附近缺乏一間大型超市,騎腳踏車都大概需要10分鐘才會抵達。不過能抵達非常不錯的生鮮超市。不過基本上如果不挑食材的話學校大門口就有可以買到很多蔬果和炸物和食物的超商,車站附近更有一些傳統市場可供選擇。(我個人是都習慣去全聯式的賣場買生鮮蔬果)

抵達手續


抵達之後,可以開始採買一些日用品,到入學式結束之後,tutor會親自帶你/妳去府中市役所辦理遷入手續和郵局帳戶和手機(如果要買新手機或是跟電信商綁約)。這裡有個重點,就是到了日本之後,基本上是要先辦理遷入取得在留卡的背面住址,然後才能去郵局辦帳戶(登錄內容中需要住址)。這裡的重點是,取得住址之後才可以去辦手機號碼。

交通和生活機能(Access to everywhere and Convenience)

基本上學校位在多磨站(Tama eki),從多磨站到新宿大約半小時;另外一個車站就是飛田給站,那裏到新宿比較快,大約20分鐘。從宿舍前往飛田給走路約需20-25分鐘,騎腳踏車約需10分鐘。

食(不需搭電車): 

學校食堂(很便宜,1F只開中午,2F開到晚上,都只有平日營業,2F有沙拉吧和小餐廳)

學校正門口: スリーエフ、可麗餅、立ち食いそば(推薦,但小貴)、焼肉や、パンや。

多磨駅:三吉(推薦)、日本屋、LAWSON、ファミマ。

味の素スタジアム:肯德基,美式餐廳,日式餐廳

飛田給駅:LAWSON 100,すきや、オリジン弁当(不想煮菜的話可以來買配菜,不想煮飯可以來買飯,也可以在店內用餐,個人推薦スタミナ丼),麥當勞,居酒屋,日式料理,中華料理

食(需搭電車): 

武藏境:南口北口附近(北口較多,有一整條街,還有假日也會開的郵局ATM), イトーヨーカドー

府中:各種餐廳。

自炊:

菜(距離順):學校正門口スリーエフ,多磨駅八百屋(開到傍晚)、みなとや(飛田給南口)

スーパー(商品多樣):飛田給マルエツ、コープみらい(西調布附近)、さえき若松町,サミット(東府中附近),CHETOS(府中)

藥妝、生活用品、米,食物: ウエルシア(警察學校對面)、武蔵境イトーヨーカドー

衣:

飛田給:UNIQLO

百貨:

東府中:唐吉軻德(所有東西,但沒什麼蔬菜且有怪味道),ニトリ(寝具)

調布:SEIYU(零食很便宜),PARCO

府中:伊勢丹,駅ビール大創,アートマン

武蔵境(南口):イトーヨーカドー

休閒(Leisure):

如果你/妳喜歡比較安靜的地方(決不是鳥不生蛋,是比較安靜),這裡是個非常好的地方,
住在這裡雖然買很多東西不是很方便,但是旁邊有很多公園,還有很多著名的觀光地,
不管是賞紅葉,賞櫻花,散步,慢跑,看星星,看歐式建築,騎腳踏車亂晃,這裡都是非常
適合的所在。如果想要一個到人潮熙攘的市區只要半小時的悠閒步調生活圈的話,東外大
的環境絕對是屈指可數的。非常適合養老,真的。Very laid-back here, I promise.


課程

   在外大,課程有分三種,第一種是JLC(Japanese Language Center)的課程,主要是給留學生的日語全方位課程,可修可不修,一開學會為大家分級(簡單考試,像日檢一樣,然後依照分級去上課。(如果吃力的話,也可以修比較下級的課程)

   另外就是學部生的課,有兩種,一種是ISEP課程(就是完全開放給留學生的課程,但日本人也會去修),另一種是各學部的課程(基本上課堂上會都是日本人。留學生要修的話需要跟任課老師要簽名,且要特別填一張申請單,一堂課填一張)。因為學部的課程我覺得比較跟語言研究相關(自己對那些比較沒有興趣),所以就只修了可以寫程式的言語情報學。然後其他ISEP的課就是幾乎是英文授課,日文授課主要是一些日本文化的課程,例如浮世繪,神社,歌舞伎。

  自己覺得我上到的課程都還滿有趣的,除了Japanese Mythology以外(不過內容是很有趣啦,主要是教授的講課方式我不太能接受,花很多時間去念課文),我幾乎都挑可以在課堂上和同學互動討論的ISEP課程。可以認識來自世界各地的人們,有著不同的想法和做事風格

==========================================================

大概敲了鍵盤快兩小時半,可能有許多遺漏也說不定,但是這是我目前想到可能對別人有所幫助的資訊,總結而言,我認為東外大對於想來學習語言(最特別的是,任何語言)的人,應該是一個非常理想的地方。但是如果想在這裡學習跟語言、文化無關的專業領域,就可能比較不適合。

這裡的學生幾乎都有留學經驗,也有將近20%是外籍師資,15%是國際學生,氣氛上來說是非常像地球村的。一堂關於文化的課可能就會有超過20個國家的人們,而且幾乎都是不超過40人的小教室,大家的距離不會太遠。

最棒的一點就是這大學裡充滿各種背景的多語人才,因此而有幸謹慎地步入了另一個領域的知識殿堂。這裡有通譯與翻譯、文化研究等課程、以及世界上各種語言的專門課程,也有幾門經濟學、政治學、統計學、法學、文學、歷史學、生物學、資訊科學的課程(事實上,最近外大改制後,學生在3年級之後都可以選一個專攻領域,例如政治或是經濟等等,不若以往是都在學習語言)這裡的語言相關書籍和課程之繁多,令人好奇到底這裡的人佔了全日本語言人才多少的百分比......同時也看到許多髮色和膚色的人都說著非常標準的日語,使我覺得自己在這地方應該能夠遇到許多志同道合的人們。

由於學校不大,大約是台大的1/10左右,上課的講義棟是多數學生上課的唯一所在,因此也不用擔心跑錯棟。

學校內也有許多社團,能想到關於日本的社團應該都存在,不關於日本的社團也所在多有。
舉凡歌牌(かるた),劍道,弓道,和樂器,花道,茶道,俳句等等。

每年11月中也有匯集世界各地文化和小吃的學園祭-外語祭,大家有興趣可以去Youtube搜尋相關影音。期間學校會有完整一周的休假,可見這件事情對此學校的重要性。5月初則是有划船大會,期間學校也會休假一天,主要是大一新鮮人參加。

總結而言,就學校該有的機能而言,東外大一項也沒少,對於想認識來自世界各地不同文化的人而言,一定是非常好的一個選項。因為小,所以才能讓大家距離不那麼遠。

如果喜歡安靜而不忙亂的生活環境,學習氣氛良好的教學場域,並且對自然和人文抱有一定的喜愛的人們,我推薦你/妳來到這兒,可以只是一趟短暫行旅,也可以是一段留學日本的美好回憶。事實上,我已經開始對10個月後就得離開這裡感到難過了。不是離開日本本身,而是離開我現在擁有的生活環境。






2015年7月25日 星期六

如何在Android Studio 1.2.2中加入library project(How to add library project in Android Studio 1.2.2)

        (2015.08.04 更新: 確認在Android Studio 1.3也是用一樣的方法)
        好久不見,最近比較少更新文章,因為前陣子是在台灣念大學期間最後的期末考(已結束)和前幾周的企業實習。今天開始發慌了之後就繼續研究Android,於是遇到了一樣的老問題,覺得應該有很多人也在找這個答案,於是在此一樣做個中文化的服務。原本的答案在此:原文網址 。
  
  問題描述如標題,有時候我們在套用別人的API的時候,會需要做Integration的部分(把他人的API code嵌入自己的APP的意思),這時候就會需要這個動作,但因為Android Studio改版很快,因此網路上很多舊的教學文可能已經不合時宜(同樣的,這篇文章可能不久也會),所以才決心發此文(過不久應該會繼續寫關於Android Training的文章,但最近要忙學習開發...),希望它能發揮功用。

     

步驟

1.





















2.





















3.





















4.


5.

接著按下Finish,稍等一下讓Gradle Rebuild。好了之後,到工具列的File>Project Structure,按下去會出現6.的視窗,選擇app>Dependencies>加號"+">Module dependency>選擇剛剛匯入的library project>完成。

6.

P.S.以上步驟完成後,有可能會造成code出現很多紅色字的Errors,這時只要到工具列>Build>Rebuild就可以恢復了。






















2015年3月3日 星期二

(Lyrics Translation/中文歌詞翻譯)Gundam ORIGIN I星屑の砂時計/星之沙漏 by yu-yu

        好久不見,我是不務正業的歌詞君。這次是在日本動畫鋼彈ORIGIN(2015春番)中出現的OP1,主唱為已於去年退出歌壇的京都出身的yu-yu,其自稱yu-yu的由來跟「友を癒す」(治癒吾友)有關,中間連接的"-"象徵人與人之間手牽著手的"手"。因為這首歌實在太好聽了所以下定決心睡前來翻一發。
========================

星屑の砂時計

作詞:山川啓介
作曲:服部隆之


千億の星屑が 私に降りかかる                 //千億的繁星  向著我墜落
自分の小ささに すくむの心が                         //因自己的渺小  畏縮著的內心
運命の箱船が 旅立つ時間(とき)の海            //那命運之船於時光之海揚帆
音のない序曲が ひびき始める                       //沒有音符的序曲也漸次鳴響
ねえ私 この世に                                              //吶,我在這世上活著
生まれてよかったの?                                       //究竟是好 是壞 ?
答えのないまま 月は                                      //無言的月亮
欠けて 満ちて                                                 //復圓 復缺
私のなかの 少女が                                        //在我內心的少女也
大人になってゆく                                               //漸漸成長

なぜ人間(ひと)は愛し合い 傷つけ憎み合う  //為何人們相愛  傷害 憎恨彼此
孤独な星たちが 引き合うみたいに                //就像孤獨的星座互相吸引
でも今は信じたい 夢という遺伝子が             //而今我相信  夢這般的基因
苦しみも涙も 越えて行くって                          //會超越苦難以及淚水
ねえどんな あしたが                                       //吶,怎樣的未來

私を待ってるの?                                              //在等著我呢
たずねてみるけど 月は                                 //向月探問  但月亮卻
ほほえむだけ                                                    //只是微笑著
誰も知らない 未来へ                                     //向著誰也不知道的未來
砂時計 落ちてゆく                                         //繁星如沙漏   緩緩下落

何光年 離れようと                                         //即便遙隔光年
ふるさとは やさしい胸                                   //故鄉依然如溫柔的胸懷

ねえ私 この世に                                            //吶,我在這世上活著
生まれてよかったの?                                     //究竟是好 是壞 ?
答えのないまま 月は                                    //無言的月亮
欠けて 満ちて                                                //復圓 復缺
私のなかの 少女が                                       //在我內心的少女也
大人になってゆく                                              //漸漸成長

千億の星屑よ 私もきらめこう…                   //千億計的繁星啊 也請照耀著我吧

2015年2月25日 星期三

(Lyrics Translation/歌詞翻譯)椎名林檎 - 月夜の肖像 form 党大会 Short Ver.

Youtube連結在此:
最近聽到最好聽的歌曲,林檎真的好迷人,雖然英文發音有點不標準,
th開頭都會變成s的音...花了大約快兩小時還是無法完全確定整首都對,
因為網路上目前沒有比較完整的"順眼"版本,於是就決定來試試看了。
在這過程中,我綜合參考了以下網址,對於翻譯進展幫助很大:
1.日文版歌詞
2.百度貼吧
3.豆瓣

若有人有更好的意見也請不吝告知!~
==============================
The cover once was found,
let me return
I'm lost in my own crowd
I ask and beg you to
turn me around
I'm calling god on you.

No vision comes to me
but I'm alone
as hard as I reach
And you know I'll never throw
my body down
again before you're thrown

Come save the night
Come down to me
And keep your faith in a while

I'll take my hands and cast a spell
On darkness spread
On time like a dream
Just show your face I wonder mine
I'll take you in my arms alive
So seek and come to me again.

I have no hope at all
Not even one
Tear faded back and fall
and if everything I think
dim after dark
It would not change a thing

A broken glass
I'll say hello,
Won't you reveal all you know

I'll take my heart and hug you tight
And spread the light on time for both
You're sinking into my own mind
The world is howling so wild
I'll keep you warm with me again

I'll take my hands and cast a spell
On darkness spread
On time like a dream
Just show your face I wonder mine
I'll take you in my arms alive
So seek and come to me again.
=================================

真的好好聽喔>_<

2015年2月14日 星期六

(Android Training系列)用Fragment來建立動態UI(上)

話說從頭


  動態(Dynamic)網頁或是APP目前是一股潮流,帶著使用者前往更加自由與客製化的未來前進。在這股潮流之中,我想要為大家介紹一個Android為大家帶來的類別,它叫做Fragment(片段)。如果你想要創造一個動態且多層的介面,用Fragment Class就對啦~(至少目前我只知道它QQ)Fragment就像是Activity裡面的便利貼一樣,或者我們也可以把一個Activity加上許多的Fragments,讓我們畫面有拼貼的效果。



上圖呈現的就是這種拼貼感,讓設計人員可以因不同的螢幕大小去決定呈現畫面的方式,因此在寫介面時就能先預訂把畫面分為幾個小部分,並且讓它互相關聯。

  這些Fragments都各自有各自的佈局(layout)和生命週期(life cycle),因此我們也可以將之視為Activity中之模組化的子Activity區塊。

創造Fragment


  一個完整的Fragment除了擁有自己的生命周期之外,也能偵聽自己的傳入事件,也可以像子Activity一般可以讓你在母Activity運行時添加或移除,也可以重複地用在許多不同的Activities中。接下來的說明會教大家如何用Android內建的Support Library來建立最低可以相容於Android 1.6版的Fragment。在開始之前,必須先確定電腦裡有安裝Support Library的SDK(可以去SDK管理員確認)。

創造Fragment Class

步驟說明:
1.建立一個繼承(extend)Fragment類別的Class,接下來與建立Activity相同,可以覆寫(Override)其生命週期方法(onStop(), onResume()..等)以建立我們的程式邏輯。

2.與Activity不一樣的地方是,我們用onCreateView()來定義Fragment的佈局。事實上,這是讓一個fragment運作唯一需要的callback函數。其長相其實跟建立功能表選單Option Menu幾乎一致,都需要Inflater。(關於callback函數可以看這裡)

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.ViewGroup;
public class ArticleFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.article_view, container, false);
    }
}
以上是使Fragment運行的必要callback方法。當我們有其他需要時,再去實做其他的生命週期方法就行了。關於更多關於Fragment的生命週期及callback方法:Fragments developer's guide.

用XML為Activity增加Fragment

  雖然fragments是可重複使用的模組化UI元件,但每一個屬於Fragment Class的instance都必須要與其母類別FragmentActivity相關聯(註:在API Level 11以後我們可以直接繼承Activity即可,但這樣一來就可能會失去Level 11以下的相容性)。我們可以在佈局xml檔中完成這個關聯。
  以下是用佈局檔在activity中產生兩個fragments的例子,請讀者留意螢幕尺寸修飾詞為-large。黑字是我認為可以稍加注意的地方。

路徑:res/layout-large/news_articles.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <fragment android:name="com.example.android.fragments.HeadlinesFragment"
              android:id="@+id/headlines_fragment"
              android:layout_weight="1"
              android:layout_width="0dp"
              android:layout_height="match_parent" />

    <fragment android:name="com.example.android.fragments.ArticleFragment"
              android:id="@+id/article_fragment"
              android:layout_weight="2"
              android:layout_width="0dp"
              android:layout_height="match_parent" />
</LinearLayout>
Tip:如果你想要支援不同螢幕尺寸,請讀Supporting Different Screen Sizes
(其實也只是多弄幾個不同的layout .xml讓系統自己判斷而已)

  再把剛剛的news_article.xml定義的layout套用至activity中:
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
public class MainActivity extends FragmentActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.news_articles);
    }
}
留意如果你是用 v7 appcompat library版本的Support Library,將會extends ActionBarActivity,一個 FragmentActivity 的子類別。想知道更多請看Adding the Action Bar

  到此即大功告成,各位可以自己試試(按這裡可以下載Sample code,下載完成後解壓縮,打開Android Studio-->Import Project,選剛剛解壓縮後產生之資料夾)。

  注意:如果用以上介紹的方法在Activity中添加fragment,將無法在運行時移除該fragment。因為我們是直接在MainActivitiy中套用R.layout.news_articles。如果你想要讓fragments能夠來去自如,我們必須在Activity啟動後再添加,此方法將會在下篇文章中介紹。