diff -ur v10/argmnt.py v11/argmnt.py
--- v10/argmnt.py	2018-10-25 03:14:33.000000000 +0900
+++ v11/argmnt.py	2018-10-27 01:28:27.000000000 +0900
@@ -3,6 +3,8 @@
 import sys
 import os
 import subprocess as sp
+import time
+import select
 import six
 import nkf
 import yaml
@@ -24,12 +26,42 @@
 class Empty:
 	pass
 
+def readable(f):
+	(rlst, wlst, xlst) = select.select( [f], [], [], 0 )
+	return rlst != []
+
+def new_nc(port):
+	e = Empty()
+	cmd = 'nc -l {}'.format(port)
+	new = lambda : sp.Popen( cmd, shell=True, stdout=sp.PIPE )
+	e.proc = new()
+	def get():
+		s = ''
+		if readable(e.proc.stdout):
+			e.proc.wait()
+			s = e.proc.stdout.read()
+			e.proc = new()
+		return s
+	e.get = get
+	return e
+
 str_width = nkf.str_width
 p_add = rect.p_add
 p_sub = rect.p_sub
 frame_rects = rect.frame_rects
 contain_rect = rect.rects_contain_rect
 
+flat_lst = lambda lst: sum( map( lambda e: flat_lst(e) if type(e) == list else [e], lst ), [] )
+
+def in_lst(t, lst):
+	if t in lst:
+		return True
+	lsts = list( filter( lambda e: type(e) == list, lst ) )
+	for lst in lsts:
+		if in_lst(t, lst):
+			return True
+	return False
+
 def get_next(lst, v):
 	i = 0
 	if v in lst:
@@ -42,6 +74,9 @@
 is_rect = lambda o: is_typ(o, 'rect')
 
 def copy_o(o):
+	if type(o) == list:
+		return list( map(copy_o, o) )
+
 	def cp_if_need(v):
 		if type(v) == list:
 			return list( map( cp_if_need, v ) )
@@ -54,9 +89,6 @@
 		setattr( o_, k, cp_if_need( getattr(o, k) ) )
 	return o_
 
-def copy_olst(olst):
-	return list( map( copy_o, olst ) )
-
 def get_vh(dxy):
 	(dx, dy) = dxy
 	if dx != 0 and dy == 0:
@@ -254,10 +286,10 @@
 			lst.pop(i)
 		i -= 1
 
-def new(lst, nkf_opt):
+def new(lst, nkf_opt, port):
 	e = Empty()
 
-	rects = sum( map( get_rects, lst ), [] )
+	rects = sum( map( get_rects, flat_lst(lst) ), [] )
 	r = contain_rect(rects)
 	view = txview.new(r, nkf_opt)
 
@@ -266,7 +298,7 @@
 
 	step_modes = ('normal', 'move', 'resize', 'line', 'rect')
 
-	is_sel = lambda o: o in e.sel
+	is_sel = lambda o: in_lst(o, e.sels)
 
 	def key_dxy(k):
 		dxy = key.dxy( k, (0,0) )
@@ -284,9 +316,13 @@
 		return e.mode in ('sel_2', 'sel_kind')
 
 	def get_o_rect(o):
+		if type(o) == list:
+			return contain_rect( list( map( get_o_rect, o ) ) )
 		return get_rect( o, frm_visible(o) )
 
 	def get_o_rects(o):
+		if type(o) == list:
+			return sum( map( get_o_rects, o ), [] )
 		return get_rects( o, frm_visible(o) )
 
 	def is_cross(o, r):
@@ -320,7 +356,7 @@
 		r = view.scroll(r)
 		buf = txbuf.new(r)
 
-		for o in lst:
+		for o in flat_lst(lst):
 			if is_cross(o, r):
 				atts = get_atts(o, buf)
 				frm_atts = None
@@ -428,29 +464,62 @@
 		return list( filter( lambda o: rect.p_in_rects( e.cur, get_o_rects(o) ), reversed(lst) ) )
 
 	def set_mode(mode):
-		bak_sel = e.mode_bak[1]
-		rs = list( map( get_o_rect, bak_sel + e.sel ) )
+		bak_sels = e.mode_bak[1]
+		rs = list( map( get_o_rect, bak_sels + e.sels ) )
 
-		idxs = list( map( lst.index, e.sel ) )
-		bak = copy_olst(lst)
-		bak_sel = list( map( lambda i: bak[i], idxs ) )
-		e.mode_bak = ( bak, bak_sel, e.cur, e.step, e.mode )
+		idxs = list( map( lst.index, e.sels ) )
+		bak = copy_o(lst)
+		bak_sels = list( map( lambda i: bak[i], idxs ) )
+		e.mode_bak = ( bak, bak_sels, e.cur, e.step, e.mode )
 
 		e.mode = mode
-		if mode == 'normal' and e.sel:
-			e.sel = []
+		if mode == 'normal' and e.sels:
+			e.sels = []
 
-		rs += list( map( get_o_rect, e.sel ) )
+		rs += list( map( get_o_rect, e.sels ) )
 		if rs:
 			r = contain_rect(rs)
 			draw_r( r, term.out )
 		draw_cur()
 
+	def group():
+		if e.sels and len(e.sels) > 1:
+			g = e.sels
+			i = lst.index( g[0] )
+			for o in g:
+				lst.remove(o)
+			lst.insert(i, g)
+			e.sels = [g]
+			return True
+		return False
+
+	def ungroup():
+		sels = e.sels
+		e.sels = []
+		ret = False
+		for o in sels:
+			if type(o) == list:
+				i = lst.index(o)
+				lst.remove(o)
+				for o_ in reversed(o):
+					lst.insert(i, o_)
+				ret = True
+			e.sels += o if type(o) == list else [o]
+		return ret
+
+	def f_group(k):
+		if k == 'g':
+			if group():
+				set_mode('normal')
+		elif k == 'u':
+			if ungroup():
+				set_mode('normal')
+
 	def f_normal(k):
 		if key.is_ok(k):
 			olst = get_olst_under_cursor()
 			if olst:
-				e.sel = olst[:1]
+				e.sels = olst[:1]
 				set_mode('sel')
 			else:
 				set_mode('sel_4')
@@ -458,11 +527,10 @@
 			move_cur_key(k)
 		elif e.clipboard and k == 'v': # paste
 			(olst, p) = e.clipboard
-			olst = copy_olst(olst)
-			for o in olst:
-				move_o( o, p_sub(e.cur, p) )
-				lst.append(o)
-			e.sel = olst
+			olst = copy_o(olst)
+			move_o( olst, p_sub(e.cur, p) )
+			lst.extend(olst)
+			e.sels = olst
 			set_mode('sel')
 		elif k == '\t':
 			set_mode('step')
@@ -472,24 +540,30 @@
 			set_mode('sel_2')
 		elif key.is_allow(k):
 			call( [ 'move', move ], k )
-		elif e.sel and k in ('c', 'x'):
-			e.clipboard = ( copy_olst(e.sel), e.cur )
+		elif e.sels and k in ('c', 'x'):
+			e.clipboard = ( copy_o(e.sels), e.cur )
 			if k == 'x':
-				for o in e.sel:
+				for o in e.sels:
 					f = new_draw(o)
 					lst.remove(o)
 					f()
-				e.sel = []
+				e.sels = []
 			set_mode('normal')
 		elif k == 'd':
 			set_mode('depth')
 		elif k == 'm':
 			set_mode('msel')
+		elif k in ('g', 'u'):
+			f_group(k)
 		elif key.is_cancel(k):
 			set_mode('normal')
 
+	def get_sel_o():
+		lst = flat_lst(e.sels)
+		return lst[-1] if lst else None
+
 	def f_sel2_ok(k):
-		o = e.sel[0]
+		o = get_sel_o()
 		if p_on_frm(e.cur, o):
 			set_mode('sel_3')
 		elif not has_typ(o) and len(o.s) > 1:
@@ -498,7 +572,7 @@
 			set_mode('normal')
 
 	def resize(k):
-		o = e.sel[0]
+		o = get_sel_o()
 		dxy = key_dxy(k)
 		f = new_draw(o)
 		if is_rect(o):
@@ -521,12 +595,16 @@
 		move_cur(dxy)
 
 	def sel_align(k):
-		o = e.sel[0]
+		o = get_sel_o()
 		f = new_draw(o)
 		o.a = get_next( ['l', 'c', 'r'], o.a )
 		f()
 
 	def move_o(o, dxy):
+		if type(o) == list:
+			for o_ in o:
+				move_o(o_, dxy)
+			return
 		(dx, dy) = dxy
 		if is_line(o):
 			for p in o.lst:
@@ -538,15 +616,14 @@
 			(o.x, o.y) = (o.x + dx, o.y + dy)
 
 	def move(k):
-		for o in e.sel:
-			dxy = key_dxy(k)
-			f = new_draw(o)
-			move_o(o, dxy)
-			f()
+		dxy = key_dxy(k)
+		f = new_draw(e.sels)
+		move_o(e.sels, dxy)
+		f()
 		move_cur(dxy)
 
 	def sel_kind(k):
-		o = e.sel[0]
+		o = get_sel_o()
 		f = new_draw(o)
 		rlst = sorted( frm_info.keys() )
 		if is_line(o):
@@ -558,7 +635,7 @@
 		f()
 
 	def frm_align(k):
-		o = e.sel[0]
+		o = get_sel_o()
 		f = new_draw(o)
 		d = key.allow(k)
 		if d in 'ud':
@@ -573,14 +650,14 @@
 		dxy = key_dxy(k)
 		if dxy == (0, 0):
 			return
-		if e.sel:
-			o = e.sel[0]
+		if e.sels:
+			o = e.sels[0]
 		else:
 			o = Empty()
 			o.typ = 'line'
 			o.lst = [ list(e.cur) ]
 			o.kind = ''
-			e.sel = [o]
+			e.sels = [o]
 			lst.append(o)
 
 		vh = get_vh(dxy)
@@ -598,15 +675,15 @@
 		dxy = key_dxy(k)
 		if dxy == (0, 0):
 			return
-		if e.sel:
-			o = e.sel[0]
+		if e.sels:
+			o = e.sels[0]
 		else:
 			o = Empty()
 			o.typ = 'rect'
 			(cx, cy) = e.cur
 			o.r = [ cx, cy, 1, 1 ]
 			o.kind = 'a'
-			e.sel = [o]
+			e.sels = [o]
 			lst.append(o)
 
 		f = new_draw(o)
@@ -615,7 +692,7 @@
 		move_cur(dxy)
 
 	def f_depth(k):
-		o = e.sel[0]
+		o = e.sels[0]
 		f = new_draw(o)
 		i = lst.index(o)
 		n = len(lst)
@@ -644,33 +721,36 @@
 				o = olst[0]
 				f = new_draw(o)
 				if is_sel(o):
-					e.sel.remove(o)
+					e.sels.remove(o)
 				else:
-					e.sel.append(o)
+					e.sels.append(o)
+					e.sels.sort( key=lst.index )
 				f()
 		elif key.is_allow(k):
 			move_cur_key(k)
 		elif k == 'm':
 			set_mode('sel')
+		elif k in ('g', 'u'):
+			f_group(k)
 		elif key.is_cancel(k):
 			f_cancel(k)
 
 	def f_cancel(k):
-		( bak, bak_sel, p, step, mode ) = e.mode_bak
+		( bak, bak_sels, p, step, mode ) = e.mode_bak
 
 		move_cur_to(p)
 		e.step = step
 
-		e.mode_bak = ( lst, e.sel, e.cur, e.step, e.mode )
+		e.mode_bak = ( lst, e.sels, e.cur, e.step, e.mode )
 
 		del lst[:]
 		lst.extend(bak)
-		e.sel = bak_sel
+		e.sels = bak_sels
 
 		set_mode(mode)
 
 	def has_bdr(k):
-		o = e.sel[0]
+		o = get_sel_o()
 		if not has_typ(o):
 			(bx, by) = o.frm.bdr
 			if bx > 0 or by > 0:
@@ -727,24 +807,52 @@
 				return call( o.get('cancel'), k )
 		return None
 
+	def try_add_str():
+		s = e.nc.get()
+		if not s:
+			return False
+		(s, nkf_opt) = nkf.to_str(s)
+
+		(o, _) = cvt_data_load(s, 0)
+		(x, y, w, h) = view.get_rect()
+		o.x = x + (w - o.w) / 2
+		o.y = y + (h - o.h) / 2
+		lst.append(o)
+		if e.mode == 'normal':
+			move_cur_to( (o.x, o.y) )
+			e.sels = [o]
+			set_mode('sel')
+		draw_r( get_tx_rect(o), term.out )
+		return True
+
 	def get_key(klst):
 		key.init()
 		while True:
-			k = key.get()
+			k = key.get( block=False )
 			if k in klst:
 				break
-			o = hdl.get(e.mode)
-			call(o, k)
+			if k:
+				o = hdl.get(e.mode)
+				call(o, k)
+				continue
+			if try_add_str():
+				continue
+			time.sleep(0.1)
 		key.fini()
 	e.get_key = get_key
 
-	e.fini = lambda : view.fini()
+	def fini():
+		e.nc.proc.kill()
+		e.nc.proc.wait()
+		view.fini()
+	e.fini = fini
 
 	e.mode = 'normal'
 	e.step = 1
 	e.mode_bak = ( [], [], e.cur, e.step, e.mode )
-	e.sel = []
+	e.sels = []
 	e.clipboard = None
+	e.nc = new_nc(port)
 
 	draw_r( r, term.out )
 
@@ -760,7 +868,11 @@
 	if isinstance(o, six.string_types):
 		o = o.strip().split('\n')
 	if type(o) == list:
-		o = { 's': o }
+		if all( map( lambda o_: isinstance(o_, six.string_types), o ) ):
+			o = { 's': o }
+		else:
+			(es, ys) = zip( *map( lambda o_: cvt_data_load(o_, y), o ) )
+			return ( list(es), max(ys) )
 	# dict
 	typ = o.get('typ')
 	if typ == 'line':
@@ -787,6 +899,8 @@
 	return (e, y)
 
 def cvt_data_save(e):
+	if type(e) == list:
+		return list( map( cvt_data_save, e ) )
 	d = {}
 	if has_typ(e):
 		d['typ'] = e.typ
@@ -814,6 +928,7 @@
 	return d
 	
 def txt_out(lst, nkf_opt):
+	lst = flat_lst(lst)
 	rects = sum( map( get_rects, lst ), [] )
 	r = contain_rect(rects)
 	buf = txbuf.new(r)	
@@ -829,11 +944,12 @@
 
 def help():
 	msg = [
-		'Usage: {} [-txt] [-i] [-o enc] yaml_file',
+		'Usage: {} [-txt] [-i] [-o enc] [-p add_str_port] yaml_file',
 		"  yaml_file == '-' or None, use stdin",
 		'  -txt : result txt to stdout',
 		'  update yaml data to stdout',
 		'  -i : in place yaml_file (over write)',
+		'  -p : port for add str, default 44317',
 	]
 	sys.stderr.write( '\n'.join(msg) + '\n' )
 	sys.exit(0)
@@ -842,7 +958,7 @@
 	if opt.index('-h') >= 0:
 		help()
 
-	argv = opt.not_opt_argv( ['-o'], ['-txt', '-i', '-h'] )
+	argv = opt.not_opt_argv( ['-o', '-p'], ['-txt', '-i', '-h'] )
 	fn_i = argv.pop(0) if argv else '-'
 
 	def f_read(fn):
@@ -869,7 +985,7 @@
 		sys.exit(0)
 
 	# edit
-	a = new(lst, o)
+	a = new( lst, o, opt.get('-p', 44317) )
 	a.get_key( ['q'] )
 	a.fini()
 
diff -ur v10/key.py v11/key.py
--- v10/key.py	2018-10-17 20:55:40.000000000 +0900
+++ v11/key.py	2018-10-26 20:44:25.000000000 +0900
@@ -2,6 +2,7 @@
 
 import os
 import term
+import select
 
 esc = term.esc
 ctl = lambda s: chr( 1 + ord(s) - ord('a') )
@@ -16,7 +17,13 @@
 	term.stty('icanon', True)
 	term.stty('echo', True)
 
-def get():
+def select_rlst(rlst):
+	( rlst, wlst, xlst ) = select.select( rlst, [], [], 0 )
+	return rlst
+
+def get(block=True):
+	if not block and not select_rlst( [ term.tty_r ] ):
+		return ''
 	s = os.read( term.tty_r.fileno(), 10 )
 	if type(s) != str:
 		s =''.join( map(chr, s) )
