meshchat 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3b78573438d48db0c4e67092319332d045ca76b2
4
- data.tar.gz: 07de08af6980a361b232fc659b38863b32c49608
3
+ metadata.gz: d0990d41d8c16d59332c7220b14e4f3e95fb6bfc
4
+ data.tar.gz: 793bb0946bd2b1944fdbdcb31469682b848b4f12
5
5
  SHA512:
6
- metadata.gz: 2273a362c088cc1eb3898f97d7c8c175d2ab62892093d0030f53fe0ec91f5927e51acf018396344ece8caa05c0c0d49143a5fa95cbf74e28dae65fad11d92c9c
7
- data.tar.gz: 3336359fe0a01a70974f0d17b4ffc444303ec88f6d71a3ccd5b1b2f09420805ba16bd8c00244b67f5fde7f647797f521a9a471d29b5cc99b3d1f9f6cb6817bdb
6
+ metadata.gz: d7fdaf5a47e96cc1047604d51c115a118f22cf574ccd74fbf0ea5c15ef1546fc03f0cfdea555d8ee8e2a4384e5cfe4d2f6d160c5b67d31a79d9f56698a7d9b3c
7
+ data.tar.gz: b75182aa773d64a418fe23c69bbe0f154bad70b048b929ce0b8a97d48ca822a49a3e16fdf1c850e98cf12d90a9bae08aac6deb7ef50c3599a9f0cb793a35fe77
@@ -8,6 +8,7 @@ require 'colorize'
8
8
  require 'io/console'
9
9
  require 'readline'
10
10
  require 'logger'
11
+ require 'libnotify'
11
12
 
12
13
  # required gems
13
14
  require 'awesome_print'
@@ -76,6 +77,8 @@ module Meshchat
76
77
 
77
78
  # by default the app_config[:input] is
78
79
  # Meshchat::Cli::KeyboardLineInput
79
- EM.open_keyboard(app_config[:input], input_receiver)
80
+ # EM.open_keyboard(app_config[:input], input_receiver)
81
+ input = app_config[:input].new(input_receiver)
82
+ input.try(:start)
80
83
  end
81
84
  end
@@ -16,12 +16,18 @@ module Meshchat
16
16
  @_options = DEFAULTS.merge(options)
17
17
  @_options[:user] = Configuration::Settings.new
18
18
 
19
- locale_path = 'lib/meshchat/locale/'
19
+ locale_path = 'locale/'
20
20
  # I18n.load_path = Dir[locale_path + '*.yml']
21
+ # puts File.read(locale_path)
22
+ root_path = File.dirname(__FILE__)
23
+ full_path = "#{root_path}/../#{locale_path}"
21
24
  I18n.backend.store_translations(:en,
22
- YAML.load(File.read(locale_path + 'en.yml')))
25
+ YAML.load(File.read(full_path + 'en.yml')))
23
26
 
24
- Meshchat.const_set(:Notify, options[:notifier])
27
+ if notifier = options[:notifier]
28
+ notifier_instance = notifier.new
29
+ Meshchat.const_set(:Notify, notifier_instance)
30
+ end
25
31
 
26
32
  # The display has to be created right away so that
27
33
  # we can start outputting to it
@@ -27,17 +27,21 @@ module Meshchat
27
27
  Display.debug('SENDING: ' + node.alias_name + ' is not on the local network')
28
28
  end
29
29
 
30
+ def subscribed_to_relay
31
+ Display.debug('Subscribed to relay...')
32
+ end
33
+
30
34
  def received_message_from_relay(message, relay_url)
31
35
  Display.debug('RECEIVING on RELAY: ' + relay_url)
32
36
  Display.debug('RECEIVING on RELAY: ')
33
37
  Display.debug(message)
34
38
  end
35
39
 
36
- def sending_message_over_relay(node, message, relay_url)
37
- Display.debug('SENDING on RELAY: ' + relay_url)
38
- Display.debug('SENDING on RELAY: ' + node.as_json.to_json)
39
- Display.debug('SENDING on RELAY: ' + message.class.name)
40
- Display.debug('SENDING on RELAY: ' + message.inspect)
40
+ def sending_message_over_relay(node, relay_pool)
41
+ Display.debug('SENDING on RELAY ---------------------- ')
42
+ Display.debug('SENDING on RELAY: ' + node.alias_name)
43
+ Display.debug('SENDING on RELAY: ' + node.uid)
44
+ Display.debug('SENDING on RELAY: ' + relay_pool._active_relay._url)
41
45
  end
42
46
 
43
47
  def receiving_message(message)
@@ -46,10 +50,14 @@ module Meshchat
46
50
  Display.debug('RECEIVING: ' + message.message.to_s)
47
51
  end
48
52
 
49
- def sending_message(message)
50
- Display.debug('SENDING: ' + message.type)
51
- Display.debug('SENDING: ' + message.sender.to_s)
52
- Display.debug('SENDING: ' + message.message.to_s)
53
+ def message_being_dispatched(node, message)
54
+ Display.debug('DISPATCHING: ---------------------')
55
+ Display.debug('DISPATCHING: u - ' + node.uid)
56
+ Display.debug('DISPATCHING: a - ' + node.alias_name)
57
+ Display.debug('DISPATCHING: r - ' + node.on_relay.to_s)
58
+ Display.debug('DISPATCHING: l - ' + node.on_local_network.to_s)
59
+ Display.debug('DISPATCHING: ' + message.type)
60
+ Display.debug('DISPATCHING: ' + message.message.to_s)
53
61
  end
54
62
 
55
63
  def person_not_online(node, message, e)
@@ -36,10 +36,15 @@ module Meshchat
36
36
  dispatch!(node, message)
37
37
  end
38
38
 
39
+ def send_to_all(message, ignore_offline_status: false)
40
+ nodes = ignore_offline_status ? Node.all : Node.online
41
+ nodes.each { |node| send_message(node: node, message: message) }
42
+ end
43
+
39
44
  private
40
45
 
41
46
  def dispatch!(node, message)
42
- Debug.sending_message(message)
47
+ Debug.message_being_dispatched(node, message)
43
48
 
44
49
  message = encrypted_message(node, message)
45
50
 
@@ -46,7 +46,7 @@ module Meshchat
46
46
  # p http.response_header.status
47
47
  # p http.response_header
48
48
  # p http.response
49
- http.callback {}
49
+ http.callback { Display.debug http.response_header.status }
50
50
  end
51
51
 
52
52
  def payload_for(encrypted_message)
@@ -18,9 +18,13 @@ module Meshchat
18
18
  if message != Node.as_sha512
19
19
  Display.debug 'node list hashes do not match'
20
20
 
21
+ node_list = _message_factory.create(
22
+ NODE_LIST,
23
+ data: { message: Node.as_json })
24
+
21
25
  _message_dispatcher.send_message(
22
26
  uid: payload['sender']['uid'],
23
- message: NodeList.new(message: Node.as_json)
27
+ message: node_list
24
28
  )
25
29
  else
26
30
  Display.debug 'node list hash matches'
@@ -4,7 +4,7 @@ module Meshchat
4
4
  module Message
5
5
  class PingReply < Base
6
6
  def display
7
- 'ping successful' if APP_CONFIG.user.debug?
7
+ super.merge(message: 'successfully responded to your ping')
8
8
  end
9
9
  end
10
10
  end
@@ -13,6 +13,7 @@ module Meshchat
13
13
  end
14
14
 
15
15
  def send_message(node, encrypted_message)
16
+ Debug.sending_message_over_relay(node, _relay_pool)
16
17
  payload = payload_for(node.uid, encrypted_message)
17
18
  _relay_pool.send_payload(payload)
18
19
  end
@@ -28,9 +28,7 @@ module Meshchat
28
28
  @_client = ActionCableClient.new(path, CHANNEL)
29
29
 
30
30
  # don't output anything upon connecting
31
- _client.connected {
32
- self._connected = true
33
- }
31
+ _client.connected { self._connected = true }
34
32
 
35
33
  # If there are errors, report them!
36
34
  _client.errored do |message|
@@ -38,6 +36,7 @@ module Meshchat
38
36
  end
39
37
 
40
38
  _client.subscribed do
39
+ Debug.subscribed_to_relay
41
40
  connected.call if connected
42
41
  end
43
42
 
@@ -96,11 +95,18 @@ module Meshchat
96
95
  def error_message_received(message)
97
96
  Display.info message['error']
98
97
  if message['status'] == 404
99
- # mark the node as offline via relay
100
- # TODO: find the intended node.
101
- # if on_local_network is true, send to http_client
102
- # Display.info "#{node.alias_name} has ventured offline"
103
- # Debug.person_not_online(node, message, e)
98
+ uid = message['uid']
99
+ mark_as_offline(uid)
100
+ end
101
+ end
102
+
103
+ def mark_as_offline(uid)
104
+ node = Node.find_by_uid(uid)
105
+ if node
106
+ Display.info "#{node.alias_name} has ventured offline"
107
+ node.update(on_relay: false)
108
+ else
109
+ Display.info 'someone directly sent you a fake offline message'
104
110
  end
105
111
  end
106
112
  end
@@ -6,21 +6,55 @@ module Meshchat
6
6
  class CLI
7
7
  extend ActiveSupport::Autoload
8
8
 
9
+ # 60 seconds times 5 minutes
10
+ AWAY_TIMEOUT = 60 * 5
11
+
9
12
  eager_autoload do
10
13
  autoload :InputFactory
11
14
  autoload :Base
12
15
  autoload :KeyboardLineInput
16
+ autoload :ReadlineInput
13
17
  end
14
18
 
15
19
  attr_reader :_message_dispatcher, :_message_factory, :_command_factory
20
+ attr_accessor :_last_input_received_at
21
+ attr_accessor :_sent_idle_message
16
22
 
17
23
  def initialize(dispatcher, message_factory, _display)
18
24
  @_message_dispatcher = dispatcher
19
25
  @_message_factory = message_factory
20
26
  @_command_factory = InputFactory.new(dispatcher, message_factory, self)
27
+ self._sent_idle_message = false
28
+ self._last_input_received_at = Time.now
29
+
30
+ # only check for timeout once a minute
31
+ EM.add_periodic_timer(60) { away_timeout }
32
+ end
33
+
34
+ def away_timeout
35
+ return unless activity_timeout_triggred?
36
+ message = _message_factory.create(Network::Message::EMOTE,
37
+ data: {
38
+ message: 'has become idle'
39
+ })
40
+
41
+ _message_dispatcher.send_to_all(message)
42
+ self._sent_idle_message = true
43
+ end
44
+
45
+ def activity_timeout_triggred?
46
+ return false if _sent_idle_message
47
+ seconds_passed = Time.now - _last_input_received_at
48
+ seconds_passed > AWAY_TIMEOUT
49
+ end
50
+
51
+ def reset_timeout_timer
52
+ self._last_input_received_at = Time.now
53
+ self._sent_idle_message = false
21
54
  end
22
55
 
23
56
  def create_input(msg)
57
+ reset_timeout_timer
24
58
  handler = _command_factory.create(for_input: msg)
25
59
  handler.handle
26
60
  rescue => e
@@ -0,0 +1,75 @@
1
+ require 'readline/callback'
2
+
3
+ # frozen_string_literal: true
4
+ module Meshchat
5
+ module Ui
6
+ class CLI
7
+ class ReadlineInput
8
+ # The class used for interpeting the line input
9
+ attr_reader :_input_receiver
10
+
11
+ def initialize(input_receiver)
12
+ @_input_receiver = input_receiver
13
+ end
14
+
15
+ module Handler
16
+
17
+ def initialize
18
+ Readline.callback_handler_install('> ') do |line|
19
+ EventMachine.next_tick { @input_receiver.create_input(line) }
20
+ end
21
+ end
22
+
23
+ def notify_readable
24
+ Readline.callback_read_char
25
+ end
26
+
27
+ def unbind
28
+ Readline.callback_handler_remove
29
+ end
30
+
31
+ def input_receiver=(receiver)
32
+ @input_receiver = receiver
33
+ end
34
+
35
+ end
36
+
37
+ class << self
38
+ def autocompletes
39
+ commands = Meshchat::Ui::Command::COMMAND_MAP.map { |k, _v| "/#{k}" }
40
+ aliases = Meshchat::Node.all.map { |n| "#{n.alias_name}" }
41
+ commands + aliases
42
+ end
43
+ end
44
+
45
+ def start
46
+ # Ripl.start
47
+
48
+ conn = EventMachine.watch $stdin, Handler
49
+ conn.notify_readable = true
50
+ conn.input_receiver = _input_receiver
51
+
52
+ # update auto completion
53
+ completion = proc { |s| self.class.autocompletes.grep(/^#{Regexp.escape(s)}/) }
54
+ Readline.completion_proc = completion
55
+ end
56
+
57
+ # def initialize(*args)
58
+ # super(args)
59
+ #
60
+ #
61
+ # end
62
+
63
+ # called every time meshchat wants a line of text from the user
64
+ # def get_input
65
+ # # update auto completion
66
+ # completion = proc { |s| self.class.autocompletes.grep(/^#{Regexp.escape(s)}/) }
67
+ # Readline.completion_proc = completion
68
+ #
69
+ # Readline.readline('> ', true)
70
+ # end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
@@ -10,10 +10,6 @@ module Meshchat
10
10
  m = _message_factory.create(type, data: { message: _input })
11
11
  show_myself(m)
12
12
 
13
- # if sending to all, iterate thorugh list of
14
- # servers, and send to each one
15
- # TODO: do this async so that one server doesn't block
16
- # the rest of the servers from receiving the messages
17
13
  servers.each do |entry|
18
14
  _message_dispatcher.send_message(node: entry, message: m)
19
15
  end
@@ -15,7 +15,7 @@ module Meshchat
15
15
  end
16
16
 
17
17
  def show_myself(message)
18
- Display.info message.display
18
+ Display.emote message.display
19
19
  end
20
20
  end
21
21
  end
@@ -8,9 +8,10 @@ module Meshchat
8
8
  end
9
9
 
10
10
  def handle
11
- Meshchat::CLI::COMMAND_MAP.each do |key, klass|
11
+ Meshchat::Ui::Command::COMMAND_MAP.each do |key, klass|
12
12
  if klass.respond_to?(:description)
13
- Display.info "/#{key}\t\t" + klass.description
13
+ line = "/%-18s %s" % [key, klass.description ]
14
+ Display.info line
14
15
  end
15
16
  end
16
17
  end
@@ -9,9 +9,7 @@ module Meshchat
9
9
 
10
10
  def handle
11
11
  ping = _message_factory.create(Network::Message::PING)
12
- Node.all.each do |n|
13
- _message_dispatcher.send_message(node: n, message: ping)
14
- end
12
+ _message_dispatcher.send_to_all(ping, ignore_offline_status: true)
15
13
  end
16
14
  end
17
15
  end
@@ -7,6 +7,7 @@ module Meshchat
7
7
  eager_autoload do
8
8
  autoload :Base
9
9
  autoload :Manager
10
+ autoload :ReadlineDisplay
10
11
  end
11
12
 
12
13
  module_function
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+ module Meshchat
3
+ module Ui
4
+ module Display
5
+ class ReadlineDisplay < Meshchat::Ui::Display::Base
6
+ def start
7
+ puts "\n"
8
+ alert 'Welcome to Spiced Rumby!'
9
+ puts "\n"
10
+ puts "\n"
11
+ # Start up Ripl, but it will not receive any user input
12
+ # Ripl.start
13
+ end
14
+
15
+ def print_non_destructively(text)
16
+ # Example of writing output while line is being edited.
17
+ #
18
+ # See also http://stackoverflow.com/questions/1512028/gnu-readline-how-do-clear-the-input-line
19
+ if buffer = Readline.line_buffer
20
+ print "\b \b" * buffer.size
21
+ print "\r"
22
+ end
23
+
24
+ begin
25
+ puts text + "\n"
26
+ ensure
27
+ Readline.forced_update_display
28
+ end
29
+ end
30
+
31
+ # TODO: find a more elegant way to handle color
32
+ def add_line(line)
33
+ print_non_destructively(line)
34
+ end
35
+
36
+ def info(msg)
37
+ if msg.is_a?(Hash)
38
+ message_parts_for(msg) do |time, name, message|
39
+ colored_time = (time.to_s + ' ').colorize(:magenta)
40
+ colored_name = (name + ' ').colorize(:light_black)
41
+ colored_message = message.colorize(:light_black)
42
+
43
+ print_non_destructively(colored_time + colored_name + colored_message)
44
+ end
45
+ else
46
+ print_non_destructively(msg.colorize(:light_black))
47
+ end
48
+ end
49
+
50
+ def warning(msg)
51
+ print_non_destructively(msg.colorize(:yellow))
52
+ end
53
+
54
+ def alert(msg)
55
+ print_non_destructively(msg.colorize(:red))
56
+ end
57
+
58
+ def success(msg)
59
+ print_non_destructively(msg.colorize(:green))
60
+ end
61
+
62
+ def emote(msg)
63
+ message_parts_for(msg) do |time, name, message|
64
+ colored_time = (time.to_s + ' ').colorize(:magenta)
65
+ colored_name = (name + ' ').colorize(:light_black)
66
+ colored_message = message.colorize(:light_black)
67
+
68
+ print_non_destructively(colored_time + colored_name + colored_message)
69
+ end
70
+ end
71
+
72
+ def chat(msg)
73
+ message_parts_for(msg) do |time, name, message|
74
+ colored_time = (time.to_s + ' ').colorize(:light_magenta)
75
+ colored_name = (name + ' ').colorize(:cyan)
76
+
77
+ print_non_destructively(colored_time + colored_name + message)
78
+ end
79
+ end
80
+
81
+ def whisper(msg)
82
+ message_parts_for(msg) do |time, name, message|
83
+ colored_time = (time.to_s + ' ').colorize(:magenta).bold
84
+ colored_name = (name + ' ').colorize(:light_black).bold
85
+ colored_message = message.colorize(:blue).bold
86
+
87
+ print_non_destructively(colored_time + colored_name + colored_message)
88
+ end
89
+ end
90
+
91
+ def message_parts_for(msg)
92
+ return yield(nil, nil, msg) if msg.is_a?(String)
93
+
94
+ time = msg[:time].strftime('%H:%M:%S')
95
+ name = msg[:from].to_s
96
+ message = msg[:message]
97
+
98
+ yield(time, name, message)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -4,6 +4,7 @@ module Meshchat
4
4
  module Notifier
5
5
  extend ActiveSupport::Autoload
6
6
  autoload :Base
7
+ autoload :LibNotify
7
8
  end
8
9
  end
9
10
  end
@@ -0,0 +1,46 @@
1
+ module Meshchat
2
+ module Ui
3
+ module Notifier
4
+ # Inherit from base to obtain singletonness
5
+ #
6
+ # Meshchat uses singletons for notifications, because an OS
7
+ # generally only has one notification system
8
+ class LibNotify < Base
9
+ # this is the only method that needs to be overwritten
10
+ def show(*args)
11
+ libnotify_message.update(*args) do |notify|
12
+ yield(notify) if block_given?
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def icon_path
19
+ unless @icon_path
20
+ relative_path = 'vendor/icons/ic_chat_bubble_black_24dp.png'
21
+ current_directory = Dir.pwd # should be the gem root
22
+ @icon_path = current_directory + '/' + relative_path
23
+ end
24
+
25
+ @icon_path
26
+ end
27
+
28
+ def libnotify_message
29
+ @message ||= Libnotify.new do |notify|
30
+ notify.summary = APP_CONFIG[:client_name]
31
+ notify.body = ''
32
+ notify.timeout = 1.5 # 1.5 (s), 1000 (ms), "2", nil, false
33
+ notify.urgency = :normal # :low, :normal, :critical
34
+ notify.append = false # default true - append onto existing notification
35
+ notify.transient = false # default false - keep the notifications around after display
36
+ # TODO: this will vary on each system - maybe package icons
37
+ # with the gem
38
+ notify.icon_path = icon_path
39
+ end
40
+
41
+ @message
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Meshchat
3
- VERSION = '0.10.0'
3
+ VERSION = '0.11.0'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meshchat
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - L. Preston Sego III
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-06 00:00:00.000000000 Z
11
+ date: 2016-05-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: sqlite3
@@ -30,28 +30,28 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 5.0.0.beta3
33
+ version: 5.0.0.rc1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 5.0.0.beta3
40
+ version: 5.0.0.rc1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: activesupport
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: 5.0.0.beta3
47
+ version: 5.0.0.rc1
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: 5.0.0.beta3
54
+ version: 5.0.0.rc1
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: colorize
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -122,6 +122,20 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: 1.1.3
125
+ - !ruby/object:Gem::Dependency
126
+ name: ripl-readline-em
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :runtime
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: action_cable_client
127
141
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +164,20 @@ dependencies:
150
164
  - - ">="
151
165
  - !ruby/object:Gem::Version
152
166
  version: 0.7.0
167
+ - !ruby/object:Gem::Dependency
168
+ name: libnotify
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - ">="
172
+ - !ruby/object:Gem::Version
173
+ version: 0.9.1
174
+ type: :runtime
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: 0.9.1
153
181
  - !ruby/object:Gem::Dependency
154
182
  name: rspec
155
183
  requirement: !ruby/object:Gem::Requirement
@@ -286,6 +314,7 @@ files:
286
314
  - lib/meshchat/ui/cli/base.rb
287
315
  - lib/meshchat/ui/cli/input_factory.rb
288
316
  - lib/meshchat/ui/cli/keyboard_line_input.rb
317
+ - lib/meshchat/ui/cli/readline_input.rb
289
318
  - lib/meshchat/ui/command.rb
290
319
  - lib/meshchat/ui/command/base.rb
291
320
  - lib/meshchat/ui/command/bind.rb
@@ -308,8 +337,10 @@ files:
308
337
  - lib/meshchat/ui/display.rb
309
338
  - lib/meshchat/ui/display/base.rb
310
339
  - lib/meshchat/ui/display/manager.rb
340
+ - lib/meshchat/ui/display/readline_display.rb
311
341
  - lib/meshchat/ui/notifier.rb
312
342
  - lib/meshchat/ui/notifier/base.rb
343
+ - lib/meshchat/ui/notifier/lib_notify.rb
313
344
  - lib/meshchat/version.rb
314
345
  homepage: https://github.com/NullVoxPopuli/meshchat
315
346
  licenses:
@@ -334,6 +365,6 @@ rubyforge_project:
334
365
  rubygems_version: 2.5.1
335
366
  signing_key:
336
367
  specification_version: 4
337
- summary: Meshchat-0.10.0
368
+ summary: Meshchat-0.11.0
338
369
  test_files: []
339
370
  has_rdoc: