infod 0.0.2 → 0.0.3.0
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.
- data/infod.rb +51 -12
- data/infod/{Th/404.rb → 404.rb} +4 -16
- data/infod/500.rb +53 -0
- data/infod/GET.rb +104 -0
- data/infod/HEAD.rb +23 -0
- data/infod/HTTP.rb +105 -0
- data/infod/{Th/PATCH.rb → PATCH.rb} +0 -0
- data/infod/POST.rb +34 -0
- data/infod/audio.rb +30 -0
- data/infod/blog.rb +34 -0
- data/infod/cal.rb +72 -0
- data/infod/{Es/code.rb → code.rb} +7 -4
- data/infod/constants.rb +55 -0
- data/infod/{Es/css.rb → css.rb} +0 -0
- data/infod/{Es/csv.rb → csv.rb} +0 -0
- data/infod/{Es/du.rb → du.rb} +0 -0
- data/infod/edit.rb +73 -0
- data/infod/{H/facets.rb → facets.rb} +20 -11
- data/infod/{Es/feed.rb → feed.rb} +17 -16
- data/infod/{Es/find.rb → find.rb} +2 -3
- data/infod/forum.rb +13 -0
- data/infod/{Es/fs.rb → fs.rb} +5 -2
- data/infod/glob.rb +26 -0
- data/infod/graph.rb +131 -0
- data/infod/{Es/grep.rb → grep.rb} +3 -3
- data/infod/{Es/groonga.rb → groonga.rb} +35 -26
- data/infod/{H/histogram.rb → histogram.rb} +23 -16
- data/infod/html.rb +231 -0
- data/infod/{Es/image.rb → image.rb} +16 -26
- data/infod/{Es/index.rb → index.rb} +44 -49
- data/infod/infod.rb +51 -12
- data/infod/json.rb +38 -0
- data/infod/{Es/kv.rb → kv.rb} +3 -9
- data/infod/{Y.rb → lambda.rb} +18 -1
- data/infod/ls.rb +49 -0
- data/infod/mail.rb +108 -0
- data/infod/{Es/man.rb → man.rb} +3 -15
- data/infod/{H/microblog.rb → microblog.rb} +22 -31
- data/infod/{K.rb → mime.rb} +68 -52
- data/infod/{N.rb → names.rb} +77 -56
- data/infod/page.rb +13 -0
- data/infod/postscript.rb +26 -0
- data/infod/rdf.rb +51 -0
- data/infod/{Rb.rb → ruby.rb} +18 -33
- data/infod/{Es/schema.rb → schema.rb} +23 -8
- data/infod/{Es/search.rb → search.rb} +5 -11
- data/infod/{Es/sh.rb → sh.rb} +0 -0
- data/infod/{Es/text.rb → text.rb} +33 -29
- data/infod/{H/threads.rb → threads.rb} +20 -27
- data/infod/{H/time.rb → time.rb} +14 -34
- data/infod/{H/wiki.rb → wiki.rb} +0 -0
- metadata +53 -64
- data/config.ru +0 -3
- data/infod/Es.rb +0 -31
- data/infod/Es/filter.rb +0 -75
- data/infod/Es/glob.rb +0 -22
- data/infod/Es/html.rb +0 -271
- data/infod/Es/in.rb +0 -68
- data/infod/Es/json.rb +0 -68
- data/infod/Es/ls.rb +0 -58
- data/infod/Es/mail.rb +0 -87
- data/infod/Es/mime.rb +0 -59
- data/infod/Es/out.rb +0 -52
- data/infod/Es/pager.rb +0 -34
- data/infod/Es/pdf.rb +0 -19
- data/infod/Es/rdf.rb +0 -35
- data/infod/H.rb +0 -15
- data/infod/H/audio.rb +0 -19
- data/infod/H/blog.rb +0 -15
- data/infod/H/cal.rb +0 -81
- data/infod/H/edit.rb +0 -88
- data/infod/H/forum.rb +0 -4
- data/infod/H/hf.rb +0 -114
- data/infod/H/mail.rb +0 -92
- data/infod/H/who.rb +0 -30
- data/infod/Th.rb +0 -36
- data/infod/Th/500.rb +0 -41
- data/infod/Th/GET.rb +0 -62
- data/infod/Th/HEAD.rb +0 -5
- data/infod/Th/POST.rb +0 -39
- data/infod/Th/perf.rb +0 -37
- data/infod/Th/uid.rb +0 -24
- data/infod/Th/util.rb +0 -89
@@ -2,20 +2,9 @@
|
|
2
2
|
class E
|
3
3
|
|
4
4
|
def triplrImage &f
|
5
|
+
yield uri,Type,E[DC+'Image']
|
5
6
|
triplrStdOut 'exiftool', EXIF, &f
|
6
7
|
end
|
7
|
-
|
8
|
-
# export EXIF to RDF-in-JSON (recursive)
|
9
|
-
def exif
|
10
|
-
take.map{|g|
|
11
|
-
if g.uri.match /(jpe?g|gif|png)$/i
|
12
|
-
e = g.ef
|
13
|
-
if !e.e || e.m < g.m
|
14
|
-
g.ef.w g.fromStream({},:triplrImage), true
|
15
|
-
puts "EXIF #{g} #{g.ef.size} bytes"
|
16
|
-
end
|
17
|
-
end}
|
18
|
-
end
|
19
8
|
|
20
9
|
fn 'req/scaleImage',->e,r{
|
21
10
|
i = [e,e.pathSegment].compact.find(&:f)
|
@@ -38,17 +27,15 @@ class E
|
|
38
27
|
end}
|
39
28
|
|
40
29
|
fn 'view/img',->i,_{
|
41
|
-
[i.values.map{|i|
|
42
|
-
[
|
43
|
-
|
44
|
-
style:'float:left;max-width:61.8%',
|
45
|
-
src: i.url}},
|
30
|
+
[i.values.select{|v|v.class==Hash}.map{|i|
|
31
|
+
i[Type] && (i[Type].class==Array ? i[Type] : [i[Type]]).map{|t|t.respond_to?(:uri) && t.uri}.include?(DC+'Image') &&
|
32
|
+
[{_: :a, href: i.url, c: {_: :img, style:'float:left;max-width:61.8%', src: i.url}},
|
46
33
|
i.html]},
|
47
34
|
(H.css '/css/img')]}
|
48
35
|
|
49
36
|
fn 'view/th',->i,e{
|
50
|
-
i.map{|u,i| u.match(/(gif|jpe?g|png|tiff)$/i) &&
|
51
|
-
{_: :a, href: i.url+'?
|
37
|
+
i.map{|u,i| u && u.match(/(gif|jpe?g|png|tiff)$/i) &&
|
38
|
+
{_: :a, href: i.url+'?view=img',
|
52
39
|
c: {_: :img, src: i.url+'?y=scaleImage&px=233'}}}}
|
53
40
|
|
54
41
|
F['view/'+MIMEtype+'image/gif'] = F['view/th']
|
@@ -56,40 +43,43 @@ class E
|
|
56
43
|
F['view/'+MIMEtype+'image/png'] = F['view/th']
|
57
44
|
|
58
45
|
# display just the images found in content
|
59
|
-
fn 'view/imgs',->m,e{
|
46
|
+
fn 'view/imgs',->m, e { seen = {}
|
60
47
|
|
61
|
-
# height argument
|
48
|
+
# optional height argument
|
62
49
|
h = e.q['h'].do{|h|
|
63
|
-
h.match(/^[0-9]+$/).do{|_|'height:'+h+'px'}}
|
64
|
-
|
65
|
-
# visited images
|
66
|
-
seen={}
|
50
|
+
h.match(/^[0-9]+$/).do{|_|'height:'+h+'px'}}||''
|
67
51
|
|
68
52
|
# extension-based filter
|
69
53
|
x=->i{i&&i.match(/(jpe?g|gif|png)$/i)&&i}
|
70
54
|
|
71
55
|
[(H.once e,:mu,H.js('/js/mu')),H.js('/js/images'),
|
72
56
|
m.values.map{|v|
|
73
|
-
# CSS
|
57
|
+
# CSS-selector search inside content
|
74
58
|
[[*v[Content]].map{|c| c.class == String &&
|
75
59
|
(Nokogiri::HTML.parse(c).do{|c|
|
60
|
+
|
76
61
|
[# <img> elements
|
77
62
|
c.css('img').map{|i|i['src']}.compact,
|
63
|
+
|
78
64
|
# <a> elements with image extensions
|
79
65
|
c.css('a').map{|i|i['href']}.select(&x)]
|
80
66
|
})},
|
67
|
+
|
81
68
|
# check subject URI for image extension
|
82
69
|
x.(v.uri),
|
70
|
+
|
83
71
|
# check object URIs for image extension
|
84
72
|
(v.respond_to?(:values) &&
|
85
73
|
v.values.flatten.map{|v|
|
86
74
|
v.respond_to?(:uri) && v.uri
|
87
75
|
}.select(&x))
|
76
|
+
|
88
77
|
].flatten.uniq.compact.map{|s|
|
89
78
|
# view
|
90
79
|
{uri: s,
|
91
80
|
# img and link to containing resource
|
92
81
|
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|
|
82
|
+
|
93
83
|
# show and mark as seen
|
94
84
|
!seen[i[:uri]] &&
|
95
85
|
(seen[i[:uri]] = true
|
@@ -1,18 +1,19 @@
|
|
1
|
-
|
1
|
+
watch __FILE__
|
2
2
|
class E
|
3
3
|
|
4
4
|
# POSIX-fs based index of triples
|
5
5
|
#
|
6
6
|
|
7
|
-
# index a triple
|
7
|
+
# index a triple
|
8
8
|
def index p,o
|
9
9
|
p = p.E
|
10
10
|
indexEdit p, (o.class == E ? o : p.literal(o)), nil
|
11
11
|
end
|
12
12
|
|
13
|
-
# index a triple - no
|
13
|
+
# index a triple - no type-normalization
|
14
14
|
def indexEdit p,o,a
|
15
15
|
return if @noIndex
|
16
|
+
# puts "index #{p} #{o} #{a}"
|
16
17
|
p.pIndex.noIndex[o,self,a]
|
17
18
|
end
|
18
19
|
def noIndex
|
@@ -22,6 +23,7 @@ class E
|
|
22
23
|
|
23
24
|
# reachable graph along named predicate
|
24
25
|
def walk p, g={}, v={}
|
26
|
+
# puts "walk #{uri}"
|
25
27
|
graph g # cumulative graph
|
26
28
|
v[uri] = true # visited mark
|
27
29
|
|
@@ -38,38 +40,47 @@ class E
|
|
38
40
|
fn 'set/subtree',->d,r,m{
|
39
41
|
c =(r['c'].do{|c|c.to_i + 1} || 3).max(100) # one extra for start of next-page
|
40
42
|
o = r['d'] =~ /^a/ ? :asc : :desc # direction
|
43
|
+
|
41
44
|
('/'.E.take c, o, d.uri).do{|s| # take subtree
|
42
45
|
desc, asc = o == :desc ? # orient pagination hints
|
43
46
|
[s.pop, s[0]] : [s[0], s.pop]
|
44
|
-
m['
|
45
|
-
|
47
|
+
u = m['#']
|
48
|
+
u[Type] = E[HTTP+'Response']
|
49
|
+
u[Prev] = {'uri' => desc.url + {'d' => 'desc'}.qs} if desc
|
50
|
+
u[Next] = {'uri' => asc.url + {'d' => 'asc'}.qs} if asc
|
46
51
|
s }}
|
47
52
|
|
48
53
|
# subtree traverse index on p+o cursor
|
49
|
-
fn 'set/index',->d,r,m
|
50
|
-
top =
|
54
|
+
fn 'set/index',->d,r,m{
|
55
|
+
top = r['p'].expand.E
|
51
56
|
count = r['c'] &&
|
52
|
-
r['c'].to_i.max(1000)
|
53
|
-
dir = r['d'] &&
|
54
|
-
r['d'].
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
57
|
+
r['c'].to_i.max(1000) || 8
|
58
|
+
dir = r['d'] && r['d'].match(/^(a|de)sc$/) &&
|
59
|
+
r['d'].to_sym || :desc
|
60
|
+
|
61
|
+
(top.rangePO count+1, dir, r['offset'], r['o']).do{|s|
|
62
|
+
# orient pagination pointers
|
63
|
+
ascending = r['d'].do{|d| d == 'asc' }
|
64
|
+
first, last = s[0], s.size > 1 && s.pop
|
65
|
+
desc, asc = ascending && [first,last] || [last,first]
|
66
|
+
# response description
|
67
|
+
u = m['#']
|
68
|
+
u[RDFs+'member'] = s
|
69
|
+
u[Prev] = {'uri' => '/index/' + r['p'] + '/' + CGI.escape(r['o']) + {'offset' => desc.uri, 'c' => count}.qs } if desc
|
70
|
+
u[Next] = {'uri' => '/index/' + r['p'] + '/' + CGI.escape(r['o']) + {'offset' => asc.uri, 'c' => count}.qs } if asc
|
71
|
+
|
72
|
+
s.map(&:docs).flatten.uniq }}
|
66
73
|
|
67
|
-
fn '
|
68
|
-
|
74
|
+
fn '/index/GET',->e,r{
|
75
|
+
a = e.pathSegment.uri[7..-1].split '/',2
|
76
|
+
r.q['set'] = 'index'
|
77
|
+
r.q['p'] = a[0]
|
78
|
+
r.q['o'] = CGI.unescape a[1]
|
79
|
+
e.response}
|
69
80
|
|
70
81
|
# predicate index
|
71
82
|
def pIndex
|
72
|
-
prependURI '/index/'
|
83
|
+
shorten.prependURI '/index/'
|
73
84
|
end
|
74
85
|
|
75
86
|
# predicate-object index
|
@@ -83,8 +94,8 @@ class E
|
|
83
94
|
end
|
84
95
|
|
85
96
|
# range query - predicate
|
86
|
-
def rangeP
|
87
|
-
pIndex.subtree(
|
97
|
+
def rangeP size=8, dir=:desc, offset=nil, object=nil
|
98
|
+
pIndex.subtree(size,dir,offset).map &:ro
|
88
99
|
end
|
89
100
|
|
90
101
|
# range query - predicate-object
|
@@ -102,32 +113,17 @@ class E
|
|
102
113
|
no.take(*a).map &:E
|
103
114
|
end
|
104
115
|
|
105
|
-
# random leaf
|
106
116
|
def randomLeaf
|
107
117
|
c.empty? && self || c.r.randomLeaf
|
108
118
|
end
|
109
119
|
|
120
|
+
def E.graphProperties g
|
121
|
+
g.values.select{|v|v.respond_to? :keys}.map(&:keys).flatten.uniq
|
122
|
+
end
|
123
|
+
|
110
124
|
fn 'set/randomLeaf',->d,e,m{[d.randomLeaf]}
|
111
125
|
fn 'req/randomLeaf',->e,r{[302, {Location: e.randomLeaf.uri},[]]}
|
112
126
|
|
113
|
-
|
114
|
-
# enumerate unique predicates in index
|
115
|
-
fn '/index/GET',->e,r{
|
116
|
-
e.pathSegment.uri.match(/^\/index$/) &&
|
117
|
-
(H [{_: :style, c: "a {font-size:3em;display:block}
|
118
|
-
a:hover {background-color:#00f}"},
|
119
|
-
'/index'.E.take.map{|e|e.uri[6..-1].unpath.do{|p|{_: :a, href: '/@'+URI.escape(p.uri)+'?set=indexP&view=page&v=linkPO&c=12', c: p}}}]).hR}
|
120
|
-
|
121
|
-
# p/o index-traversal pointers
|
122
|
-
fn 'view/linkPO',->d,e{
|
123
|
-
p = e['uri']
|
124
|
-
[(H.css '/css/index'),(H.js '/js/search'),{_: :b, c: p},
|
125
|
-
# front-end to search on SIOC predicate+object URIs
|
126
|
-
%w{sioc:has_creator sioc:addressed_to}.member?(p).do{|_|
|
127
|
-
{_: :form, action: '/whois',c: [{_: :input, type: :hidden, name: :p, value: p},{_: :input, name: :q}]}
|
128
|
-
},
|
129
|
-
d.map{|u,r| {c: {_: :a, href: r.url+'?set=indexPO&p=' + (URI.escape p) + '&view=page&views=timegraph,mail&v=multi&c=8', c: u}}}]}
|
130
|
-
|
131
127
|
end
|
132
128
|
|
133
129
|
|
@@ -137,7 +133,7 @@ class Pathname
|
|
137
133
|
def take count=1000, direction=:desc, offset=nil
|
138
134
|
|
139
135
|
# construct offset-path
|
140
|
-
offset = to_s + offset.gsub(/\/+/,'/').E.path if offset
|
136
|
+
offset = (to_s + offset).gsub(/\/+/,'/').E.path if offset
|
141
137
|
|
142
138
|
# in-range indicator
|
143
139
|
ok = false
|
@@ -151,7 +147,7 @@ class Pathname
|
|
151
147
|
|
152
148
|
# visitation function
|
153
149
|
visit=->nodes{
|
154
|
-
|
150
|
+
|
155
151
|
# sort nodes in asc or desc order
|
156
152
|
nodes.sort_by(&:to_s).send(v).each{|n|
|
157
153
|
ns = n.to_s
|
@@ -174,8 +170,7 @@ class Pathname
|
|
174
170
|
ok = true # iterator is now within range
|
175
171
|
end )}}
|
176
172
|
|
177
|
-
visit.(c) # start
|
178
|
-
|
173
|
+
visit.(c) # start
|
179
174
|
# result set
|
180
175
|
set
|
181
176
|
end
|
data/infod/infod.rb
CHANGED
@@ -1,12 +1,51 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
1
|
+
%w{
|
2
|
+
constants
|
3
|
+
lambda
|
4
|
+
mime
|
5
|
+
404
|
6
|
+
500
|
7
|
+
audio
|
8
|
+
blog
|
9
|
+
cal
|
10
|
+
code
|
11
|
+
css
|
12
|
+
csv
|
13
|
+
du
|
14
|
+
edit
|
15
|
+
facets
|
16
|
+
feed
|
17
|
+
find
|
18
|
+
forum
|
19
|
+
fs
|
20
|
+
GET
|
21
|
+
glob
|
22
|
+
graph
|
23
|
+
grep
|
24
|
+
groonga
|
25
|
+
HEAD
|
26
|
+
histogram
|
27
|
+
html
|
28
|
+
HTTP
|
29
|
+
image
|
30
|
+
index
|
31
|
+
json
|
32
|
+
kv
|
33
|
+
ls
|
34
|
+
mail
|
35
|
+
man
|
36
|
+
microblog
|
37
|
+
names
|
38
|
+
page
|
39
|
+
PATCH
|
40
|
+
POST
|
41
|
+
postscript
|
42
|
+
rdf
|
43
|
+
ruby
|
44
|
+
schema
|
45
|
+
search
|
46
|
+
sh
|
47
|
+
text
|
48
|
+
threads
|
49
|
+
time
|
50
|
+
wiki
|
51
|
+
}.map{|e|require_relative e}
|
data/infod/json.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
class Hash
|
2
|
+
|
3
|
+
def graph g
|
4
|
+
g.merge!({uri=>self})
|
5
|
+
end
|
6
|
+
|
7
|
+
def mergeGraph g
|
8
|
+
g.triples{|s,p,o|
|
9
|
+
self[s] = {'uri' => s} unless self[s].class == Hash
|
10
|
+
self[s][p] ||= []
|
11
|
+
self[s][p].push o unless self[s][p].member? o } if g
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
# self -> tripleStream
|
16
|
+
def triples &f
|
17
|
+
map{|s,r|
|
18
|
+
r.map{|p,o|
|
19
|
+
o.class == Array ? o.each{|o| yield s,p,o} : yield(s,p,o) unless p=='uri'} if r.class == Hash
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class E
|
26
|
+
|
27
|
+
def triplrJSON
|
28
|
+
yield uri, '/application/json', (JSON.parse read) if e
|
29
|
+
rescue Exception => e
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_json *a
|
33
|
+
to_h.to_json *a
|
34
|
+
end
|
35
|
+
|
36
|
+
fn Render+'application/json',->d,_=nil{[d].to_json}
|
37
|
+
|
38
|
+
end
|
data/infod/{Es/kv.rb → kv.rb}
RENAMED
@@ -27,17 +27,11 @@ class E
|
|
27
27
|
unless t.e # triple exists?
|
28
28
|
indexEdit p,o,nil # index triple
|
29
29
|
if o.f # add triple
|
30
|
-
# link
|
31
|
-
# puts "link #{o} #{t}"
|
32
|
-
o.ln t
|
30
|
+
o.ln t # hard link
|
33
31
|
elsif o.e
|
34
|
-
#
|
35
|
-
# puts "symlink #{o} #{t}"
|
36
|
-
o.ln_s t
|
32
|
+
o.ln_s t # symbolic link
|
37
33
|
else
|
38
|
-
#
|
39
|
-
puts "origin missing #{t} , adding URI ref"
|
40
|
-
t.mk
|
34
|
+
t.mk # dir entry
|
41
35
|
end
|
42
36
|
end
|
43
37
|
end
|
data/infod/{Y.rb → lambda.rb}
RENAMED
@@ -5,6 +5,20 @@ def watch f
|
|
5
5
|
|
6
6
|
class E
|
7
7
|
|
8
|
+
def initialize uri
|
9
|
+
@uri = uri.to_s
|
10
|
+
end
|
11
|
+
|
12
|
+
def E arg=nil
|
13
|
+
if arg
|
14
|
+
E.new arg
|
15
|
+
else
|
16
|
+
self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def E.[] u; u.E end
|
21
|
+
|
8
22
|
F={}
|
9
23
|
Watch={}
|
10
24
|
|
@@ -29,6 +43,9 @@ def fn u,y
|
|
29
43
|
end
|
30
44
|
|
31
45
|
def Fn a,*g
|
32
|
-
puts "missing #{a} from #{caller[0]}" unless E::F[a]
|
33
46
|
E::F[a][*g]
|
34
47
|
end
|
48
|
+
|
49
|
+
def E e
|
50
|
+
E.new e
|
51
|
+
end
|
data/infod/ls.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#watch __FILE__
|
2
|
+
class E
|
3
|
+
|
4
|
+
fn 'view/dir',->i,e{
|
5
|
+
a = -> i { i = i.E
|
6
|
+
{_: :a, href: i.localURL(e), c: i.uri.match(/(gif|jpe?g|png)$/i) ? {_: :img, src: i.uri+'?y=scaleImage&px=233'} : i.uri.sub(/.*\//,'')}}
|
7
|
+
|
8
|
+
[(H.once e, 'dir', (H.css '/css/ls')),
|
9
|
+
i.map{|u,r|
|
10
|
+
url = r.E.localURL e
|
11
|
+
{class: :dir, style: "background-color: #{E.cs}", # dir wrapper
|
12
|
+
c: [{c: [{_: :a, href: url.t + '?view=ls', c: r.uri.sub('http://'+e['SERVER_NAME'],'')},
|
13
|
+
{_: :a, href: url.t, c: '/'}]},
|
14
|
+
r[Posix+'dir#child'].do{|c|c.map{|c|a[c]}}]}}]}
|
15
|
+
|
16
|
+
F['view/'+MIMEtype+'inode/directory'] = F['view/dir']
|
17
|
+
|
18
|
+
fn 'view/ls',->i,e{
|
19
|
+
dir = e['uri'].E
|
20
|
+
path = dir.pathSegment
|
21
|
+
up = (!path || path.uri == '/') ? '/' : dir.parent.url
|
22
|
+
i = i.dup
|
23
|
+
i.delete_if{|u,r|!r[Stat+'ftype']}
|
24
|
+
f = {}
|
25
|
+
['uri', Posix+'dir#child', Stat+'ftype', Stat+'mtime', Stat+'size'].map{|p|f[p] = true}
|
26
|
+
i.values.map{|r|
|
27
|
+
r.class==Hash &&
|
28
|
+
r.delete_if{|p,o|!f[p]}}
|
29
|
+
[(H.css '/css/ls'),
|
30
|
+
{_: :a, class: :up, href: up+'?view=ls', c: '↑'},
|
31
|
+
{class: :ls, c: (Fn 'view/table',i,e)},'<br clear=all>',
|
32
|
+
{_: :a, class: :down, href: e['uri'].E.url.t, c: '↓'}]}
|
33
|
+
|
34
|
+
# user-patchable default-handler
|
35
|
+
fn '/GET',->e,r{
|
36
|
+
x = 'index.html'
|
37
|
+
i = [e,e.pathSegment].compact.map{|e|e.as x}.find &:e
|
38
|
+
if i
|
39
|
+
if e.uri[-1] == '/' # inside dir?
|
40
|
+
i.env(r).getFile # show index
|
41
|
+
else # descend to indexed dir
|
42
|
+
[301, {Location: e.uri.t}, []]
|
43
|
+
end
|
44
|
+
else
|
45
|
+
# default handler
|
46
|
+
e.response
|
47
|
+
end}
|
48
|
+
|
49
|
+
end
|