infod 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. data/infod.rb +2 -3
  2. data/infod/Es.rb +31 -67
  3. data/infod/{W/source.rb → Es/code.rb} +6 -10
  4. data/infod/Es/css.rb +21 -0
  5. data/infod/{W → Es}/csv.rb +0 -0
  6. data/infod/Es/du.rb +16 -0
  7. data/infod/{W → Es}/feed.rb +13 -11
  8. data/infod/Es/filter.rb +75 -0
  9. data/infod/Es/find.rb +20 -0
  10. data/infod/Es/fs.rb +145 -136
  11. data/infod/Es/glob.rb +22 -0
  12. data/infod/Es/grep.rb +61 -0
  13. data/infod/Es/groonga.rb +47 -56
  14. data/infod/Es/html.rb +271 -0
  15. data/infod/Es/image.rb +114 -0
  16. data/infod/Es/in.rb +68 -0
  17. data/infod/Es/index.rb +183 -0
  18. data/infod/{W → Es}/json.rb +28 -4
  19. data/infod/Es/kv.rb +60 -0
  20. data/infod/Es/ls.rb +58 -0
  21. data/infod/Es/mail.rb +87 -0
  22. data/infod/Es/man.rb +112 -0
  23. data/infod/Es/mime.rb +59 -0
  24. data/infod/Es/out.rb +52 -0
  25. data/infod/{W/page.rb → Es/pager.rb} +7 -3
  26. data/infod/Es/pdf.rb +19 -0
  27. data/infod/Es/rdf.rb +35 -0
  28. data/infod/Es/schema.rb +99 -0
  29. data/infod/Es/search.rb +24 -0
  30. data/infod/Es/sh.rb +21 -0
  31. data/infod/{W → Es}/text.rb +26 -14
  32. data/infod/H.rb +15 -29
  33. data/infod/H/audio.rb +19 -0
  34. data/infod/H/blog.rb +15 -0
  35. data/infod/{W → H}/cal.rb +2 -31
  36. data/infod/H/edit.rb +88 -0
  37. data/infod/{W/examine/examine.rb → H/facets.rb} +17 -17
  38. data/infod/{W → H}/forum.rb +1 -0
  39. data/infod/{W/examine/sw.rb → H/hf.rb} +12 -12
  40. data/infod/H/histogram.rb +78 -0
  41. data/infod/H/mail.rb +92 -0
  42. data/infod/{W/chat.rb → H/microblog.rb} +21 -16
  43. data/infod/H/threads.rb +77 -0
  44. data/infod/H/time.rb +131 -0
  45. data/infod/H/who.rb +30 -0
  46. data/infod/{W → H}/wiki.rb +0 -0
  47. data/infod/K.rb +28 -60
  48. data/infod/N.rb +151 -74
  49. data/infod/Rb.rb +3 -3
  50. data/infod/Th.rb +27 -101
  51. data/infod/Th/404.rb +29 -36
  52. data/infod/Th/500.rb +36 -5
  53. data/infod/Th/GET.rb +48 -118
  54. data/infod/Th/POST.rb +31 -11
  55. data/infod/Th/perf.rb +37 -0
  56. data/infod/Th/util.rb +89 -0
  57. data/infod/Y.rb +24 -7
  58. data/infod/infod.rb +2 -3
  59. metadata +92 -64
  60. data/infod/Es/redis.rb +0 -3
  61. data/infod/Es/sqlite.rb +0 -3
  62. data/infod/Th/local.rb +0 -22
  63. data/infod/W.rb +0 -34
  64. data/infod/W/audio.rb +0 -56
  65. data/infod/W/blog.rb +0 -3
  66. data/infod/W/color.rb +0 -28
  67. data/infod/W/core.rb +0 -77
  68. data/infod/W/css.rb +0 -24
  69. data/infod/W/du.rb +0 -35
  70. data/infod/W/edit.rb +0 -8
  71. data/infod/W/examine/exhibit.rb +0 -34
  72. data/infod/W/examine/hist.rb +0 -55
  73. data/infod/W/examine/history.rb +0 -19
  74. data/infod/W/examine/normal.rb +0 -31
  75. data/infod/W/examine/protovis.rb +0 -30
  76. data/infod/W/examine/time/graph.rb +0 -86
  77. data/infod/W/examine/time/line.rb +0 -24
  78. data/infod/W/find.rb +0 -24
  79. data/infod/W/grep.rb +0 -27
  80. data/infod/W/html.rb +0 -143
  81. data/infod/W/image.rb +0 -61
  82. data/infod/W/kv.rb +0 -66
  83. data/infod/W/ls.rb +0 -50
  84. data/infod/W/mail.rb +0 -248
  85. data/infod/W/pdf.rb +0 -16
  86. data/infod/W/post.rb +0 -9
  87. data/infod/W/rdf.rb +0 -32
  88. data/infod/W/schema.rb +0 -172
  89. data/infod/W/search.rb +0 -33
  90. data/infod/W/shell.rb +0 -30
  91. data/infod/W/table.rb +0 -87
  92. data/infod/W/tree.rb +0 -26
  93. 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/examine',->a,m,e{
6
- a=Hash[(a.split ',').map{|a|[a,{}]}] # facets
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['ev'] || 'divine') + '/item']
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.(p),r[p].do{|o| # value
24
+ [n[p], r[p].do{|o| # value
26
25
  (o.class==Array ? o : [o]).map{|o|
27
- n.(o.to_s) # identifier
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.(r,e), # resource
30
+ view[r,e], # resource
32
31
  (0..f.size-1).map{|c|'</div>'}]}}}
33
32
 
34
- [(H.css'/css/examine'),(H.js'/js/examine'),(H.js'/js/mu'),
33
+ [(H.css'/css/facets'),(H.js'/js/facets'),(H.js'/js/mu'),
35
34
 
36
- a.map{|b,_|{_: :style, class: n.(b)}},
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.(f), # predicate
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['ev']+'/base']||
47
+ (F['view/'+e.q['fv']+'/base']||
49
48
  ->m,e,r{r.()}).(m,e,resources)]}
50
49
 
51
- fn 'view/examine/selectFacets',->m,e{
52
- [(H.js '/js/examine.selectFacet'),(H.js '/js/mu'),(H.css '/css/examine'),
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/e',->m,e{
57
- e.q['a'].do{|a|Fn 'view/examine',a,m,e} ||
58
- (Fn 'view/examine/selectFacets',m,e)}
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
@@ -1,3 +1,4 @@
1
1
  class E
2
2
 
3
+
3
4
  end
@@ -1,9 +1,9 @@
1
1
  #watch __FILE__
2
2
 
3
- #curl http://eibispace.de/dx/sked-b11.csv > s.ssv
4
- #wget http://www1.m2.mediacat.ne.jp/binews/bib11.zip http://hfcc.org/data/b11/b11allx2.zip
5
- #unzip bia11.zip ;unzip b11allx2.zip
6
- #xlsx2csv
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+)-(\d+)/)
70
- b=u[1].to_i; e=u[2].to_i
71
- f=r['FREQ'][0].to_f
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 (d > 2400) && (d < 30000)
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 + ' &rarr; ' + 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: '&uarr;'} 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: '&nbsp;'},
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*(&gt;)(&gt;|\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*(&gt;|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: '&#160;'}),
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
- def triplrLog &f
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].join('-')
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
- chan = bare
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: r[Atom+"/link/image"][0].uri},
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],
@@ -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}, '&nbsp;',
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: '&darr;',
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