2010-09-11
Multi-column Layout Module
css3 |
早見表
| プロパティ | 値 | 初期値 |
|---|---|---|
| column-width | <length> | auto | auto |
| column-count | <integer> | auto | auto |
| columns | <'column-width'> || <'column-count'> | 各項目を参照 |
| column-gap | <length> | normal | normal |
| column-rule-width | <'border-width'> | medium |
| column-rule-style | <'border-style'> | none |
| column-rule-color | <color> | - |
| column-rule | <column-rule-width> || <border-style> || [ <color> | transparent ] | 各項目を参照 |
| break-before | auto | always | avoid | left | right | page | column | avoid-page | avoid-column | auto |
| break-after | auto | always | avoid | left | right | page | column | avoid-page | avoid-column | auto |
| break-inside | auto | avoid | avoid-page | avoid-column | auto |
| column-span | 1 | all | 1 |
| column-fill | auto | balance | balance |
参考
2010-07-31
FORM の action の URI にクエリをつけたまま GET で送信できなかったのでなんでか調べてみた
html |
あれ?タイトルわかりづらい?
要はこういうことです
1 <html> 2 3 <body> 4 <form method="GET" action="./form.html?key1=value1"> 5 <input type="text" name="key2" value="value2" /> 6 <input type="submit" value="test" /> 7 </form> 8 </body> 9 10 </html>
これでボタン押したときにクエリとして
- key1 : value1
- key2 : value2
が送られてきてほしいのです
しかし、結果として key2 しか送られてきません
...おい、key1 どこいった?
というわけでアクセスログを見てみると
::1 - - [25/Jul/2010:23:06:04 +0900] "GET /~xxx/form.html?key2=value2 HTTP/1.1" 200 191
となっています。はい、 key1 どっかに消えました
そこで以下のように GET, POST の両方を作って実験してみました
1 <html> 2 3 <body> 4 <form method="GET" action="./form.php?key1=value1"> 5 method : GET <br /> 6 <input type="text" name="key2" value="value2" /> 7 <input type="submit" value="test" /> 8 </form> 9 10 <form method="POST" action="./form.php?key1=value1"> 11 method : POST <br /> 12 <input type="text" name="key2" value="value2" /> 13 <input type="submit" value="test" /> 14 </form> 15 16 <pre> 17 $_GET : <?php var_dump($_GET); ?> 18 </pre> 19 20 <pre> 21 $_POST : <?php var_dump($_POST); ?> 22 </pre> 23 24 25 </body> 26 27 </html>
GET の結果
$_GET : array(1) {
["key2"]=>
string(6) "value2"
}
$_POST : array(0) {
}
POST の結果
$_GET : array(1) {
["key1"]=>
string(6) "value1"
}
$_POST : array(1) {
["key2"]=>
string(6) "value2"
}
ここからわかる状況
なんでこのようなことになっているのかは調べきれなかったので、また今度調べます
なんとなくブラウザの仕様なんじゃないかなーと思ったりもしました
(あれ?ブラウザの仕様なら HTML の定義のどっかに書いてあるのかな。。。でも見つけられんかった。。。
参考
http://labs.uechoco.com/blog/2007/11/htmlformactionget.html
http://chaichan.web.infoseek.co.jp/perlnote/perlnote2010-05-31.htm
2010-05-25
websocket の echo server を作ってみた
目的
- html5 の websocket を使って簡単な通信をしてみる
ソース
websocket.html
1 <!DOCTYPE html> 2 3 <html> 4 5 <head> 6 <meta charset="utf-8"> 7 8 <script type="text/javascript"> 9 var ws = new WebSocket("ws://localhost:8080/"); 10 11 ws.onopen = function(event) { 12 alert("websocket " + event + " is opened"); 13 }; 14 15 ws.onmessage = function(event) { 16 alert(event.data); 17 }; 18 19 function send() { 20 var msg = document.getElementById("msg").value; 21 ws.send(msg); 22 } 23 24 </script> 25 </head> 26 27 <body> 28 <input type="text" id="msg" /> 29 <button onclick="send();">send</button> 30 </body> 31 32 </html>
echo_server.py
1 import socket 2 3 BUFSIZE = 4096 4 5 host = socket.gethostbyname('localhost') 6 port = 8080 7 8 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 9 sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 10 sock.bind((host, port)) 11 sock.listen(1) 12 13 print 'waiting for connection...' 14 15 (client_sock, client_addr) = sock.accept() 16 msg = client_sock.recv(BUFSIZE) 17 18 [head, body] = msg.split("\r\n", 1) 19 header = {} 20 21 for line in body.splitlines(): 22 if line == "": 23 break 24 else: 25 [key, value] = line.split(": ", 1) 26 header[key] = value.strip() 27 28 # websocket handshake 29 handshake = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" 30 handshake += "Upgrade: %s\r\n" % header['Upgrade'] 31 handshake += "Connection: %s\r\n" % header['Connection'] 32 handshake += "WebSocket-Origin:%s\r\n" % header['Origin'] 33 handshake += "WebSocket-Location: ws://localhost:8080/\r\n" 34 handshake += "\r\n" 35 36 client_sock.send(handshake) 37 38 print 'connection start' 39 print '---------- ---------- ----------' 40 41 while True: 42 msg = client_sock.recv(BUFSIZE) 43 44 if msg == "": 45 break 46 else: 47 print "client: %s" % msg[0:len(msg)-1] 48 client_sock.send(msg) 49 50 client_sock.close() 51 52 sock.close() 53 54 print '---------- ---------- ----------' 55 print 'connection end' 56
実行
connection start ---------- ---------- ---------- client: this client: is client: a client: test ---------- ---------- ---------- connection end
考察
- そもそも最初は通信自体がうまくいなかった
- handshake を行わないと通信を確立してくれない
- 47行目で受け取った文字列の後ろ2バイトを削っている
- 終端文字として何か入ってるみたいだが文字化けするので削った
参考
2010-05-18
memcache クライアントを実装してみた その2
目的
- 前回 methaneさんにコメントで指摘された部分の修正
ソース
- 修正した関数は以下の2つなので今回はその部分のソースのみ載せます
- set
- get
21 def set(self, key, value, exptime=0, flags=0): 22 # translate value to binary 23 pickled_value = pickle.dumps(value, 2) 24 length = len(pickled_value) 25 totalsent = 0 26 27 # request 28 sendmsg = "set %s %d %s %d" % (key, flags, exptime, length) 29 sendmsg += "\r\n" 30 sendmsg += pickled_value 31 sendmsg += "\r\n" 32 33 while totalsent < length: 34 sent = self.__sock.send(sendmsg[totalsent:]) 35 totalsent += sent 36 37 # response 38 recvmsg = '' 39 40 while True: 41 chunk = self.__sock.recv(BUFSIZE) 42 recvmsg += chunk 43 44 if recvmsg.find("\r\n") != -1: 45 break 46 47 # return 48 if recvmsg == "STORED\r\n": 49 return True 50 else: 51 return False 52 53 54 def get(self, key): 55 # request 56 sendmsg = "get %s\r\n" % key 57 length = len(sendmsg) 58 totalsent = 0 59 60 while totalsent < length: 61 sent = self.__sock.send(sendmsg[totalsent:]) 62 totalsent += sent 63 64 # response 65 recvmsg = '' 66 67 ## header 68 header = '' 69 70 while True: 71 chunk = self.__sock.recv(BUFSIZE) 72 recvmsg += chunk 73 74 if header == '' and recvmsg.find("\r\n") != -1: 75 [header, dummy] = recvmsg.split("\r\n", 1) 76 break 77 78 [dummy1, dummy2, dummy3, length] = header.split() 79 80 ## body 81 body = '' 82 length = len(header) + len("\r\n") + int(length) + len("\r\n") + len("END\r\n") 83 84 totalrecv = len(recvmsg) 85 86 while totalrecv < length: 87 chunk = self.__sock.recv(BUFSIZE) 88 recvmsg += chunk 89 totalrecv += len(chunk) 90 91 [header, body] = recvmsg.split("\r\n", 1) 92 [pickled_value, dummy1, dummy2] = body.rsplit("\r\n", 2) 93 94 # return 95 return pickle.loads(pickled_value)
修正点
- set
- value をバイナリに変換
- メッセージを確実に全て送信
- メッセージを少なくとも必要な分は全て受信
- get
- メッセージを確実に全て送信
- メッセージの一つ目の改行文字"\r\n"で分割して header とする
- header から set した value の長さを取得
- メッセージの全ての長さを計算
- header + "\r\n" + value + "\r\n" + "END\r\n"
- メッセージを少なくとも必要な分は全て受信
- バイナリから value へ変換
結果
- BUFSIZE = 2 (recv が一度に受信する最大バイト数) として実行したが、前回と同様の結果が得られた
2010-05-03
memcache クライアントを実装してみた
目的
- 主に自分の勉強です
- クライアントはいろんな言語で実装されてるけど、やっぱり自分でやってみることに意義があるよね
実装項目
以下の3つを実装する
- set
- get
- stats
ソース
my_memcache.py
1 # -*- coding:utf-8 -*- 2 import socket 3 import pickle 4 import base64 5 6 class MyMemcache: 7 8 def __init__(self): 9 self.__sock = socket.socket() 10 11 def __del__(self): 12 self.__sock.close() 13 14 def connect(self, host, port): 15 self.__sock.connect((host, port)) 16 17 def close(self): 18 self.__sock.close() 19 20 def set(self, key, value, exptime=0, flags=0): 21 serialized_value = base64.b64encode(pickle.dumps(value)) 22 self.__sock.send("set %s %d %s %d\r\n" % (key, flags, exptime, len(serialized_value)) ) 23 self.__sock.send("%s\r\n" % serialized_value) 24 25 result = self.__sock.recv(64) 26 27 if result == "STORED\r\n": 28 return True 29 else: 30 return False 31 32 def get(self, key): 33 self.__sock.send("get %s\r\n" % key) 34 lines = self.__sock.recv(1024).splitlines() 35 serialized_value = lines[1] 36 value = pickle.loads(base64.b64decode(serialized_value)) 37 return value 38 39 def stats(self): 40 self.__sock.send("stats\r\n") 41 lines = self.__sock.recv(1024).splitlines() 42 43 values = {} 44 45 for line in lines: 46 if line == 'END': 47 break 48 49 else: 50 [dummy, key, value] = line.split() 51 values[key] = value 52 53 return values 54
解説
set
- 返り値が "STORED\r\n" のときに "True" を返すようにした
- それ以外は "False" としたため、若干処理が甘いかもしれない
get
- 返り値が3行の文字列なので、まず改行文字で分割した
stats
- 以下のフォーマットで返ってくる
- STAT version 1.2.8
テストコード
my_memcache.py
55 if __name__ == '__main__': 56 memcache = MyMemcache() 57 memcache.connect("localhost", 11211) 58 59 print "########## stats ##########" 60 print memcache.stats() 61 print "\n" 62 63 print "########## string ##########" 64 key = "string_key" 65 value = "string_value" 66 print "key :" , key 67 print "value :" , value 68 print "---------- set ----------" 69 print memcache.set(key, value) 70 print "---------- get ----------" 71 print memcache.get(key) 72 print type(memcache.get(key)) 73 print "\n" 74 75 print "########## list ##########" 76 key = "list_key" 77 value = ['a', 'b', 'c'] 78 print "key :" , key 79 print "value :" , value 80 print "---------- set ----------" 81 print memcache.set(key, value) 82 print "---------- get ----------" 83 print memcache.get(key) 84 print type(memcache.get(key)) 85 print "\n" 86 87 print "########## tuple ##########" 88 key = "tuple_key" 89 value = (1, 2, 3) 90 print "key :" , key 91 print "value :" , value 92 print "---------- set ----------" 93 print memcache.set(key, value) 94 print "---------- get ----------" 95 print memcache.get(key) 96 print type(memcache.get(key)) 97 print "\n" 98 99 print "########## dict ##########" 100 key = "dict_key" 101 value = {'a' : 1, 'b' : 2, 'c' : 3} 102 print "key :" , key 103 print "value :" , value 104 print "---------- set ----------" 105 print memcache.set(key, value) 106 print "---------- get ----------" 107 print memcache.get(key) 108 print type(memcache.get(key)) 109 print "\n" 110
実行
$ python my_memcache.py
########## stats ##########
{'pid': '11509', 'total_items': '64', 'uptime': '47141', 'listen_disabled_num': '0', 'version': '1.2.8', 'limit_maxbytes': '134217728', 'rusage_user': '0.138425', 'bytes_read': '4793', 'accepting_conns': '1', 'rusage_system': '0.238628', 'cmd_get': '86', 'curr_connections': '6', 'threads': '2', 'total_connections': '35', 'cmd_set': '65', 'curr_items': '6', 'get_misses': '0', 'cmd_flush': '0', 'evictions': '0', 'bytes': '618', 'connection_structures': '7', 'bytes_written': '8006', 'time': '1272860539', 'pointer_size': '64', 'get_hits': '86'}
########## string ##########
key : string_key
value : string_value
---------- set ----------
True
---------- get ----------
string_value
<type 'str'>
########## list ##########
key : list_key
value : ['a', 'b', 'c']
---------- set ----------
True
---------- get ----------
['a', 'b', 'c']
<type 'list'>
########## tuple ##########
key : tuple_key
value : (1, 2, 3)
---------- set ----------
True
---------- get ----------
(1, 2, 3)
<type 'tuple'>
########## dict ##########
key : dict_key
value : {'a': 1, 'c': 3, 'b': 2}
---------- set ----------
True
---------- get ----------
{'a': 1, 'c': 3, 'b': 2}
<type 'dict'>
- 格納した値が、ちゃんと返ってきてるよ、やったね
- リストとか辞書は、型も正しいよ、やったね
また、根本的な問題として、ソケットの send や recv は、1回で送受信したいデータを全部送受信してくれるとは限りません。試しに、数百キロバイト以上のデータを送受信してみてください。
英語が読めるのであれば、 http://docs.python.org/howto/sockets.html を参照してください。
send/recvが使いこなせるようになったら、今度はTCP_NODELAYなどについても調べてみると、より速いクライアントを作れるようになるかもしれません。
memcache のデータ部分は、自分がまだしっかりと理解できていないようなので、調べ直してみます。
ソケットの send や recv はたしかに実装が甘かったので、紹介いただいたサイトを見て修正してみます。
ご指摘ありがとうございました!