infod 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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,86 +0,0 @@
1
- #watch __FILE__
2
- class E
3
-
4
- F["?"]||={}
5
- F["?"].update({'taft'=>{
6
- 'graph'=>'|',
7
- '|'=>'triplrMozHist',
8
- 'view'=>'page',
9
- 'v'=>'timegraph',
10
- 'arc'=>'referer'}})
11
-
12
- # massage data for timegraph
13
- fn 'filter/timegraph',->e,m,_{
14
-
15
- e['timegraph'] ||= true
16
-
17
- x = e['x'] || Date # x prop
18
- y = e['y'] # y property
19
-
20
- # 2D values
21
- vX = m.map{|_,r|r[x]}.flatten.compact.map(&:to_time).map &:to_f
22
- vY = m.map{|_,r|r[y]}.flatten.compact.map &:to_f
23
- maxX = vX.max
24
- minX = vX.min
25
- maxY = vY.max
26
- minY = vY.min
27
-
28
- # scaling-ratio to normalize values to %
29
- scaleX = 100/((maxX-minX).do{|v|v==0 ? 100 : v}||100)
30
- scaleY = 100/((maxY-minY).do{|v|v==0 ? 100 : v}||100)
31
-
32
- # annotate resources with positioning data
33
- m.map{|u,r|
34
- r['x'] = [*r[x]][0].do{|v|(maxX - v.to_time.to_f)*scaleX} || 0
35
- r['y'] = y.do{|y|[*r[y]][0].do{|v|(maxY - v.to_f)*scaleY} || 0} || rand(100)}
36
- }
37
-
38
- # a linked-timeline view
39
- fn 'view/timegraph',->d,e{
40
- # use standard structure for examine faceted-filtering
41
- i=F['view/timegraph/item']
42
- Fn 'view/timegraph/base',d,e,->{d.map{|u,r|i.(r,e)}}}
43
-
44
- # timegraph container-element
45
- fn 'view/timegraph/base',->d,e,c{
46
- Fn 'filter/timegraph', e.q, d, nil unless e.q['timegraph']==true
47
-
48
- e[:graph] = d
49
- e[:group] = {}
50
- e[:color] = E.c
51
-
52
- [H.css('/css/timegraph'),{class: :timegraph, c: c.()}]}
53
-
54
- # timegraph entry
55
- fn 'view/timegraph/item',->r,x{
56
- # skip resources w/o x-axis field
57
- if r[x.q['x'] || Date]
58
-
59
- labelP = x.q['label'].expand || Creator
60
- label = (r[labelP][0]).do{|l|
61
- l.respond_to?(:uri) ? l.uri : l.to_s}
62
- lc = x[:group][label] ||= E.c
63
-
64
- [{style: "top: #{r['x']}%; left: 0", class: :date, c: r[Date][0]},
65
- {style: "top: #{r['x']}%; left: #{r['y']}%",
66
- c: [{_: :a, href: r.url, c: '#', class: :link},
67
- {_: :a,
68
- title: r[Date][0],
69
- href: '#'+r.uri,
70
- class: :label,
71
- style: "background-color: #{lc}",
72
- c: label,
73
- }]},
74
-
75
- # arc(s)
76
- {_: :svg, c:
77
- r[x.q['arc'].expand].map{|e|
78
- # target resource
79
- x[:graph][e.uri].do{|e|
80
- # arc path
81
- {_: :line, class: :arc, stroke: x[:color], 'stroke-dasharray'=>"2,2",
82
- y1: e['x'].to_s+'%', x1: e['y'].to_s+'%',
83
- y2: r['x'].to_s+'%', x2: r['y'].to_s+'%'}}}}]
84
- end }
85
-
86
- end
@@ -1,24 +0,0 @@
1
- class E
2
-
3
- ## SIMILE Timeline
4
- # http://www.simile-widgets.org/
5
-
6
- # JSON format
7
- fn Render+'application/timeline',->d,e{
8
- {dateTimeFormat: 'iso8601',
9
- events: d.values.map{|r|
10
- r[Date].do{|d|
11
- {description: r.uri,
12
- title: r[Title],
13
- start: [*d][0],
14
- link: r.url,
15
- }}}.compact}.to_json}
16
-
17
- fn 'head/timeline',->d,e{
18
- ['<script>var t="'+e['REQUEST_PATH']+e.q.except('view','?').merge({format: 'application/timeline'}).qs+'"</script>',
19
- (H.js '/js/timeline'),
20
- (H.js 'http://api.simile-widgets.org/timeline/2.3.1/timeline-api')]}
21
-
22
- fn 'view/timeline',->d,e{'<div id="tl" class="timeline-default" style="height: 300px;"></div>'}
23
-
24
- end
data/infod/W/find.rb DELETED
@@ -1,24 +0,0 @@
1
- #watch __FILE__
2
- class E
3
-
4
- fn 'set/find',->e,q,m{
5
- t=q['day'] && q['day'].match(/^\d+$/) && '-ctime -'+q['day']
6
- s=q['size'] && q['size'].match(/^\d+$/) && '-size +'+q['size']+'M'
7
- r=q['q'] && '-iregex ' + ('.*'+q['q']+'.*').sh
8
- `find #{e.sh} #{t} #{s} #{r} | head -n 1024`.lines.map &:pathToURI}
9
-
10
- fn 'graph/find',->e,q,m{
11
- (Fn 'set/find', e,q,m).do{|f|
12
- if f.size < 256
13
- f.map{|r|r.fromStream m,:triplrInode,false}
14
- else
15
- f.map{|r|m[r.uri]=r}
16
- end}}
17
-
18
- fn 'view/find',->i,e{
19
- {_: :form, method: :GET, action: e['REQUEST_PATH'].t, style: 'float: right',
20
- c: [{_: :input, name: :graph, value: :find, type: :hidden},
21
- {_: :input, name: :view, value: :ls, type: :hidden},
22
- {_: :input, name: :q}]}}
23
-
24
- end
data/infod/W/grep.rb DELETED
@@ -1,27 +0,0 @@
1
- #watch __FILE__
2
- class E
3
-
4
- fn 'set/grep',->e,q,m{
5
- `grep -rl#{q.has_key?('i') && 'i'} #{q['q'].sh} #{e.sh}`.lines.map &:pathToURI
6
- }
7
-
8
- fn 'view/grep',->d,e{
9
- w=e.q['q'].scan(/[\w]+/).map(&:downcase).uniq # split/dedupe words
10
- c={}; w.each_with_index{|w,i|c[w]=i} # word index
11
- a=/(#{w.join '|'})/i # OR pattern
12
- p=/#{w.join '.*'}/i # sequential pattern
13
- [H.css('/css/search'),{_: :style, c: c.values.map{|i| # word styles
14
- b = rand(16777216) # random color
15
- f = b > 8388608 ? :black : :white # keep text contrasty
16
- ".w#{i} {background-color: #{'#%06x' % b}; color: #{f}}\n"}},# CSS
17
- d.map{|u,r| l = r.to_s.gsub(/<[^>]*>/,'').lines # plaintextify
18
- g = l.grep p # sequential match first
19
- g = l.grep a if g.empty? # OR match second
20
- !g.empty? && # find anything?
21
- [r.E.do{|e|{_: :a,href: e.url,c: e}},'<br>', # doc link
22
- [g[-1*(g.size.max 3)..-1].map{|l| # show 3 matches per doc
23
- l[0..404].gsub(a){|g| # create exerpt
24
- H({_: :span, class: "w w#{c[g.downcase]}",c: g})} # style exerpt
25
- },"<br>"]]}]}
26
-
27
- end
data/infod/W/html.rb DELETED
@@ -1,143 +0,0 @@
1
- #watch __FILE__
2
-
3
- class Array
4
- def html table=true
5
- map(&:html).join ' '
6
- end
7
- end
8
-
9
- class Object
10
- def html *a
11
- to_s.gsub('<','&lt;').gsub('>','&gt;')
12
- end
13
- end
14
-
15
- class String
16
- def br
17
- gsub(/\n/,"<br>\n")
18
- end
19
- def href name=nil
20
- '<a href="'+self+'">'+(name||(Fn 'abbrURI',self))+'</a>'
21
- end
22
- def html
23
- if match /\A(https?:\/\/)[\S]+\Z/
24
- href
25
- else
26
- self
27
- end
28
- rescue
29
- self
30
- end
31
- end
32
-
33
- class Hash
34
- def html
35
- H({_: :table, class: :html, c:
36
- map{|k,v|
37
- {_: :tr, property: k, c:
38
- [{_: :td,c: (Fn 'abbrURI',k), class: :key},
39
- {_: :td,
40
- c: (case k
41
- when E::Content
42
- {_: :pre, style: "white-space: pre-wrap", c: v}
43
- when 'uri'
44
- u = v.E
45
- {_: :a, id: u, href: u.url, c: v}
46
- else
47
- v.html
48
- end), class: :val}].cr}}.cr})
49
- end
50
- end
51
-
52
- class E
53
- def html name=nil,l=false
54
- (l ? url : uri).href name
55
- end
56
-
57
- def link
58
- html '#',true
59
- end
60
-
61
- fn 'abbrURI',->u{
62
- u.to_s.sub(/(?<scheme>[a-z]+:\/\/)?(?<abbr>.*?)(?<frag>[^#\/]+)$/,
63
- '<span class="abbr"><span class="scheme">\k<scheme></span>\k<abbr></span><span class="frag">\k<frag></span>')
64
- }
65
-
66
- fn 'head',->d,e{
67
- [{_: :title, c: d.attr(Title) || e.uri},
68
- (Fn 'head.formats',e),
69
- (Fn 'head.icon')].cr}
70
-
71
- fn 'head.formats',->e{
72
- F.keys.grep(/^render/).map{|f|
73
- f = f[7..-1]
74
- {_: :link, rel: :meta, type: f, href:'http://' + e['SERVER_NAME'] + e['REQUEST_PATH'] + e.q.merge({'format' => f}).qs}}.cr}
75
-
76
- fn 'head.icon',->{{_: :link, href:'/css/i/favicon.ico', rel: :icon}}
77
-
78
- # domain-specific view
79
- fn 'view',->d,e{( Fn 'view/divine/set',d,e)||
80
- d.values.map{|r|Fn 'view/divine/item',r,e}}
81
-
82
- # no domain-specific view
83
- fn 'view/base',->d,e{[H.css('/css/html'),d.values.map(&:html)]}
84
-
85
- # select view - filesystem hints
86
- fn 'view/divine/set',->d,e{
87
- d.values.map{|e|e.E.base}.do{|b|
88
- s = b.size.to_f
89
- t = 0.42 # threshold
90
- if b.grep(/^msg\./).size / s > t # email
91
- Fn 'view/threads',d,e
92
- elsif b.grep(/(aif|wav|flac|mp3|m4a|aac|ogg)$/i).size / s > t # audio
93
- Fn 'view/audioplayer', d,e
94
- elsif b.grep(/(gif|jpe?g|png)$/i).size / s > t # images
95
- Fn 'view/th', d,e
96
- elsif b.grep(/\.log$/).size / s > t
97
- Fn 'view/chat', d,e
98
- else false
99
- end}}
100
-
101
- Data['view/divine/item'] = "use RDF typeclass hints to choose view for a resource"
102
- fn 'view/divine/item',->r,e{
103
- r.class==Hash && r[Type] && r[Type][0] && r[Type][0].respond_to?(:uri) &&
104
- (t = r[Type][0].uri; !t.empty? && # a RDF type
105
- (F['view/'+t] ||
106
- F['view/'+t.split(/\//)[-2]]).do{|f|
107
- f.({r.uri => r},e)}) ||
108
- [r.html,H.once(e,'css',H.css('/css/html'))] }
109
-
110
- Data['view/select'] = "show a menu of all views available"
111
- fn 'view/select',->d,e{
112
- [{_: :style, c: 'a {min-width:22em;text-align:right}'},
113
- F.keys.grep(/^view\/(?!application)/).map{|v|
114
- [{_: :a, href: e['REQUEST_PATH']+e.q.merge({'view' => v[5..-1]}).qs,c: v},'<br>']}]}
115
- F['view/?'] = F['view/select']
116
-
117
- F['doc/view/multi'] = "display multiple comma-separated <b>views</b>"
118
- fn 'view/multi',->d,e{e.q['views'].split(',').map{|v|Fn'view/'+v,d,e}}
119
-
120
- def triplrBlob
121
- glob.select(&:f).do{|f|f.map{|r|
122
- yield r.uri,Type,E('blob')
123
- yield r.uri,Content,r.r}} end
124
- graphFromStream :triplrBlob
125
-
126
- def triplrHref e=nil
127
- yield uri,Content,read.do{|r|e ? r.force_encoding(e).to_utf8 : r}.hrefs
128
- end
129
-
130
- fn Render+'text/html',->d,e{
131
- v = e.q['view'].to_s
132
- h = F['head/'+v] || F['head']
133
- v = F['view/'+v] || F['view']
134
-
135
- H(e.q.has_key?('un') ? v.(d,e) :
136
- ['<!DOCTYPE html>',
137
- {_: :html,
138
- c: [{_: :head,
139
- c: ['<meta charset="utf-8" />',
140
- h.(d,e)]},
141
- {_: :body, c: v.(d,e)}].cr}].cr)}
142
-
143
- end
data/infod/W/image.rb DELETED
@@ -1,61 +0,0 @@
1
- #watch __FILE__
2
- class E
3
-
4
- def thumb?
5
- mime.match(/^(image|video)/) && # is file an image?
6
- @r.qs.match(/^[0-9]{0,3}x[0-9]{0,3}$/) && # valid dimensions?
7
- base.match(/^[^.]/) # skip "invisible" images
8
- end
9
-
10
- def thumb
11
- E['/E/images/'+
12
- [no.stat.do{|s|
13
- [s.ino,s.mtime]},
14
- @r.qs].h.dive+'.png'].do{|n| n.e ||
15
- (n.dirname.dir
16
- mime.match(/^video/) &&
17
- `ffmpegthumbnailer -s #{@r.qs.match(/[0-9]+/).to_s} -i #{sh} -o #{n.sh}` ||
18
- `gm convert #{sh} -thumbnail "#{@r.qs}" #{n.sh}`)
19
- n.env @r }
20
- end
21
-
22
- fn 'view/img',->i,_{
23
- [i.values.map{|i|
24
- [{_: :a, href: i.url,
25
- c: {_: :img,
26
- style:'float:left;max-width:61.8%',
27
- src: i.url}},
28
- i.html]},
29
- (H.css '/css/img')
30
- ]}
31
-
32
- fn 'view/th',->i,e{
33
- s=e.q['s']||'233'
34
- i.map{|u,i| u.match(/(gif|jpg|png|tiff)$/i) &&
35
- {_: :a, href: i.url+'?view=img',
36
- c: {_: :img, src: i.url+'?'+s+'x'+s}}}}
37
-
38
- F['view/'+MIMEtype+'image/gif'] = F['view/th']
39
- F['view/'+MIMEtype+'image/jpeg']= F['view/th']
40
- F['view/'+MIMEtype+'image/png'] = F['view/th']
41
-
42
- fn 'view/imgs',->m,e{ require 'nokogiri'
43
- h=e.q['h'].do{|h|h.match(/^[0-9]+$/).do{|_|'height:'+h+'px'}}
44
- seen={}
45
- x=->i{i&&i.match(/(jpg|gif|png)$/i)&&i}
46
- [(H.once e,:mu,H.js('/js/mu')),H.js('/js/images'),
47
- m.values.map{|v|
48
- [[*v[Content]].map{|c|
49
- c.class == String &&
50
- (Nokogiri::HTML.parse(c).do{|c|
51
- [c.css('img').map{|i|i['src']}.compact,
52
- c.css( 'a').map{|i|i['href']}.select(&x)]
53
- })},
54
- x.(v.uri),
55
- (v.respond_to?(:values)&&v.values.flatten.map{|v|v.respond_to?(:uri)&&v.uri}.select(&x))
56
- ].flatten.uniq.compact.map{|s|
57
- {s: s,c: ->{"<a href='#{v.uri.to_s.do{|u|u.path? ? u : u.E.url}}'><img style='float:left;#{h}' src='#{s}'></a>"}}}}.flatten.map{|i|
58
- !seen[i[:s]] && (seen[i[:s]]=true; i[:c].())
59
- }]}
60
-
61
- end
data/infod/W/kv.rb DELETED
@@ -1,66 +0,0 @@
1
- class E
2
-
3
- # a simple key/value RDF store on a fs
4
-
5
- # *get*
6
- # (E'http://www.kanzaki.com/ns/music#EnglishHorn')[RDFs+'comment']
7
- # -> ["A double-reed woodwind instrument, larger member of the oboe family."]
8
- #
9
- # *set*
10
- # (E'lement')['level']='trace'
11
- #
12
- # *update*
13
- # (E'lement')['level','trace','abundant']
14
- #
15
- def [] p,o=nil, v=nil
16
- unless o
17
- (s p).listPredicates
18
- else
19
- edit E(p),(o.class == E ? o : E(p).literal(o)),v
20
- end
21
- end
22
-
23
- def []= p,o
24
- self[p,o]
25
- end
26
-
27
- def edit p,o,v=nil
28
- d=(s p).s o # object
29
- if v # edit
30
- if d.e
31
- d.deleteNode # remove
32
- indexEdit p,o,'' # unindex
33
- end
34
- self[p,v] unless v.empty? # add
35
- else
36
- unless d.e
37
- indexEdit p,o,nil # index add
38
- d.dir # create
39
- end
40
- end
41
- touch if e
42
- end
43
-
44
- def triplrFsStore
45
- listPredicates.map{|p|
46
- self[p].map{|o|
47
- yield uri, p.uri, o }}
48
- end
49
-
50
- def deletePredicate p
51
- self[p].each{|o| self[p,o,'']}
52
- end
53
-
54
- # property list
55
- # E -> [E]
56
- def listPredicates
57
- s = u.to_s.size+1
58
- subtree.map{|n|n.uri[s..-1].unpath}
59
- end
60
-
61
- def literalBlob o
62
- u = literalBlobURI o
63
- u.w o,!o.class==String unless u.f
64
- end
65
-
66
- end
data/infod/W/ls.rb DELETED
@@ -1,50 +0,0 @@
1
- #watch __FILE__
2
- class E
3
-
4
- fn 'set/ls',->d,e,m{d.c}
5
-
6
- # filesystem metadata only
7
- fn 'graph/ls',->d,e,m{d.c.map{|c|c.fromStream m, :triplrInode, false}}
8
-
9
- # basic directory view
10
- fn 'view/dir',->i,e{
11
-
12
- # localize URL
13
- h = 'http://' + e['SERVER_NAME'] + '/'
14
- l = -> u {
15
- if u.index(h) == 0
16
- u # already a local link
17
- else
18
- # generate local link
19
- Prefix + u
20
- end}
21
-
22
- # item thumbnail / link
23
- a = -> i { e = i.E
24
- {_: :a, href: l[e.uri],
25
- c: e.uri.match(/(gif|jpe?g|png)$/i) ? {_: :img, src: i.uri+'?233x233'} :
26
- e.uri.sub(/.*\//,'')
27
- }}
28
-
29
- [(H.once e, 'dir', (H.css '/css/ls')),
30
- i.map{|u,r| r[Posix+'dir#child'] ? # directory?
31
- {class: :dir, style: "background-color: #{E.c}", # dir wrapper
32
- c: [{c: [{_: :a, href: l[r.uri]+'?graph=ls&view=ls', c: r.uri.sub( 'http://'+e['SERVER_NAME'],'')}, # link to ls
33
- {_: :a, href: l[r.uri].t, c: '/'}]},
34
- r[Posix+'dir#child'].map{|c|a[c]}]} : # children
35
- a[r]}]} # item
36
-
37
- F['view/'+MIMEtype+'inode/directory']=F['view/dir']
38
-
39
- # tabular rendering
40
- fn 'view/ls',->i,e{
41
- [(H.css '/css/ls'),
42
- {_: :a, class: :up, href: E(e['uri']).parent.url+'?graph=ls&view=ls', c: '&uarr;'},
43
- {class: :ls,
44
- c: (Fn 'view/tab',i,e)},
45
- {_: :a, class: :du, href: e['REQUEST_PATH'].t+'??=du', c: :du, rel: :nofollow},
46
- (Fn 'view/find',i,e),'<br clear=all>',
47
- {_: :a, class: :down, href: e['uri'].E.url.t, c: '&darr;'},
48
- ]}
49
-
50
- end