termtter 1.0.7 → 1.0.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,6 +1,7 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
3
  require 'erb'
4
+ require 'set'
4
5
 
5
6
  config.plugins.standard.set_default(
6
7
  :limit_format,
@@ -8,40 +9,61 @@ config.plugins.standard.set_default(
8
9
 
9
10
  module Termtter::Client
10
11
 
11
- # standard commands
12
-
13
12
  register_command(
14
13
  :name => :update, :aliases => [:u],
15
14
  :exec_proc => lambda {|arg|
16
- unless /^\s*$/ =~ arg
17
- # TODO: Change to able to disable erb.
18
- text = ERB.new(arg).result(binding).gsub(/\n/, ' ')
19
- result = Termtter::API.twitter.update(text)
20
- puts "=> #{text}"
21
- result
15
+ unless arg.empty?
16
+ Termtter::API.twitter.update(arg)
17
+ puts "=> #{arg}"
22
18
  end
23
19
  },
24
20
  :completion_proc => lambda {|cmd, args|
25
21
  if /(.*)@([^\s]*)$/ =~ args
26
22
  find_user_candidates $2, "#{cmd} #{$1}@%s"
27
23
  end
28
- }
24
+ },
25
+ :help => ["update,u TEXT", "Post a new message"]
29
26
  )
30
27
 
28
+ direct_message_struct = Struct.new(:id, :text, :user, :created_at)
29
+ direct_message_struct.class_eval do
30
+ def method_missing(*args, &block)
31
+ nil
32
+ end
33
+ end
31
34
  register_command(
32
35
  :name => :direct, :aliases => [:d],
33
36
  :exec_proc => lambda {|arg|
34
- if /^([^\s]+)\s+(.*)\s*$/ =~ arg
37
+ case arg
38
+ when /^([^\s]+)\s+(.*)\s*$/
35
39
  user, text = $1, $2
36
40
  Termtter::API.twitter.direct_message(user, text)
37
41
  puts "=> to:#{user} message:#{text}"
42
+ when 'list'
43
+ output(
44
+ Termtter::API.twitter.direct_messages.map { |d|
45
+ direct_message_struct.new(d.id, "#{d.text} => #{d.recipient_screen_name}", d.sender, d.created_at)
46
+ },
47
+ :direct_messages
48
+ )
49
+ when 'sent_list'
50
+ output(
51
+ Termtter::API.twitter.sent_direct_messages.map { |d|
52
+ direct_message_struct.new(d.id, "#{d.text} => #{d.recipient_screen_name}", d.sender, d.created_at)
53
+ },
54
+ :direct_messages
55
+ )
38
56
  end
39
57
  },
40
- :completion_proc => lambda {|cmd, args|
41
- if /^([^\s]+)$/ =~ args
42
- find_user_candidates $1, "#{cmd} %s"
43
- end
44
- }
58
+ :completion_proc => lambda {|cmd, arg|
59
+ find_user_candidates(arg, "#{cmd} %s") +
60
+ ["list", "sent_list"].grep(/^#{Regexp.quote(arg)}/).map { |i| "#{cmd} #{i}" }
61
+ },
62
+ :help => [
63
+ ["direct,d USERNAME TEXT", "Send direct message"],
64
+ ["direct,d list", 'List direct messages'],
65
+ ["direct,d sent_list", 'List sent direct messages']
66
+ ]
45
67
  )
46
68
 
47
69
  register_command(
@@ -60,7 +82,8 @@ module Termtter::Client
60
82
  },
61
83
  :completion_proc => lambda {|cmd, arg|
62
84
  find_user_candidates arg, "#{cmd} %s"
63
- }
85
+ },
86
+ :help => ["profile,p USERNAME", "Show user's profile"]
64
87
  )
65
88
 
66
89
  register_command(
@@ -75,9 +98,13 @@ module Termtter::Client
75
98
  followers += tmp = Termtter::API.twitter.followers(user_name, :page => page+=1)
76
99
  end until tmp.empty?
77
100
  Termtter::Client.public_storage[:followers] = followers
101
+ public_storage[:users] += followers.map(&:screen_name)
78
102
  puts followers.map(&:screen_name).join(' ')
79
- }
80
- # TODO :completion_proc
103
+ },
104
+ :completion_proc => lambda {|cmd, arg|
105
+ find_user_candidates arg, "#{cmd} %s"
106
+ },
107
+ :help => ["followers", "Show followers"]
81
108
  )
82
109
 
83
110
  register_command(
@@ -94,22 +121,30 @@ module Termtter::Client
94
121
  },
95
122
  :completion_proc => lambda {|cmd, arg|
96
123
  find_user_candidates arg, "#{cmd} %s"
97
- }
124
+ },
125
+ :help => ["list,l [USERNAME]", "List the posts"]
98
126
  )
99
127
 
128
+ public_storage[:search_keywords] = Set.new
100
129
  register_command(
101
130
  :name => :search, :aliases => [:s],
102
131
  :exec_proc => lambda {|arg|
103
132
  statuses = Termtter::API.twitter.search(arg)
133
+ public_storage[:search_keywords] << arg
104
134
  output(statuses, :search)
105
- }
135
+ },
136
+ :completion_proc => lambda {|cmd, arg|
137
+ public_storage[:search_keywords].grep(/#{Regexp.quote(arg)}/).map { |i| "#{cmd} #{i}" }
138
+ },
139
+ :help => ["search,s TEXT", "Search for Twitter"]
106
140
  )
107
141
 
108
142
  register_command(
109
143
  :name => :replies, :aliases => [:r],
110
144
  :exec_proc => lambda {|arg|
111
145
  output(Termtter::API.twitter.replies, :replies)
112
- }
146
+ },
147
+ :help => ["replies,r", "List the most recent @replies for the authenticating user"]
113
148
  )
114
149
 
115
150
  register_command(
@@ -130,7 +165,8 @@ module Termtter::Client
130
165
  find_status_ids(arg).map {|id| "#{cmd} #{id}"}
131
166
  end
132
167
  end
133
- }
168
+ },
169
+ :help => ["show ID", "Show a single status"]
134
170
  )
135
171
 
136
172
  register_command(
@@ -138,7 +174,8 @@ module Termtter::Client
138
174
  :exec_proc => lambda {|arg|
139
175
  id = arg.gsub(/.*:\s*/, '')
140
176
  # TODO: Implement
141
- output([Termtter::API.twitter.show(id)], :show)
177
+ #output([Termtter::API.twitter.show(id)], :show)
178
+ puts "Not implemented yet."
142
179
  },
143
180
  :completion_proc => get_command(:show).completion_proc
144
181
  )
@@ -173,6 +210,61 @@ module Termtter::Client
173
210
  :help => ['leave USER', 'Leave user']
174
211
  )
175
212
 
213
+ register_command(
214
+ :name => :favorite, :aliases => [:fav],
215
+ :exec_proc => lambda {|arg|
216
+ id = 0
217
+ case arg
218
+ when /^\d+/
219
+ id = arg.to_i
220
+ when /^@([A-Za-z0-9_]+)/
221
+ user = $1
222
+ statuses = Termtter::API.twitter.user_timeline(user)
223
+ return if statuses.empty?
224
+ id = statuses[0].id
225
+ when /^\/(.*)$/
226
+ word = $1
227
+ raise "Not implemented yet."
228
+ else
229
+ return
230
+ end
231
+
232
+ r = Termtter::API.twitter.favorite id
233
+ puts "Favorited status ##{r.id} on user @#{r.user.screen_name} #{r.text}"
234
+ },
235
+ :completion_proc => lambda {|cmd, arg|
236
+ case arg
237
+ when /@(.*)/
238
+ find_user_candidates $1, "#{cmd} @%s"
239
+ when /(\d+)/
240
+ find_status_ids(arg).map{|id| "#{cmd} #{id}"}
241
+ else
242
+ %w(favorite).grep(/^#{Regexp.quote arg}/)
243
+ end
244
+ },
245
+ :help => ['favorite,fav (ID|@USER|/WORD)', 'Favorite a status']
246
+ )
247
+
248
+ def self.show_settings(conf, level = 0)
249
+ conf.__values__.each do |k, v|
250
+ if v.instance_of? Termtter::Config
251
+ puts "#{k}:"
252
+ show_settings v, level + 1
253
+ else
254
+ print ' ' * level
255
+ puts "#{k} = #{v.nil? ? 'nil' : v.inspect}"
256
+ end
257
+ end
258
+ end
259
+
260
+ register_command(
261
+ :name => :settings, :aliases => [:set],
262
+ :exec_proc => lambda {|_|
263
+ show_settings config
264
+ },
265
+ :help => ['settings,set', 'Show your settings']
266
+ )
267
+
176
268
  # TODO: Change colors when remaining_hits is low.
177
269
  # TODO: Simmulate remaining_hits.
178
270
  register_command(
@@ -210,61 +302,23 @@ module Termtter::Client
210
302
  :help => ['exit,e', 'Exit']
211
303
  )
212
304
 
213
- register_hook(
214
- :name => :default_error_handler,
215
- :points => [:on_error],
216
- :exec_proc => lambda {|e|
217
- case e
218
- when Rubytter::APIError
219
- case e.response.code
220
- when /401/
221
- warn '[ERROR] Unauthorized: maybe you tried to show protected user status'
222
- when /403/
223
- warn '[ERROR] Access denied: maybe that user is protected'
224
- when /404/
225
- warn '[ERROR] Not found: maybe there is no such user'
226
- end
227
- else
228
- warn "[ERROR] Something wrong: #{e.message}"
229
- end
230
- raise e if config.system.devel == true
231
- }
232
- )
233
-
234
305
  register_command(
235
306
  :name => :help, :aliases => [:h],
236
307
  :exec_proc => lambda {|arg|
237
- # TODO: move to each commands
238
- helps = [
239
- ["help,h", "Print this help message"],
240
- ["list,l", "List the posts in your friends timeline"],
241
- ["list,l USERNAME", "List the posts in the the given user's timeline"],
242
- ["update,u TEXT", "Post a new message"],
243
- ["direct,d USERNAME TEXT", "Send direct message"],
244
- ["profile,p USERNAME", "Show user's profile"],
245
- ["replies,r", "List the most recent @replies for the authenticating user"],
246
- ["search,s TEXT", "Search for Twitter"],
247
- ["show ID", "Show a single status"]
248
- ]
249
- helps += @commands.map {|name, command| command.help}
250
- helps.compact!
251
- puts formatted_help(helps)
252
- }
253
- )
254
-
255
- register_command(
256
- :name => :execute,
257
- :exec_proc => lambda{|arg|
258
- if arg
259
- `#{arg}`.each_line do |line|
260
- unless line.strip.empty?
261
- Termtter::API.twitter.update(line)
262
- puts "=> #{line}"
263
- end
308
+ helps = []
309
+ @commands.map do |name, command|
310
+ next unless command.help
311
+ case command.help[0]
312
+ when String
313
+ helps << command.help
314
+ when Array
315
+ helps += command.help
264
316
  end
265
317
  end
318
+ helps.compact!
319
+ puts formatted_help(helps)
266
320
  },
267
- :help => ['execute COMMAND', 'execute the command']
321
+ :help => ["help,h", "Print this help message"]
268
322
  )
269
323
 
270
324
  def self.formatted_help(helps)
@@ -278,9 +332,9 @@ module Termtter::Client
278
332
 
279
333
  # completion for standard commands
280
334
 
281
- require 'set'
282
335
  public_storage[:users] ||= Set.new
283
336
  public_storage[:status_ids] ||= Set.new
337
+ public_storage[:last_status_id] ||= Hash.new
284
338
 
285
339
  register_hook(
286
340
  :name => :for_completion,
@@ -291,24 +345,180 @@ module Termtter::Client
291
345
  public_storage[:users] += s.text.scan(/@([a-zA-Z_0-9]*)/).flatten
292
346
  public_storage[:status_ids].add(s.id)
293
347
  public_storage[:status_ids].add(s.in_reply_to_status_id) if s.in_reply_to_status_id
348
+ public_storage[:last_status_id].store(s.user.screen_name, s.id)
349
+ end
350
+ }
351
+ )
352
+
353
+ public_storage[:plugins] = (Dir["#{File.dirname(__FILE__)}/*.rb"] + Dir["#{Termtter::CONF_DIR}/plugins/*.rb"]).map do |f|
354
+ f.match(%r|([^/]+).rb$|)[1]
355
+ end
356
+
357
+ register_command(
358
+ :name => :plugin,
359
+ :exec_proc => lambda {|arg|
360
+ if arg.empty?
361
+ puts 'Should specify plugin name.'
362
+ return
363
+ end
364
+ begin
365
+ result = plugin arg
366
+ rescue LoadError
367
+ ensure
368
+ puts "=> #{result.inspect}"
369
+ end
370
+ },
371
+ :completion_proc => lambda {|cmd, args|
372
+ find_user_candidates args, "#{cmd} %s"
373
+ unless args.empty?
374
+ find_plugin_candidates args, "#{cmd} %s"
375
+ else
376
+ public_storage[:plugins].sort
377
+ end
378
+ },
379
+ :help => ['plugin FILE', 'Load a plugin']
380
+ )
381
+
382
+ register_command(
383
+ :name => :plugins,
384
+ :exec_proc => lambda {|arg|
385
+ puts public_storage[:plugins].sort.join("\n")
386
+ },
387
+ :help => ['plugins', 'Show list of plugins']
388
+ )
389
+
390
+ register_command(
391
+ :name => :reply,
392
+ :aliases => [:re],
393
+ :exec_proc => lambda {|arg|
394
+ case arg
395
+ when /^\s*(?:list|ls)\s*(?:\s+(\w+))?\s*$/
396
+ public_storage[:log4re] = if $1
397
+ public_storage[:log].
398
+ select{|l| l.user.screen_name == $1}.
399
+ sort {|a,b| a.id <=> b.id}
400
+ else
401
+ public_storage[:log].sort {|a,b| a.id <=> b.id}
402
+ end
403
+ public_storage[:log4re].each_with_index do |s, i|
404
+ puts "#{i}: #{s.user.screen_name}: #{s.text}"
405
+ end
406
+ when /^\s*(?:up(?:date)?)\s+(\d+)\s+(.+)$/
407
+ id = public_storage[:log4re][$1.to_i].id
408
+ text = $2
409
+ user = public_storage[:log4re][$1.to_i].user
410
+ update_with_user_and_id(text, user.screen_name, id) if user
411
+ public_storage.delete :log4re
412
+ when /^\s*(\d+)\s+(.+)$/
413
+ id, text = $1, $2
414
+ user = public_storage[:log].select {|l| l.id == id.to_i }.first.user
415
+ update_with_user_and_id(text, user.screen_name, id) if user
416
+ when /^\s*@(\w+)/
417
+ in_reply_to_status_id = Termtter::API.twitter.user($1).status.id rescue nil
418
+ params = in_reply_to_status_id ? {:in_reply_to_status_id => in_reply_to_status_id} : {}
419
+ Termtter::API.twitter.update(arg, params)
420
+ puts "=> #{arg}"
421
+ end
422
+ },
423
+ :completion_proc => lambda {|cmd, arg|
424
+ case arg
425
+ when /(.*)@([^\s]*)$/
426
+ find_user_candidates $2, "#{cmd} #{$1}@%s"
427
+ when /(\d+)/
428
+ find_status_ids(arg).map{|id| "#{cmd} #{id}"}
294
429
  end
295
430
  }
296
431
  )
297
432
 
433
+ register_command(
434
+ :name => :redo,
435
+ :aliases => [:"."],
436
+ :exec_proc => lambda {|arg|
437
+ break if Readline::HISTORY.length < 2
438
+ i = Readline::HISTORY.length - 2
439
+ input = ""
440
+ begin
441
+ input = Readline::HISTORY[i]
442
+ i -= 1
443
+ return if i <= 0
444
+ end while input == "redo" or input == "."
445
+ begin
446
+ Termtter::Client.call_commands(input)
447
+ rescue CommandNotFound => e
448
+ warn "Unknown command \"#{e}\""
449
+ warn 'Enter "help" for instructions'
450
+ rescue => e
451
+ handle_error e
452
+ end
453
+ },
454
+ :help => ["redo,.", "Execute previous command"]
455
+ )
456
+
457
+ def self.update_with_user_and_id(text, username, id)
458
+ text = ERB.new("@#{username} #{text}").result(binding).gsub(/\n/, ' ')
459
+ result = Termtter::API.twitter.update(text, {'in_reply_to_status_id' => id})
460
+ puts "=> #{text}"
461
+ result
462
+ end
463
+
464
+ =begin
465
+ = Termtter reply command
466
+ == Usage
467
+ === list
468
+ * ステータスリストを連番と一緒に出す。
469
+ > reply [list|ls]
470
+ 0: foo: foo's message
471
+ 1: bar: bar's message
472
+ ..
473
+
474
+ * ユーザ指定してリスト作成。
475
+ > reply [list|ls] foo
476
+ 0: foo: foo's message0
477
+ 1: foo: foo's message1
478
+
479
+ === reply
480
+ メッセージ送信の際、@usernameが自動的に付与される。
481
+
482
+ * status_idを自分で入力してreply送信
483
+ > reply 1234567890 message to status_id
484
+ => @foo message to status_id (reply to 1234567890)
485
+
486
+ * reply listコマンドで出したステータス番号に対してreply送信
487
+ > reply up 0 message to status no
488
+ => @foo message to status_no
489
+
490
+ * 対象ユーザの最後の発言に対してreply
491
+ > reply @foo message to foo
492
+ => @foo message to foo
493
+
494
+ == Todo
495
+ * 英語で説明 => ヘルプを設定する
496
+ * リファクタ
497
+ * 補完
498
+ * 確認画面を出したい
499
+ =end
500
+
501
+ def self.find_plugin_candidates(a, b)
502
+ public_storage[:plugins].
503
+ grep(/^#{Regexp.quote a}/i).
504
+ map {|u| b % u }
505
+ end
506
+
298
507
  def self.find_status_ids(text)
299
508
  public_storage[:status_ids].select {|id| /#{Regexp.quote(text)}/ =~ id.to_s}
300
509
  end
301
510
 
302
511
  def self.find_users(text)
303
- public_storage[:users].select {|user| /#{Regexp.quote(text)}/ =~ user}
512
+ public_storage[:users].select {|user| /^#{Regexp.quote(text)}/ =~ user}
304
513
  end
305
514
 
306
515
  def self.find_user_candidates(a, b)
307
- if a.nil? || a.empty?
308
- public_storage[:users].to_a
309
- else
310
- public_storage[:users].grep(/^#{Regexp.quote a}/i)
311
- end.
312
- map {|u| b % u }
516
+ users =
517
+ if a.nil? || a.empty?
518
+ public_storage[:users].to_a
519
+ else
520
+ public_storage[:users].grep(/^#{Regexp.quote a}/i)
521
+ end
522
+ users.map {|u| b % u }
313
523
  end
314
524
  end
@@ -46,11 +46,17 @@ module Termtter
46
46
  status_color = config.plugins.stdout.colors[s.user.id.hash % config.plugins.stdout.colors.size]
47
47
  status = "#{s.user.screen_name}: #{TermColor.escape(text)}"
48
48
  if s.in_reply_to_status_id
49
- status += " (repl. to #{s.in_reply_to_status_id})"
49
+ status += " (reply to #{s.in_reply_to_status_id})"
50
50
  end
51
51
 
52
52
  time = "(#{Time.parse(s.created_at).strftime(time_format)})"
53
53
  id = s.id
54
+ source =
55
+ case s.source
56
+ when />(.*?)</ then $1
57
+ when 'web' then 'web'
58
+ end
59
+
54
60
  erbed_text = ERB.new(config.plugins.stdout.timeline_format).result(binding)
55
61
  output_text << TermColor.parse(erbed_text) + "\n"
56
62
  end
@@ -0,0 +1,22 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module Termtter::Client
4
+ register_command(
5
+ :name => :switch_user,
6
+ :exec_proc => lambda {|arg|
7
+ Termtter::API.switch_user(arg)
8
+ },
9
+ :completion_proc => lambda {|cmd, arg|
10
+ # TODO
11
+ },
12
+ :help => ["switch_user USERNAME", "Switch twitter account."]
13
+ )
14
+
15
+ register_command(
16
+ :name => :restore_user,
17
+ :exec_proc => lambda {|arg|
18
+ Termtter::API.restore_user
19
+ },
20
+ :help => ["restore_user", "Restore default twitter account."]
21
+ )
22
+ end
@@ -0,0 +1,20 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ Termtter::Client.register_hook(
4
+ :name => :tinyurl,
5
+ :points => [:modify_arg_for_update],
6
+ :exec_proc => lambda {|cmd, arg|
7
+ arg = arg.gsub(URI.regexp) do |url|
8
+ if url =~ %r!^https?:!
9
+ Termtter::API.connection.start('tinyurl.com', 80) do |http|
10
+ http.get('/api-create.php?url=' + URI.escape(url)).body
11
+ end
12
+ else
13
+ url
14
+ end
15
+ end
16
+ }
17
+ )
18
+
19
+ # tinyuri.rb
20
+ # make URLs in your update to convert tinyurl.com/XXXXXXX.
@@ -0,0 +1,94 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ config.plugins.typable_id.set_default(:typable_keys, %w[ a i u e o
4
+ ka ki ku ke ko
5
+ ga gi gu ge go
6
+ sa si su se so
7
+ za zi zu ze zo
8
+ ta ti tu te to
9
+ da di du de do
10
+ na ni nu ne no
11
+ ha hi hu he ho
12
+ ba bi bu be bo
13
+ pa pi pu pe po
14
+ ma mi mu me mo
15
+ ya yu yo
16
+ ra ri ru re ro
17
+ wa wo
18
+ nn ])
19
+
20
+ module Termtter::Client
21
+ public_storage[:typable_id] = []
22
+ config.plugins.typable_id.typable_keys.each {|key|
23
+ public_storage[:typable_id].push([key, '', ''])
24
+ }
25
+
26
+ register_hook(
27
+ :name => :typable_id,
28
+ :points => [:post_filter],
29
+ :exec_proc => lambda {|filtered, event|
30
+ filtered.each do |s|
31
+ current_id = public_storage[:typable_id].shift
32
+ current_id[1] = s.id.to_s
33
+ current_id[2] = s
34
+ public_storage[:typable_id].push(current_id)
35
+ end
36
+ }
37
+ )
38
+
39
+ def self.typable_id_convert(id)
40
+ if current_id = public_storage[:typable_id].assoc(id.to_s)
41
+ return current_id[1]
42
+ elsif current_id = public_storage[:typable_id].rassoc(id.to_s)
43
+ return current_id[0]
44
+ else
45
+ return nil
46
+ end
47
+ end
48
+
49
+ def self.typable_id_status(id)
50
+ if current_id = (public_storage[:typable_id].assoc(id.to_s)||\
51
+ public_storage[:typable_id].rassoc(id.to_s))
52
+ return current_id[2]
53
+ else
54
+ return nil
55
+ end
56
+ end
57
+
58
+ def self.typable_id?(id)
59
+ if public_storage[:typable_id].assoc(id.to_s)
60
+ return true
61
+ else
62
+ return false
63
+ end
64
+ end
65
+ end
66
+
67
+ #Setting
68
+ # ex)
69
+ # config.plugins.stdout.timeline_format = '<90><%=time%></90> <<%=status_color%>><%=status%></<%=status_color%>> <90><%=id%>>[<%=Termtter::Client.typable_id_convert(id)%>]</90>
70
+ #Optional Settng
71
+ # ex) Like hepburn system
72
+ # config.plugins.typable_id.typable_keys = %w[ a i u e o
73
+ # ka ki ku ke ko ga gi gu ge go
74
+ # sa shi su se so za ji zu ze zo
75
+ # ta chi tsu te to da di du de do
76
+ # na ni nu ne no
77
+ # ha hi fu he ho ba bi bu be bo pa pi pu pe po
78
+ # ma mi mu me mo
79
+ # ya yu yo
80
+ # ra ri ru re ro
81
+ # wa wo
82
+ # nn ]
83
+ # ex) Hiragana
84
+ # config.plugins.typable_id.typable_keys = %w[あ い う え お
85
+ # か き く け こ が ぎ ぐ げ ご
86
+ # さ し す せ そ ざ じ ず ぜ ぞ
87
+ # た ち つ て と だ ぢ づ で ど
88
+ # な に ぬ ね の
89
+ # は ひ ふ へ ほ ば び ぶ べ ぼ ぱ ぴ ぷ ぺ ぽ
90
+ # ま み む め も
91
+ # や ゆ よ
92
+ # ら り る れ ろ
93
+ # わ を
94
+ # ん ]