tag:blogger.com,1999:blog-26389139480915750222024-03-16T16:45:02.383+08:00思考要在空白頁Passion & Innovation
- I write, therefore I amAnonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.comBlogger134125tag:blogger.com,1999:blog-2638913948091575022.post-6574700865918015182014-04-05T15:34:00.000+08:002014-04-06T12:39:51.867+08:00Coroutine in Tornado Web FrameworkCoroutine 可以讓我們在程式中按照自己的意思去安排執行順序,有點像是 jump 的概念,它允許短暫離開 function 並且保留 local variable 的狀態,等到某個時間點再跳回來,從上一次離開的地方繼續。第一次接觸到 coroutine 的概念是從 python,coroutine 是一種語言特性,從 <a href="http://en.wikipedia.org/wiki/Coroutine">wiki</a> 可以看到很多語言都有這種特性。<br />
<br />
那我們沒事幹嘛讓程式跳來跳去的?思考一種狀況,當在 single thread 下,你執行到一個 blocking function,這時候如果讓 CPU 去做其他事情是不是很好,等到 I/O 有回應的,再跳回來原本的地方繼續執行。等等,這不就是 event-driven 的 programming 嗎?它們的表達方式還是有點區別。<br />
<br />
<br />
舉一個例子,我們發出一個 HTTP request 去抓 Yahoo weather 的資訊,然後利用 XML parser 從回應得資料中取出溫度,以下是利用一般非同步的方式去撰寫:<br />
<pre class="brush: py">from tornado.ioloop import IOLoop
from tornado.web import Application, RequestHandler, asynchronous
from tornado.httpclient import AsyncHTTPClient
from xml.dom import minidom
class MainHandler(RequestHandler):
url = "http://weather.yahooapis.com/forecastrss?w=2306179&u=c"
@asynchronous
def get(self):
http_client = AsyncHTTPClient()
http_client.fetch(self.url, callback=self._on_fetch)
def _on_fetch(self, response):
degree = self._parse_xml(response.body)
self.finish("Taipei: %d" % degree)
def _parse_xml(self, xml):
xml_doc = minidom.parseString(xml)
weather_list = xml_doc.getElementsByTagName('yweather:condition')
degree = float(weather_list[0].attributes['temp'].value)
return degree
if __name__ == "__main__":
application = Application([
(r"/", MainHandler),
])
application.listen(8888)
IOLoop.instance().start()
</pre>
第 12 行:在發出 request 同時指定 callback<br />
第 14 行:在收到 server 回應後,執行 _on_fetch()<br />
<br />
<br />
換成 coroutine 的方式<br />
<pre class="brush: py">from tornado.ioloop import IOLoop
from tornado.web import Application, RequestHandler, asynchronous
from tornado.httpclient import AsyncHTTPClient
import tornado.gen as gen
from xml.dom import minidom
class MainHandler(RequestHandler):
url = "http://weather.yahooapis.com/forecastrss?w=2306179&u=c"
@gen.coroutine
def get(self):
http_client = AsyncHTTPClient()
response = yield http_client.fetch(self.url)
degree = self._parse_xml(response.body)
self.finish("Taipei: %d" % degree)
def _parse_xml(self, xml):
xml_doc = minidom.parseString(xml)
weather_list = xml_doc.getElementsByTagName('yweather:condition')
degree = float(weather_list[0].attributes['temp'].value)
return degree
if __name__ == "__main__":
application = Application([
(r"/", MainHandler),
])
application.listen(8888)
IOLoop.instance().start()
</pre>
第 13 行:程式執行完 yield 後面的 statement 這個 function 就會立刻 return,直到 tornado io loop 收到 server 回應,然後跳回第 13 行,把 fetch() 的結果 assign 給 response,然後繼續執行下去。<br />
底層一樣是非同步I/O,但這種表達方式擁有在寫同步 I/O 般的直覺。<br />
<br />
<br />
單一個 callback 可能顯示不出直覺在哪裡,如果連存取 database/memcach... 任何跟I/O相關的事情都採用非同步方式,那就會需要在 callback 中執行另一個 callback<br />
<pre class="brush: py">class MainHandler(RequestHandler):
@tornado.web.asynchronous
def get(self):
req1(argument1, callback=self._res1)
@tornado.web.asynchronous
def _res1(self, response1):
...do something with response
req2(argument2, callback=self._res2)
def _res2(self, response2):
...do something with response
self.finish("result...")
</pre>
<br />
改用 coroutine 的方式<br />
<pre class="brush: py">class MainHandler(RequestHandler):
@tornado.gen.coroutine
def get(self):
response1 = yield req1(argument1)
...do something with response1
response2 = yield req2(argument2)
...do something with response2
self.finish("result...")
</pre>
<br />
是不是直覺很多!Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com1tag:blogger.com,1999:blog-2638913948091575022.post-68353480412706019912014-03-22T11:53:00.000+08:002014-03-24T23:04:23.549+08:00C語言的記憶體洩漏(Memory Leak)偵測 - Valgrind寫 C 的人對於記憶體管理要非常的精確,不像其他高階語言有 garbage collection,好習慣可以減少錯誤發生,讓 malloc() 與 free() 對等的出現,而且寫在同一個層級。但不免還是會有疏忽的時候,像我自己在寫 daemon,這種長期服務的程式,如果遇到 memroy leak,就會看到系統的記憶體一點一點的被吃光,最後免不了要重開的命運,如果是線上的服務器豈不就要重斷服務了!<br />
<br />
好在有強大的 <a href="http://valgrind.org/">Valgrind</a> 可以幫助我們真測出問題。<br />
<br />
<br />
<h3>
Case 1: Memory Leak</h3>
最常見的錯誤,就是 allocate 的記憶體忘記 free,而且已經沒有任何指標指著它。<br />
我們舉個簡單的例子,並使用 valgrind 來協助偵測:<br />
<pre class="brush: c">#include <stdlib.h>
void func (void)
{
char *buff = malloc(10);
}
int main (void)
{
func();
return 0;
}
</pre>
<br />
編譯並執行 (記得編譯時要加 -g 的參數,valgrind 的報告才會指明有問題的行數)<br />
<pre class="brush: bash; gutter: false;"># gcc -g -o mem_test mem_test.c
</pre>
<br />
Valgrind 使用方法很簡單,不需要修改程式碼,用 valgrind 把自己的 program 帶起來即可,如果有參數就加在後面,程式執行結束就會產生報告。<br />
valgrind [-valgrind parameter] ./my_program [-program parameter]
<br />
<pre class="brush: bash; gutter: false;"># valgrind --leak-check=full ./mem_test
</pre>
<br />
<pre class="brush: bash; gutter: false;">==59095== Memcheck, a memory error detector
==59095== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==59095== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==59095== Command: ./mem_test
==59095==
==59095==
==59095== HEAP SUMMARY:
==59095== in use at exit: 10 bytes in 1 blocks
==59095== total heap usage: 1 allocs, 0 frees, 10 bytes allocated
==59095==
==59095== 10 bytes in 1 blocks are definitely lost in loss record 1 of 1
==59095== at 0x4C2C857: malloc (vg_replace_malloc.c:291)
==59095== by 0x400505: func (mem_test.c:5)
==59095== by 0x400514: main (mem_test.c:10)
==59095==
==59095== LEAK SUMMARY:
==59095== definitely lost: 10 bytes in 1 blocks
==59095== indirectly lost: 0 bytes in 0 blocks
==59095== possibly lost: 0 bytes in 0 blocks
==59095== still reachable: 0 bytes in 0 blocks
==59095== suppressed: 0 bytes in 0 blocks
==59095==
==59095== For counts of detected and suppressed errors, rerun with: -v
==59095== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
</pre>
報告中指明有一個 10 bytes 的 block 被偵測為 "definitely lost",位置在 mem_test.c 的第 5 行
<br />
<br />
可以看到 memory lost 分成幾種類型:<br />
<ul>
<li>definitely lost: 真的 memory leak 了</li>
<li>indirectly lost: 間接的 memory leak,structure 本身發生 memory leak,而內部的 member 如果是 allocate 的出來的,一樣會 memory leak,但是只要修好前面的問題,後面的問題也會跟著修復。</li>
<li>possibly lost: allocate 一塊記憶體,並且放到指標 ptr,但事後又改變 ptr 指到這會計一體的中間 (這一點我目前也不是很清楚,建議看<a href="http://valgrind.org/docs/manual/faq.html#faq.deflost">原文說明</a>)</li>
<li>still reachable: 程式結束時有未釋放的記憶體,不過卻還有指標指著,通常會發生在 global 變數</li>
</ul>
就算是 library 所 malloc 的記憶體,如 evbuffer_new(),也都可以偵測的到。<br />
<br />
<br />
<br />
<h3>
Case 2: Invalid Memory Access</h3>
Invalid memory access 有時候並不會立即造成 segmentation fault,所以不會有 core dump可以查詢,需要借助像 valgrind 這類的工具來偵測。<br />
一般情況可能是用了 allocate 的 memory 之外的地方,或是用了已經 free 的 memory,請看下面幾個例子:<br />
<pre class="brush: c">#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main (void)
{
// 1. Invalid write
char *str = malloc(4);
strcpy(str, "Brian");
free(str);
// 2. Invalid read
int *arr = malloc(3);
printf("%d", arr[4]);
free(arr);
// 3. Invalid read
printf("%d", arr[0]);
// 4. Invalid free
free(arr);
return 0;
}
</pre>
編譯並執行
<br />
<pre class="brush: bash; gutter: false;">==60019== Memcheck, a memory error detector
==60019== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==60019== Using Valgrind-3.9.0 and LibVEX; rerun with -h for copyright info
==60019== Command: ./mem_test
==60019==
==60019== Invalid write of size 2
==60019== at 0x4005AB: main (mem_test.c:9)
==60019== Address 0x51f4044 is 0 bytes after a block of size 4 alloc'd
==60019== at 0x4C2C857: malloc (vg_replace_malloc.c:291)
==60019== by 0x400595: main (mem_test.c:8)
==60019==
==60019== Invalid read of size 4
==60019== at 0x4005D1: main (mem_test.c:14)
==60019== Address 0x51f40a0 is 13 bytes after a block of size 3 alloc'd
==60019== at 0x4C2C857: malloc (vg_replace_malloc.c:291)
==60019== by 0x4005C4: main (mem_test.c:13)
==60019==
==60019== Invalid read of size 4
==60019== at 0x4005F7: main (mem_test.c:18)
==60019== Address 0x51f4090 is 0 bytes inside a block of size 3 free'd
==60019== at 0x4C2B75D: free (vg_replace_malloc.c:468)
==60019== by 0x4005F2: main (mem_test.c:15)
==60019==
==60019== Invalid free() / delete / delete[] / realloc()
==60019== at 0x4C2B75D: free (vg_replace_malloc.c:468)
==60019== by 0x400618: main (mem_test.c:21)
==60019== Address 0x51f4090 is 0 bytes inside a block of size 3 free'd
==60019== at 0x4C2B75D: free (vg_replace_malloc.c:468)
==60019== by 0x4005F2: main (mem_test.c:15)
==60019==
00==60019==
==60019== HEAP SUMMARY:
==60019== in use at exit: 0 bytes in 0 blocks
==60019== total heap usage: 2 allocs, 3 frees, 7 bytes allocated
==60019==
==60019== All heap blocks were freed -- no leaks are possible
==60019==
==60019== For counts of detected and suppressed errors, rerun with: -v
==60019== ERROR SUMMARY: 4 errors from 4 contexts (suppressed: 0 from 0)
</pre>
錯誤一:Invalid write of size 2,試圖寫入一個非法的區域,valgrind 還好心告訴你這個地方是在 mem_test.c:6 allocate 出來的 memory 之後的 3 byte,通常遇到這種情況都是忘記檢查 buffer 的 size 就去用。<br />
錯誤二:Invalid read of size 4,試圖讀取一個非法的區域。<br />
錯誤三:Invalid read of size 4,讀取的區域已經被 free 了,free 的位置 valgrind 也幫你指出來 mem_test.c:12。<br />
錯誤四:Invalid free,也就是 free 一個不存在的地方,或是 double free<br />
<br />
<br />
<br />
<h3>
其他提醒</h3>
遇到 Conditional jump or move depends on uninitialised value(s) 的錯誤<br />
可能是用了沒有結束字元 (Null-terminated string) 的字串<br />
<br />
有一種錯誤不太好找,如 A function 用到用到 B function 產生出來的 memory,對於系統本身並無任何違法,但卻會造成程式出現不預期的值。<br />
<br />
對於 local variable 的存取如果超過範圍,還有可能造成 stack corrupt,然後噴出這類的錯誤:<br />
<pre class="brush: bash; gutter: false;">*** stack smashing detected ***: ./mem_test terminated
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x37)[0x64f8f47]
/lib/x86_64-linux-gnu/libc.so.6(__fortify_fail+0x0)[0x64f8f10]
./mem_test(func+0x2db)[0x407f22]
======= Memory map: ========
00400000-00420000 r-xp 00000000 08:01 280804 /tmp/mem_test
0061f000-00620000 r--p 0001f000 08:01 280804 /tmp/mem_test
00620000-00622000 rw-p 00020000 08:01 280804 /tmp/mem_test
00622000-00623000 rw-p 00000000 00:00 0
04000000-04022000 r-xp 00000000 08:01 160861 /lib/x86_64-linux-gnu/ld-2.15.so
</pre>
<br />
如果不想 show possibly lost,可以加下面的參數<br />
3.9版 --show-leak-kinds=definite<br />
3.7版 --show-possibly-lost=no<br />
<br />
另外 file descriptor 開了沒關也可以偵測,只要加上 --track-fds=yes
<br />
<br />
之前有遇過 valgrind 在 ubuntu 12.04 一直有錯誤訊息,記得要安裝額外的套件 sudo apt-get install libc6-dbg<br />
<a href="http://askubuntu.com/questions/148236/valgrind-does-debug-error">12.04 - Valgrind does debug error - Ask Ubuntu</a>Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com16tag:blogger.com,1999:blog-2638913948091575022.post-42443922773612880342014-02-18T16:46:00.000+08:002014-02-25T07:57:30.821+08:00AWS VPC 設定教學在 AWS VPC(Virtual Private Cloud) 介紹中列了四種 scenario,在此以 <a href="http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Scenario2.html">Scenario 2: VPC with Public and Private Subnets</a> 為例來說明操作過程。<br />
整個過程會建立 public, private 兩個 subnet,public subnet 用來放置對外服務的 instance 具有 public IP,如 web server。而 private subnet,只允許 VPC 內部存取,如 database。<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-HXAUcY_Lp5I/UwMetvSTRzI/AAAAAAAABW8/SDTMuHPjdks/s1600/Case2_Diagram.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-HXAUcY_Lp5I/UwMetvSTRzI/AAAAAAAABW8/SDTMuHPjdks/s400/Case2_Diagram.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<h3>
Create VPC</h3>
1. 建立 VPC,指定 CIDR block 爲 10.0.0.0/16<br />
Local IP 位址從 10.0.0.0 - 10.0.255.255 共 256*256 個 IP<br />
<br />
<br />
2. 切兩個 subnet<br />
Public subnet CIDR: 10.0.0.0/16,IP 從 10.0.0.0 - 10.0.0.255<br />
Private subnet CIDR: 10.0.1.0/16,IP 從 10.0.1.0 - 10.0.1.255<br />
預設所有在 VPC 底下任何 subnet 的 IP 都可以互通<br />
<br />
<a name='more'></a><br />
<br />
<h3>
Public Subnet</h3>
3. 建立 Internet Gateway 並 attach 到我們的 VPC,這樣才能把 VPC private network 與 Internet 接軌<br />
<br />
<br />
4. 建立 route table for public subnet<br />
新增一組 rule,把 0.0.0.0/0 導向 Internet Gateway<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-wCvC7wou7vQ/UwMDLhhJewI/AAAAAAAABVc/VZ9i6jlpXow/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%882.50.01.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://1.bp.blogspot.com/-wCvC7wou7vQ/UwMDLhhJewI/AAAAAAAABVc/VZ9i6jlpXow/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%882.50.01.png" height="119" width="320" /></a></div>
再來把此 route table 與 public subnet (10.0.0.0/24)關聯起來<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-XOoNvXRJUDI/UwMDYh8o8UI/AAAAAAAABVk/LcMW-S2ThRU/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%882.50.27.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-XOoNvXRJUDI/UwMDYh8o8UI/AAAAAAAABVk/LcMW-S2ThRU/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%882.50.27.png" height="152" width="320" /></a></div>
<br />
<br />
5. 接著我們就可以把 instance 開在此 subnet 之下,為了後續 private subnet 可以連到 Internet,以下示範開啟一個 <a href="http://nat%20instances%20-%20amazon%20virtual%20private%20cloud/">NAT instance</a>。<br />
先建立 VPC instance,從 Community AMIs 找到 amzn-ami-vpc image,使用 micro 等級即可。指定所屬的 VPC 與 subnet<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-kNptr53hlTo/UwMEffkj9iI/AAAAAAAABVw/jrJIwPwh-3A/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%882.57.16.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-kNptr53hlTo/UwMEffkj9iI/AAAAAAAABVw/jrJIwPwh-3A/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%882.57.16.png" height="71" width="400" /></a></div>
設定 NAT 的 private IP 爲 10.0.0.4 (optional)<br />
一直下一步下一步,建立 security group 與 key pair。<br />
架在 public subnet 表示要對外服務,security group 要特別設定 inbound rule<br />
<br />
舉例來說,一個 HTTP server 可以建立 3 條 rule<br />
a) 讓所有人可以存取 80 port<br />
b) 內部 IP 可以任意存取<br />
c) 只有特定外部 IP 能夠 SSH 進來<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-RE9dEYz-UZ4/UwMO1ky1ThI/AAAAAAAABWg/wk08Z1B9zs0/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%883.41.42.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-RE9dEYz-UZ4/UwMO1ky1ThI/AAAAAAAABWg/wk08Z1B9zs0/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%883.41.42.png" height="80" width="400" /></a></div>
<br />
在此我們的 instance 只做 NAT 服務,只接受內部連線,至少要有一條 rule<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-ETeC7gJrhU0/UwMQ9WY9nuI/AAAAAAAABWs/MxS5sQKEDQ8/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%883.50.54.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-ETeC7gJrhU0/UwMQ9WY9nuI/AAAAAAAABWs/MxS5sQKEDQ8/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%883.50.54.png" height="35" width="400" /></a></div>
Outbound rule 預設是 allow all<br />
<br />
另外要記得 disable NAT instance 的 Source/Dest. Check<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-7f01IglU8nI/UwQSXsE8wvI/AAAAAAAABXU/rcKjoCn8dNI/s1600/Screen+Shot+2014-02-19+at+%E4%B8%8A%E5%8D%8810.08.56.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-7f01IglU8nI/UwQSXsE8wvI/AAAAAAAABXU/rcKjoCn8dNI/s1600/Screen+Shot+2014-02-19+at+%E4%B8%8A%E5%8D%8810.08.56.png" height="299" width="320" /></a></div>
<br />
<br />
<br />
6. 再來申請一個 EIP 並且 bind 在 NAT instance 之上<br />
<br />
<br />
7. 使用 SSH 連進去 instance<br />
$ ssh -i YOUR_KEY_PAIR.pem ec2-user@YOUR_NAT_IP<br />
ping google.com 也沒有問題<br />
<br />
到此為止,我們已經建立一個 instance 在 VPC public subnet,可以從外部存取,也可以從內部連到 Internet<br />
<br />
<br />
<h3>
Private Subnet</h3>
8. 再來我們要建立另一組 route table 給 private subnet<br />
把 default gateway 指向 NAT instance,也就是所有對外的封包都會先到 NAT<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-msaUCZGSIPc/UwMJ2UQo7yI/AAAAAAAABWI/iOUvkq_SCgs/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%883.20.04.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-msaUCZGSIPc/UwMJ2UQo7yI/AAAAAAAABWI/iOUvkq_SCgs/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%883.20.04.png" height="138" width="400" /></a></div>
一樣 associate with private subnet (10.0.1.0/24)<br />
<br />
<br />
9. 試著建立 instance 在 private subnet 內,<br />
可以建立一個 security group for internal traffic<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-45DDhGFkXEQ/UwMNmyGUzXI/AAAAAAAABWU/vSMpcQbpqnM/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%883.36.40.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://4.bp.blogspot.com/-45DDhGFkXEQ/UwMNmyGUzXI/AAAAAAAABWU/vSMpcQbpqnM/s1600/Screen+Shot+2014-02-18+at+%E4%B8%8B%E5%8D%883.36.40.png" height="143" width="320" /></a></div>
由於此 instance 不能從外部進來,要透過 public instance 當跳板。SSH 進去後一樣試試看能不能連到 Internet<br />
<br />
<h3>
Note</h3>
要從 instance 連到 Internet 只有兩種辦法:<br />
- Binding EIP 並且把 default gateway 指到 Internet gateway<br />
- 把 default gateway 指到 NAT instance,再由 NAT 轉到 Internet gateway<br />
<br />
Security Group 是針對 instance 做設定<br />
Network ACLs 是針對 subnet 做設定<br />
以上兩種設定已經能滿足大部份的需求,就沒必要再去修改 iptable 了,改壞了自己進不去,AWS console 沒有這種問題。<br />
<br />
* 或許有人會跟我有一樣的疑問,如果只開一個 subnet (10.0.0.0/16),所有 instance 放在裡面,要對外的再 bind public IP,這樣就不用分什麼 public/private subnet 了。問題就在於 VPC route table 的套用是以 subnet 為單位,而不是針對各個 instance 做設定,所以這個 subnet 只會有一個 gateway 就是 Internet gateway,但這樣只有 private IP 的 instance 就連不到 Internet了。除非你去改 linux 內部的 route table,把 gateway 指到 NAT server,不過會有改壞掉的風險,失去了 software defined network 的優勢。<br />
<br />
<h3>
Reference</h3>
<ul>
<li><a href="http://docs.aws.amazon.com/AmazonVPC/latest/GettingStartedGuide/ExerciseOverview.html">Overview of the Exercise - Amazon Virtual Private Cloud</a></li>
<li><a href="http://blog.clifflu.net/blog/2013/10/aws-vpc-%E5%BF%83%E5%BE%97/">AWS VPC 心得 | clifflu 又架 blog 了 O.o/</a></li>
<li><a href="http://blog.clifflu.net/blog/2013/08/%E8%BF%91%E6%B3%81-%E4%B8%80%E9%BB%9E-aws-vpc-%E5%B0%8F%E5%BF%83%E5%BE%97/">近況 + 一點 AWS (VPC) 小心得</a></li>
<li><a href="http://aws.typepad.com/aws/amazon-vpc/">Amazon Web Services Blog: Amazon VPC</a></li>
<li><a href="http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_NAT_Instance.html">NAT Instances - Amazon Virtual Private Cloud</a></li>
<li><a href="http://aws.amazon.com/articles/2781451301784570">High Availability for Amazon VPC NAT Instances: An Example : Articles & Tutorials : Amazon Web Services</a></li>
</ul>
<br />
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com1tag:blogger.com,1999:blog-2638913948091575022.post-88102855902809045562014-02-12T22:52:00.002+08:002014-02-13T17:55:20.079+08:00Install YouTube plugin in PhoneGapI develop app with PhoneGap 3.3.1, and import the YouTube plugin from <a href="https://github.com/matiasmolinas/YTPhoneGapPlugin">YTPhoneGapPlugin</a>.<br />
<br />
Integrate steps:<br />
1. Use command to install plugin<br />
<pre class="brush: bash; gutter: false;">$ cordova local plugin add https://github.com/matiasmolinas/YTPhoneGapPlugin.git
</pre>
<br />
2. Download <a href="https://developers.google.com/youtube/android/player/downloads/">YouTube api</a> to project libs folder<br />
<br />
3. Register the YouTube API Key from <a href="https://code.google.com/apis/youtube/dashboard/gwt/index.html">here</a>, and fill the key in<br />
android project/src/gdg/youtube/YouTube.java<br />
<br />
4. Implementation<br />
<pre class="brush: js">var videoId = "YSxYCMlkLsw";
var success = function() { console.log("Success"); };
var error = function(message) { console.log("Oopsie! " + message); };
window.youtube.playVideo(videoId, success, error);
</pre>
<br />
If you met error message as following:<br />
<blockquote>
I/Web Console( 1614): Oopsie! No Activity found to handle Intent { act=com.google.android.youtube.api.StandalonePlayerActivity.START (has extras) } at file:///android_asset/www/app.js:1</blockquote>
Try to install YouTube app in your Android system, if you use emulator, try to download from google play and use command line to install it.
<br />
<pre class="brush: bash; gutter: false;">adb install com.google.android.youtube.apk
</pre>
Reference
<br />
<div style="font-family: Times; white-space: normal;">
<ul>
<li><a href="http://stackoverflow.com/questions/19402082/unable-to-start-activity-youtubestandaloneplayer">android - Unable to start activity - YouTubeStandalonePlayer - Stack Overflow</a></li>
<li><a href="http://stackoverflow.com/questions/14477067/youtube-api-activitynotfoundexception-on-gingerbread">android - Youtube API ActivityNotFoundException on Gingerbread - Stack Overflow</a></li>
</ul>
</div>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-66759783570735555462013-08-31T12:55:00.000+08:002013-08-31T14:40:36.377+08:00Embedded Sencha Touch Demo Code in My Blog今天在思考怎麼在我的 blog 嵌入 Sencha Touch 的 library,之後寫 demo code 就可以看到 preview了!<br />
<br />
<br />
<h3>
首先選擇必要的 library</h3>
Sencha Touch 專案預設是用 micro-loader 載入設定在 app.json 的 js / css 檔,不過檔案太零碎需要發很多 request,若透過 internet 會拖慢速度,SDK 內同時也有提供整合的版本:<br />
<ul>
<li>sencha-touch.js 131KB</li>
<li>sencha-touch-debug.js 514KB</li>
<li>sencha-touch-all.js 671KB</li>
<li>sencha-touch-all-debug.js 2.7M</li>
</ul>
<br />
各版本的用途可以參考 <a href="http://docs.sencha.com/touch/2.2.1/#!/guide/building">Using and Creating Builds</a>,由於我需要使用到 widget,所以要選 all 的版本,sencha-touch-all.js (671KB) 雖然壓縮過了還是好肥大...<br />
<br />
CSS 的部分,SDK 內也提供不同組的 theme 可以套:<br />
<ul>
<li>base.css 230KB</li>
<li>bb10.css 184KB BlackBerry</li>
<li>sencha-touch.css 258KB</li>
<li>wp.css 194KB Windows Phone</li>
</ul>
<br />
<a name='more'></a><br />
<h3>
尋找 Host Javascript / CSS 的主機</h3>
CDN 有下面幾種選擇<br />
<ul>
<li><a href="https://help.github.com/articles/creating-project-pages-manually">Github page</a> 具版本控管,速度OK,但有個缺點就是 file commit 後要10分鐘才能 access 到</li>
<li><a href="https://googledrive.com/host/0B716ywBKT84AMXBENXlnYmJISlE/GoogleDriveHosting.html">Google drive</a> 最方便,放 html、js、css 都 OK</li>
<li><a href="https://www.dropbox.com/">Dropbox</a> 速度慢,有時候還會載入失敗</li>
<li><a href="https://code.google.com/intl/zh-TW/">Google code</a> host js file 會載入失敗 </li>
</ul>
<br />
<br />
<h3>
把資源整合進 <a href="http://codepen.io/">Codepen</a>,然後開始寫 code 啦!</h3>
Codepen 是個線上網頁編輯器,編輯後可以即時看到,支援的語言也很多 CoffeeScript、SCSS/Sass。我覺得比 <a href="http://jsfiddle.net/">jsfiddle</a> 好用,jsfiddle 沒有支援 SCSS,theme 也沒有 codepen好看,比較討厭的是 jsfiddle 儲存後就強迫開一個新的版本,若 blog 想 link 到最新版本還要手動更新。<br />
<br />
在 Codepen 編輯 Sencha Touch 的程式碼後,選擇下方的 embedded codepen,可以取得 embedded 的 HTML,就可以嵌在自己的 blog 啦,而且未來若有更新,blog 這邊也可以看到,因為是同一個版本。<br />
<br />
<br />
預覽如下<br />
<div class="codepen" data-default-tab="result" data-height="497" data-slug-hash="efJIh" data-theme-id="907" data-user="ys25">
See the Pen <a href="http://codepen.io/ys25/pen/efJIh">Sencha Touch - Hello World</a> by Brian Lin (<a href="http://codepen.io/ys25">@ys25</a>) on <a href="http://codepen.io/">CodePen</a></div>
<script async="" src="http://codepen.io/assets/embed/ei.js"></script>Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-63080312322719617602013-08-28T11:01:00.000+08:002013-08-28T11:02:58.817+08:00Sencha Touch AJAX 跨網域存取 (Cross Domain Request)通常為了省麻煩,我們會把『提供網頁的 server』與『提供資料的 API server』放在同一個網域下,除非是存取第三方的 server,但現在大多走 OAuth 配合 token 在做存取...<br />
<br />
<br />
<h3>
那為何我會遇到跨網域問題?</h3>
是這樣的,使用 PhoneGap 開發 app 時,若要跟 API server 要資料也屬於跨網域存取,不過 PhoneGap 的 webkit 設計不像我們平常在用的 browser,所以不會有此限制。<br />
<br />
只是開發過程我們會直接利用 browser debug,不會每次都把網頁放到 PhoneGap 內,然後 build、deploy 到 mobile device... 這實在太花時間了,這就是為何我需要解決 cross domain 的原因。<br />
<br />
<a name='more'></a><br />
先來看看直接存取會發生什麼事:<br />
這是一個基本的 AJAX request,POST 帳號密碼做登入的動作<br />
<pre class="brush: js">Ext.Ajax.request({
url: 'http://api.example.com/login.php',
params: {
username: 'sylar',
password: '123456'
},
success: function(response, opts) {
console.log(response.responseText);
},
failure: function(response, opts) {
console.log('server-side failure with status code ' + response.status);
}
});
</pre>
<br />
於是瀏覽器 console 出現錯誤訊息:<br />
<ul>
<li>OPTIONS http://api.example.com/login.php?_dc=1377654028515 Origin http://localhost is not allowed by Access-Control-Allow-Origin.</li>
<li>XMLHttpRequest cannot load http://api.example.com/login.php?_dc=1377654028515. Origin http://app.localhost is not allowed by Access-Control-Allow-Origin.</li>
</ul>
跨網域存取時,browser 會先使用 HTTP OPTIONS method 詢問 server 是否允許這樣的 request,由於沒有得到正確的回應,browser 終止存取。<br />
<br />
<br />
<h3>
解法一:修改瀏覽器執行方式</h3>
這也是最快的方法<br />
Windows
<br />
<pre class="brush: bash; gutter: false">chrome.exe --disable-web-security
</pre>
<br />
MacOS
<br />
<pre class="brush: bash; gutter: false">open -a Google\ Chrome --args --disable-web-security
</pre>
<br />
<br />
<h3>
解法二:Server 回應特定 header</h3>
也就是允許任何來源<br />
<pre class="brush: bash; gutter: false">Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
</pre>
不過會發現有個缺點,就是每次 GET / POST 時,browser 總是會先發送 OPTIONS 詢問 server,造成頻寬浪費,可以在 Ajax.request 加入下列的參數就可避免<br />
<pre class="brush: bash; gutter: false">useDefaultXhrHeader: false
</pre>
<br />
<br />
<h3>
Cookie 無法儲存?</h3>
由於我的 server 認證方式是使用 session,也就是登入成功後,server 會使用 set-cookie 的方式要求 browser 把 session key 存在 cookie 內,不過上述方法並無法儲存 cookie。<br />
<br />
解決的方式就是在 Ajax.request 加入參數
<br />
<pre class="brush: bash; gutter: false">withCredentials: true
</pre>
<br />
而 server 也必須明確指定允許的來源位址,不能用 wildcard (*),再來是 Access-Control-Allow-Credentials 值要為 true
<br />
<pre class="brush: bash; gutter: false">Access-Control-Allow-Origin: http://localhost
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Credentials: true
</pre>
<br />
以上就是跨網域存取,server / client 要做的修改,更多關於 Sencha Touch Ajax 的用法請參考官網的 Guideline:<a href="http://docs.sencha.com/touch/2.2.1/#!/guide/ajax">Using AJAX - Touch 2.2.1 - Sencha Docs</a><br />
<br />
<br />
參考資料<br />
<a href="http://stackoverflow.com/questions/10830334/ext-ajax-request-sending-options-request-cross-domain-when-jquery-ajax-sends-get">javascript - Ext.Ajax.request sending OPTIONS request cross-domain when jQuery.ajax sends GET - Stack Overflow</a><br />
<a href="http://stackoverflow.com/questions/14257156/cookies-not-saved-in-sencha-touch-2">ajax - Cookies not saved in Sencha Touch 2 - Stack Overflow</a>Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-9204791603088777212013-08-26T15:19:00.001+08:002013-09-02T14:44:17.437+08:00PhoneGap 開發:Android back button 事件處理使用 PhoneGap 開發 app 時,在 Android 平台上,預設按下 back button 的處理方式是關閉程式,這應該會讓使用者崩潰。PhoneGap 有提供對應的 backbutton 事件可以註冊,這樣就可以照自己的方式來處理。<br />
<br />
<br />
這邊的處理方式是呼叫原生的 confirm 對話框,詢問 user 是否離開:
<br />
<pre class="brush: js">// Register event for back button
document.addEventListener("backbutton", function() {
navigator.notification.confirm(
'你確定要離開程式嗎?',
onConfirmQuit,
'關閉',
['確定', '取消']
);
}, true);
function onConfirmQuit(button) {
if (button == "1") {
// Leave app
navigator.app.exitApp();
}
}
</pre>
<div style="text-align: left;">
<a href="http://3.bp.blogspot.com/-Gj4biZ_B9Ts/UhsAJRFjg3I/AAAAAAAABQI/AZDjVMaCT-k/s1600/Screen+Shot+2013-08-26+at+%E4%B8%8B%E5%8D%882.47.34.png" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="125" src="http://3.bp.blogspot.com/-Gj4biZ_B9Ts/UhsAJRFjg3I/AAAAAAAABQI/AZDjVMaCT-k/s200/Screen+Shot+2013-08-26+at+%E4%B8%8B%E5%8D%882.47.34.png" width="200" /></a></div>
<br />
<br />
身為一個 Sencha Touch 的使用者,用客制化的視窗也是可以 OK 的
<br />
<pre class="brush: js">document.addEventListener("backbutton", function() {
Ext.Msg.confirm("關閉", "你確定要離開程式嗎?", function(buttonId) {
if (buttonId == 'yes')
navigator.app.exitApp();
});
}, true);
</pre>
<div style="text-align: left;">
<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-YmAKSu0KlAk/UhsARlU2oKI/AAAAAAAABQQ/jLxgOqkZNGY/s1600/Screen+Shot+2013-08-26+at+%E4%B8%8B%E5%8D%883.01.59.png" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="92" src="http://2.bp.blogspot.com/-YmAKSu0KlAk/UhsARlU2oKI/AAAAAAAABQQ/jLxgOqkZNGY/s200/Screen+Shot+2013-08-26+at+%E4%B8%8B%E5%8D%883.01.59.png" width="200" /></a></div>
<div style="text-align: left;">
</div>
</div>
<br />
更進階的做法就是讓使用者按下 back 時可以回到上一層的畫面,不過這邊我也還沒試過,目前的想法是啓用 location hash,按下 back 時就像瀏覽器回到上一頁一樣。參考:<a href="http://docs.sencha.com/touch/2.2.1/#!/guide/history_support">History Support - Touch 2.2.1 - Sencha Docs</a>Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-91495860233634880292013-08-26T11:54:00.002+08:002013-08-26T11:58:07.380+08:00利用 ImageMagick 製作 App 所需的 icon size以下是 Android / iOS 兩種平台的 icon 開發指南,裡面有條列解析度/機型對應的 icon size<br />
<ul>
<li>Android: <a href="http://developer.android.com/design/style/iconography.html">Iconography | Android Developers</a></li>
<li>iOS: <a href="https://developer.apple.com/library/ios/documentation/userexperience/conceptual/mobilehig/IconsImages/IconsImages.html">iOS Human Interface Guidelines: Custom Icon and Image Creation Guidelines</a></li>
</ul>
<br />
<br />
在此我是利用 PhoneGap 建立 mobile 專案,預設就有一組 icon,我們只要準備相同解析度的圖片覆蓋過去就可以了<br />
<br />
Android 各解析度 icon 分別放置在不同的資料夾底下<br />
<ul>
<li>res/drawable/logo.png 96x96</li>
<li>res/drawable-xhdpi/logo.png 96x96</li>
<li>res/drawable-hdpi/logo.png 72x72</li>
<li>res/drawable-mdpi/logo.png 48x48</li>
<li>res/drawable-ldpi/logo.png 36x36</li>
</ul>
<br />
iOS 擺放 icon 的位置在專案資料夾底下的 {project-name}/Resources/icons/<br />
<ul>
<li>icon-72.png 72x72</li>
<li>icon-72@2x.png 144x144</li>
<li>icon.png 57x57</li>
<li>icon@2x.png 114x114</li>
</ul>
<br />
<br />
利用 ImageMagick 搭配 shell script 就可以一次轉出所有解析度的 icon<br />
<br />
安裝 <a href="http://www.imagemagick.org/script/index.php">ImageMagick</a> 目前最新版本 <a href="http://www.imagemagick.org/download/ImageMagick.tar.gz">6.8.6-8</a><br />
<pre class="brush: bash; gutter: false">$ ./configure --with-png=yes
$ make && make install
</pre>
<br />
轉換解析度
<br />
<pre class="brush: bash; gutter: false">$ convert logo-src.png -resize 72x72 logo-72.png
</pre>
<br />
批次轉換 script: convert.sh<br />
<pre class="brush: bash">#/bin/sh
res=(144 114 96 72 57 48 36)
for i in "${res[@]}"
do
echo "convert icon for ${i}x${i}"
convert logo-src.png -resize ${i}x${i} logo-${i}.png
done
</pre>
<br />
記得 icon 的來源檔案解析度至少要大於144,轉出來才不會糊掉<br />
<br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com1tag:blogger.com,1999:blog-2638913948091575022.post-67202264185364126372013-08-19T23:53:00.001+08:002014-06-28T22:39:48.487+08:00PhoneGap + Sencha Touch Quickstart (Part III)<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-Ja5FjBaWTPA/UhG89PsADVI/AAAAAAAABOI/hV2UkTbOqlw/s1600/phonegap_logo.png" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" src="http://2.bp.blogspot.com/-Ja5FjBaWTPA/UhG89PsADVI/AAAAAAAABOI/hV2UkTbOqlw/s200/phonegap_logo.png" height="120" /></a><a href="http://1.bp.blogspot.com/-zWLjDABz3qs/UhG8_diYIyI/AAAAAAAABOQ/r42_gUY7w6A/s1600/sencha-large.png" imageanchor="1" style="text-align: center;"><img border="0" src="http://1.bp.blogspot.com/-zWLjDABz3qs/UhG8_diYIyI/AAAAAAAABOQ/r42_gUY7w6A/s320/sencha-large.png" height="120" /></a></div>
<br />
透過前兩篇(<a href="http://blog.yslin.tw/2013/08/phonegap-sencha-touch-quickstart-part-i.html">Part I</a>, <a href="http://blog.yslin.tw/2013/08/phonegap-sencha-touch-quickstart-part-ii.html">Part II</a>)我們分別建立的 PhoneGap 專案與 Sencha Touch 專案,再來就是將他們合併,也就是讓 Sencha Touch 透過 PhoneGap run 在模擬器上<br />
<br />
<br />
<br />
<h3>
Part III:Sencha Touch 與 PhoneGap 的結合</h3>
<br />
<h4>
1. 把 Sencha Touch web page 複製到 PhoneGap</h4>
我們可以把 PhoneGap 想像成一個載體 (webview),上面運行著 Sencha Touch web page,而透過 javascript 可以和底層的 device 溝通。<br />
<br />
所以最快的方式就是把 build 出來的 Sencha Touch package 複製到 PhoneGap 底下的 www 資料夾,然後重新 build PhoneGap,再重新 build 各平台的專案。<br />
(在此為了簡化示範流程,才會用手動的方式複製,真正在開發時應該使用 ST project 內的 build.xml 去描述此步驟)<br />
<br />
<div>
<div style="float: left;">
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://4.bp.blogspot.com/-mjjW0qeIo7k/UhIwppDnAHI/AAAAAAAABO0/PP9cu5FqBCw/s1600/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%8810.45.12.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" src="http://4.bp.blogspot.com/-mjjW0qeIo7k/UhIwppDnAHI/AAAAAAAABO0/PP9cu5FqBCw/s320/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%8810.45.12.png" height="320" width="212" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">編譯出來的 ST 程式碼</td></tr>
</tbody></table>
</div>
<div style="float: left;">
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="http://3.bp.blogspot.com/-f8dqUdYCg90/UhIwpupuASI/AAAAAAAABOw/ZJ5pTA43s7c/s1600/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%8810.49.02.png" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto; text-align: center;"><img border="0" src="http://3.bp.blogspot.com/-f8dqUdYCg90/UhIwpupuASI/AAAAAAAABOw/ZJ5pTA43s7c/s1600/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%8810.49.02.png" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Copy 到 PhoneGap 的www</td></tr>
</tbody></table>
</div>
</div>
<div style="clear: both;">
</div>
注意來源跟目的,一個是 ST 一個是 PhoneGap。<br />
另外原本在 www 裡面的 config.xml 要留著,編譯時會用到!<br />
<pre class="brush: html; gutter: false">$ cp -a SenchaTouch/hello/build/HelloWorld/package/* PhoneGap/hello/www/
$ phonegap build ios
$ phonegap build android
</pre>
<br />
按照 <a href="http://blog.yslin.tw/2013/08/phonegap-sencha-touch-quickstart-part-i.html">Part I</a> 的方式分別編譯 ios/android 並運行<br />
Good! It works.<br />
<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-fiUsYeFzOZQ/UhI0O1jechI/AAAAAAAABPI/60BOJSkysog/s1600/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%8811.03.18.png" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" src="http://2.bp.blogspot.com/-fiUsYeFzOZQ/UhI0O1jechI/AAAAAAAABPI/60BOJSkysog/s320/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%8811.03.18.png" height="290" /></a><a href="http://2.bp.blogspot.com/-Xjyh9sRdUG0/UhI0O3vYJqI/AAAAAAAABPE/PRnuJiap4xs/s1600/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%8811.04.30.png" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" src="http://2.bp.blogspot.com/-Xjyh9sRdUG0/UhI0O3vYJqI/AAAAAAAABPE/PRnuJiap4xs/s320/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%8811.04.30.png" height="300" /></a></div>
<br />
<br />
<h4>
2. 加入 PhoneGap deviceready event</h4>
由於 Sencha Touch demo 程式中並未使用到 PhoneGap 提供的 API,為了證明它可以work,所以我們要修改 Sencha Touch project 中的 index.html,加入很簡單的程式碼:當 deviceready event 觸發時就在 debug window 印出 deviceready (註:device ready 就表示 API 可以呼叫了)<br />
加在 <head></head>之間,include "touch/microloader/development.js" 之後<br />
<pre class="brush: html; gutter: false"><script type="text/javascript" src="phonegap.js"></script>
<script type="text/javascript">
document.addEventListener('deviceready', function() {
console.log('deviceready');
}, false);
</script>
</pre>
<br />
重新編譯 Sencha Touch project 後產生 package,將其 copy 到 PhoneGap ... (<u><b>重複步驟1</b></u>)<br />
還記得編譯 ST 的指令嗎<br />
<pre class="brush: html; gutter: false">$ sencha app build package
</pre>
<br />
若看到 demo 網頁出現,同時 console 也跑出 deviceready 字眼,表示我們成功結合 Sencha Touch 與 PhonaGap 了!<br />
<br />
iOS 訊息<br />
<pre class="brush: html; gutter: false">2013-08-19 23:51:55.016 HelloWorld[71208:c07] deviceready
</pre>
Android 訊息
<br />
<pre class="brush: html; gutter: false">I/Web Console( 1291): deviceready at file:///android_asset/www/index.html:61
</pre>
<br />
註:<br />
ios 的 debug window 在 Xcode 裡面<br />
android 可以透過下面指令觀看整個系統的 log<br />
<pre class="brush: html; gutter: false">$ adb -s emulator-5554 logcat
</pre>
<br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-24753496728730886972013-08-19T16:39:00.000+08:002013-08-20T08:18:30.136+08:00PhoneGap + Sencha Touch Quickstart (Part II)<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-Ja5FjBaWTPA/UhG89PsADVI/AAAAAAAABOI/hV2UkTbOqlw/s1600/phonegap_logo.png" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="120" src="http://2.bp.blogspot.com/-Ja5FjBaWTPA/UhG89PsADVI/AAAAAAAABOI/hV2UkTbOqlw/s200/phonegap_logo.png" /></a><a href="http://1.bp.blogspot.com/-zWLjDABz3qs/UhG8_diYIyI/AAAAAAAABOQ/r42_gUY7w6A/s1600/sencha-large.png" imageanchor="1" style="text-align: center;"><img border="0" height="120" src="http://1.bp.blogspot.com/-zWLjDABz3qs/UhG8_diYIyI/AAAAAAAABOQ/r42_gUY7w6A/s320/sencha-large.png" /></a></div>
<br />
<a href="http://blog.yslin.tw/2013/08/phonegap-sencha-touch-quickstart-part-i.html">上一篇</a>講完了如何建立 PhoneGap 專案並且 run 在模擬器上,再來要講 Sencha Touch 這個 mobile web framework<br />
<br />
<br />
<br />
<h3>
Part II: 建立 Sencha Touch 專案</h3>
<br />
<h4>
1. 下載 Sencha Touch SDK 與 Sencha Cmd</h4>
SDK 有分兩種版本 GPL 與 Commercial,目前最新版本為 2.2.1 <a href="http://www.sencha.com/products/touch/download/">在此下載</a><br />
解壓縮開之後可以得到 touch-2.2.1 資料夾<br />
<br />
Sencha Cmd 有 Mac 專屬版本,最新版本為 3.1.2 <a href="http://www.sencha.com/products/sencha-cmd/download">在此下載</a><br />
下載後是個安裝檔,請指定安裝路徑。安裝後請把 sencha 執行檔的路徑加到環境變數 $PATH<br />
<br />
試一下是否 work<br />
<pre class="brush: bash; gutter: false">$ sencha help | head -n 1
Sencha Cmd v3.1.2.342
</pre>
<br />
<br />
<h4>
2. 建立專案</h4>
利用 Sencha CMD 來建立專案,請指定 sdk 路徑到剛剛下載的 touch-2.2.1,HelloWorld 為專案名,"./hello"是專案建立的位置
<pre class="brush: bash; gutter: false">$ sencha -sdk ~/Development/touch-2.2.1 generate app HelloWorld ./hello
</pre>
產生專案資料夾 hello,裡面的 index.html 就是 app 的首頁<br />
app.js 是程式進入點,app 資料夾依據 MVC 的分類放置自己的程式碼<br />
resources 擺放 css, image, icon 這些檔案<br />
touch 放置 Sencha Touch 原始碼,編譯時會引用<br />
<br />
<br />
<h4>
3. 編譯專案</h4>
夠過編譯可以將引用到的 javascript 從 source 中抽出並壓縮,SCSS 的部分也是會經過 compass 編譯壓縮<br />
<pre class="brush: bash; gutter: false">$ sencha app build package
</pre>
在 hello/build/HelloWorld/package 資料夾下可以看到編譯結果<br />
<br />
<br />
<h4>
4. 測試</h4>
啓動 MacOS 內建 apache<br />
<pre class="brush: bash; gutter: false">$ sudo apachectl start
</pre>
<br />
將 hello/build/HelloWorld/package copy 到 apache 預設的 document root: /Library/WebServer/Documents/hello<br />
瀏覽網頁 http://localhost/hello/ 即可看到 demo 網站<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-ocrWDQSd1mk/UhHXlG3FwYI/AAAAAAAABOg/11aPdwANYxE/s1600/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%884.29.47.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="294" src="http://4.bp.blogspot.com/-ocrWDQSd1mk/UhHXlG3FwYI/AAAAAAAABOg/11aPdwANYxE/s320/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%884.29.47.png" width="320" /></a></div>
<br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-71454545035027774802013-08-19T14:17:00.000+08:002013-08-20T08:01:01.874+08:00PhoneGap + Sencha Touch Quickstart (Part I)<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-Ja5FjBaWTPA/UhG89PsADVI/AAAAAAAABOI/hV2UkTbOqlw/s1600/phonegap_logo.png" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="120" src="http://2.bp.blogspot.com/-Ja5FjBaWTPA/UhG89PsADVI/AAAAAAAABOI/hV2UkTbOqlw/s200/phonegap_logo.png" /></a><a href="http://1.bp.blogspot.com/-zWLjDABz3qs/UhG8_diYIyI/AAAAAAAABOQ/r42_gUY7w6A/s1600/sencha-large.png" imageanchor="1" style="text-align: center;"><img border="0" height="120" src="http://1.bp.blogspot.com/-zWLjDABz3qs/UhG8_diYIyI/AAAAAAAABOQ/r42_gUY7w6A/s320/sencha-large.png" /></a></div>
<br />
PhoneGap + Sencha Touch 這是跨平台 mobile app 開發的一種組合,在開發速度與效能都能接受的情況下,我近期都投入在這個 framework。在此要與大家分享如何快速建立一個 mobile app,系列文章包含三部分:
<br />
<ul>
<li><a href="http://blog.yslin.tw/2013/08/phonegap-sencha-touch-quickstart-part-i.html">Part I: 建立 PhoneGap 專案</a></li>
<li><a href="http://blog.yslin.tw/2013/08/phonegap-sencha-touch-quickstart-part-ii.html">Part II: 建立 Sencha Touch 專案</a></li>
<li><a href="http://blog.yslin.tw/2013/08/phonegap-sencha-touch-quickstart-part.html">Part III: Sencha Touch 與 PhoneGap 的結合</a></li>
</ul>
<br />
<h3>
基本需求</h3>
開發環境 MacOS<br />
PhoneGap 3.0.0<br />
SenchaTouch 2.2.1<br />
<br />
<br />
<h3>
Part I:建立 PhoneGap 專案</h3>
<br />
<h4>
1. 安裝 Mobile SDK</h4>
PhoneGap 支援的 mobile 平台有很多種,在這邊只針對 iOS 與 Android 做說明。<br />
iOS 需要安裝 Xcode,可以從 app store 下載,目前我使用的版本是 4.6.3。<br />
而 Android 的部分請參照 <a href="http://docs.phonegap.com/en/3.0.0/guide_platforms_android_index.md.html#Android%20Platform%20Guide">Android Platform Guide</a> 下載 ADT,裡面包含了 Eclipse 編輯器與 SDK,SDK 的路徑必須加到環境變數 $PATH,日後 command line 會使用到。
<br />
<br />
<br />
<h4>
2. 安裝 PhoneGap</h4>
PhoneGap 3.0.0 開始的 command line tool 改由 npm 套件管理程式來維護,所以我們要先安裝 node。<a href="http://nodejs.org/download/">Node.js官方網站</a>有提供 Mac 專屬的.pkg可以下載,不過我習慣抓 source code 下來編譯,node 安裝好之後自然也會有 npm 指令可以用<br />
<br />
利用 npm 來安裝 phonegap
<br />
<pre class="brush: bash; gutter: false">$ sudo npm install -g phonegap
$ phonegap -v
3.0.0-0.14.3
</pre>
<br />
<br />
<h4>
3. 建立 PhoneGap 專案</h4>
<pre class="brush: bash; gutter: false">$ phonegap create hello com.example.hello HelloWorld
</pre>
產生 hello 資料夾,裡面包含 merges, platforms, plugins, www<br />
platform 擺放各 mobile 平台的專案,plugins 存放提供你存取 device-level API 的 plugin,而 www 就是 app 主程式,平時就是編譯這一份檔案,預設會有基本的 demo 程式在裡面<br />
<br />
剛建立好的 phonegap project 是不包含任何 mobile 平台支援,我們要加入 ios, android
<br />
<pre class="brush: bash; gutter: false">$ phonegap build ios
$ phonegap build android
</pre>
可以看到 hello/platform/ 之下有這兩個平台的專案資料夾
<br />
<br />
再來我們安裝 device-level API 支援,在此僅安裝最基本的 console plugin,至少可以拿來 debug,其它像是 camera, geolocation... 日後都可以依需求再安裝
<br />
<pre class="brush: bash; gutter: false">$ phonegap local plugin add https://git-wip-us.apache.org/repos/asf/cordova-plugin-console.git
</pre>
<br />
<br />
<h4>
4. 編譯 PhoneGap 專案</h4>
PhoneGap 提供 command line 的方式可以編譯與運行,在此我則採用自己的方式<br />
<pre class="brush: bash; gutter: false">$ phonegap build</pre>
下達此指令後,PhoneGap 會從 hello/www 去建立各平台的必要資源,包含 app 原始碼與 plugin,可以在下面資料夾看到編譯結果<br />
hello/platform/ios/www<br />
hello/platform/android/assets/www<br />
<br />
<br />
<h4>
5. 編譯各平台的專案並運行</h4>
iOS 的部分,用 Xcode 開啓 hello/platform/ios/HelloWorld.xcodeproj,按下左上角的編譯就可以在模擬器上面運行了。同時間在 console window 也可以看到 deviceready 的字眼<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-PpGjqMiOpCU/UhG5ZNv21cI/AAAAAAAABN0/iRWz4nxWGLA/s1600/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%882.02.34.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-PpGjqMiOpCU/UhG5ZNv21cI/AAAAAAAABN0/iRWz4nxWGLA/s320/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%882.02.34.png" width="170" /></a></div>
<br />
<br />
Android 的部分程序比較多,請先參照 <a href="http://docs.phonegap.com/en/3.0.0/guide_platforms_android_index.md.html#Android%20Platform%20Guide">Android Platform Guide</a> 設定模擬器並開啓<br />
<br />
編譯 android 專案<br />
<pre class="brush: bash; gutter: false">$ cd platform/android
$ ant debug
</pre>
<br />
列出可用的模擬器<br />
<pre class="brush: bash; gutter: false">$ adb devices
List of devices attached
emulator-5554 device
</pre>
<br />
安裝到模擬器<br />
<pre class="brush: bash; gutter: false">$ adb -s emulator-5554 install -r bin/HelloWorld-debug.apk
337 KB/s (1579758 bytes in 4.565s)
pkg: /data/local/tmp/HelloWorld-debug.apk
Success
</pre>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-_GbTJiT8Nk0/UhG5epR-SyI/AAAAAAAABN8/04prxf-ieLo/s1600/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%882.02.17.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="297" src="http://2.bp.blogspot.com/-_GbTJiT8Nk0/UhG5epR-SyI/AAAAAAAABN8/04prxf-ieLo/s320/Screen+Shot+2013-08-19+at+%E4%B8%8B%E5%8D%882.02.17.png" width="320" /></a></div>
<br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-54934341165906157912013-06-20T08:22:00.000+08:002013-06-20T08:23:23.453+08:00jQuery Mobile: Page 動態載入與切換jQuery Mobile Page 是在 implement mobile app 很常用到的元件,它可以模擬 iOS navigation controller + view controller 的操作界面,不用寫太多程式碼就可以達到這樣的 UI 呈現,但真正在使用時,常常會遇到動態載入 page 或是同一個 page 要呈現不同 content 的時候,對於我這個初學者而言,也還在摸索怎麼管理這些page。<br /><br />
以下列出幾種動態載入 page 的方式:<br />
<br />
<h3>
Static page</h3>
提供兩種切換頁面的方式<br />
In html file
<br />
<pre class="brush: html"><div data-role="page" id="page1">
<div data-role="header">
<h1>Page 1</h1>
</div>
<div data-role="content">
<a href="#page2">Change Page</a>
<a href="#" onclick="$.mobile.changePage('#page2');">Change Page</a>
</div>
<div data-role="footer">
<h4>Page Footer</h4>
</div>
</div>
<div data-role="page" id="page2">
<div data-role="header">
<h1>Page 2</h1>
</div>
<div data-role="content">
<p>In page 2</p>
</div>
<div data-role="footer">
<h4>Page Footer</h4>
</div>
</div>
</pre>
<br />
<br />
<h3>
Load from html file</h3>
先放一個空的 page,再用 ChangePage() 的方式 load 下一個 page,把 page 分開在不同的檔案,code 比較清楚<br />
In html file
<br />
<pre class="brush: html"><div data-role="page" id="page1">
</div>
</pre>
<br />
In js file
<br />
<pre class="brush: js">$(function(){
$.mobile.changePage("tpl/page2.html", {
transition: "pop",
reverse: false,
changeHash: false
});
});
</pre>
<br />
<br />
<h3>
Load html file as template</h3>
用 ajax 的方式去 load html 並當成 template,套用 data 後變成 page<br />
index.html
<br />
<pre class="brush: html"><div data-role="page" id="page2">
<div data-role="header">
<h1><%= title %></h1>
</div>
<div data-role="content">
<p><%= content %></a>
</div>
<div data-role="footer">
<h4>Page Footer</h4>
</div>
</div>
</pre>
<br />
In js file<br />
需要搭配 underscore.js 的 template
<br />
<pre class="brush: js">$(function(){
$.get('tpl/page2.html', function(data) {
var tpl = _.template(data);
var m = {title: "This is title", content: "In the page 2"};
var newPage = $(tpl(m));
newPage.appendTo($.mobile.pageContainer);
$.mobile.changePage(newPage);
});
});
</pre>
<br />
但上述的方法有個問題,就是 page 一直用 append 的方式加到 html 裡,對記憶體是個消耗,尚在思考要怎麼管理這些 page...
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-49940892096254068582013-06-16T23:12:00.000+08:002013-06-16T23:15:16.519+08:00jQuery Mobile + PhoneGap 快速打造 App再次回到 mobile app 的世界。<br />
<br />
最近接了一個 case,要做一個跨平台的 news feed,想到的組合就是 jQuery Mobile + PhoneGap,為了讓 code 更乾淨,也加入了 backbone.js 這個 MV* framework,說真的,這樣的組合我還沒開發過任何一支產品,本身是 back-end 起家,frontend 算是玩興趣的,兜一些小玩意還可以,開發大 project 就辛苦些...<br />
<br />
<br />
用 jQuery mobile 兜 UI 比 native code 快了 n 倍,常用的 page view、table view、navigation bar...都可以在簡單的幾行 html 搞定。呈現 static 資料很容易,如果是 dynamic 資料對我這新手就...<br />
分析需求之後,大概就幾個版型:category list、title list、content display,然後塞進不同的資料(來源可以是 api server 吐回來的 json)<br />
<br />
<br />
Main menu 打算用 <a href="http://jquerymobile.com/demos/1.3.0-beta.1/docs/panels/">slide panel</a> 來呈現,panel 這物件是要擺在 page 裡面的,那如果每個 page 都需要 panel 該怎做?<br />
<a href="http://stackoverflow.com/questions/15222589/jquery-mobile-do-i-have-to-create-a-new-panel-for-every-page">javascript - jquery mobile: do I have to create a new panel for every page - Stack Overflow</a><br />
一份 menu 共用摟,我想到的是把 panel 獨立成一個 template,在 pageshow event 去加載<br />
看到一些蠻炫的 panel<br />
<ul>
<li><a href="http://designhuntr.com/15-slide-panel-jquery-plugins/">15 Slide Panel jQuery Plugins - DesignHuntR</a></li>
<li><a href="http://www.jquery4u.com/plugins/10-jquery-panel-slider-plugins/">10 jQuery Panel Slider Plugins | jQuery4u</a></li>
</ul>
<br />
<br />
jQM 的 <a href="http://jquerymobile.com/demos/1.3.0-rc.1/docs/pages/page-anatomy.html">page sample</a> 中,同個 html 嵌了多個 page,這在現實環境也是不合需求的。第一、全部的 page 放在同一頁肯定 code 會過長,第二、page 的內容會是 dynamic 的,page 本身應該只是個樣版<br />
官網有提到動態載入 page 的方式:<a href="http://jquerymobile.com/demos/1.2.1/docs/pages/page-dynamic.html">jQuery Mobile and Dynamic Page Generation</a><br />
很明顯的沒有 router 與 template 的支援,code 相當冗長,於是就引入了 backbone.js 的 route 與 underscore.js 的 template<br />
<br />
由於 jQM 與 backbone.js 都會監聽 hash change event,若要使用後者的 router,請參考<br />
<ul>
<li><a href="http://jquerymobile.com/demos/1.3.0-rc.1/docs/pages/backbone-require.html">jQuery Mobile, Backbone.js and Require.js</a></li>
<li><a href="http://coenraets.org/blog/2012/03/using-backbone-js-with-jquery-mobile/">Using Backbone.js with jQuery Mobile | Christophe Coenraets</a></li>
</ul>
<br />
<br />
如果閒自己寫 html 太慢,可以使用 jQM UI builder<br />
<ul>
<li><a href="http://jquerymobile.com/">jquery mobile UI builder</a></li>
<li><a href="http://www.mobjectify.com/">mobjectify - Mockups and more for the mobile web</a></li>
<li><a href="http://www.codiqa.com/">The Fastest Mobile Prototyping - Codiqa</a></li>
</ul>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com1tag:blogger.com,1999:blog-2638913948091575022.post-63386281745272163252013-05-21T14:47:00.001+08:002013-05-21T14:47:57.784+08:00解開 fd_set size limitation寫 socket programming 時會用 select 搭配 fd_set 來偵測 file descriptor 是否可讀寫<br />
但 Linux 系統預設的 fd_set size 只有 1024,若同時間處理的 fd 超過 1024 就會出問題<br />
<br />
<br />
修改下面這兩個檔案,重新 build application 時就會引用到新的 define 值<br />
<br />
/usr/include/bits/typesizes.h:<br />
<pre class="brush: c; gutter: false">#define __FD_SETSIZE 1024
</pre>
<br />
/usr/include/linux/posix_types.h:<br />
<pre class="brush: c; gutter: false">#define __FD_SETSIZE 1024
</pre>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com1tag:blogger.com,1999:blog-2638913948091575022.post-83776560496032018132013-04-25T20:41:00.002+08:002013-06-20T07:54:14.750+08:00初次玩 Backbone.js: 多種 Template 的實作方式假設我想設計一個公司資料,model 為單一員工資料,包含 id 與 name。collection 為部門資料,由多個員工所組成。而 view 用來顯示部門資料之用。<br />
<pre class="brush: js">// Models
company.models.Employee = Backbone.Model.extend({
defaults: {
id: undefined,
name: undefined
}
});
// Collections
company.collections.Department = Backbone.Collection.extend({
model: company.models.Employee
});
// Views
company.views.EmployeeList = Backbone.View.extend({
el: "#container",
render: function() {
...
}
});
// Create base data
var c = new company.collections.Department(
[{id:1, name: "Star Willard"},
{id:2, name: "Rhona Eggleston"},
{id:3, name: "Cassi Chowdhury"},
{id:4, name: "Leigh Nilson"},
{id:5, name: "Niesha Auger"}
]);
// Create view
var v = new company.views.EmployeeList({collection: c});
v.render();
</pre>
<br />
<br />
以下就來探討 render function 該怎麼把 collection 套用到 template 並呈現在 UI 上
<br />
<br />
<a name='more'></a><br />
<h3>
方法一:土法煉鋼,串成 string</h3>
<br />
這種方法當然是很差啦,程式可讀性下降,也很難維護<br />
<br />
Render function in app.js
<br />
<pre class="brush: js">render: function() {
var that = this;
this.collection.each(function(m) {
var html = "<div>" +
"<b>" + m.get("id") + "</b> " +
"<u>" + m.get("name") + "</u>" +
"</div>";
that.$(".list").append(html);
});
return this;
}
</pre>
<br />
<br />
<h3>
方法二:寫在 stript 內</h3>
<br />
利用 underscore.js template engine<br />
比前一種好一點點,但還是有缺點,沒有把 template 切出去,一方面 IDE 的 syntax 會失效<br />
<br />
in index.html
<br />
<pre class="brush: html"><script id="template-item" type="text/template">
<div>
<b><%= id %></b>
<u><%= name %></u>
</div>
</script>
</pre>
Render function in app.js
<br />
<pre class="brush: js">template: _.template($("#template-item").html()),
render: function() {
var that = this;
this.collection.each(function(m) {
that.$(".list").append(that.template(m.toJSON()));
});
return this;
}
</pre>
<br />
<br />
<h3>
方法三:從獨立的 html 檔案中讀取</h3>
<br />
把 template 寫在個別的 html 檔,利用 ajax 的方式去 load。<br />
程式碼較好管理,但每讀取一次 template 就要多發一個 http request<br />
<br />
tpl/template-item.html
<br />
<pre class="brush: html"><div>
<b><%= id %></b>
<u><%= name %></u>
</div>
</pre>
<br />
Add the template manager to app.js<br />
其實只是把 get request 包起來啦
<br />
<pre class="brush: js">company.utils.TemplateManager = {
load: function(name, callback) {
$.get('tpl/' + name + '.html', function(data) {
callback(data);
});
}
};
</pre>
<br />
Render function in app.js
<br />
<pre class="brush: js">render: function() {
var that = this;
company.utils.TemplateManager.load('template-item', function(data) {
var tpl = _.template(data);
that.collection.each(function(m) {
that.$(".list").append(tpl(m.toJSON()));
});
});
return this;
}
</pre>
<br />
<br />
<h3>
方法四:Asynchronously load template</h3>
<br />
與其說是非同步,正確來說應該是預先載入(preload),之後使用時就可以直接從 local variable 取出,加快反應速度,也可以省去從 server 抓取相同 template 的功耗<br />
<br />
TemplateLoader in app.js
<br />
<pre class="brush: js">company.utils.TemplateManager = {
templates: {},
load: function(names) {
var that = this;
$.each(names, function(index, name) {
$.get('tpl/' + name + '.html', function(data) {
that.templates[name] = data;
});
});
},
get: function(name, callback) {
return this.templates[name];
}
};
</pre>
<br />
Render function in app.js
<br />
<pre class="brush: js">render3: function() {
var that = this;
var tpl = _.template(company.utils.TemplateManager.get('template-item'));
this.collection.each(function(m) {
that.$(".list").append(tpl(m.toJSON()));
});
}
</pre>
<br />
in app.js<br />
Preload the template before render the view.
<br />
<pre class="brush: js">company.utils.TemplateManager.load(['template-item', 'other-template']);
var v = new company.views.EmployeeList({collection: c});
v.render();
</pre>
<br />
如果要保證全部的 template 都載入才進行之後的事情,可以使用 <a href="http://api.jquery.com/jQuery.when/">jquery.when()</a>
<br />
<pre class="brush: js">load: function(names, callback) {
var deferreds = [];
var that = this;
$.each(names, function(index, name) {
deferreds.push($.get('tpl/' + name + '.html', function(data) {
that.templates[name] = data;
}));
});
$.when.apply(null, deferreds).done(callback);
}
</pre>
<br />
<br />
參考資料<br />
<ul>
<li><a href="http://coenraets.org/blog/2012/01/backbone-js-lessons-learned-and-improved-sample-app/">Backbone.js Lessons Learned and Improved Sample App | Christophe Coenraets</a></li>
<li><a href="http://liquidmedia.org/blog/2011/02/backbone-js-part-3/">An Intro to Backbone.js: Part 3 – Binding a Collection to a View - Liquid Media</a></li>
<li><a href="http://lostechies.com/derickbailey/2012/03/20/trafficcop-a-jquery-plugin-to-limit-ajax-requests-for-a-resource/">TrafficCop: A jQuery Plugin To Limit AJAX Requests For A Resource | ThoughtStream.new :derick_bailey</a></li>
</ul>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-3032749718458869322013-04-23T11:56:00.000+08:002013-04-23T11:56:00.205+08:00WebSocket on Tornado<a href="http://en.wikipedia.org/wiki/Tornado_(web_server)">Tornado</a> 一直是我愛用的 <a href="http://wiki.python.org/moin/WebFrameworks">python web framework</a>,這幾年工作上一直在寫 event-drivent socket programming,所以被它 non-blocking 的特性給深深吸引,如果每件 block 的工作都能用 asynchronous 的方式來解決,那程式執行的效率一定超好!<br />
<br />
<br />
延續『<a href="http://blog.yslin.tw/2013/04/websocket.html">WebSocket 雙向即時通訊 - 初探</a>』,今天就以 Tornado 來寫個簡單的 WebSocket 範例。當 client 連到 server 後,會傳送 hello ,而 server 回應一樣的訊息,傳送到第五次,server 就把 client 斷掉。<br />
<br />
Server (ws_server.py)<br />
<pre class="brush: py">import tornado.ioloop
import tornado.web
from tornado import websocket
class WSHandler(websocket.WebSocketHandler):
count = 0
def open(self):
print "Client connected"
def on_message(self, msg):
print "[%d] Got message [%s] from client" % (self.count, msg)
if self.count == 4:
self.close()
return
# Write back message
self.write_message("[%d] Echo: %s" % (self.count, msg))
self.count += 1
def on_close(self):
print "Client disconnected"
application = tornado.web.Application([
(r"/", WSHandler),
])
if __name__ == "__main__":
application.listen(8888)
tornado.ioloop.IOLoop.instance().start()
</pre>
<br />
<br />
<br />
Client (ws_client.py)<br />
<pre class="brush: py">from tornado.websocket import websocket_connect
from tornado.ioloop import IOLoop
class ws_client():
conn = None # This is WebSocketClientConnection
def __init__(self):
websocket_connect('ws://localhost:8888/', callback=self.conn_cb)
def conn_cb(self, future):
self.conn = future.result()
self.conn.write_message("hello")
self.conn.read_message(self.read_cb)
def read_cb(self, future):
msg = future.result()
if msg is None:
print "Server disconnected"
IOLoop.instance().stop()
else:
print msg
self.conn.write_message("hello")
self.conn.read_message(self.read_cb)
if __name__ == '__main__':
ws_client()
IOLoop.instance().start()
</pre>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-91611816300617462122013-04-21T07:56:00.000+08:002013-04-21T09:04:26.777+08:00人生 就該有限度的冒險一件事六成把握就去做吧<br />
要相信自己的應變能力<br />
最差的時候 你還有求生存的自我保護機制<br />
<br />
一件事不要尋求全部人的認同<br />
如果想迎合全部的人<br />
那肯定會失去初衷 失去原始的自我<br />
<br />
追求完美的境界 永無止境<br />
有時候 留一成餘地給別人<br />
反而可以創造更多機會<br />
<br />
沒有什麼是絕對的<br />
要說可以做到十成<br />
我想只有你堅定的信心<br />
<br />
人生 就該有限度的冒險Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-56346146150787532392013-04-18T07:48:00.000+08:002013-04-20T12:25:04.232+08:00對於今日電視新聞的看法<a href="http://www.inside.com.tw/2013/04/16/news-is-bad-for-you">新聞有毒,勇敢戒斷你會更快樂</a><br />
--- Inside 硬塞的網路趨勢觀察<br />
<div>
<br /></div>
<br />
這半年沒看過幾次電視新聞 但不因而跟社會脫節<br />
網路 書籍 所帶來的更多 不管是 及時性 時事 知識<br />
選擇性也更廣 不只有藍台 綠台<br />
<br />
網路新聞雖然也是記者寫的 但有更多評判的機會<br />
很容易可以看到正反兩面<br />
<br />
通常新聞報導都是不好的居多 而且越糟糕的的報越久<br />
畢竟 這件事情只是一小部份 社會上還是有很多好的地方<br />
很容易過度恐慌 造成大家對社會的觀感不好<br />
<br />
像之前三餐都配人頭案 很倒胃口<br />
每天看這些 心情會好才怪<br />
<br />
畫面的呈現蔚為一種趨勢<br />
記者還要充當演員 還原現場演一次<br />
不如看寶傑的關鍵時刻娛樂性更甚<br />
人對於畫面的理解較好<br />
相對 思考 評斷能力也降低了<br />
照單全收 很好洗腦<br />
<br />
<br />
究竟 新聞的目的在於?<br />
原始概念應該接近<br />
客觀的呈現當下的情況 由收看的人思考而後斷<br />
媒體只是扮演傳遞的角色<br />
<br />
furthermore<br />
讓社會進步 而不是圖利政黨財團<br />
監督社會 揚善伐惡 但評斷的人 素質待加強<br />
畢竟 結論是直接深植到大眾<br />
<br />
播放的內容該跟大眾利益有關<br />
腥羶色 奇人異事 是新聞 但我相信有更重要的東西可以報<br />
世界觀 整體趨勢 試著把層次拉的更高<br />
<br />
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-51561230994979082712013-04-17T22:00:00.000+08:002013-04-20T12:28:02.425+08:00來去基隆走走吧愛上了平日逛街、平日旅遊的感覺,除了人比較少之外,可以和正在工作的人形成一種對比,心情特別不一樣 :P<br />
<br />
今天請假在家休息,下午一個衝動就想去基隆走走,從汐止過去還蠻快的,沿新台五路走20分鐘就到了。基隆的路真不是普通亂的,除了很多單行道,還有一些路彎彎曲曲的,感覺很容易就逆向,尤其在港邊,差點誤闖貨運專用道。<br />
<br />
查了一下比較 popular 的景點有<br />
<ul>
<li>基隆廟口夜市</li>
<li>和平島公園</li>
<li>白米甕砲台</li>
<li>外木山漁港</li>
</ul>
<br />
港邊<br />
<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-ML64XBwDzaM/UXCBO3TsIrI/AAAAAAAABIg/OHKO9MkcBdk/s1600/IMG_9176.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="200" src="http://2.bp.blogspot.com/-ML64XBwDzaM/UXCBO3TsIrI/AAAAAAAABIg/OHKO9MkcBdk/s200/IMG_9176.JPG" width="" /></a></div>
<a href="http://2.bp.blogspot.com/-DhH23Pn-8LI/UXCBPbFij3I/AAAAAAAABIo/0iOI3dIxkYU/s1600/IMG_9179.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="200" src="http://2.bp.blogspot.com/-DhH23Pn-8LI/UXCBPbFij3I/AAAAAAAABIo/0iOI3dIxkYU/s200/IMG_9179.JPG" width="" /></a> <a href="http://2.bp.blogspot.com/-AvxSVkAy5Lg/UXCBP6jQ-lI/AAAAAAAABIs/iLHMyDra_Y4/s1600/IMG_9180.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="200" src="http://2.bp.blogspot.com/-AvxSVkAy5Lg/UXCBP6jQ-lI/AAAAAAAABIs/iLHMyDra_Y4/s200/IMG_9180.JPG" width="" /></a><br />
<br />
<br />
和平島公園<br />
<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-lcpGLyars14/UXCBw6ie5yI/AAAAAAAABI4/iNvYnyC9Pk8/s1600/IMG_9183.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="200" src="http://2.bp.blogspot.com/-lcpGLyars14/UXCBw6ie5yI/AAAAAAAABI4/iNvYnyC9Pk8/s200/IMG_9183.JPG" width="" /></a> <a href="http://1.bp.blogspot.com/-0-yVeT9YcNE/UXCCR6qkuoI/AAAAAAAABJw/RDDFfK-ZJBQ/s1600/IMG_9216.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="200" src="http://1.bp.blogspot.com/-0-yVeT9YcNE/UXCCR6qkuoI/AAAAAAAABJw/RDDFfK-ZJBQ/s320/IMG_9216.JPG" width="" /></a></div>
<span id="goog_865267143"></span><span id="goog_865267144"></span>
<br />
<div style="text-align: left;">
<br />
走著走著 沙灘上突然浮現一些文字...</div>
<div style="text-align: left;">
<a href="http://4.bp.blogspot.com/-E4cu5Nwk1YA/UXCCS7sDqmI/AAAAAAAABKA/Uf8pmwM0yXI/s1600/IMG_9215.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="200" src="http://4.bp.blogspot.com/-E4cu5Nwk1YA/UXCCS7sDqmI/AAAAAAAABKA/Uf8pmwM0yXI/s320/IMG_9215.JPG" width="" /></a></div>
<br />
<br />
<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-wproroF8Fi4/UXCB0jNnPdI/AAAAAAAABJA/m5wUUobd8Gs/s1600/IMG_9188.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="" src="http://2.bp.blogspot.com/-wproroF8Fi4/UXCB0jNnPdI/AAAAAAAABJA/m5wUUobd8Gs/s320/IMG_9188.JPG" width="200" /></a> <a href="http://2.bp.blogspot.com/-_QEto061ix0/UXCB1LvJnpI/AAAAAAAABJI/M6UOh9ssfIE/s1600/IMG_9189.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="" src="http://2.bp.blogspot.com/-_QEto061ix0/UXCB1LvJnpI/AAAAAAAABJI/M6UOh9ssfIE/s320/IMG_9189.JPG" width="200" /></a> <a href="http://1.bp.blogspot.com/-1QBGRPNCa8o/UXCCHQlX2XI/AAAAAAAABJY/iHSijlpKehQ/s1600/IMG_9191.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="" src="http://1.bp.blogspot.com/-1QBGRPNCa8o/UXCCHQlX2XI/AAAAAAAABJY/iHSijlpKehQ/s320/IMG_9191.JPG" width="200" /></a></div>
<br />
<br />
發現外星生物與外星地表<br />
<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-_DVpYOscw3o/UXCCHLqghFI/AAAAAAAABJQ/VgLA4Y3IA80/s1600/IMG_9205.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="" src="http://2.bp.blogspot.com/-_DVpYOscw3o/UXCCHLqghFI/AAAAAAAABJQ/VgLA4Y3IA80/s320/IMG_9205.JPG" width="200" /></a> <a href="http://3.bp.blogspot.com/-2lFh3iv6jho/UXCCIkf-9TI/AAAAAAAABJk/PG0Vdu3YuCs/s1600/IMG_9206.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="" src="http://3.bp.blogspot.com/-2lFh3iv6jho/UXCCIkf-9TI/AAAAAAAABJk/PG0Vdu3YuCs/s320/IMG_9206.JPG" width="200" /></a></div>
<br />
夕陽餘暉<br />
<div style="text-align: left;">
<a href="http://3.bp.blogspot.com/-ho3D3B7r_HI/UXCCSApFffI/AAAAAAAABJ0/I8NhFgjVD3U/s1600/IMG_9211.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="" src="http://3.bp.blogspot.com/-ho3D3B7r_HI/UXCCSApFffI/AAAAAAAABJ0/I8NhFgjVD3U/s320/IMG_9211.JPG" width="200" /></a> <a href="http://3.bp.blogspot.com/-W8pi6pp8M-w/UXCCHfS_7yI/AAAAAAAABJc/nNMh-e5vZIw/s1600/IMG_9193.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="" src="http://3.bp.blogspot.com/-W8pi6pp8M-w/UXCCHfS_7yI/AAAAAAAABJc/nNMh-e5vZIw/s320/IMG_9193.JPG" width="200" /></a></div>
<br />
<br />
天黑前趕快前往白米甕砲台<br />
原來這邊的炮台早撤了 不過這是個制高點 瞭望港邊還不錯<br />
如果晚上來 港邊燈火應該更漂亮<br />
<div style="text-align: left;">
<a href="http://4.bp.blogspot.com/-eryTr6OR2QU/UXCFR6_bMgI/AAAAAAAABKY/Y1FPJyhFTgI/s1600/IMG_9219.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="200" src="http://4.bp.blogspot.com/-eryTr6OR2QU/UXCFR6_bMgI/AAAAAAAABKY/Y1FPJyhFTgI/s320/IMG_9219.JPG" width="" /></a> <a href="http://2.bp.blogspot.com/-_FHteLEFjOY/UXCE6b9MiEI/AAAAAAAABKI/UlN9m4ZWZ1o/s1600/IMG_9217.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="200" src="http://2.bp.blogspot.com/-_FHteLEFjOY/UXCE6b9MiEI/AAAAAAAABKI/UlN9m4ZWZ1o/s320/IMG_9217.JPG" width="" /></a></div>
<br />
核彈基地?<br />
<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-0q6H21jufUI/UXCE6Z5acEI/AAAAAAAABKM/cF9KkrDSL_M/s1600/IMG_9218.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="" src="http://2.bp.blogspot.com/-0q6H21jufUI/UXCE6Z5acEI/AAAAAAAABKM/cF9KkrDSL_M/s320/IMG_9218.JPG" width="200" /></a></div>
<br />
<br />
基隆廟口 奠濟宮<br />
<div style="text-align: left;">
<a href="http://1.bp.blogspot.com/-bJ_a5hrGsqU/UXCINKgfUBI/AAAAAAAABKg/aJyW_qA-JDE/s1600/IMG_9226.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="320" src="http://1.bp.blogspot.com/-bJ_a5hrGsqU/UXCINKgfUBI/AAAAAAAABKg/aJyW_qA-JDE/s320/IMG_9226.JPG" width="240" /></a> <a href="http://1.bp.blogspot.com/-vbH84sQPTVA/UXCINc_GBYI/AAAAAAAABKk/bSuMVr-UbmE/s1600/IMG_9233.JPG" imageanchor="1" style="clear: left; display: inline !important; margin-bottom: 1em; margin-right: 1em; text-align: center;"><img border="0" height="320" src="http://1.bp.blogspot.com/-vbH84sQPTVA/UXCINc_GBYI/AAAAAAAABKk/bSuMVr-UbmE/s320/IMG_9233.JPG" width="240" /></a></div>
<br />
來到廟口當然別忘了伴手禮呀<br />
李鵠餅店的綠豆椪<br />
連珍的芋泥球~超好吃<br />
<br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com6tag:blogger.com,1999:blog-2638913948091575022.post-86130923079367608562013-04-13T15:40:00.003+08:002013-04-13T15:40:41.138+08:00WebSocket 雙向即時通訊 - 初探Web 已經走向 Application 的概念,其中即時性(real-time)這個特點扮演很重要的角色<br />
<br />
早期 Web service 要做到即時通訊不外乎兩種<br />
<ul>
<li>Polling<br />每n秒問一次 server,n 越小即時性越好,但相對 server loading 就越大</li>
<li>Long polling<br />需要 Server support,延遲 response,確切來說是需要的時候再 response</li>
</ul>
<br />
<br />
但這兩種方式都需要額外的 overhead<br />
<ul>
<li>HTTP 協定限制,一個 request 配一個 response,然後結束 connection,每次重新連線都需要 tcp 3-way handshake</li>
<li>Request 只能從 client 主動發出,若要做到 server push,client 得先建立一條連線讓 server 需要時 send back</li>
<li>每次連線都要帶上 HTTP header,對頻寬也是一種浪費</li>
<li>Connection 斷掉再建立有個空窗期</li>
</ul>
<br />
<br />
而 WebSocket 正是改善這些缺點<br />
<ul>
<li>全雙工通訊(full-duplex communication),連線一旦建立,server/client 隨時都可以發送資料給對方</li>
<li>除了第一次 handshake 外,過程中傳送資料的 header 很小</li>
<li>避免對同一個網站建立多條 connection</li>
</ul>
<br />
<br />
WebSocket 的 implementation<br />
<ul>
<li>Server library<br /><a href="http://en.wikipedia.org/wiki/WebSocket#Server_side">WebSocket - Server Side - Wikipedia, the free encyclopedia</a> 幾乎各語言都有對應的 library 可以用</li>
<li>Frontend client library<br /><a href="http://socket.io/">Socket.io</a></li>
</ul>
<br />
<br />
WebSocket 對各種瀏覽器版本的支援度<br />
<ul>
<li><a href="http://caniuse.com/websockets">Can I use Web Sockets?</a></li>
<li><a href="http://en.wikipedia.org/wiki/Comparison_of_WebSocket_implementations">Comparison of WebSocket implementations - Wikipedia, the free encyclopedia</a></li>
</ul>
<div>
<br /></div>
<div>
<br /></div>
WebSocket Protocol/Packet 分析<br />
<ul>
<li><a href="http://tools.ietf.org/html/rfc6455">RFC-6455</a></li>
<li><a href="http://en.wikipedia.org/wiki/WebSocket#WebSocket_protocol_handshake">WebSocket - WebSocket protocol handshake - Wikipedia, the free encyclopedia</a></li>
<li><a href="http://zhuowater.appspot.com/2010/08/30/webscoket-python.html">websocket新版协议分析+python实现 - 小小的世界</a></li>
<li><a href="http://www.cnblogs.com/caosiyang/archive/2012/08/14/2637721.html">WebSocket协议分析 - 功夫Panda - 博客园</a></li>
</ul>
<div>
<br /></div>
<div>
<br /></div>
<div>
其實在 HTTP 1.0 與 1.1 也有 <a href="http://en.wikipedia.org/wiki/HTTP_persistent_connection">persistent connection</a> 的實作<br />
<ul>
<li>HTTP 1.0 persistent connection:又稱 HTTP keep-alive 或 HTTP connection reuse,可以在同個 connection 下發送多次 request/response </li>
<li>HTTP 1.1 提出了 <a href="http://en.wikipedia.org/wiki/HTTP_pipelining">pipelining</a>:允許一次發送多個 request 給 server,但 server response 時也必需按照順序</li>
</ul>
<div>
但這機制卻沒有被廣泛的應用?是因為早期的 web server 存在 C10K problem 嗎?還是 server 支援度的問題?加上 proxy 與 browser 有限制 client 到 web server 的 current connection 只能建立兩條,避免浪費 server 資源</div>
<br />
詳細可以參考 <a href="http://ihower.tw/blog/archives/1517">HTTP 連線管理 | ihower { blogging }</a></div>
<div>
<br /></div>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-8544520277820508402013-04-12T16:32:00.000+08:002013-04-13T10:55:01.700+08:00SQL Injection Prevention - Postgresql這是一個 C 版本的 postgresql database 存取<br />
<pre class="brush: c; highlight: [3, 4, 23]">#include <libpq-fe.h>
#define UPDATE_COMMAND \
"UPDATE employee SET password='%s' WHERE username='%s';"
int db_update(char *username, char *password)
{
PGconn *conn;
PGresult *res;
ExecStatusType status;
char query[1024];
// connect to server
/*
* Set parameter
*/
snprintf(query, sizeof(query), UPDATE_COMMAND, password, username);
/*
* Execute the query.
*/
res = PQexec(conn, query);
if (res) {
status = PQresultStatus(res);
if (status == PGRES_COMMAND_OK)) {
printf("Update successfully\n");
} else {
printf("error message=[%s]\n", PQresultErrorMessage(res));
}
}
}
</pre>
初學者容易犯的錯誤就是把 user input 直接跟 SQL query 串接在一起,如果 username, password 存在不安全的字眼,很有可能會造成 <b><a href="https://zh.wikipedia.org/wiki/SQL%E8%B3%87%E6%96%99%E9%9A%B1%E7%A2%BC%E6%94%BB%E6%93%8A">SQL injection</a></b>,切記永遠不要相信 user 的資料,該做的檢查、防呆都不能少。<br />
<br />
<br />
改成參數形式就可以避免 :)<br />
Database client library 都會有提供類似的用法<br />
<pre class="brush: c; highlight: [3, 4, 5, 6, 23, 32, 33]">#include <libpq-fe.h>
#define UPDATE_COMMAND \
"UPDATE employee SET password=$1 WHERE username=$2;"
#define PREPARED_STMT "my_update"
#define NPARAMS 2
int db_update(char *username, char *password)
{
PGconn *conn;
PGresult *res;
ExecStatusType status;
char *params[NPARAMS];
// connect to server
/*
* Set parameter
*/
params[0] = password;
params[1] = username;
res = PQprepare(conn, PREPARED_STMT, UPDATE_COMMAND, NPARAMS, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK) {
printf("PQprepare() failed [%s]", PQresultErrorMessage(res));
return -1;
}
/*
* Execute the query.
*/
res = PQexecPrepared(conn, PREPARED_STMT, NPARAMS,
(const char **)params, NULL, NULL, 0);
if (res) {
status = PQresultStatus(res);
if (status == PGRES_COMMAND_OK)) {
printf("Update successfully\n");
} else {
printf("error message=[%s]\n", PQresultErrorMessage(res));
}
}
}
</pre>
關於 <i>PQprepare()</i>、<i>PQexecPrepared()</i> 的使用方式可以參考<a href="http://www.postgresql.org/docs/9.2/static/libpq-exec.html">官方文件</a><br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-16378512547149665542013-04-11T08:26:00.000+08:002013-04-12T08:30:00.078+08:00Basic Authentication for Apache Virtual Host最近裝了 phpmemcacheadmin 這套 monitor tool 來用,但它本身沒有使用者驗證的機制,雖然是內部使用,但擁有這麼大的權限應該要控管一下。<br />
在不動到 source 的前提,想到了可以在 Apache web server 端加上 basic authentication:<br />
<br />
<br />
<h3>
Apache virtual host 設定檔 vhost.conf</h3>
<pre class="brush: bash; gutter: false"><VirtualHost 10.0.0.1:80>
ServerName example.com
DocumentRoot /home/user/www
DirectoryIndex index.php
<Directory /home/user/www>
Deny from all
# Allow from 10.0.2.1 # 允許從這個 IP 來的不用認證
AuthUserFile ~/.htpasswd
AuthName authorization
AuthType Basic
Satisfy Any
require valid-user
</Directory>
</VirtualHost>
</pre>
重啓 Apache 就生效了<br />
<br />
<br />
<h3>
用 htpasswd 建立帳號/密碼設定檔</h3>
<pre class="brush: bash; gutter: false">$ htpasswd ~/.htpasswd brian
New password:
Re-type new password:
Adding password for user brian
</pre>
<br />
關於 htpasswd 的使用方式請參考 <a href="http://httpd.apache.org/docs/2.2/programs/htpasswd.html">htpasswd - Manage user files for basic authentication</a><br />
<br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-67520086616053842292013-04-05T23:29:00.000+08:002013-04-20T12:31:20.425+08:00第一次做西餐就上手今天要請好朋友來家裡一起做西餐,這算是難度最高的一次了<br />
<br />
<div style="text-align: left;">
<a href="http://2.bp.blogspot.com/-nhVstO1BMI0/UWGOiAYkWMI/AAAAAAAABH4/2L_CBmX_CmY/s1600/003.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="213" src="http://2.bp.blogspot.com/-nhVstO1BMI0/UWGOiAYkWMI/AAAAAAAABH4/2L_CBmX_CmY/s320/003.jpg" width="320" /></a> <a href="http://2.bp.blogspot.com/-sEKOrXNaIhM/UWGOiJH2-bI/AAAAAAAABH0/GzforZAs6j0/s1600/004.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="320" src="http://2.bp.blogspot.com/-sEKOrXNaIhM/UWGOiJH2-bI/AAAAAAAABH0/GzforZAs6j0/s320/004.jpg" width="213" /></a></div>
<br />
幸好有各位的幫忙 最後當然是完美上菜啦<br />
<div style="text-align: left;">
<a href="http://3.bp.blogspot.com/-obrLtguVbwQ/UWGP0urtNbI/AAAAAAAABIM/hBh3s4kKmYI/s1600/016.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="213" src="http://3.bp.blogspot.com/-obrLtguVbwQ/UWGP0urtNbI/AAAAAAAABIM/hBh3s4kKmYI/s320/016.jpg" width="320" /></a></div>
<br />
<br />
<h3>
沙拉</h3>
生菜佐優格醬<br />
加點柳橙跟檸檬 酸酸的比較開胃<br />
<br />
<h3>
前菜</h3>
煎馬鈴薯 兩種做法<br />
可以切片後直接下去煎 口感是酥脆的<br />
另外可以切成條狀 先滾一下變鬆軟 再下去煎 表皮焦焦的很香<br />
<br />
<h3>
海鮮巧達湯</h3>
玉米 紅蘿蔔 洋蔥 蘑菇 綠花椰 馬鈴薯 全部切丁下去滾<br />
要滾到馬鈴薯變成泥 湯頭的口感才會濃郁<br />
加一些蛤蠣 蝦子 干貝 也不錯<br />
<br />
<h3>
拿坡里茄汁義大利麵</h3>
鹽巴 + 義大利麵煮七分鐘 -> 起鍋拌橄欖油<br />
番茄 洋蔥 切丁 + 蝦 花枝 + 紅酒 炒一下<br />
倒入茄汁義大利麵醬 還有撈起來的麵條 再翻炒一下<br />
最後撒上起司粉 羅勒葉裝飾<br />
<div style="text-align: left;">
<a href="http://4.bp.blogspot.com/-alcLMItDTUg/UWGN4UpUkqI/AAAAAAAABHk/4ofrLU1nbSU/s1600/009.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="213" src="http://4.bp.blogspot.com/-alcLMItDTUg/UWGN4UpUkqI/AAAAAAAABHk/4ofrLU1nbSU/s320/009.jpg" width="320" /></a></div>
<br />
<br />
<h3>
煎沙朗牛排、松版豬排</h3>
先把牛排血水用紙巾擦乾<br />
大火煎第一面 90 秒鎖住肉汁 翻面上色即可<br />
不過平底鍋似乎火侯不夠 發現要煎久一點 不然裡頭還很生<br />
佐蒜片 岩鹽<br />
<br />
蒜片製作:蒜頭切片 -> 川燙去辣味 -> 油炸呈金黃色 -> 用紙巾把油吸掉 -> 烤稍微酥脆<br />
<div>
配菜:綠花椰 番薯 紅蘿蔔 燉梨 都不錯</div>
<br />
最後當然要來一杯紅酒啦<br />
松版豬排就煎全熟 肉質真的帶勁 撒上黑胡椒 海鹽 就很好吃<br />
<div style="text-align: left;">
<a href="http://4.bp.blogspot.com/-GFu-XWa1Dx0/UWGOCVE_OcI/AAAAAAAABHs/yiXu0MjDjC4/s1600/017.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="320" src="http://4.bp.blogspot.com/-GFu-XWa1Dx0/UWGOCVE_OcI/AAAAAAAABHs/yiXu0MjDjC4/s320/017.jpg" width="213" /></a><a href="http://4.bp.blogspot.com/-w-TYqug_Jxg/UWGPPMw5poI/AAAAAAAABIE/v5RyLaxFtEo/s1600/002.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="213" src="http://4.bp.blogspot.com/-w-TYqug_Jxg/UWGPPMw5poI/AAAAAAAABIE/v5RyLaxFtEo/s320/002.jpg" width="320" /></a></div>
<br />
<br />
<h3>
mojito</h3>
方糖 1 顆 + 薄荷葉 10片 + 檸檬汁 用搗棒搗碎<br />
碎冰 + 1/4 片檸檬 + Rum 45oz + soda 少許<br />
最上面薄荷枝葉裝飾<br />
<div style="text-align: left;">
<a href="http://3.bp.blogspot.com/-aZ6SwqfWxA4/UWGL2a4HYlI/AAAAAAAABHc/6v5pVgvNeLQ/s1600/020_1.jpg" imageanchor="1" style="clear: left; margin-bottom: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-aZ6SwqfWxA4/UWGL2a4HYlI/AAAAAAAABHc/6v5pVgvNeLQ/s320/020_1.jpg" width="320" /></a></div>
<br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-6002835638432950612013-04-03T14:00:00.000+08:002013-04-13T17:17:36.007+08:00成大事必備9種能力、9種心態、9種手段轉載自網路,收納到我的做人做事小語裡面<br />
<br />
<blockquote style="background-color: #f9f9f9;">
成大事必備的九種能力 – 挑戰生存的能力:善於在現實中尋找答案<br />
<br />
1、擺正心態,敢於面對現實<br />
<br />
對於那些不停地抱怨現實惡劣的人來說,不能稱心如意的現實,就如同生活的牢籠,既束縛手腳,又束縛身心,因此常屈從於現實的壓力,成為懦弱者;而那些真正成大事的人,則敢於挑戰現實,在現實中磨煉自己的生存能力,這就叫強者!<br />
<br />
在此,我們可以得出一條成大事的經驗:適應現實的變化而迅速改變自己的觀念,最重要的是需要我們有一副聰慧的頭腦和靈活的眼睛,做生活的有心人。<br />
<br />
在現實的壓力之下,如果你能改變觀念,適時而進,可收到事半功倍的效果。<br />
<br />
我們的自下而上須臾離不開現實,隨著現實的變化,我們必須隨之調整自己的觀念、思想、行動及目標。這是生存的必須。<br />
<br />
如果我們有辦法來改變現實,使之適合我們能力和欲望的發展需要,則是最難能可貴的。<br />
<br />
<br />
2、讓你擁有過硬的自制能力<br />
<br />
自制,就是要克服欲望,不要因為有點壓力就心裏浮躁,遇到一點不稱心的事就大發脾氣。<br />
<br />
一個人除非先控制了自己,否則將無法控制別人。<br />
<br />
一個人只要有成大事的目標,知道自己想要的,然後采取行動,告訴自己絕對不要放棄,成功只是時間早晚而已。<br />
<br />
假使你在途中遇上了麻煩或阻礙,你就去面對它、解決它、然後再繼續前進,這樣問題才不會愈積愈多。<br />
<br />
你在一步步向上爬時,千萬別對自己說“不”,因為“不”也許導致你決心的動搖,放棄你的目標,從而前功盡棄。<br />
<br />
人最難戰勝的是自己,這話的含義是說,一個人成功的最大障礙不是來自於外界是,而是自身。只有控制住自己,才能控制住壓力,讓壓力在你面前屈服。<br />
<br />
<br />
3、把情感裝入理性之盒<br />
<br />
一種抵觸情緒的產生往往是潛移默化的,但它對人一生的影響卻是巨大的,這種影響從諸多小事上體現出來。我們應盡量消除自己的不良情緒、因為它不僅會給我們造成身心上的傷害,而且在我們通往成功的路途上,不良情緒有時會成為絆腳石。<br />
<br />
為了你的成功,你必須把情感裝入理性之盒,你必須去適應別人,適應形勢,不然的話,你註定成不了大事,註定會被淘汰。<br />
<br />
<br />
4、獨處可以激發思考的力量<br />
<br />
如果你知道怎麼獨處的話,成大事者都是善於獨處的人--在獨處的過程中激發思考的力量。<br />
<br />
自卑可以像一座大山把人壓倒並讓你永遠沈默,也可以像推進器產生強大的動力。<br />
<br />
比別人先走一步,能創造一種成功的心境。<br />
<br />
在獨處時,你應當有所思考,不要總人浮於事。<br />
<br />
<br />
5、壓力是最好的推動力<br />
<br />
欲成大事者,因目標高遠,壓力可能會更大。但若欲成大事,就必須能承受這種壓力,把壓力當成推進人生的動力。<br />
<br />
人們最出色的工作往往是在外於逆境的情況下做出的。人要有所為就要有所不為。應做的一定要做好,不該做的堅決不做。<br />
<br />
得到的並不一定就值得慶幸,失去的也並不完全是壞事情。<br />
<br />
<br />
6、以變應變,才有出路<br />
<br />
順應時勢,善於變化,及時調整自己的行動方案,這是成大事者適應現實的一種方法。<br />
<br />
一個人如果沒有和人打交道的高超技巧,沒有把各種情況都考慮周全的頭腦,靈活應變的手段,就根本無法駕馭大的局面,將很難成大事。<br />
<br />
一個人能看清自己的現狀,心態就會平衡許多,就能以一種客觀的眼光去看待,認識這個世界,並且相應地調整自己的行為。<br />
<br />
<br />
7、自信心是人生的堅強支柱<br />
<br />
自信心充足者的適應能力就高,反之則適應能力較低。<br />
<br />
一般信心不足較嚴重的人常有一些身心癥狀,比如孤僻,害怕與人交往,說話過於偏激,悲觀失望。<br />
<br />
如果做事成功的經驗越多,那麼自信心就越強。<br />
<br />
自我成功鍛煉的機會越少,自信心就越弱,以致產生嚴重的自卑情緒。<br />
<br />
十九世紀的思想家愛默生說:“相信自己‘能’,便會攻無不克。”拿破侖說:“在我的字典裏沒有不可能。”<br />
<br />
<br />
8、把精力投入到自己的強項上<br />
<br />
大多數人的生活層次只停留在:為吃飯而吃、為搭公車而搭、為工作而工作、為了回家而回家。<br />
<br />
成大事者與不成大事者只差別在一些小小的動作:每天花5分鐘閱讀、多打一個電話、多努力一點、在適當時機的一個表示、表演上多費一點心思、多做一些研究,或在實驗室中多試驗一次。<br />
<br />
在行動之前你自己就知道你是否足以勝任這一個任務。<br />
<br />
沒有任何藉口可以解釋你為什麼會長時間仍然無法勝任一項工作。<br />
<br />
不論你想追求的是什麼,你必須強迫自己增強能力以實現目標。<br />
<br />
勤加練習、勤加練習、最後還是勤加練習!決不放棄學習,而且一定要將學到的知識運用於日常生活中。<br />
<br />
<br />
9、要專心地做好一件事<br />
<br />
如果大多數人集中精力專註於一項工作,他們都能把這項工作做得很好。<br />
<br />
最成大事者的商人是能夠迅速而果斷作出決定的人,他們總是首先確定一個明確的目標,並集中精力,專心致誌地朝這個目標努力。<br />
<br />
一次只專心地做一件事,全身心地投入並積極地希望它成功,這樣你的心裏就不會感到筋疲力盡。<br />
<br />
把你需要做的事想象成是一大排抽屜中的一個小抽屜。不要總想著所有的抽屜,而要將精力集中於你已經打開的那個抽屜。每個人做人辦事的手段都是不一樣的,可以講,一個人就有一種手段,一個人就有一種靠自己手段獲得成功的途徑。無數事實表明,有些人就是太過於自信,想念自己確認的手段能夠解決任何問題,但不知道這種往往是起不到任何作用。因此,他們總覺得離成功的目標不是越來越近,而實際上越來越遠。<br />
<br />
<br />
<br />
<br />
<br />
成大事必備的九種心態 + 六要素<br />
<br />
心態之一:積極向上<br />
1. 時刻想著出人頭地<br />
2. 做“小人物”時要向“大人物”看齊<br />
3. 惟有進取心,才能成大事<br />
4. 摒棄逆境的干擾,尋找向上的根源<br />
5. 放棄也是一種成功的開始<br />
6. 在平凡中做不平凡的事<br />
7. 保持年輕的心態很重要<br />
<br />
心態之二:勤勉謙恭<br />
1. 壯志淩雲地想,腳踏實地地幹 <br />
2. 勤敬產業,謙恭做人<br />
3. 勤勉高於天賦<br />
4. 勤奮造就成功,懶惰摧毀天才<br />
5. 養成勤奮的習慣會終生受益<br />
6. 有一份耕耘,就有一份收穫<br />
7. 恒心與支持能“點石成金”<br />
8. 莫道君行早,更有早行人<br />
<br />
心態之三:誠實守信<br />
1. 誠實是一種源自自身的本質<br />
2. 誠實守信才是大贏家<br />
3. 以誠信奠定成功基業<br />
4. 真誠的友誼會使你的事業更發達<br />
5. 做人要有正直的品行<br />
6. 誠實守信是成大事的“信用卡”<br />
7. 要成大事,擇友不可草率<br />
8. 以真誠待人,用熱忱做事<br />
<br />
心態之四:敢於挑戰<br />
1. 敢於挑戰自我,克服貶低心理<br />
2. 挑戰無極限<br />
3. 堅持到底造靠勇氣,半途而廢是懦夫<br />
4. 用於挑戰激起成大事的信心<br />
5. 勇氣是戰勝困難的良方<br />
6. 勝人者力,自勝者強<br />
7. 毅力與恒心是成大事的基本功<br />
8. 堅持不懈成大事,淺嘗輒止無出路<br />
<br />
心態之五:善於合作<br />
心態之六:知足平衡<br />
心態之七:樂觀豁達<br />
心態之八:寬厚容人<br />
心態之九:永遠自信<br />
<br />
<br />
一:沉穩<br />
(1)不要隨便顯露你的情緒。<br />
(2)不要逢人就訴說你的困難和遭遇。<br />
(3)在徵詢別人的意見之前,自己先思考,但不要先講。<br />
(4)不要一有機會就嘮叨你的不滿。<br />
(5)重要的決定儘量有別人商量,最好隔一天再發佈。<br />
(6)講話不要有任何的慌張,走路也是。<br />
<br />
二:細心<br />
(1)對身邊發生的事情,常思考它們的因果關係。<br />
(2)對做不到位的執行問題,要發掘它們的根本癥結。<br />
(3)對習以為常的做事方法,要有改進或優化的建議。<br />
(4)做什麼事情都要養成有條不紊和井然有序的習慣。<br />
(5)經常去找幾個別人看不出來的毛病或弊端。<br />
(6)自己要隨時隨地對有所不足的地方補位。<br />
<br />
三:膽識<br />
(1)不要常用缺乏自信的詞句<br />
(2)不要常常反悔,輕易推翻已經決定的事。<br />
(3)在眾人爭執不休時,不要沒有主見。<br />
(4)整體氛圍低落時,你要樂觀、陽光。<br />
(5)做任何事情都要用心,因為有人在看著你。<br />
(6)事情不順的時候,歇口氣,重新尋找突破口,就結束也要乾淨俐落。<br />
<br />
四:大度<br />
(1)不要刻意把有可能是夥伴的人變成對手。<br />
(2)對別人的小過失、小錯誤不要斤斤計較。<br />
(3)在金錢上要大方,學習三施(財施、法施、無畏施)<br />
(4)不要有權力的傲慢和知識的偏見。<br />
(5)任何成果和成就都應和別人分享。<br />
(6)必須有人犧牲或奉獻的時候,自己走在前面。<br />
<br />
五:誠信<br />
(1)做不到的事情不要說,說了就努力做到。<br />
(2)虛的口號或標語不要常掛嘴上。<br />
(3)針對客戶提出的“不誠信"問題,拿出改善的方法。<br />
(4)停止一切“不道德"的手段。<br />
(5)耍弄小聰明,要不得!<br />
(6)計算一下產品或服務的誠信代價,那就是品牌成本。<br />
<br />
六:擔當<br />
(1)檢討任何過失的時候,先從自身或自己人開始反省。<br />
(2)事項結束後,先審查過錯,再列述功勞。<br />
(3)認錯從上級開始,表功從下級啟動<br />
(4)著手一個計畫,先將權責界定清楚,而且分配得當。<br />
(5)對“怕事"的人或組織要挑明瞭說。<br />
(6)因為勇於承擔責任所造成的損失,公司應該承擔<br />
<br />
<br />
<br />
<br />
<br />
成大事的九種手段:<br />
<br />
1、敢於決斷--克服猶豫不定的習性<br />
很多人之所以一事無成,最大的毛病就是缺乏敢於決斷的手段,總是左顧右盼、思前想後,從而錯失成功的最佳時機。成大事者在看到事情的成功可能性到來時,敢於做出重大決斷,因此取得先機。<br />
<br />
2、挑戰弱點--徹底改變自己的缺陷<br />
人人都有弱點,不能成大事者總是固守自己的弱點,一生都不會發生重大轉變;能成大事者總是善於從自己的弱點上開刀,去把自己變成一個能力超強的人。一個連自己的缺陷都不能糾正的人,只能是失敗者!<br />
<br />
3、突破困境--從失敗中撮成功的資本<br />
人生總要面臨各種困境的挑戰,甚至可以說困境就是“鬼門關”。一般人會在困境面前渾身發抖,而成大事者則能把困境變為成功的有力跳板。<br />
<br />
4、抓住機遇--善於選擇、善於創造<br />
機遇就是人生最大的財富。有些人浪費機遇輕而易舉,所以一個個有巨大潛力的機遇都悄然溜跑,成大事都是絕對不允許溜走,並且能縱身撲向機遇。<br />
<br />
5、發揮強項--做自己最擅長的事情<br />
一個能力極弱的人肯定難以打開人生局面,他必定是人生舞臺上重量級選手的犧牲品;成大事者關於在自己要做的事情上,充分施展才智,一步一步地拓寬成功之路。<br />
<br />
6、調整心態--切忌讓情緒傷害自己<br />
心態消極的人,無論如何都挑不起生活和重擔,因為他們無法直面一個個人生挫折,成大事者則關注於高速心態,即使在毫無希望時,也能看到一線成功的亮光。<br />
<br />
7、立即行動--只說不做,徒勞無益<br />
一次行動勝過百遍心想。有些人是“語言的巨人,行動的矮子”,所以看不到更為實際現實的事情在他身上發生;成大事者是每天都靠行動來落實自己的人生計畫的。<br />
<br />
8、善於交往--巧妙利用人力資源<br />
一個人不懂得交往,必然會推動人際關係的力量。成大事者的特點之一是:善於靠借力、借熱去營造成功的局勢,從而能把一件件難以辦成的事辦成,實現自己人生的規劃。<br />
<br />
9、重新規劃--站到更高的起點上<br />
人生是一個過程,成功也是一個過程。你如果滿足于小成功,就會推動大成功。成大事者懂得從小到大的艱辛過程,所以在實現了一個個小成功之後,能繼續拆開下一個人生的“密封袋”。<br />
<br />
成大事者總是選擇最佳的手段,達到最完善的結果,這就是非一般人所能做到的。因此在成功之路上,你要想成大事,首先要解決的問題就是:你的手段對你推動成功的計畫是否立竿見影!</blockquote>
Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0tag:blogger.com,1999:blog-2638913948091575022.post-14044617476643028352013-04-02T11:30:00.000+08:002013-04-13T17:16:27.371+08:00一位年輕女董事長的47個忠告!轉載自網路,收納到我的做人做事小語裡面<br />
<br />
<blockquote style="background-color: #f9f9f9;">
無論你是男人,還是女人,做人想成功,下面就是你必須要參考的<br />
<br />
1、好朋友裡面,一定要培養出一個知己,不要以為你有多麼八面玲<br />
瓏,到處是朋友,最後真心對你的,只有一個,相信我。<br />
<br />
2、給自己定目標,一年,兩年,五年,也許你出生不如別人好,通過努力,往往可以改變70%的命運。破罐子破摔只能和懦弱做朋友。<br />
<br />
3、朋友請你吃飯,不要覺得理所當然,請禮尚往來,否則你的名聲會越來越差。<br />
<br />
4、這是個現實的社會,感情不能當飯吃,貧窮夫妻百事哀。不要相信電影裡的故事情節,那只是個供許多陌生人喧囂情感的場所。只有不理智和不現實的人才相信。<br />
<br />
5、不要相信算卦星座命理,那是哄小朋友的,命運掌握在自己手中。坐在家裡等什麼房子,車子,還不如睡一覺做個好夢。<br />
<br />
6、不喜歡的人少接觸,但別在背後說壞話,說是非之人,必定是是非之人,謹記,禍從口出。<br />
<br />
7、少玩遊戲,這不是韓國,你打不出房子車子還有資本。可以有愛好,但要把握尺度,少玩農場、牧場、鬥地主等一些高度吸引人思想的晉級遊戲,也許你的級別很高,但不代表你有多麼成功,反而會影響和占據你成功的時間。<br />
<br />
8、是人都有惰性,這是與生俱來的,但是我們後天可以改變這種惰性,因為有很多人正在改變。對於某種事物或是生意不要等別人做到了,我才想到。不要等別人已經賺到錢了,我才想去做。沒有人相信的是市場和機遇,大家都相信的叫做膨脹。<br />
<br />
9、知道自己要幹什麼,夜深人靜,問問自己,將來的打算,並朝著那個方向去實現。而不是無所事事和做一些無謂的事。<br />
<br />
10、出路出路,走出去了,總是會有路的。困難苦難,困在家裡就是難。<br />
<br />
11、作為女人,不要倚老賣老,認為事業跟自己沒關係,以為自己就是洗衣服,做飯,看孩子,那就是大錯特錯。<br />
<br />
12、做人,要做到;萬事孝為先,教童品之道,夫妻和諧美,幸福萬年長。但是這些不是拿來用嘴說說就能辦到的,解放初期年代要做到這些,需要付出很大的努力和辛苦,當今現實的社會需要你付出很大的金錢,聰明的人都知道這個道理。<br />
<br />
13、空閒時間不要經常上網做無聊的事和玩一些沒有意義的遊戲,讀點文學作品,學習一些經營流程,管理規範,國際時事,法律常識。這能保證你在任何聚會都有談資。<br />
<br />
14、寧可錯殺一千次來自各方面的信息,也不放過任何一個有可能成功的機會。只有這樣你才不會去買後悔藥。<br />
<br />
15、要做一件事,成功之前,沒有必要告訴其他人。成功之後不用你說,其他人都會知道的。這就是信息時代所帶來的效應。<br />
<br />
16、頭髮,指甲,鬍子,打理好。社會是個排斥性的接受體,這個星球所需要的藝術家極其有限,請不要冒這個險,就算你留長頭髮比較好看,也要盡量給人乾淨的感覺。<br />
<br />
17、不要以為你是個男人,就不需要保養。至少飲食方面不能太隨便,多吃番茄,海產品,韭菜,香蕉,都是對男性健康有益處的食物。你要是看不到價值,我可以告訴你。至少你能把看病節約下來的錢給你的女人多買幾個化妝品。<br />
<br />
18、力求上進的人,不要總想著靠誰誰,人都是自私的,自己才是最靠得住的人。<br />
<br />
19、面對失敗,不要太計較,天將降大任於斯人也,必先苦其心志,勞其筋骨,餓起體膚……但要學會自責,找到原因,且改掉壞習慣。二十歲沒錢,那很正常;三十歲沒錢,可能是沒有好的家境,需要更大的努力;四十歲沒錢,只能自己找原因。窮人變成富人是可能的,而且很可能。窮人能窮一輩子,也是必然的,存在就是理由,只是有所選擇。<br />
<br />
20、每個人都有成功的機會!就看你給不給自己機會!<br />
<br />
21、記住,平均每天看電視超過三個小時以上的,一定都是那些月收入不超過五萬元的,如果你想要月收入超過五萬,請不要把時間浪費在電視上。同樣的道理,那些平均每天玩網路遊戲或聊天超過三個小時以上的,也都是那些月收入不超過五萬的。<br />
<br />
22、因為窮人很多,並且窮人沒有錢,所以,他們才會在網路上聊天抱怨,消磨時間。你有見過哪個企業老總或主管經理有事沒事經常在臉書裡閒聊的?<br />
<br />
23、這個世界,有這麼一小撮的人,打開報紙,是他們的消息,打開電視,是他們的消息,街頭巷尾,議論的是他們的消息,仿佛世界是為他們準備的,他們能夠呼風喚雨,無所不能。你的目標,應該是努力成為這一小撮人。<br />
<br />
24、如果,你真的愛你的爸媽,愛你的女朋友,就好好的去奮鬥,去拼搏吧,這樣,你才有能力,有經濟條件,有自由時間,去陪他們,去好好愛他們。<br />
<br />
25、這個社會,是快魚吃慢魚,而不是慢魚吃快魚。<br />
<br />
26、這個社會,是贏家通吃,輸者一無所有,社會,永遠都是只以成敗論英雄。<br />
<br />
27、如果你問周圍朋友,如果十個人,九個人說不知道,那麼,這是一個機遇,如果十個人,九個人都知道了,就是一個行業。<br />
<br />
28、任何一個行業,一個市場,都是先來的有肉吃,後來的湯都沒的喝。<br />
<br />
29、這個世界上,一流的人才,可以把三流項目做成二流或更好,但是,三流人才,會把一流項目,做的還不如三流。<br />
<br />
30、趁著年輕,多出去走走看看。讀萬卷書,不如行萬里路,行萬里路,不如閱人無數。<br />
<br />
31、與人交往的時候,多聽少說。這就是,上帝為什麼給我們一個嘴巴兩個耳朵的原因。<br />
<br />
32、記得,要做最後出牌的人,出讓別人覺得出其不意的牌,在他們以為你要輸掉的時候,這樣,你才能贏得牌局。<br />
<br />
33、不要裝大,對於裝大的人,最好的辦法就是,撿塊磚頭,悄悄跟上去,一下子從背後放倒他。<br />
<br />
34、不要隨便說髒話,這會讓別人覺得你沒涵養,不大願意和你交往。即使交往,也是敷衍。因為他內心認定你素質很差。<br />
<br />
35、想要抽煙的時候,先問下周圍的人可不可以,要學會尊重別人。少在女生面前耍酷抽煙,你不知道,其實她們內心很反感。<br />
<br />
36、買衣服的時候,要自己去挑,不要讓家人給你買,雖然你第一、第二次買的都不怎麼樣,可是,你會慢慢有眼光的。<br />
<br />
37、要想進步,就只有吸取教訓,成功的經驗都是歪曲的,成功了,想怎麼說都可以,失敗者沒有發言權,可是,你可以通過他的事例反思,總結。教訓,不僅要從自己身上吸取,還要從別人身上吸取。<br />
<br />
38、學習,學習,再學習,有事沒事,去書店看看書,關於管理,金融,行銷,人際交往,未來趨勢等這些,你能獲得很多。這個社會競爭太激烈了,你不學習,就會被淘汰。中國2008底,有一百多萬大學生找不到工作。競爭這麼激烈,所以,一定要認識一點,大學畢業了,不是學習結束了,而是學習剛剛開始。還有,我個人推薦一個很好的視頻節目,《誰來一起午餐》。<br />
<br />
39、如果你不是歌手,不是畫家,也不是玩行為藝術的,那麼,請在平時注意你的衣著。現在這個社會,衣著能表現出你屬於哪一個群體,哪一個圈子。<br />
<br />
40、 一個年輕人,如果三年的時間裡,沒有任何想法,他這一生,就基本這個樣子,沒有多大改變了。<br />
<br />
41、 成功者就是膽識加魄力,曾經在火車上聽人談起過溫州人的成功,說了這麼三個字,“膽子大”。這其實,就是膽識,而拿得起,放得下,就是魄力。<br />
<br />
42、無論你以後是不是從事銷售部門,都看一下關於行銷的書籍。因為,生活中,你處處都是在向別人推銷展示你自己。<br />
<br />
43、平時的時候,多和你的朋友溝通交流一下,不要等到需要朋友的時候,才想到要和他們聯繫,到了社會,你才會知道,能夠認識一個真正的朋友,有多難?<br />
<br />
44、如果你想知道自己將來的年收入如何。找你最經常來往的六個朋友,把他們的年收入加起來,除以六,就差不多是你的了。這個例子,可以充分的說明一點,物以類聚。<br />
<br />
45、給自己定一個五年的目標,然後,把它分解成一年一年,半年半年的,三個月的,一個月的。這樣,你才能找到自己的目標和方向。<br />
<br />
46、無論什麼時候,記住尊嚴這兩個字,做人是要有尊嚴,有原則,有底線的。否則,沒有人會尊重你。<br />
<br />
47、如果我只能送你一句忠告,那就是,這個世界上沒有免費的午餐,永遠不要走捷徑!</blockquote>
<br />
<br />Anonymoushttp://www.blogger.com/profile/16090704880953704344noreply@blogger.com0