infod 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/infod.rb +2 -3
- data/infod/Es.rb +31 -67
- data/infod/{W/source.rb → Es/code.rb} +6 -10
- data/infod/Es/css.rb +21 -0
- data/infod/{W → Es}/csv.rb +0 -0
- data/infod/Es/du.rb +16 -0
- data/infod/{W → Es}/feed.rb +13 -11
- data/infod/Es/filter.rb +75 -0
- data/infod/Es/find.rb +20 -0
- data/infod/Es/fs.rb +145 -136
- data/infod/Es/glob.rb +22 -0
- data/infod/Es/grep.rb +61 -0
- data/infod/Es/groonga.rb +47 -56
- data/infod/Es/html.rb +271 -0
- data/infod/Es/image.rb +114 -0
- data/infod/Es/in.rb +68 -0
- data/infod/Es/index.rb +183 -0
- data/infod/{W → Es}/json.rb +28 -4
- data/infod/Es/kv.rb +60 -0
- data/infod/Es/ls.rb +58 -0
- data/infod/Es/mail.rb +87 -0
- data/infod/Es/man.rb +112 -0
- data/infod/Es/mime.rb +59 -0
- data/infod/Es/out.rb +52 -0
- data/infod/{W/page.rb → Es/pager.rb} +7 -3
- data/infod/Es/pdf.rb +19 -0
- data/infod/Es/rdf.rb +35 -0
- data/infod/Es/schema.rb +99 -0
- data/infod/Es/search.rb +24 -0
- data/infod/Es/sh.rb +21 -0
- data/infod/{W → Es}/text.rb +26 -14
- data/infod/H.rb +15 -29
- data/infod/H/audio.rb +19 -0
- data/infod/H/blog.rb +15 -0
- data/infod/{W → H}/cal.rb +2 -31
- data/infod/H/edit.rb +88 -0
- data/infod/{W/examine/examine.rb → H/facets.rb} +17 -17
- data/infod/{W → H}/forum.rb +1 -0
- data/infod/{W/examine/sw.rb → H/hf.rb} +12 -12
- data/infod/H/histogram.rb +78 -0
- data/infod/H/mail.rb +92 -0
- data/infod/{W/chat.rb → H/microblog.rb} +21 -16
- data/infod/H/threads.rb +77 -0
- data/infod/H/time.rb +131 -0
- data/infod/H/who.rb +30 -0
- data/infod/{W → H}/wiki.rb +0 -0
- data/infod/K.rb +28 -60
- data/infod/N.rb +151 -74
- data/infod/Rb.rb +3 -3
- data/infod/Th.rb +27 -101
- data/infod/Th/404.rb +29 -36
- data/infod/Th/500.rb +36 -5
- data/infod/Th/GET.rb +48 -118
- data/infod/Th/POST.rb +31 -11
- data/infod/Th/perf.rb +37 -0
- data/infod/Th/util.rb +89 -0
- data/infod/Y.rb +24 -7
- data/infod/infod.rb +2 -3
- metadata +92 -64
- data/infod/Es/redis.rb +0 -3
- data/infod/Es/sqlite.rb +0 -3
- data/infod/Th/local.rb +0 -22
- data/infod/W.rb +0 -34
- data/infod/W/audio.rb +0 -56
- data/infod/W/blog.rb +0 -3
- data/infod/W/color.rb +0 -28
- data/infod/W/core.rb +0 -77
- data/infod/W/css.rb +0 -24
- data/infod/W/du.rb +0 -35
- data/infod/W/edit.rb +0 -8
- data/infod/W/examine/exhibit.rb +0 -34
- data/infod/W/examine/hist.rb +0 -55
- data/infod/W/examine/history.rb +0 -19
- data/infod/W/examine/normal.rb +0 -31
- data/infod/W/examine/protovis.rb +0 -30
- data/infod/W/examine/time/graph.rb +0 -86
- data/infod/W/examine/time/line.rb +0 -24
- data/infod/W/find.rb +0 -24
- data/infod/W/grep.rb +0 -27
- data/infod/W/html.rb +0 -143
- data/infod/W/image.rb +0 -61
- data/infod/W/kv.rb +0 -66
- data/infod/W/ls.rb +0 -50
- data/infod/W/mail.rb +0 -248
- data/infod/W/pdf.rb +0 -16
- data/infod/W/post.rb +0 -9
- data/infod/W/rdf.rb +0 -32
- data/infod/W/schema.rb +0 -172
- data/infod/W/search.rb +0 -33
- data/infod/W/shell.rb +0 -30
- data/infod/W/table.rb +0 -87
- data/infod/W/tree.rb +0 -26
- data/infod/W/vfs.rb +0 -175
@@ -1,9 +1,9 @@
|
|
1
1
|
#watch __FILE__
|
2
|
-
%w{exhibit hist history normal protovis sw time/graph time/line}.each{|e|require_relative e}
|
3
2
|
class E
|
4
3
|
|
5
|
-
fn 'view/
|
6
|
-
|
4
|
+
fn 'view/facets/main',->a,m,e{
|
5
|
+
# facets
|
6
|
+
a = Hash[(a.split ',').map{|a|[a,{}]}]
|
7
7
|
|
8
8
|
# facet stats
|
9
9
|
m.map{|s,r| a.map{|p,_|
|
@@ -17,27 +17,26 @@ class E
|
|
17
17
|
n=->o{
|
18
18
|
i[o]||='f'+(c+=1).to_s}
|
19
19
|
|
20
|
-
view=F['view/'+ (e.q['
|
21
|
-
|
20
|
+
view=F['view/'+ (e.q['fv'] || 'divine') + '/resource']
|
22
21
|
resources=->{
|
23
22
|
m.map{|u,r| # each resource
|
24
23
|
a.map{|p,_| # each facet
|
25
|
-
[n
|
24
|
+
[n[p], r[p].do{|o| # value
|
26
25
|
(o.class==Array ? o : [o]).map{|o|
|
27
|
-
n
|
26
|
+
n[o.to_s] # identifier
|
28
27
|
}}].join ' '
|
29
28
|
}.do{|f|
|
30
29
|
[f.map{|o|'<div class="'+o+'">'}, # facet wrapper
|
31
|
-
view
|
30
|
+
view[r,e], # resource
|
32
31
|
(0..f.size-1).map{|c|'</div>'}]}}}
|
33
32
|
|
34
|
-
[(H.css'/css/
|
33
|
+
[(H.css'/css/facets'),(H.js'/js/facets'),(H.js'/js/mu'),
|
35
34
|
|
36
|
-
a.map{|b,_|{_: :style, class: n
|
35
|
+
a.map{|b,_|{_: :style, class: n[b]}},
|
37
36
|
|
38
37
|
# facet selection
|
39
38
|
{class: :sidebar, c: a.map{|f,v|
|
40
|
-
{class: :facet, title: f, facet: n
|
39
|
+
{class: :facet, title: f, facet: n[f], # predicate
|
41
40
|
c: [f.label,
|
42
41
|
v.sort_by{|k,v|v}.reverse.map{|k,v| # sort by popularity
|
43
42
|
k.respond_to?(:label) &&
|
@@ -45,15 +44,16 @@ class E
|
|
45
44
|
c: [{_: :span, class: :count, c: v},
|
46
45
|
{_: :span, class: :name, c: k.label}]}}]}}},
|
47
46
|
|
48
|
-
(F['view/'+e.q['
|
47
|
+
(F['view/'+e.q['fv']+'/base']||
|
49
48
|
->m,e,r{r.()}).(m,e,resources)]}
|
50
49
|
|
51
|
-
fn 'view/
|
52
|
-
[(H.js '/js/
|
50
|
+
fn 'view/facets/select',->m,e{
|
51
|
+
[(H.js '/js/facets.select'),(H.js '/js/mu'),(H.css '/css/facets'),
|
53
52
|
E.graphProperties(m).map{|e|[{c: e},' ']},
|
54
53
|
{_: 'button', c: 'Go'}]}
|
55
54
|
|
56
|
-
fn 'view/
|
57
|
-
e.q['a'].do{|a|Fn 'view/
|
58
|
-
(Fn 'view/
|
55
|
+
fn 'view/facets',->m,e{
|
56
|
+
e.q['a'].do{|a|Fn 'view/facets/main',a,m,e} ||
|
57
|
+
(Fn 'view/facets/select',m,e)}
|
58
|
+
|
59
59
|
end
|
data/infod/{W → H}/forum.rb
RENAMED
@@ -1,9 +1,9 @@
|
|
1
1
|
#watch __FILE__
|
2
2
|
|
3
|
-
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
3
|
+
# databases of HF frequencies
|
4
|
+
# curl http://eibispace.de/dx/sked-b11.csv > s.ssv
|
5
|
+
# wget http://www1.m2.mediacat.ne.jp/binews/bib11.zip http://hfcc.org/data/b11/b11allx2.zip
|
6
|
+
# unzip *zip
|
7
7
|
|
8
8
|
class E
|
9
9
|
|
@@ -42,8 +42,7 @@ class E
|
|
42
42
|
e[:clr]={}
|
43
43
|
e[:fmax]=d.map{|_,r|r['FREQ'][0].to_f}.flatten.max||30000.0
|
44
44
|
e[:scale]=100/(e[:fmax] - (d.map{|_,r|r['FREQ'][0].to_f}.flatten.min||0))
|
45
|
-
[(H.css '/css/sw'),(H.js '/js/sw'),
|
46
|
-
# [(H.css '/css/sw',true),(H.js '/js/sw',true),
|
45
|
+
[(H.css '/css/sw'),(H.js '/js/mu'),(H.js '/js/sw'),
|
47
46
|
{id: :bands,
|
48
47
|
c: bands.map{|meters,bounds|
|
49
48
|
band += 1
|
@@ -66,9 +65,10 @@ class E
|
|
66
65
|
fn 'view/sw/item',->r,x{
|
67
66
|
min=->t{t='%04d' % (t.class==String && t.empty? ? 0 : t)
|
68
67
|
t[0..1].to_i*60+t[2..3].to_i}
|
69
|
-
u=r['UTC'][0].match(/(\d+)
|
70
|
-
b=u[1].to_i
|
71
|
-
|
68
|
+
u = r['UTC'][0].to_s.match(/(\d+)-?(\d+)?/)
|
69
|
+
b = u[1].to_i.max 2359
|
70
|
+
e = (u[2] ? u[2].to_i : b + 30).max 2359
|
71
|
+
f = r['FREQ'][0].to_f
|
72
72
|
fi = f.to_i
|
73
73
|
n = fi / 100
|
74
74
|
x[:clr][n] ||= '#%06x' % rand(16777216)
|
@@ -101,10 +101,10 @@ width:#{(e-b) * 4.0}px;
|
|
101
101
|
'big'=>[l.scan(/\b[A-Z][A-Z][A-Z]+\b/)],
|
102
102
|
Content=>[l]}
|
103
103
|
l.scan(/\d{4,}/){|d| d=d.to_i
|
104
|
-
if
|
104
|
+
if d < 2400
|
105
|
+
m[u]['UTC']=[d]
|
106
|
+
elsif d < 30000
|
105
107
|
m[u]['FREQ']=[d]
|
106
|
-
elsif
|
107
|
-
m[u]['UTC']=["#{d}-#{d+30}"]
|
108
108
|
end}
|
109
109
|
m.delete u unless m[u].has_keys ['UTC','FREQ']
|
110
110
|
)}
|
@@ -0,0 +1,78 @@
|
|
1
|
+
#watch __FILE__
|
2
|
+
class E
|
3
|
+
|
4
|
+
fn 'view/histogram',->d,e{
|
5
|
+
|
6
|
+
# a :: attribute to chart
|
7
|
+
a = e.q['a'].do{|e|e.expand} || Date
|
8
|
+
|
9
|
+
# bins :: number of buckets
|
10
|
+
n = e.q['bins'].do{|b| b.to_f.max(999.0).min(1)} || 64.0
|
11
|
+
|
12
|
+
# hv :: bin template
|
13
|
+
v = F['view/'+e.q['hv']]
|
14
|
+
|
15
|
+
# construct histogram bins
|
16
|
+
(Fn 'view/histogram/bins',d,a,n).do{|h,m|
|
17
|
+
|
18
|
+
[H.css('/css/hist'),%w{mu hist}.map{|s|H.js('/js/'+s)},
|
19
|
+
(Fn 'view/histogram/render',h),{style: "width: 100%; height: 5em"},
|
20
|
+
h.map{|b,r|
|
21
|
+
# skip empty bins
|
22
|
+
r.empty? ? ' ' :
|
23
|
+
(x = m[:min] + m[:bw] * b
|
24
|
+
from = a == Date ? Time.at(x).to_s : x.to_s
|
25
|
+
to = a == Date ? Time.at(x + m[:bw]).to_s : (x + m[:bw]).to_s
|
26
|
+
# wrap bin
|
27
|
+
{ class: 'histBin b'+b.to_s,
|
28
|
+
c: [# label bin
|
29
|
+
{_: :h3, c: from + ' → ' + to },
|
30
|
+
# bin children view
|
31
|
+
(v.(r,e) if v)]})}]}}
|
32
|
+
|
33
|
+
F['view/h']=F['view/histogram']
|
34
|
+
|
35
|
+
# Graph, property, numBins -> {bin -> Graph}
|
36
|
+
fn 'view/histogram/bins',->m,p,nb{
|
37
|
+
h = {}; bw = 0; min = 0; max = 0
|
38
|
+
m.map{|u,r|
|
39
|
+
# attribute accessor
|
40
|
+
r[p]
|
41
|
+
}.flatten.do{|v|
|
42
|
+
# values
|
43
|
+
v = v.compact.map{|v|
|
44
|
+
( p == Date ? v.to_time : v ).to_f}
|
45
|
+
max = v.max || 0
|
46
|
+
min = v.min || 0
|
47
|
+
width = (max-min).do{|w| w.zero? ? 1 : w}
|
48
|
+
bw = width / nb }
|
49
|
+
|
50
|
+
# construct bins
|
51
|
+
(0..nb).map{|b|h[b] = {}}
|
52
|
+
|
53
|
+
# each resource
|
54
|
+
m.map{|u,r|
|
55
|
+
|
56
|
+
# binnable properties
|
57
|
+
r[p].do{|v|
|
58
|
+
v.each{|v|
|
59
|
+
# bin selector
|
60
|
+
b = (((p == Date ? v.to_time : v).to_f - min) / bw).floor
|
61
|
+
|
62
|
+
# append to bin
|
63
|
+
h[b][u] = r }}}
|
64
|
+
|
65
|
+
# histogram model
|
66
|
+
[h, {min: min, max: max, bw: bw}] }
|
67
|
+
|
68
|
+
fn 'view/histogram/render',->h{
|
69
|
+
scale = 255 / h.map{|b,r|r.keys.size}.max.do{|m|m.zero? ? 1 : m}.to_f
|
70
|
+
bins = h.keys.sort
|
71
|
+
['<table class=histogram><tr>',
|
72
|
+
bins.map{|b|
|
73
|
+
mag = h[b].keys.size
|
74
|
+
{_: :td, class: 'b' + b.to_s,
|
75
|
+
style: 'background-color:#'+('%02x' % (255-mag*scale)).do{|x|'ff'+x+x}}},
|
76
|
+
'</tr></table>']}
|
77
|
+
|
78
|
+
end
|
data/infod/H/mail.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
class E
|
2
|
+
|
3
|
+
fn 'view/mail',->d,e{
|
4
|
+
title = nil
|
5
|
+
|
6
|
+
# JS/CSS
|
7
|
+
[(H.once e,'mail.js',
|
8
|
+
(H.css '/css/mail'), {_: :style, c: "a {background-color: #{E.cs}}"},
|
9
|
+
(H.js '/js/mail'),
|
10
|
+
(H.once e,:mu,(H.js '/js/mu')),
|
11
|
+
|
12
|
+
# up to set-overview
|
13
|
+
({_: :a, id: :up, href: e['REQUEST_PATH'] + e.q.merge({'view' => 'page', 'v' => 'threads'}).qs, c: '↑'} if d.keys.size > 2),
|
14
|
+
|
15
|
+
# collapse/expand quoted content
|
16
|
+
{id: :showQuote, c: :quotes, show: :true},{_: :style, id: :quote}),'<br>',
|
17
|
+
|
18
|
+
# each message
|
19
|
+
d.values.map{|m|
|
20
|
+
|
21
|
+
# content available?
|
22
|
+
[m.class == Hash && (m.has_key? E::SIOC+'content') &&
|
23
|
+
|
24
|
+
{:class => :mail,
|
25
|
+
|
26
|
+
c: [# message link
|
27
|
+
{_: :a, name: m.uri, href: m.url+'?view=base', rel: :raw, title: :raw, c: ' '},
|
28
|
+
|
29
|
+
# To:, From: index search links
|
30
|
+
[['sioc:has_creator',Creator],['sioc:addressed_to',To]].map{|a|
|
31
|
+
m[a[1]].do{|m|
|
32
|
+
m.map{|f| f.respond_to?(:uri) &&
|
33
|
+
{_: :a, property: a[0], href: f.url+'?set=indexPO&p='+a[0]+'&view=threads&c=12', c: f.uri}}}},
|
34
|
+
|
35
|
+
# mailto URI with embedded reply metadata
|
36
|
+
(m['/mail/reply_to']||m[Creator]).do{|r| r[0] && r[0].respond_to?(:uri) &&
|
37
|
+
{_: :a, title: :reply, c: 'r',
|
38
|
+
href: "mailto:#{r[0].uri}?References=<#{m.uri}>&In-Reply-To=<#{m.uri}>&Subject=#{m[Title].join}"}},
|
39
|
+
|
40
|
+
{class: :timestamp, c: m[Date].do{|d|d.map{|d|d.to_s[0..18]}}}, '<br clear=all>',
|
41
|
+
|
42
|
+
# content
|
43
|
+
{_: :pre,
|
44
|
+
c: m[Content].map{|b|
|
45
|
+
|
46
|
+
# line count
|
47
|
+
i = 0
|
48
|
+
|
49
|
+
# HTML message content
|
50
|
+
b.class==String && b.
|
51
|
+
|
52
|
+
# erase empty quoted lines
|
53
|
+
gsub(/^\s*(>)(>|\s)*\n/,"").
|
54
|
+
|
55
|
+
# each line
|
56
|
+
lines.to_a.map{|l|
|
57
|
+
|
58
|
+
# line identifier
|
59
|
+
f = m.uri + ':' + (i+=1).to_s
|
60
|
+
|
61
|
+
# wrapper
|
62
|
+
{_: :span,
|
63
|
+
|
64
|
+
# is line quoted?
|
65
|
+
class: ((l.match /(^\s*(>|On[^\n]+(said|wrote))[^\n]*)\n/) ? 'q' : 'u'), c:
|
66
|
+
|
67
|
+
# id
|
68
|
+
[{_: :a, id: f},
|
69
|
+
|
70
|
+
# line
|
71
|
+
l.chomp,
|
72
|
+
|
73
|
+
# link
|
74
|
+
(l.size > 64 &&
|
75
|
+
{_: :a, class: :line, href: '#'+f,c: ' '}),
|
76
|
+
|
77
|
+
"\n" ]}}}}, # collate lines
|
78
|
+
|
79
|
+
# title
|
80
|
+
m[Title].do{|t|
|
81
|
+
# only show if changed from previous
|
82
|
+
title != t[0] && (
|
83
|
+
title = t[0] # update title
|
84
|
+
[{:class => :title, c: t.html, _: :a, href: m.url+'??=thread#'+m.uri},
|
85
|
+
'<br clear=all>'])}]}]}]}
|
86
|
+
|
87
|
+
# set a default view for RFC822 and SIOC types
|
88
|
+
[MIMEtype+'message/rfc822',
|
89
|
+
SIOCt+'MailMessage'].
|
90
|
+
map{|m| F['view/'+m] = F['view/mail'] }
|
91
|
+
|
92
|
+
end
|
@@ -1,23 +1,27 @@
|
|
1
1
|
#watch __FILE__
|
2
2
|
class E
|
3
3
|
|
4
|
-
|
4
|
+
# sprintf() formats in <https://github.com/infodaemon/www/blob/60a9b5f51cf15d5723afd9172767843d97190d8f/css/i/lotek.theme>
|
5
|
+
def triplrIRC &f
|
5
6
|
i=-1
|
6
|
-
day = dirname.uri.split('/')[-3..-1].
|
7
|
+
day = dirname.uri.split('/')[-3..-1].do{|dp|
|
8
|
+
dp.join('-') if dp[0].match(/^\d{4}$/)
|
9
|
+
}||''
|
7
10
|
doc = uri.sub '#','%23'
|
8
|
-
|
9
|
-
yield doc,'chan',chan
|
10
|
-
r.scan(/(\d\d):(\d\d) \[[\s@]*([^\(\]]+)[^\]]*\] (.*)/){|m|
|
11
|
-
s = doc + '#' + doc + ':' + (i+=1).to_s
|
12
|
-
yield s,Date,day+'T'+m[0]+':'+m[1]+':00'
|
13
|
-
yield s,'chan',chan
|
14
|
-
yield s,Creator,m[2]
|
15
|
-
yield s,Content,m[3].hrefs(true)
|
16
|
-
yield s,Type,E[SIOCt+'InstantMessage']
|
17
|
-
yield s,'hasLink',(m[3].match(/http:\//) ? 'true' : 'false')
|
18
|
-
yield s,'hasNum','true' if m[3].match(/\d/)
|
19
|
-
} rescue nil
|
11
|
+
channel = bare
|
20
12
|
yield doc,Date,day
|
13
|
+
r.lines.map{|l|
|
14
|
+
l.scan(/(\d\d):(\d\d) \[[\s@]*([^\(\]]+)[^\]]*\] (.*)/){|m|
|
15
|
+
s = doc + '#' + doc + ':' + (i+=1).to_s
|
16
|
+
yield s, Date, day+'T'+m[0]+':'+m[1]+':00'
|
17
|
+
yield s, SIOCt+'ChatChannel', channel
|
18
|
+
yield s, Creator, m[2]
|
19
|
+
yield s, Content, m[3].hrefs(true)
|
20
|
+
yield s, Type, E[SIOCt+'InstantMessage']
|
21
|
+
yield s, Type, E[SIOC+'Post']
|
22
|
+
yield s, 'hasLink', (m[3].match(/http:\//) ? 'true' : 'false')
|
23
|
+
yield s, 'hasNum', 'true' if m[3].match(/\d/)} rescue (puts "skipped #{l}")
|
24
|
+
}
|
21
25
|
end
|
22
26
|
|
23
27
|
def tw g='m'
|
@@ -30,6 +34,7 @@ class E
|
|
30
34
|
nokogiri.css('div.tweet').map{|t|
|
31
35
|
s = base + t.css('a.details').attr('href') # subject URI
|
32
36
|
yield s, Type, E[SIOCt+'MicroblogPost']
|
37
|
+
yield s, Type, E[SIOC+'Post']
|
33
38
|
yield s, Creator, E(base+'/'+t.css('.username b')[0].inner_text)
|
34
39
|
yield s, SIOC+'name',t.css('.fullname')[0].inner_text
|
35
40
|
yield s, Atom+"/link/image", E(t.css('.avatar')[0].attr('src'))
|
@@ -58,11 +63,11 @@ class E
|
|
58
63
|
[{_: :a, id: line},
|
59
64
|
{_: :a, :class => :date, href: r.url, c: r[Date][0].match(/T([0-9:]{5})/)[1]},
|
60
65
|
{_: :span, :class => :nick, c: {_: :a, href: r[Atom+'/link/alternate'].do{|a|a[0].uri}||r.url,
|
61
|
-
c: [{_: :img, class: :a, src:
|
66
|
+
c: [r[Atom+"/link/image"].do{|p| {_: :img, class: :a, src: p[0].uri}},
|
62
67
|
{_: :span, c: r[SIOC+'name']||r[Creator]||'#'}]}},' ',
|
63
68
|
{_: :span, :class => :tw,
|
64
69
|
c: [r[Atom+'/link/media'].do{|a|
|
65
|
-
a.map{|a|{_: :a, href: r.url, c: {_: :img, src: a.uri}}}},
|
70
|
+
a.compact.map{|a|{_: :a, href: r.url, c: {_: :img, src: a.uri}}}},
|
66
71
|
((r[Title].to_s==r[Content].to_s || r.uri.match(/twitter/)) && '' ||
|
67
72
|
{_: :a, href: r.url, c: r[Title],:class => r[:mail] ? :titleMail : :title}),
|
68
73
|
r[:mail] ? (r[Content].map{|c|c.lines.to_a.grep(/^[^&@_]+$/)[0..21]}) : r[Content],
|
data/infod/H/threads.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
watch __FILE__
|
2
|
+
class E
|
3
|
+
|
4
|
+
fn 'protograph/thread',->d,_,g{
|
5
|
+
d.walk SIOC+'reply_of',g
|
6
|
+
F['docsID'][g]}
|
7
|
+
|
8
|
+
fn 'view/threads',->d,env{
|
9
|
+
|
10
|
+
# CSS
|
11
|
+
[(H.css '/css/threads'),{_: :style, c: "body {background-color: ##{rand(2).even? ? 'fff' : '000'}}"},
|
12
|
+
|
13
|
+
# predicate tafting & search
|
14
|
+
(p = env.q['p']
|
15
|
+
o = env['uri'].E
|
16
|
+
[(H.js '/js/search'),
|
17
|
+
{_: :a, class: :rangeP, href: '/@'+p+'?set=indexP&view=page&v=linkPO&c=12', c: {'sioc:addressed_to' => 'to', 'sioc:has_creator' => 'From'}[p] || p}, ' ',
|
18
|
+
{_: :a, class: :rangePO, href: o.url+'?set=indexPO&view=page&v=threads&c=32&p='+p, c: env['uri']},
|
19
|
+
{_: :form, action: (URI.escape (p.expand.E.poIndex o).uri),
|
20
|
+
c: [{_: :input, name: :set, value: :grep, type: :hidden},
|
21
|
+
{_: :input, name: :view,value: :grep, type: :hidden},
|
22
|
+
{_: :input, name: :q}
|
23
|
+
]},
|
24
|
+
] if env.q['set']=='indexPO'),
|
25
|
+
|
26
|
+
'<table>',
|
27
|
+
|
28
|
+
# group posts by thread name
|
29
|
+
d.values.select{|r| r[Type].do{|t| t.map(&:uri).member? SIOC+'Post'}
|
30
|
+
}.group_by{|r|
|
31
|
+
[*r[Title]][0].do{|t|t.sub(/^[rR][eE][^A-Za-z]./,'')}}.
|
32
|
+
|
33
|
+
# group by recipient
|
34
|
+
group_by{|r,k| k[0].do{|k|
|
35
|
+
k[To].do{|o|o.head.uri}}}.map{|e|
|
36
|
+
|
37
|
+
# group
|
38
|
+
c = E.c
|
39
|
+
['<tr><td class=subject>', e[1].map{|t|
|
40
|
+
|
41
|
+
# thread
|
42
|
+
[{_: :a, property: Title, :class => 'thread', style: "border-color:#{c}", href: t[1][0].url+'??=thread',
|
43
|
+
c: t[0].to_s.gsub(/[<>]/,'_').gsub(/\[([a-z\-A-Z0-9]+)\]/,'<span class=g>\1</span>')},
|
44
|
+
|
45
|
+
|
46
|
+
# post
|
47
|
+
(t[1].size > 1 &&
|
48
|
+
['<br>', t[1].map{|s|
|
49
|
+
|
50
|
+
# author name and RDFa
|
51
|
+
{_: :a, property: Creator, href: s.url+'??=thread#'+s.uri, :class => 'sender', style: 'background-color:'+c,
|
52
|
+
c: (s[SIOC+'name']||s[Creator]).do{|n|n[0]}
|
53
|
+
}}]),'<br>']},'</td>',
|
54
|
+
|
55
|
+
{_: :td, class: :group, property: To,
|
56
|
+
c: {_: :a, :class => :to, style: 'background-color:'+c, c: e[0] && e[0].split(/@/)[0],
|
57
|
+
href: e[0] && e[0].E.url+'?set=indexPO&p=sioc:addressed_to&view=page&v=threads'}},
|
58
|
+
|
59
|
+
'</tr>']},'</table>',
|
60
|
+
|
61
|
+
# link to unabbreviated content of post-set
|
62
|
+
{_: :a, id: :down, c: '↓',
|
63
|
+
href: env['REQUEST_PATH'] + env.q.merge({'view'=>'page','views'=>'timegraph,mail','arc'=>'/parent','v'=>'multi','sort'=>'dc:date','reverse'=>true}).qs}]}
|
64
|
+
|
65
|
+
F["?"] ||= {}
|
66
|
+
F["?"].update({'thread' =>{
|
67
|
+
'graph'=>'thread',
|
68
|
+
'sort' => 'dc:date',
|
69
|
+
'reverse' => nil,
|
70
|
+
'view' => 'mail'},
|
71
|
+
'ann' =>{
|
72
|
+
'view'=>'threads',
|
73
|
+
'set'=>'glob',
|
74
|
+
'matchP' => 'dc:title',
|
75
|
+
'match' => /[^a-zA-Z][Aa][Nn][nN]([oO][uU]|[^a-zA-Z])/}})
|
76
|
+
|
77
|
+
end
|
data/infod/H/time.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
#watch __FILE__
|
2
|
+
|
3
|
+
class Time
|
4
|
+
def html; H({_: :time, datetime: iso8601, c: to_s}) end
|
5
|
+
end
|
6
|
+
|
7
|
+
class Object
|
8
|
+
def time?
|
9
|
+
(self.class == Time) || (self.class == DateTime)
|
10
|
+
end
|
11
|
+
def to_time
|
12
|
+
time? ? self : Time.parse(self)
|
13
|
+
rescue
|
14
|
+
nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class E
|
19
|
+
|
20
|
+
# linked-timeline
|
21
|
+
fn 'view/timegraph',->g,e{
|
22
|
+
i = F['view/timegraph/item']
|
23
|
+
Fn 'view/timegraph/base',g,e,->{
|
24
|
+
g.map{|u,r|i.(r,e)}}}
|
25
|
+
|
26
|
+
# timegraph container-element
|
27
|
+
fn 'view/timegraph/base',->d,e,c{
|
28
|
+
Fn 'filter/timegraph', e.q,d,nil
|
29
|
+
|
30
|
+
e[:graph] = d
|
31
|
+
e[:group] = {}
|
32
|
+
e[:color] = E.cs
|
33
|
+
h = e.q['height'].do{|h|h.match(/[0-9]+/) && h.to_i.min(1).max(1024) } || '64'
|
34
|
+
|
35
|
+
|
36
|
+
[H.css('/css/timegraph'),{class: :timegraph, style: "height: #{h}em", c: c.()}]}
|
37
|
+
|
38
|
+
# timegraph entry
|
39
|
+
fn 'view/timegraph/item',->r,x{
|
40
|
+
|
41
|
+
# on resources w x-axis field
|
42
|
+
if r[x.q['x'] || Date]
|
43
|
+
|
44
|
+
labelP = x.q['label'].do{|l|l.expand} || Creator
|
45
|
+
label = ([*r[labelP]][0]).do{|l|
|
46
|
+
l.respond_to?(:uri) ? l.uri : l.to_s}
|
47
|
+
lc = x[:group][label] ||= E.c
|
48
|
+
arc = x.q['arc'].do{|a| a.expand }
|
49
|
+
|
50
|
+
[{style: "top: #{r['x']}%; left: #{r['y']}%",
|
51
|
+
c: [{_: :a,
|
52
|
+
title: r[Date][0],
|
53
|
+
href: r.url,
|
54
|
+
class: :label,
|
55
|
+
style: "background-color: #{lc}",
|
56
|
+
c: label,
|
57
|
+
}]},
|
58
|
+
|
59
|
+
# arc(s)
|
60
|
+
{_: :svg, c:
|
61
|
+
r[arc].do{|a|a.map{|e|
|
62
|
+
# target resource
|
63
|
+
x[:graph][e.uri].do{|e|
|
64
|
+
# arc path
|
65
|
+
{_: :line, class: :arc, stroke: x[:color], 'stroke-dasharray'=>"2,2",
|
66
|
+
y1: e['x'].to_s+'%', x1: e['y'].to_s+'%',
|
67
|
+
y2: r['x'].to_s+'%', x2: r['y'].to_s+'%'}}}}}]
|
68
|
+
end }
|
69
|
+
|
70
|
+
fn 'filter/timeofday',->e,m,_{
|
71
|
+
m.map{|_,r|r[Date].do{|ds| ds.map{|d|
|
72
|
+
d = d.to_time
|
73
|
+
r['timeofday']=[60 * d.hour + d.min]}}}}
|
74
|
+
|
75
|
+
fn 'filter/timegraph',->e,m,_{
|
76
|
+
|
77
|
+
x = e['x'] || Date # x property
|
78
|
+
y = e['y'] # y property
|
79
|
+
|
80
|
+
# 2D values
|
81
|
+
vX = m.map{|_,r|r[x]}.flatten.compact.map(&:to_time).map &:to_f
|
82
|
+
vY = m.map{|_,r|r[y]}.flatten.compact.map &:to_f
|
83
|
+
maxX = vX.max || 0
|
84
|
+
minX = vX.min || 0
|
85
|
+
maxY = vY.max || 0
|
86
|
+
minY = vY.min || 0
|
87
|
+
|
88
|
+
# scaling-ratio to normalize values to %
|
89
|
+
scaleX = 100/((maxX-minX).do{|v|v==0 ? 100 : v}||100)
|
90
|
+
scaleY = 100/((maxY-minY).do{|v|v==0 ? 100 : v}||100)
|
91
|
+
|
92
|
+
# annotate resources
|
93
|
+
m.map{|u,r|
|
94
|
+
r['x'] = [*r[x]][0].do{|v|(maxX - v.to_time.to_f)*scaleX} || 0
|
95
|
+
r['y'] = y.do{|y|[*r[y]][0].do{|v|(maxY - v.to_f)*scaleY} || 0} || rand(100)}}
|
96
|
+
|
97
|
+
## SIMILE Timeline
|
98
|
+
# http://www.simile-widgets.org/
|
99
|
+
|
100
|
+
fn Render+'application/timeline',->d,e{
|
101
|
+
{dateTimeFormat: 'iso8601',
|
102
|
+
events: d.values.map{|r|
|
103
|
+
r[Date].do{|d|
|
104
|
+
{description: r.uri,
|
105
|
+
title: r[Title],
|
106
|
+
start: [*d][0],
|
107
|
+
link: r.url,
|
108
|
+
}}}.compact}.to_json}
|
109
|
+
|
110
|
+
fn 'head/timeline',->d,e{
|
111
|
+
['<script>var t="'+e['REQUEST_PATH']+e.q.except('view','?').merge({format: 'application/timeline'}).qs+'"</script>',
|
112
|
+
(H.js '/js/timeline'),
|
113
|
+
(H.js 'http://api.simile-widgets.org/timeline/2.3.1/timeline-api')]}
|
114
|
+
|
115
|
+
fn 'view/timeline',->d,e{'<div id="tl" class="timeline-default" style="height: 300px;"></div>'}
|
116
|
+
|
117
|
+
# tripleStream -> tripleStream
|
118
|
+
def dateNorm *f
|
119
|
+
send(*f){|s,p,o|
|
120
|
+
yield *({'CreationDate' => true,
|
121
|
+
'Date' => true,
|
122
|
+
RSS+'pubDate' => true,
|
123
|
+
Date => true,
|
124
|
+
Purl+'dc/elements/1.1/date' => true,
|
125
|
+
Atom+'published' => true,
|
126
|
+
Atom+'updated' => true
|
127
|
+
}[p] ?
|
128
|
+
[s,Date,Time.parse(o).utc.iso8601] : [s,p,o])}
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|