infod 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/infod.rb +52 -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 +123 -0
- data/infod/{Es/grep.rb → grep.rb} +2 -2
- data/infod/{Es/groonga.rb → groonga.rb} +41 -33
- 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} +38 -25
- data/infod/infod.rb +52 -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 +90 -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} +78 -45
- 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} +22 -7
- 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} +17 -27
- data/infod/{H/time.rb → time.rb} +14 -34
- data/infod/{H/who.rb → whois.rb} +6 -4
- data/infod/{H/wiki.rb → wiki.rb} +0 -0
- metadata +54 -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/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
|
@@ -4,13 +4,13 @@ class E
|
|
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
16
|
p.pIndex.noIndex[o,self,a]
|
@@ -22,6 +22,7 @@ class E
|
|
22
22
|
|
23
23
|
# reachable graph along named predicate
|
24
24
|
def walk p, g={}, v={}
|
25
|
+
# puts "walk #{uri}"
|
25
26
|
graph g # cumulative graph
|
26
27
|
v[uri] = true # visited mark
|
27
28
|
|
@@ -38,16 +39,19 @@ class E
|
|
38
39
|
fn 'set/subtree',->d,r,m{
|
39
40
|
c =(r['c'].do{|c|c.to_i + 1} || 3).max(100) # one extra for start of next-page
|
40
41
|
o = r['d'] =~ /^a/ ? :asc : :desc # direction
|
42
|
+
|
41
43
|
('/'.E.take c, o, d.uri).do{|s| # take subtree
|
42
44
|
desc, asc = o == :desc ? # orient pagination hints
|
43
45
|
[s.pop, s[0]] : [s[0], s.pop]
|
44
|
-
m['
|
45
|
-
|
46
|
+
u = m['#']
|
47
|
+
u[Type] = E[HTTP+'Response']
|
48
|
+
u[Prev] = {'uri' => desc.url + {'d' => 'desc'}.qs} if desc
|
49
|
+
u[Next] = {'uri' => asc.url + {'d' => 'asc'}.qs} if asc
|
46
50
|
s }}
|
47
51
|
|
48
52
|
# subtree traverse index on p+o cursor
|
49
53
|
fn 'set/index',->d,r,m,f=:rangePO{
|
50
|
-
top = (f == :rangeP ? d : r['p']).expand.E
|
54
|
+
top = (f == :rangeP ? d : (r['p'] || '/')).expand.E
|
51
55
|
count = r['c'] &&
|
52
56
|
r['c'].to_i.max(1000)+1 || 22
|
53
57
|
dir = r['d'] &&
|
@@ -56,20 +60,25 @@ class E
|
|
56
60
|
:desc
|
57
61
|
|
58
62
|
(top.send f, count, dir, r['offset'],(d if f == :rangePO)).do{|s|
|
59
|
-
# pagination pointers
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
63
|
+
# orient pagination pointers
|
64
|
+
ascending = r['d'].do{|d| d == 'asc' }
|
65
|
+
first, last = s[0], s.size > 1 && s.pop
|
66
|
+
desc, asc = ascending && [first,last] || [last,first]
|
67
|
+
|
68
|
+
# response description
|
69
|
+
u = m['#']
|
70
|
+
u[RDFs+'member'] = s
|
71
|
+
u[Prev] = {'uri' => d.url + {'d' => 'desc','offset' => desc.uri}.qs} if desc
|
72
|
+
u[Next] = {'uri' => d.url + {'d' => 'asc', 'offset' => asc.uri}.qs} if asc
|
73
|
+
|
74
|
+
s.map(&:docs).flatten.uniq }}
|
66
75
|
|
67
76
|
fn 'set/indexP',->d,r,m{Fn 'set/index',d,r,m,:rangeP}
|
68
|
-
|
77
|
+
F['set/indexPO'] = F['set/index']
|
69
78
|
|
70
79
|
# predicate index
|
71
80
|
def pIndex
|
72
|
-
prependURI '/index/'
|
81
|
+
shorten.prependURI '/index/'
|
73
82
|
end
|
74
83
|
|
75
84
|
# predicate-object index
|
@@ -83,8 +92,8 @@ class E
|
|
83
92
|
end
|
84
93
|
|
85
94
|
# range query - predicate
|
86
|
-
def rangeP
|
87
|
-
pIndex.subtree(
|
95
|
+
def rangeP size=8, dir=:desc, offset=nil, object=nil
|
96
|
+
pIndex.subtree(size,dir,offset).map &:ro
|
88
97
|
end
|
89
98
|
|
90
99
|
# range query - predicate-object
|
@@ -102,23 +111,25 @@ class E
|
|
102
111
|
no.take(*a).map &:E
|
103
112
|
end
|
104
113
|
|
105
|
-
# random leaf
|
106
114
|
def randomLeaf
|
107
115
|
c.empty? && self || c.r.randomLeaf
|
108
116
|
end
|
109
117
|
|
118
|
+
def E.graphProperties g
|
119
|
+
g.values.select{|v|v.respond_to? :keys}.map(&:keys).flatten.uniq
|
120
|
+
end
|
121
|
+
|
110
122
|
fn 'set/randomLeaf',->d,e,m{[d.randomLeaf]}
|
111
123
|
fn 'req/randomLeaf',->e,r{[302, {Location: e.randomLeaf.uri},[]]}
|
112
124
|
|
113
|
-
|
114
125
|
# enumerate unique predicates in index
|
115
126
|
fn '/index/GET',->e,r{
|
116
127
|
e.pathSegment.uri.match(/^\/index$/) &&
|
117
128
|
(H [{_: :style, c: "a {font-size:3em;display:block}
|
118
129
|
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&
|
130
|
+
'/index'.E.take.map{|e|e.uri[6..-1].unpath.do{|p|{_: :a, href: '/@'+URI.escape(p.uri)+'?set=indexP&c=12', c: p}}}]).hR}
|
120
131
|
|
121
|
-
# p
|
132
|
+
# p+o index-traversal pointers
|
122
133
|
fn 'view/linkPO',->d,e{
|
123
134
|
p = e['uri']
|
124
135
|
[(H.css '/css/index'),(H.js '/js/search'),{_: :b, c: p},
|
@@ -126,7 +137,10 @@ a:hover {background-color:#00f}"},
|
|
126
137
|
%w{sioc:has_creator sioc:addressed_to}.member?(p).do{|_|
|
127
138
|
{_: :form, action: '/whois',c: [{_: :input, type: :hidden, name: :p, value: p},{_: :input, name: :q}]}
|
128
139
|
},
|
129
|
-
|
140
|
+
# set members
|
141
|
+
d['#'][RDFs+'member'].do{|m|
|
142
|
+
m.map{|r|
|
143
|
+
{c: {_: :a, href: r.url+'?set=indexPO&p=' + (URI.escape p) + '&c=8', c: r.uri}}}}]}
|
130
144
|
|
131
145
|
end
|
132
146
|
|
@@ -137,7 +151,7 @@ class Pathname
|
|
137
151
|
def take count=1000, direction=:desc, offset=nil
|
138
152
|
|
139
153
|
# construct offset-path
|
140
|
-
offset = to_s + offset.gsub(/\/+/,'/').E.path if offset
|
154
|
+
offset = (to_s + offset).gsub(/\/+/,'/').E.path if offset
|
141
155
|
|
142
156
|
# in-range indicator
|
143
157
|
ok = false
|
@@ -151,7 +165,7 @@ class Pathname
|
|
151
165
|
|
152
166
|
# visitation function
|
153
167
|
visit=->nodes{
|
154
|
-
|
168
|
+
|
155
169
|
# sort nodes in asc or desc order
|
156
170
|
nodes.sort_by(&:to_s).send(v).each{|n|
|
157
171
|
ns = n.to_s
|
@@ -174,8 +188,7 @@ class Pathname
|
|
174
188
|
ok = true # iterator is now within range
|
175
189
|
end )}}
|
176
190
|
|
177
|
-
visit.(c) # start
|
178
|
-
|
191
|
+
visit.(c) # start
|
179
192
|
# result set
|
180
193
|
set
|
181
194
|
end
|
data/infod/infod.rb
CHANGED
@@ -1,12 +1,52 @@
|
|
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
|
+
whois
|
51
|
+
wiki
|
52
|
+
}.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
|