tree checksum vpatch file split hunks
all signers: lobbes asciilifeform diana_coman
antecedents: uniturds_etc.kv line_wraps.kv raw_line_fix.kv uptimefix_bye_cache.kv irssi_format.kv
press order:
patch:
(9 . 3)(9 . 4)
5 593779 uptimefix_bye_cache lobbes "Fix in bot.py for global time_last_conn. Remove Cache from reader.py. Small README fix re: create database."
6 594463 raw_line_fix lobbes "Fix to raw line export in reader.py to remove semi-colon from right side of nick on action lines"
7 595435 irssi_format diana_coman "Updates the irssi2tmsr converter to work on out-of-the-box irssi format. Updated README file too with example of format."
8 596907 sept_fixes asciilifeform "Several small improvements to bot and reader."
- A6BFA0BC96BDE13236F34D83BFF5D8053E73031BE0BA1AAFE29C84F8E38F475470919E785D2A9AFA6E134F02A6C64908E14BE04C89465C8CFCF5958FBA23B13B(92 . 3)(92 . 29)
13 (4) WWW: Links in log lines now open in new browser tab (a la Phf's log)
14 (5) WWW: Can now be loaded 'in reverse gear', http://...../log?rev=1
15 (6) WWW: 'Random' knob, takes reader to an arbitrary moment in past log.
16
17 ###############
18 Sep. 28 Update:
19 ###############
20
21 (1) Bot: incorporated reconnector fixes.
22 (2) Bot: 'seen', 'seen-all', and 'version' knobs implemented.
23 (3) WWW: up/down arrows for mouse-driven operation on pocket comps
24 (4) WWW: double-quotes prevent breakup of search query
25 (Note: still needs improvement to force matching on word boundaries)
26 (5) WWW: demarkation of "action" lines
27 (6) WWW: Raw 'Tape" knob:
28
29 e.g. http://logs.nosuchlabs.com/tape?istart=1937934&iend=1937941
30 returns:
31
32 trilema;1937934;1569444908;asciilifeform;achtung panzers! piz pipe down ?!
33 trilema;1937935;1569444920;diana_coman;seems so
34 trilema;1937936;1569444957;asciilifeform;paging BingoBoingo !
35 trilema;1937937;1569444974;diana_coman;well, apparetly he was connected from piz too, lol
36 trilema;1937938;1569444982;diana_coman;ossasepia.com (pizarro) is down too, yes
37 trilema;1937939;1569445010;asciilifeform;dulap unreachable for 1st time since year+ ago when bb elbowed the mains cord
38 trilema;1937940;1569445073;diana_coman;apparently back on
39 trilema;1937941;1569445079;diana_coman;wb BingoBoingo !
40
41 Still needs a variant of 'eater' that will eat these.
- 19772A67F431072DE4C51C6600D860C8CBB77F4E5172F4C20F43078565EDA7C07C599E165EE588552741A703CBD13B1043D6C2850858CBE2CC9D3F5249F54C8F(13 . 6)(13 . 11)- 932DB323BE19AE3D24ECEC90B63D8E0E551EDDFE2278233CFB73E66E89CF36108768D3FB8A0E5BB330D25BA31B0634F7805ADF2BE3E0ABE2D18E6A546179C6F9
46
47 ##############################################################################
48
49 # Version. If changing this program, always set this to same # as in MANIFEST
50 Ver = 596907
51
52 ##############################################################################
53
54 cfg = ConfigParser.ConfigParser()
55
56 ##############################################################################
(211 . 6)(216 . 9)
58 if act:
59 action = True
60 text = act.group(1)
61 # Remove turd if present:
62 if text[-1:] == '\x01':
63 text = text[:-1]
64 # This line is edible, process it.
65 eat_logline(user, chan, text, action)
66
(312 . 6)(320 . 15)
68
69 ##############################################################################
70
71 # Get perma-URL corresponding to given log line
72 def line_url(l):
73 return "{0}log/{1}/{2}#{3}".format(Base_URL,
74 l['chan'],
75 l['t'].strftime(Date_Short_Format),
76 l['idx'])
77
78 ##############################################################################
79
80 # Commands:
81
82 def cmd_help(arg, user, chan):
(324 . 7)(341 . 68)
84 speak(chan, get_search_res(chan, arg))
85
86 def cmd_seen(arg, user, chan):
87 speak(chan, "%s: this command is not yet implemented." % user);
88 # Empty query is prohibited:
89 if arg == "":
90 speak(chan, "Required argument: USER")
91 return
92
93 # Perform query:
94 seen_line = query_db(
95 '''select t, idx, payload, chan from loglines where
96 chan=%s and speaker=%s order by t desc limit 1;''',
97 [chan, arg], one=True)
98
99 # Where output will go
100 result = ""
101
102 # If user has been seen in THE CURRENT chan:
103 if seen_line != None:
104 time_txt = seen_line['t'].strftime(Date_Long_Format)
105 time_link = "[%s][%s]" % (line_url(seen_line), time_txt)
106 seen_line = "%s last seen here on %s: %s" % (arg,
107 time_link,
108 seen_line['payload'])
109 result = seen_line
110 else:
111 # If user has never been seen in this chan:
112 result = "The user %s has never been seen in #%s." % (arg, chan)
113
114 # Speak the result into the chan where command was issued
115 speak(chan, result)
116
117 def cmd_seen_anywhere(arg, user, chan):
118 # Empty query is prohibited:
119 if arg == "":
120 speak(chan, "Required argument: USER")
121 return
122
123 # Perform query:
124 seen_line = query_db(
125 '''select t, idx, payload, chan from loglines where speaker=%s
126 order by t desc limit 1;''',
127 [arg], one=True)
128
129 # Where output will go
130 result = ""
131
132 # If user has been seen in ANY logged chan:
133 if seen_line != None:
134 time_txt = seen_line['t'].strftime(Date_Long_Format)
135 time_link = "[%s][%s]" % (line_url(seen_line), time_txt)
136 seen_line = "%s last seen in #%s on %s: %s" % (arg,
137 seen_line['chan'],
138 time_link,
139 seen_line['payload'])
140 result = seen_line
141 else:
142 # If user has never been seen at all:
143 result = "The user %s has never been seen by this logger." % arg
144
145 # Speak the result into the chan where command was issued
146 speak(chan, result)
147
148 def cmd_version(arg, user, chan):
149 speak(chan, "I am bot version %s." % Ver);
150
151 def cmd_src(arg, user, chan):
152 speak(chan, "%s: my source code can be seen at: %s" % (user, Src_URL));
(343 . 11)(421 . 13)
154 (user, uptime_txt));
155
156 Commands = {
157 "help" : cmd_help,
158 "s" : cmd_search,
159 "seen" : cmd_seen,
160 "uptime" : cmd_uptime,
161 "src" : cmd_src
162 "help" : cmd_help,
163 "s" : cmd_search,
164 "seen" : cmd_seen,
165 "seen-anywhere" : cmd_seen_anywhere,
166 "uptime" : cmd_uptime,
167 "src" : cmd_src,
168 "version" : cmd_version
169 }
170
171 ##############################################################################
(384 . 8)(464 . 7)
173
174
175 # RE for finding log refs
176 logref_re = re.compile(Base_URL + """log\/([^/]+)/([^/]+)#(\d+)""")
177
178 logref_re = re.compile(Base_URL + """log\/([^/]+)/[^/]+#(\d+)""")
179
180 # All valid received lines end up here
181 def eat_logline(user, chan, text, action):
(422 . 7)(501 . 7)
183 else:
184 # Finally, see if contains log refs:
185 for ref in re.findall(logref_re, text):
186 ref_chan, ref_date, ref_idx = ref
187 ref_chan, ref_idx = ref
188 # Find this line in DB:
189 ref_line = query_db(
190 '''select t, speaker, payload from loglines
(430 . 10)(509 . 20)
192 [ref_chan, ref_idx], one=True)
193 # If retrieved line is valid, echo it:
194 if ref_line != None:
195 time_txt = ref_line['t'].strftime(Date_Long_Format)
196 my_line = "Logged on %s %s: %s" % (time_txt,
197 ref_line['speaker'],
198 ref_line['payload'])
199 # If referred line was spoken in THIS chan:
200 if ref_chan == chan:
201 time_txt = ref_line['t'].strftime(Date_Long_Format)
202 my_line = "Logged on %s %s: %s" % (time_txt,
203 ref_line['speaker'],
204 ref_line['payload'])
205 else:
206 # If this is a cross-chan echo:
207 time_txt = ref_line['t'].strftime(Date_Short_Format)
208 my_line = "(%s) %s %s: %s" % (ref_chan,
209 time_txt,
210 ref_line['speaker'],
211 ref_line['payload'])
212
213 # Speak the line echo into the chan where ref was seen
214 speak(chan, my_line)
215
(15 . 6)(15 . 7)- 8A0C101964AE3AE0CE1687E8A6DA575C9DE35990DD0BCA507B58539DD01AF67D6E3F775F8F00CCC9EA40053B80F63815FF02E12E6A7E69A0B832949C3B8F50AD
220 import os
221 import threading
222 import re
223 import shlex
224 from datetime import datetime
225 from urlparse import urljoin
226 from flask import Flask, request, session, url_for, redirect, Response, \
(276 . 16)(277 . 26)
228 if ss <= l['idx'] <= se:
229 dclass = "highlight"
230
231 speaker = l['speaker']
232 separator = ":"
233
234 # If 'action', annotate:
235 if l['self']:
236 separator = ""
237 payload = "<i>" + payload + "</i>"
238 speaker = "<i>" + speaker + "</i>"
239
240 # HTMLize the given line :
241 s = ("<div id='{0}' class='{6}{5}'>"
242 "<a class='nick' title='{2}'"
243 " href=\"{3}\">{1}</a>: {4}</div>").format(l['idx'],
244 l['speaker'],
245 l['t'],
246 line_url(l),
247 payload,
248 bot,
249 dclass)
250 " href=\"{3}\">{1}</a>{5} {4}</div>").format(l['idx'],
251 speaker,
252 l['t'],
253 line_url(l),
254 payload,
255 bot,
256 dclass,
257 separator)
258 return s
259
260 # Make above callable from inside htm templater:
(436 . 6)(447 . 49)
262 return Response(res, mimetype='text/plain')
263
264
265 # "Tape" is a raw log containing entried from ALL logged chans:
266 @app.route('/tape')
267 def tape():
268 res = ""
269
270 # Get start and end indices:
271 idx_start = request.args.get('istart', default = 0, type = int)
272 idx_end = request.args.get('iend', default = 0, type = int)
273
274 # Malformed bounds?
275 if idx_start > idx_end:
276 return Response("EGGOG: Start must precede End!",
277 mimetype='text/plain')
278
279 # Demanded too many in one burst ?
280 if (idx_end - idx_start) > Max_Raw_Ln :
281 return Response("EGGOG: May request Max. of %s Lines !" % Max_Raw_Ln,
282 mimetype='text/plain')
283
284 # Get the loglines from DB
285 lines = query_db(
286 '''select * from loglines where
287 idx between %s and %s order by idx asc;''',
288 [idx_start, idx_end], one=False)
289
290 # Retrieve raw lines in Tape format:
291 for l in lines:
292 action = ""
293 speaker = "%s;" % l['speaker']
294 if l['self']:
295 action = "*;"
296 speaker = "%s " % l['speaker']
297 res += "%s;%s;%s;%s%s%s\n" % (l['chan'],
298 l['idx'],
299 l['t'].strftime('%s'),
300 action,
301 speaker,
302 l['payload'])
303
304 # Return plain text:
305 return Response(res, mimetype='text/plain')
306
307
308 Name_Chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-"
309
310 def sanitize_speaker(s):
(464 . 7)(518 . 7)
312 # Forbid query that is too short:
313 if len(query) >= Min_Query_Length:
314 # Get the search tokens to use:
315 tokens = query.split()
316 tokens = shlex.split(query)
317 tokens_standard = []
318 from_users = []
319
(78 . 11)(78 . 19)- 52D528C55A54D0077907DDAE6D862D9B3E9C4AFB9D787874A8844DE4C3231B8C8D714DC2BEF369004EFBEF7CBDBA4B81EC1081F71A1EA48F5598B5780FACEF6A
324 .annotations a {
325 text-decoration: none;
326 }
327
328 #navbar {
329
330 .navbarblock {
331 margin-bottom: 1em;
332 }
333
334
335 .navbar {
336 float:left;
337 }
338
339 .jump {
340 float:right;
341 }
342
343 .highlight {
344 background: yellow !important;;
345 padding: 1px;
(93 . 6)(101 . 8)
347
348 <body>
349
350 <a name="head">
351
352 <p>
353 <table align="center">
354 <tr>
(137 . 6)(147 . 9)
356 <div align="center">
357 <a href="/rnd/{{ chan }}">Random({{ chan }})</a> | <a href="{{ url_for('static', filename='log_db.gz') }}">Download daily DB snapshot</a> | <a href="http://www.loper-os.org/?p=3452">Get Source Code</a>
358 </div>
359
360 <a name="tail">
361
362 </body>
363
364 </html>
(6 . 7)(6 . 11)
369
370 {% block body %}
371
372 <div id='navbar'>{{ generate_navbar(date, tail, chan) | safe }}</div>
373 <div id="navbarblock">
374 <p class='navbar'>{{ generate_navbar(date, tail, chan) | safe }}</p>
375 <p class='jump'><a href="#tail">↓</a></p>
376 </div>
377 <div style="clear: both;"></div>
378
379 <div class='loglines'>
380 {% for l in loglines %}
(14 . 6)(18 . 10)
382 {% endfor %}
383 </div>
384
385 <div id='navbar'>{{ generate_navbar(date, tail, chan) | safe }}</div>
386 <div id="navbarblock">
387 <p class='navbar'>{{ generate_navbar(date, tail, chan) | safe }}</p>
388 <p class='jump'><a href="#head">↑</a></p>
389 </div>
390 <div style="clear: both;"></div>
391
392 {% endblock %}