sup 0.2 → 0.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sup might be problematic. Click here for more details.
- data/History.txt +10 -0
- data/bin/sup +50 -68
- data/doc/NewUserGuide.txt +11 -7
- data/doc/TODO +34 -22
- data/lib/sup.rb +30 -24
- data/lib/sup/buffer.rb +124 -39
- data/lib/sup/colormap.rb +4 -4
- data/lib/sup/draft.rb +1 -1
- data/lib/sup/hook.rb +18 -5
- data/lib/sup/imap.rb +11 -13
- data/lib/sup/index.rb +52 -14
- data/lib/sup/keymap.rb +1 -1
- data/lib/sup/logger.rb +1 -0
- data/lib/sup/maildir.rb +9 -0
- data/lib/sup/mbox.rb +3 -1
- data/lib/sup/message-chunks.rb +21 -7
- data/lib/sup/message.rb +31 -15
- data/lib/sup/mode.rb +2 -0
- data/lib/sup/modes/buffer-list-mode.rb +7 -3
- data/lib/sup/modes/compose-mode.rb +14 -16
- data/lib/sup/modes/contact-list-mode.rb +2 -2
- data/lib/sup/modes/edit-message-mode.rb +55 -23
- data/lib/sup/modes/forward-mode.rb +22 -5
- data/lib/sup/modes/inbox-mode.rb +3 -7
- data/lib/sup/modes/label-list-mode.rb +30 -10
- data/lib/sup/modes/label-search-results-mode.rb +12 -0
- data/lib/sup/modes/line-cursor-mode.rb +13 -0
- data/lib/sup/modes/log-mode.rb +0 -6
- data/lib/sup/modes/poll-mode.rb +0 -3
- data/lib/sup/modes/reply-mode.rb +19 -11
- data/lib/sup/modes/scroll-mode.rb +111 -20
- data/lib/sup/modes/search-results-mode.rb +21 -0
- data/lib/sup/modes/text-mode.rb +10 -2
- data/lib/sup/modes/thread-index-mode.rb +200 -90
- data/lib/sup/modes/thread-view-mode.rb +27 -10
- data/lib/sup/person.rb +1 -0
- data/lib/sup/poll.rb +15 -7
- data/lib/sup/source.rb +6 -1
- data/lib/sup/suicide.rb +1 -1
- data/lib/sup/textfield.rb +14 -14
- data/lib/sup/thread.rb +6 -2
- data/lib/sup/util.rb +111 -9
- metadata +13 -6
@@ -1,8 +1,6 @@
|
|
1
1
|
module Redwood
|
2
2
|
|
3
3
|
class ThreadViewMode < LineCursorMode
|
4
|
-
include CanSpawnComposeMode
|
5
|
-
|
6
4
|
## this holds all info we need to lay out a message
|
7
5
|
class MessageLayout
|
8
6
|
attr_accessor :top, :bot, :prev, :next, :depth, :width, :state, :color, :star_color, :orig_new
|
@@ -27,7 +25,7 @@ class ThreadViewMode < LineCursorMode
|
|
27
25
|
k.add :jump_to_prev_open, "Jump to previous open message", 'p'
|
28
26
|
k.add :toggle_starred, "Star or unstar message", '*'
|
29
27
|
k.add :toggle_new, "Toggle new/read status of message", 'N'
|
30
|
-
# k.add :collapse_non_new_messages, "Collapse all but
|
28
|
+
# k.add :collapse_non_new_messages, "Collapse all but unread messages", 'N'
|
31
29
|
k.add :reply, "Reply to a message", 'r'
|
32
30
|
k.add :forward, "Forward a message", 'f'
|
33
31
|
k.add :alias, "Edit alias/nickname for a person", 'i'
|
@@ -37,6 +35,8 @@ class ThreadViewMode < LineCursorMode
|
|
37
35
|
k.add :compose, "Compose message to person", 'm'
|
38
36
|
k.add :archive_and_kill, "Archive thread and kill buffer", 'a'
|
39
37
|
k.add :delete_and_kill, "Delete thread and kill buffer", 'd'
|
38
|
+
k.add :subscribe_to_list, "Subscribe to/unsubscribe from mailing list", "("
|
39
|
+
k.add :unsubscribe_from_list, "Subscribe to/unsubscribe from mailing list", ")"
|
40
40
|
end
|
41
41
|
|
42
42
|
## there are a couple important instance variables we hold to format
|
@@ -107,11 +107,27 @@ class ThreadViewMode < LineCursorMode
|
|
107
107
|
BufferManager.spawn "Reply to #{m.subj}", mode
|
108
108
|
end
|
109
109
|
|
110
|
+
def subscribe_to_list
|
111
|
+
m = @message_lines[curpos] or return
|
112
|
+
if m.list_subscribe && m.list_subscribe =~ /<mailto:(.*?)\?(subject=(.*?))>/
|
113
|
+
ComposeMode.spawn_nicely :from => AccountManager.account_for(m.recipient_email), :to => [PersonManager.person_for($1)], :subj => $3
|
114
|
+
else
|
115
|
+
BufferManager.flash "Can't find List-Subscribe header for this message."
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def unsubscribe_from_list
|
120
|
+
m = @message_lines[curpos] or return
|
121
|
+
if m.list_unsubscribe && m.list_unsubscribe =~ /<mailto:(.*?)\?(subject=(.*?))>/
|
122
|
+
ComposeMode.spawn_nicely :from => AccountManager.account_for(m.recipient_email), :to => [PersonManager.person_for($1)], :subj => $3
|
123
|
+
else
|
124
|
+
BufferManager.flash "Can't find List-Unsubscribe header for this message."
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
110
128
|
def forward
|
111
129
|
m = @message_lines[curpos] or return
|
112
|
-
|
113
|
-
BufferManager.spawn "Forward of #{m.subj}", mode
|
114
|
-
mode.edit_message
|
130
|
+
ForwardMode.spawn_nicely m
|
115
131
|
end
|
116
132
|
|
117
133
|
include CanAliasContacts
|
@@ -131,9 +147,9 @@ class ThreadViewMode < LineCursorMode
|
|
131
147
|
def compose
|
132
148
|
p = @person_lines[curpos]
|
133
149
|
if p
|
134
|
-
|
150
|
+
ComposeMode.spawn_nicely :to => [p]
|
135
151
|
else
|
136
|
-
|
152
|
+
ComposeMode.spawn_nicely
|
137
153
|
end
|
138
154
|
end
|
139
155
|
|
@@ -145,7 +161,7 @@ class ThreadViewMode < LineCursorMode
|
|
145
161
|
@thread.labels = (reserved_labels + new_labels).uniq
|
146
162
|
new_labels.each { |l| LabelManager << l }
|
147
163
|
update
|
148
|
-
UpdateManager.relay self, :
|
164
|
+
UpdateManager.relay self, :label_thread, @thread
|
149
165
|
end
|
150
166
|
|
151
167
|
def toggle_starred
|
@@ -193,7 +209,7 @@ class ThreadViewMode < LineCursorMode
|
|
193
209
|
|
194
210
|
def edit_as_new
|
195
211
|
m = @message_lines[curpos] or return
|
196
|
-
mode = ComposeMode.new(:body => m.
|
212
|
+
mode = ComposeMode.new(:body => m.quotable_body_lines, :to => m.to, :cc => m.cc, :subj => m.subj, :bcc => m.bcc)
|
197
213
|
BufferManager.spawn "edit as new", mode
|
198
214
|
mode.edit_message
|
199
215
|
end
|
@@ -236,6 +252,7 @@ class ThreadViewMode < LineCursorMode
|
|
236
252
|
end
|
237
253
|
|
238
254
|
def jump_to_next_open
|
255
|
+
return continue_search_in_buffer if in_search? # hack: allow 'n' to apply to both operations
|
239
256
|
m = @message_lines[curpos] or return
|
240
257
|
while nextm = @layout[m].next
|
241
258
|
break if @layout[nextm].state != :closed
|
data/lib/sup/person.rb
CHANGED
@@ -21,6 +21,7 @@ class PersonManager
|
|
21
21
|
File.open(@fn, "w") do |f|
|
22
22
|
@@people.each do |email, p|
|
23
23
|
next if p.email == p.name
|
24
|
+
next if p.email =~ /=/ # drop rfc2047-encoded, and lots of other useless emails. definitely a heuristic.
|
24
25
|
f.puts "#{p.email}: #{p.timestamp} #{p.name}"
|
25
26
|
end
|
26
27
|
end
|
data/lib/sup/poll.rb
CHANGED
@@ -5,6 +5,12 @@ module Redwood
|
|
5
5
|
class PollManager
|
6
6
|
include Singleton
|
7
7
|
|
8
|
+
HookManager.register "before-add-message", <<EOS
|
9
|
+
Executes immediately before a message is added to the index.
|
10
|
+
Variables:
|
11
|
+
message: the new message
|
12
|
+
EOS
|
13
|
+
|
8
14
|
HookManager.register "before-poll", <<EOS
|
9
15
|
Executes immediately before a poll for new messages commences.
|
10
16
|
No variables.
|
@@ -18,7 +24,7 @@ Variables:
|
|
18
24
|
not auto-archived).
|
19
25
|
from_and_subj: an array of (from email address, subject) pairs
|
20
26
|
from_and_subj_inbox: an array of (from email address, subject) pairs for
|
21
|
-
messages appearing in the inbox
|
27
|
+
only those messages appearing in the inbox
|
22
28
|
EOS
|
23
29
|
|
24
30
|
DELAY = 300
|
@@ -33,7 +39,8 @@ EOS
|
|
33
39
|
end
|
34
40
|
|
35
41
|
def buffer
|
36
|
-
BufferManager.spawn_unless_exists("<poll for new messages>", :hidden => true) { PollMode.new }
|
42
|
+
b, new = BufferManager.spawn_unless_exists("<poll for new messages>", :hidden => true) { PollMode.new }
|
43
|
+
b
|
37
44
|
end
|
38
45
|
|
39
46
|
def poll
|
@@ -44,7 +51,7 @@ EOS
|
|
44
51
|
BufferManager.flash "Polling for new messages..."
|
45
52
|
num, numi, from_and_subj, from_and_subj_inbox = buffer.mode.poll
|
46
53
|
if num > 0
|
47
|
-
BufferManager.flash "Loaded #{num
|
54
|
+
BufferManager.flash "Loaded #{num.pluralize 'new message'}, #{numi} to inbox."
|
48
55
|
else
|
49
56
|
BufferManager.flash "No new messages."
|
50
57
|
end
|
@@ -56,7 +63,7 @@ EOS
|
|
56
63
|
end
|
57
64
|
|
58
65
|
def start
|
59
|
-
@thread = Redwood::reporting_thread do
|
66
|
+
@thread = Redwood::reporting_thread("periodic poll") do
|
60
67
|
while true
|
61
68
|
sleep DELAY / 2
|
62
69
|
poll if @last_poll.nil? || (Time.now - @last_poll) >= DELAY
|
@@ -81,7 +88,7 @@ EOS
|
|
81
88
|
yield "Loading from #{source}... " unless source.done? || source.has_errors?
|
82
89
|
rescue SourceError => e
|
83
90
|
Redwood::log "problem getting messages from #{source}: #{e.message}"
|
84
|
-
Redwood::report_broken_sources
|
91
|
+
Redwood::report_broken_sources :force_to_top => true
|
85
92
|
next
|
86
93
|
end
|
87
94
|
|
@@ -94,7 +101,7 @@ EOS
|
|
94
101
|
unless entry
|
95
102
|
num += 1
|
96
103
|
from_and_subj << [m.from.longname, m.subj]
|
97
|
-
if m.labels.
|
104
|
+
if m.has_label?(:inbox) && ([:spam, :deleted, :killed] & m.labels).empty?
|
98
105
|
from_and_subj_inbox << [m.from.longname, m.subj]
|
99
106
|
numi += 1
|
100
107
|
end
|
@@ -147,6 +154,7 @@ EOS
|
|
147
154
|
end
|
148
155
|
|
149
156
|
docid, entry = Index.load_entry_for_id m.id
|
157
|
+
HookManager.run "before-add-message", :message => m
|
150
158
|
m = yield(m, offset, entry) or next
|
151
159
|
Index.sync_message m, docid, entry
|
152
160
|
UpdateManager.relay self, :add, m unless entry
|
@@ -156,7 +164,7 @@ EOS
|
|
156
164
|
end
|
157
165
|
rescue SourceError => e
|
158
166
|
Redwood::log "problem getting messages from #{source}: #{e.message}"
|
159
|
-
Redwood::report_broken_sources
|
167
|
+
Redwood::report_broken_sources :force_to_top => true
|
160
168
|
end
|
161
169
|
end
|
162
170
|
end
|
data/lib/sup/source.rb
CHANGED
@@ -1,6 +1,11 @@
|
|
1
1
|
module Redwood
|
2
2
|
|
3
|
-
class SourceError < StandardError
|
3
|
+
class SourceError < StandardError
|
4
|
+
def initialize *a
|
5
|
+
raise "don't instantiate me!" if SourceError.is_a?(self.class)
|
6
|
+
super
|
7
|
+
end
|
8
|
+
end
|
4
9
|
class OutOfSyncSourceError < SourceError; end
|
5
10
|
class FatalSourceError < SourceError; end
|
6
11
|
|
data/lib/sup/suicide.rb
CHANGED
data/lib/sup/textfield.rb
CHANGED
@@ -64,7 +64,7 @@ class TextField
|
|
64
64
|
case c
|
65
65
|
when Ncurses::KEY_ENTER # submit!
|
66
66
|
@value = get_cursed_value
|
67
|
-
@history.push @value
|
67
|
+
@history.push @value unless @value =~ /^\s*$/
|
68
68
|
return false
|
69
69
|
when Ncurses::KEY_CANCEL # cancel
|
70
70
|
@value = nil
|
@@ -108,23 +108,23 @@ class TextField
|
|
108
108
|
Ncurses::Form::REQ_END_FIELD
|
109
109
|
when 11 # ctrl-k
|
110
110
|
Ncurses::Form::REQ_CLR_EOF
|
111
|
-
when Ncurses::KEY_UP
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
111
|
+
when Ncurses::KEY_UP, Ncurses::KEY_DOWN
|
112
|
+
unless @history.empty?
|
113
|
+
value = get_cursed_value
|
114
|
+
@i ||= @history.size
|
115
|
+
#Redwood::log "history before #{@history.inspect}"
|
116
|
+
@history[@i] = value #unless value =~ /^\s*$/
|
117
|
+
@i = (@i + (c == Ncurses::KEY_UP ? -1 : 1)) % @history.size
|
118
|
+
@value = @history[@i]
|
119
|
+
#Redwood::log "history after #{@history.inspect}"
|
120
|
+
set_cursed_value @value
|
121
|
+
Ncurses::Form::REQ_END_FIELD
|
122
|
+
end
|
123
123
|
else
|
124
124
|
c
|
125
125
|
end
|
126
126
|
|
127
|
-
Ncurses::Form.form_driver @form, d
|
127
|
+
Ncurses::Form.form_driver @form, d if d
|
128
128
|
true
|
129
129
|
end
|
130
130
|
|
data/lib/sup/thread.rb
CHANGED
@@ -86,8 +86,12 @@ class Thread
|
|
86
86
|
def dirty?; any? { |m, *o| m && m.dirty? }; end
|
87
87
|
def date; map { |m, *o| m.date if m }.compact.max; end
|
88
88
|
def snippet
|
89
|
-
|
90
|
-
|
89
|
+
with_snippets = select { |m, *o| m && m.snippet && !m.snippet.empty? }
|
90
|
+
first_unread, * = with_snippets.select { |m, *o| m.has_label?(:unread) }.sort_by { |m, *o| m.date }.first
|
91
|
+
return first_unread.snippet if first_unread
|
92
|
+
last_read, * = with_snippets.sort_by { |m, *o| m.date }.last
|
93
|
+
return last_read.snippet if last_read
|
94
|
+
""
|
91
95
|
end
|
92
96
|
def authors; map { |m, *o| m.from if m }.compact.uniq; end
|
93
97
|
|
data/lib/sup/util.rb
CHANGED
@@ -136,6 +136,7 @@ class Object
|
|
136
136
|
|
137
137
|
## clone of java-style whole-method synchronization
|
138
138
|
## assumes a @mutex variable
|
139
|
+
## TODO: clean up, try harder to avoid namespace collisions
|
139
140
|
def synchronized *meth
|
140
141
|
meth.each do
|
141
142
|
class_eval <<-EOF
|
@@ -146,6 +147,32 @@ class Object
|
|
146
147
|
EOF
|
147
148
|
end
|
148
149
|
end
|
150
|
+
|
151
|
+
def ignore_concurrent_calls *meth
|
152
|
+
meth.each do
|
153
|
+
mutex = "@__concurrent_protector_#{meth}"
|
154
|
+
flag = "@__concurrent_flag_#{meth}"
|
155
|
+
oldmeth = "__unprotected_#{meth}"
|
156
|
+
class_eval <<-EOF
|
157
|
+
alias #{oldmeth} #{meth}
|
158
|
+
def #{meth}(*a, &b)
|
159
|
+
#{mutex} = Mutex.new unless defined? #{mutex}
|
160
|
+
#{flag} = true unless defined? #{flag}
|
161
|
+
run = #{mutex}.synchronize do
|
162
|
+
if #{flag}
|
163
|
+
#{flag} = false
|
164
|
+
true
|
165
|
+
end
|
166
|
+
end
|
167
|
+
if run
|
168
|
+
ret = #{oldmeth}(*a, &b)
|
169
|
+
#{mutex}.synchronize { #{flag} = true }
|
170
|
+
ret
|
171
|
+
end
|
172
|
+
end
|
173
|
+
EOF
|
174
|
+
end
|
175
|
+
end
|
149
176
|
end
|
150
177
|
|
151
178
|
class String
|
@@ -165,6 +192,7 @@ class String
|
|
165
192
|
ret
|
166
193
|
end
|
167
194
|
|
195
|
+
## one of the few things i miss from perl
|
168
196
|
def ucfirst
|
169
197
|
self[0 .. 0].upcase + self[1 .. -1]
|
170
198
|
end
|
@@ -175,6 +203,64 @@ class String
|
|
175
203
|
split(/,\s*(?=(?:[^"]*"[^"]*")*(?![^"]*"))/)
|
176
204
|
end
|
177
205
|
|
206
|
+
## ok, here we do it the hard way. got to have a remainder for purposes of
|
207
|
+
## tab-completing full email addresses
|
208
|
+
def split_on_commas_with_remainder
|
209
|
+
ret = []
|
210
|
+
state = :outstring
|
211
|
+
pos = 0
|
212
|
+
region_start = 0
|
213
|
+
while pos <= length
|
214
|
+
newpos = case state
|
215
|
+
when :escaped_instring, :escaped_outstring: pos
|
216
|
+
else index(/[,"\\]/, pos)
|
217
|
+
end
|
218
|
+
|
219
|
+
if newpos
|
220
|
+
char = self[newpos]
|
221
|
+
else
|
222
|
+
char = nil
|
223
|
+
newpos = length
|
224
|
+
end
|
225
|
+
|
226
|
+
case char
|
227
|
+
when ?"
|
228
|
+
state = case state
|
229
|
+
when :outstring: :instring
|
230
|
+
when :instring: :outstring
|
231
|
+
when :escaped_instring: :instring
|
232
|
+
when :escaped_outstring: :outstring
|
233
|
+
end
|
234
|
+
when ?,, nil
|
235
|
+
state = case state
|
236
|
+
when :outstring, :escaped_outstring:
|
237
|
+
ret << self[region_start ... newpos].gsub(/^\s+|\s+$/, "")
|
238
|
+
region_start = newpos + 1
|
239
|
+
:outstring
|
240
|
+
when :instring: :instring
|
241
|
+
when :escaped_instring: :instring
|
242
|
+
end
|
243
|
+
when ?\\
|
244
|
+
state = case state
|
245
|
+
when :instring: :escaped_instring
|
246
|
+
when :outstring: :escaped_outstring
|
247
|
+
when :escaped_instring: :instring
|
248
|
+
when :escaped_outstring: :outstring
|
249
|
+
end
|
250
|
+
end
|
251
|
+
pos = newpos + 1
|
252
|
+
end
|
253
|
+
|
254
|
+
remainder = case state
|
255
|
+
when :instring
|
256
|
+
self[region_start .. -1].gsub(/^\s+/, "")
|
257
|
+
else
|
258
|
+
nil
|
259
|
+
end
|
260
|
+
|
261
|
+
[ret, remainder]
|
262
|
+
end
|
263
|
+
|
178
264
|
def wrap len
|
179
265
|
ret = []
|
180
266
|
s = self
|
@@ -223,6 +309,20 @@ class Fixnum
|
|
223
309
|
"<#{self}>"
|
224
310
|
end
|
225
311
|
end
|
312
|
+
|
313
|
+
## hacking the english language
|
314
|
+
def pluralize s
|
315
|
+
to_s + " " +
|
316
|
+
if self == 1
|
317
|
+
s
|
318
|
+
else
|
319
|
+
if s =~ /(.*)y$/
|
320
|
+
$1 + "ies"
|
321
|
+
else
|
322
|
+
s + "s"
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
226
326
|
end
|
227
327
|
|
228
328
|
class Hash
|
@@ -299,6 +399,7 @@ class Array
|
|
299
399
|
def to_boolean_h; Hash[*map { |x| [x, true] }.flatten]; end
|
300
400
|
|
301
401
|
def last= e; self[-1] = e end
|
402
|
+
def nonempty?; !empty? end
|
302
403
|
end
|
303
404
|
|
304
405
|
class Time
|
@@ -405,19 +506,20 @@ module Singleton
|
|
405
506
|
end
|
406
507
|
end
|
407
508
|
|
408
|
-
## wraps an object. if it throws an exception, keeps a copy
|
409
|
-
## rethrows it for any further method calls.
|
509
|
+
## wraps an object. if it throws an exception, keeps a copy.
|
410
510
|
class Recoverable
|
411
511
|
def initialize o
|
412
512
|
@o = o
|
413
|
-
@
|
513
|
+
@error = nil
|
514
|
+
@mutex = Mutex.new
|
414
515
|
end
|
415
516
|
|
416
|
-
|
417
|
-
|
418
|
-
def error
|
517
|
+
attr_accessor :error
|
518
|
+
|
519
|
+
def clear_error!; @error = nil; end
|
520
|
+
def has_errors?; !@error.nil?; end
|
419
521
|
|
420
|
-
def method_missing m, *a, &b; __pass m, *a, &b
|
522
|
+
def method_missing m, *a, &b; __pass m, *a, &b end
|
421
523
|
|
422
524
|
def id; __pass :id; end
|
423
525
|
def to_s; __pass :to_s; end
|
@@ -430,8 +532,8 @@ class Recoverable
|
|
430
532
|
begin
|
431
533
|
@o.send(m, *a, &b)
|
432
534
|
rescue Exception => e
|
433
|
-
@
|
434
|
-
raise
|
535
|
+
@error ||= e
|
536
|
+
raise
|
435
537
|
end
|
436
538
|
end
|
437
539
|
end
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: sup
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: "0.
|
7
|
-
date: 2007-
|
6
|
+
version: "0.3"
|
7
|
+
date: 2007-11-27 00:00:00 -08:00
|
8
8
|
summary: A console-based email client with the best features of GMail, mutt, and emacs. Features full text search, labels, tagged operations, multiple buffers, recent contacts, and more.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -103,10 +103,17 @@ files:
|
|
103
103
|
- lib/sup/util.rb
|
104
104
|
test_files: []
|
105
105
|
|
106
|
-
rdoc_options:
|
107
|
-
|
108
|
-
|
109
|
-
|
106
|
+
rdoc_options:
|
107
|
+
- --main
|
108
|
+
- README.txt
|
109
|
+
extra_rdoc_files:
|
110
|
+
- History.txt
|
111
|
+
- Manifest.txt
|
112
|
+
- README.txt
|
113
|
+
- doc/FAQ.txt
|
114
|
+
- doc/Hooks.txt
|
115
|
+
- doc/NewUserGuide.txt
|
116
|
+
- doc/Philosophy.txt
|
110
117
|
executables:
|
111
118
|
- sup
|
112
119
|
- sup-add
|