nitro 0.3.0 → 0.4.1
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/ChangeLog +284 -0
- data/{LICENCE → LICENSE} +1 -1
- data/README +13 -17
- data/RELEASES +13 -1
- data/Rakefile +1 -9
- data/bin/cluster.rb +5 -5
- data/examples/blog/README +45 -0
- data/examples/blog/apache.conf +0 -0
- data/examples/blog/app.rb +21 -0
- data/examples/blog/config.rb +88 -0
- data/examples/blog/lib/blog.rb +104 -0
- data/examples/blog/log/app.log +117 -0
- data/examples/blog/root/comments.xhtml +38 -0
- data/examples/blog/root/entry_form.xhtml +18 -0
- data/examples/blog/root/index.xhtml +43 -0
- data/examples/blog/root/login.xhtml +24 -0
- data/examples/blog/root/m/bubbles.gif +0 -0
- data/examples/blog/root/m/comments_curve.gif +0 -0
- data/examples/blog/root/m/down.gif +0 -0
- data/examples/blog/root/m/footer_bg.gif +0 -0
- data/examples/blog/root/m/garrow.gif +0 -0
- data/examples/blog/root/m/gbull.gif +0 -0
- data/examples/blog/root/m/grbull.gif +0 -0
- data/examples/blog/root/m/h1_bg.gif +0 -0
- data/examples/blog/root/m/header_bg.gif +0 -0
- data/examples/blog/root/m/obull.gif +0 -0
- data/examples/blog/root/m/page_bg.gif +0 -0
- data/examples/blog/root/m/side_title_bg.gif +0 -0
- data/examples/blog/root/m/sidebar_bg.gif +0 -0
- data/examples/blog/root/recent_posts.xhtml +14 -0
- data/examples/blog/root/style.css +201 -0
- data/examples/blog/root/style.xsl +118 -0
- data/examples/blog/root/view_entry.xhtml +29 -0
- data/examples/og/run.rb +27 -29
- data/examples/tiny/README +3 -4
- data/examples/tiny/app.rb +6 -16
- data/examples/tiny/config.rb +30 -0
- data/examples/tiny/log/app.log +23 -0
- data/examples/tiny/root/{index.sx → index.xhtml} +3 -6
- data/lib/{n/std.rb → nitro.rb} +9 -4
- data/lib/{n → nitro}/application.rb +13 -7
- data/lib/{n → nitro}/config.rb +38 -8
- data/lib/{n → nitro}/events.rb +1 -1
- data/lib/{n → nitro}/l10n.rb +1 -1
- data/lib/{n → nitro}/logger.rb +8 -8
- data/lib/{n → nitro}/macros.rb +3 -3
- data/lib/{n → nitro}/mixins.rb +1 -1
- data/lib/nitro/properties.rb +301 -0
- data/lib/{n → nitro}/server.rb +2 -2
- data/lib/{n → nitro}/server/appserver.rb +14 -5
- data/lib/{n → nitro}/server/cluster.rb +5 -5
- data/lib/{n → nitro}/server/cookie.rb +1 -1
- data/lib/nitro/server/dispatcher.rb +66 -0
- data/lib/{n → nitro}/server/filters.rb +7 -7
- data/lib/{n → nitro}/server/filters/autologin.rb +3 -3
- data/lib/{n → nitro}/server/fragment.rb +3 -3
- data/lib/{n → nitro}/server/handlers.rb +3 -3
- data/lib/nitro/server/render.rb +200 -0
- data/lib/{n → nitro}/server/request.rb +6 -6
- data/lib/{n → nitro}/server/requestpart.rb +5 -5
- data/lib/{n → nitro}/server/script.rb +3 -3
- data/lib/{n → nitro}/server/server.rb +4 -4
- data/lib/{n → nitro}/server/session.rb +3 -3
- data/lib/nitro/server/shaders.rb +165 -0
- data/lib/{n → nitro}/server/user.rb +1 -1
- data/lib/nitro/server/webrick.rb +175 -0
- data/lib/nitro/service.rb +25 -0
- data/lib/{n → nitro}/sitemap.rb +2 -2
- data/lib/{n → nitro}/ui/date-select.rb +0 -0
- data/lib/{n → nitro}/ui/pager.rb +1 -1
- data/lib/{n → nitro}/ui/popup.rb +1 -1
- data/lib/{n → nitro}/ui/select.rb +1 -1
- data/lib/{n → nitro}/ui/tabs.rb +1 -1
- data/lib/{n → nitro}/utils/array.rb +1 -1
- data/lib/{n → nitro}/utils/cache.rb +1 -1
- data/lib/{n → nitro}/utils/gfx.rb +1 -1
- data/lib/{n → nitro}/utils/hash.rb +1 -1
- data/lib/{n → nitro}/utils/html.rb +1 -1
- data/lib/{n → nitro}/utils/http.rb +1 -1
- data/lib/{n → nitro}/utils/mail.rb +1 -1
- data/lib/{n → nitro}/utils/number.rb +1 -1
- data/lib/{n → nitro}/utils/pool.rb +1 -1
- data/lib/{n → nitro}/utils/string.rb +19 -95
- data/lib/{n → nitro}/utils/template.rb +0 -0
- data/lib/{n → nitro}/utils/time.rb +1 -1
- data/lib/{n → nitro}/utils/uri.rb +3 -3
- data/lib/nitro/version.rb +11 -0
- data/lib/{n/og.rb → og.rb} +61 -31
- data/lib/{n/og → og}/backend.rb +13 -7
- data/lib/{n/og → og}/backends/mysql.rb +43 -39
- data/lib/{n/og → og}/backends/psql.rb +42 -38
- data/lib/{n/og → og}/connection.rb +21 -9
- data/lib/{n/og → og}/meta.rb +18 -12
- data/lib/xsl/base.xsl +11 -88
- data/test/n/server/tc_cookie.rb +1 -1
- data/test/n/server/tc_filters.rb +1 -1
- data/test/n/server/tc_request.rb +3 -3
- data/test/n/server/tc_requestpart.rb +2 -2
- data/test/n/server/tc_session.rb +1 -1
- data/test/n/tc_events.rb +1 -1
- data/test/n/tc_og.rb +16 -18
- data/test/n/tc_properties.rb +22 -18
- data/test/n/tc_sitemap.rb +2 -2
- data/test/n/ui/tc_pager.rb +4 -4
- data/test/n/utils/tc_cache.rb +1 -1
- data/test/n/utils/tc_hash.rb +1 -1
- data/test/n/utils/tc_html.rb +1 -1
- data/test/n/utils/tc_http.rb +1 -1
- data/test/n/utils/tc_number.rb +1 -1
- data/test/n/utils/tc_strings.rb +1 -46
- data/test/n/utils/tc_uri.rb +1 -1
- metadata +101 -108
- data/examples/simple/README +0 -42
- data/examples/simple/app.rb +0 -31
- data/examples/simple/conf/apache.conf +0 -100
- data/examples/simple/conf/config.rb +0 -72
- data/examples/simple/conf/debug-config.rb +0 -26
- data/examples/simple/conf/live-config.rb +0 -26
- data/examples/simple/conf/requires.rb +0 -43
- data/examples/simple/ctl +0 -32
- data/examples/simple/env.rb +0 -32
- data/examples/simple/install.rb +0 -12
- data/examples/simple/lib/articles/entities.rb +0 -37
- data/examples/simple/lib/articles/lc-en.rb +0 -36
- data/examples/simple/lib/articles/methods.rb +0 -55
- data/examples/simple/lib/articles/part.rb +0 -57
- data/examples/simple/root/add-article.sx +0 -15
- data/examples/simple/root/article-form.ss +0 -20
- data/examples/simple/root/comments-form.ss +0 -16
- data/examples/simple/root/comments.si +0 -30
- data/examples/simple/root/index.sx +0 -44
- data/examples/simple/root/shader/shader.xsl +0 -100
- data/examples/simple/root/shader/style.css +0 -9
- data/examples/simple/root/view-article.sx +0 -29
- data/examples/tiny/conf/config.rb +0 -62
- data/examples/tiny/conf/requires.rb +0 -33
- data/examples/tiny/ctl +0 -16
- data/lib/n/parts.rb +0 -157
- data/lib/n/properties.rb +0 -199
- data/lib/n/server/dispatcher.rb +0 -55
- data/lib/n/server/handlers/code-handler.rb +0 -182
- data/lib/n/server/handlers/page-handler.rb +0 -612
- data/lib/n/server/webrick.rb +0 -283
- data/lib/n/shaders.rb +0 -166
- data/lib/n/sync/clc.rb +0 -110
- data/lib/n/sync/handler.rb +0 -229
- data/lib/n/sync/server.rb +0 -176
- data/lib/p/README +0 -1
data/lib/n/sync/handler.rb
DELETED
@@ -1,229 +0,0 @@
|
|
1
|
-
# code:
|
2
|
-
# * George Moschovitis <gm@navel.gr>
|
3
|
-
# * Anastasios Koutoumanos <ak@navel.gr>
|
4
|
-
#
|
5
|
-
# (c) 2004 Navel, all rights reserved.
|
6
|
-
# $Id: handler.rb 101 2004-10-22 12:35:39Z gmosx $
|
7
|
-
|
8
|
-
require "timeout"
|
9
|
-
require "n/server"
|
10
|
-
|
11
|
-
module N; module Sync
|
12
|
-
|
13
|
-
class HandlerExitException < Exception; end
|
14
|
-
|
15
|
-
# = Handler
|
16
|
-
#
|
17
|
-
# Sync Server Handler
|
18
|
-
#
|
19
|
-
# === Design:
|
20
|
-
#
|
21
|
-
# Override this to create your handler. A handler can
|
22
|
-
# act as a multiplexer to implement multiple services per server.
|
23
|
-
#
|
24
|
-
class Handler
|
25
|
-
SEPARATOR = "\000"
|
26
|
-
|
27
|
-
# socket timeout in seconds
|
28
|
-
@@socket_timeout = 30
|
29
|
-
|
30
|
-
# handler timeout in seconds
|
31
|
-
@@handler_timeout = 60 * 60
|
32
|
-
|
33
|
-
attr :server, :socket
|
34
|
-
|
35
|
-
attr :thread, :touch_time
|
36
|
-
|
37
|
-
# status
|
38
|
-
attr_accessor :status
|
39
|
-
|
40
|
-
STATUS_IDLE = 0
|
41
|
-
STATUS_RUNNING = 10
|
42
|
-
STATUS_STOPPED = 20
|
43
|
-
|
44
|
-
def initialize(server, socket)
|
45
|
-
@server, @socket = server, socket
|
46
|
-
end
|
47
|
-
|
48
|
-
# Called when the handler starts.
|
49
|
-
#
|
50
|
-
def start
|
51
|
-
touch!
|
52
|
-
@thread = Thread.new(&method("run").to_proc)
|
53
|
-
end
|
54
|
-
|
55
|
-
# Called when the handler stops.
|
56
|
-
#
|
57
|
-
def stop
|
58
|
-
unless STATUS_STOPPED == @status
|
59
|
-
@status = STATUS_STOPPED
|
60
|
-
$log.debug "Stoping handler" if $DBG
|
61
|
-
|
62
|
-
begin
|
63
|
-
@socket.close()
|
64
|
-
rescue Exception, StandardError => e
|
65
|
-
# gmosx: this is needed to be FAULT TOLERANT
|
66
|
-
# DRINK IT!
|
67
|
-
$log.error "Cannot close exception when stoping handler."
|
68
|
-
end
|
69
|
-
|
70
|
-
# gmosx: why not? more FAULT TOLERANT.
|
71
|
-
@server.handlers.delete_if {|h| STATUS_STOPPED == h.status}
|
72
|
-
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
# called by the garbage collector.
|
77
|
-
#
|
78
|
-
def gc!
|
79
|
-
@thread.raise HandlerExitException.new()
|
80
|
-
end
|
81
|
-
|
82
|
-
# Perform the handler's action.
|
83
|
-
#
|
84
|
-
def run
|
85
|
-
@status = STATUS_RUNNING
|
86
|
-
|
87
|
-
while (STATUS_RUNNING == @status) and (not @socket.closed?)
|
88
|
-
begin
|
89
|
-
unless cmd = read()
|
90
|
-
$log.error "Client closed connection"
|
91
|
-
@status = STATUS_IDLE
|
92
|
-
else
|
93
|
-
touch!
|
94
|
-
handle(cmd.chop())
|
95
|
-
end
|
96
|
-
rescue HandlerExitException => ex
|
97
|
-
@status = STATUS_IDLE
|
98
|
-
$log.debug "Handler exit" if $DBG
|
99
|
-
rescue Exception, StandardError => ex
|
100
|
-
@status = STATUS_IDLE
|
101
|
-
$log.debug ex if $DBG
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
begin
|
106
|
-
stop()
|
107
|
-
rescue Exception, StandardError => e
|
108
|
-
# gmosx: this rescue block needed to get debug info!
|
109
|
-
#
|
110
|
-
$log.error pp_exception(e)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def touch!
|
115
|
-
@touch_time = Time.now()
|
116
|
-
end
|
117
|
-
|
118
|
-
def live?
|
119
|
-
return Time.now < @touch_time + @@handler_timeout
|
120
|
-
end
|
121
|
-
|
122
|
-
# Read xml from the socket
|
123
|
-
#
|
124
|
-
def read
|
125
|
-
return unless @status == STATUS_RUNNING
|
126
|
-
|
127
|
-
cmd = nil
|
128
|
-
|
129
|
-
# gmosx: no timeout here!
|
130
|
-
cmd = @socket.gets(SEPARATOR)
|
131
|
-
$log.debug "in: #{cmd}" if $DBG
|
132
|
-
|
133
|
-
return cmd
|
134
|
-
end
|
135
|
-
|
136
|
-
# Write xml to the socket
|
137
|
-
#
|
138
|
-
def write(cmd)
|
139
|
-
return unless @status == STATUS_RUNNING
|
140
|
-
|
141
|
-
$log.debug "out: #{cmd}" if $DBG
|
142
|
-
|
143
|
-
begin
|
144
|
-
timeout(@@socket_timeout) { @socket << "#{cmd}#{SEPARATOR}" }
|
145
|
-
rescue Exception, StandardError => e
|
146
|
-
# gmosx: the socket is invalid close the handler.
|
147
|
-
$log.error pp_exception(e)
|
148
|
-
stop()
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
# parse the xml commnad to create a ruby method call.
|
153
|
-
#
|
154
|
-
def parse(cmd)
|
155
|
-
return unless @status == STATUS_RUNNING
|
156
|
-
|
157
|
-
cmd = REXML::Document.new(cmd).root()
|
158
|
-
|
159
|
-
method = cmd.name().gsub(/-/, "_")
|
160
|
-
unless cmd.attributes.empty?
|
161
|
-
args = "(#{cmd.attributes.collect { |k, v| ":#{k.gsub(/-/, "_")} => '#{v}'" }.join(", ")})"
|
162
|
-
else
|
163
|
-
args = nil
|
164
|
-
end
|
165
|
-
|
166
|
-
return "cmd_#{method}#{args}"
|
167
|
-
end
|
168
|
-
|
169
|
-
# Generic handler.
|
170
|
-
#
|
171
|
-
def handle(cmd)
|
172
|
-
if cmd = parse(cmd)
|
173
|
-
$log.debug "exec: #{cmd}" if $DBG
|
174
|
-
begin
|
175
|
-
eval(cmd)
|
176
|
-
rescue => ex
|
177
|
-
$log.error ex
|
178
|
-
end
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
# Send to another handler
|
183
|
-
#
|
184
|
-
def send(cmd, handler)
|
185
|
-
handler.write(cmd)
|
186
|
-
end
|
187
|
-
|
188
|
-
# Broadcast to all handlers (clients)
|
189
|
-
#
|
190
|
-
def broadcast(cmd)
|
191
|
-
@server.broadcast(cmd)
|
192
|
-
end
|
193
|
-
|
194
|
-
# Broadcast to all other handlers (clients)
|
195
|
-
#
|
196
|
-
def broadcast_to_others(cmd)
|
197
|
-
for handler in @server.handlers
|
198
|
-
unless self == handler
|
199
|
-
handler.write(cmd)
|
200
|
-
end
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
# ------------------------------------------------------------------
|
205
|
-
|
206
|
-
def info(txt)
|
207
|
-
write(%|<info text="#{txt}" />|)
|
208
|
-
end
|
209
|
-
|
210
|
-
def error(txt)
|
211
|
-
write(%|<error text="#{txt}" />|)
|
212
|
-
end
|
213
|
-
|
214
|
-
# ------------------------------------------------------------------
|
215
|
-
# Commands
|
216
|
-
|
217
|
-
# A sample command
|
218
|
-
#
|
219
|
-
def cmd_ping(args)
|
220
|
-
cmd = %{<pong time="#{Time.now}"}
|
221
|
-
cmd += %{ challenge="#{args[:challenge]}"} if args
|
222
|
-
cmd += " />"
|
223
|
-
|
224
|
-
write(cmd)
|
225
|
-
end
|
226
|
-
|
227
|
-
end
|
228
|
-
|
229
|
-
end; end #modules
|
data/lib/n/sync/server.rb
DELETED
@@ -1,176 +0,0 @@
|
|
1
|
-
# code:
|
2
|
-
# * George Moschovitis <gm@navel.gr>
|
3
|
-
# * Anastasios Koutoumanos <ak@navel.gr>
|
4
|
-
#
|
5
|
-
# (c) 2004 Navel, all rights reserved.
|
6
|
-
# $Id: server.rb 101 2004-10-22 12:35:39Z gmosx $
|
7
|
-
|
8
|
-
require "thread"
|
9
|
-
require "socket"
|
10
|
-
require "rexml/document"
|
11
|
-
|
12
|
-
require "n/std"
|
13
|
-
require "n/application"
|
14
|
-
require "n/utils/array"
|
15
|
-
require "n/sync/handler"
|
16
|
-
|
17
|
-
module N; module Sync
|
18
|
-
|
19
|
-
# = Server
|
20
|
-
#
|
21
|
-
# A Synchronous server tha communicates with clients using
|
22
|
-
# application specific xml protocols. Typically communicates with
|
23
|
-
# Flash clients utilising the XmlSocket functionality to enable 'push'
|
24
|
-
# flash applications.
|
25
|
-
#
|
26
|
-
# The Macromedia XML Socket protocol is used, \000 is used as a eof
|
27
|
-
# marker. NO: the XML protocol is not really appropriate, better use
|
28
|
-
# a space optimized delimited ASCII protocol.
|
29
|
-
#
|
30
|
-
# === Design:
|
31
|
-
#
|
32
|
-
# Should support clustered operation: A cluster of servers is spawned.
|
33
|
-
# The client connects to one of the servers at random. The client sticks
|
34
|
-
# to the server. Each server considers the others as clients and
|
35
|
-
# rebroadcasts all the events.
|
36
|
-
#
|
37
|
-
# We keep one service per server for simplicity, if we need multiple
|
38
|
-
# services we can implement a multiplexer service (handler).
|
39
|
-
#
|
40
|
-
# === TODO:
|
41
|
-
#
|
42
|
-
# - Investigate if this server can be done with select.
|
43
|
-
#
|
44
|
-
class Server < N::Application
|
45
|
-
MONITOR_INTERVAL = 2 * 60
|
46
|
-
|
47
|
-
# a single tcp server accepts all tcp requests
|
48
|
-
attr :tcp_server
|
49
|
-
|
50
|
-
# the listening address/port for this server.
|
51
|
-
attr_reader :address, :port
|
52
|
-
|
53
|
-
# the handler class, used to instantiate handlers
|
54
|
-
attr :handler_class
|
55
|
-
|
56
|
-
# maximum number of clients to connect.
|
57
|
-
attr_accessor :max_handlers
|
58
|
-
|
59
|
-
# the handler list, all handler attached to the server.
|
60
|
-
attr_accessor :handlers
|
61
|
-
|
62
|
-
# status
|
63
|
-
attr_accessor :status
|
64
|
-
|
65
|
-
STATUS_IDLE = 0
|
66
|
-
STATUS_RUNNING = 10
|
67
|
-
STATUS_STOPPED = 20
|
68
|
-
|
69
|
-
def initialize(address = "localhost", port = 2121, handler_class = N::Sync::Handler, max_handlers = nil)
|
70
|
-
@address, @port = address, port
|
71
|
-
@max_handlers = max_handlers
|
72
|
-
@name, @title = "nsync", "Navel Sync"
|
73
|
-
@status = STATUS_IDLE
|
74
|
-
|
75
|
-
@handlers = N::SafeArray.new()
|
76
|
-
@handler_class = handler_class
|
77
|
-
|
78
|
-
super()
|
79
|
-
end
|
80
|
-
|
81
|
-
# Start the server.
|
82
|
-
#
|
83
|
-
def start()
|
84
|
-
# a single tcp server accepts all tcp requests
|
85
|
-
@tcp_server = TCPServer.new(address, port)
|
86
|
-
|
87
|
-
start_monitor()
|
88
|
-
run()
|
89
|
-
end
|
90
|
-
|
91
|
-
# Stop the server.
|
92
|
-
#
|
93
|
-
def stop()
|
94
|
-
@status = STATUS_STOPED
|
95
|
-
end
|
96
|
-
|
97
|
-
# Run the main loop of the server.
|
98
|
-
#
|
99
|
-
def run()
|
100
|
-
@status = STATUS_RUNNING
|
101
|
-
$log.info "Server is running."
|
102
|
-
|
103
|
-
begin
|
104
|
-
while (STATUS_RUNNING == @status)
|
105
|
-
socket = @tcp_server.accept()
|
106
|
-
$log.debug "Socket accepted" if $DBG
|
107
|
-
handler = @handler_class.new(self, socket)
|
108
|
-
handlers << handler
|
109
|
-
handler.start()
|
110
|
-
end
|
111
|
-
rescue Exception, StandardError => e
|
112
|
-
$log.error pp_exception(e)
|
113
|
-
# tml, FIXME:
|
114
|
-
# this is dangerous! make more FAULT TOLERANT!
|
115
|
-
end
|
116
|
-
|
117
|
-
@status = STATUS_IDLE
|
118
|
-
end
|
119
|
-
|
120
|
-
def shutdown()
|
121
|
-
end_monitor()
|
122
|
-
for handler in handlers
|
123
|
-
handler.stop()
|
124
|
-
end
|
125
|
-
Thread.exit()
|
126
|
-
end
|
127
|
-
|
128
|
-
# ------------------------------------------------------------------
|
129
|
-
|
130
|
-
def start_monitor
|
131
|
-
@monitor = Thread.new {
|
132
|
-
begin
|
133
|
-
while true
|
134
|
-
sleep(MONITOR_INTERVAL)
|
135
|
-
$log.debug "monitor beat -- #{@handlers.size()} handlers" if $DBG
|
136
|
-
|
137
|
-
for handler in @handlers
|
138
|
-
unless handler.live?
|
139
|
-
$log.info "Idle handler detected!"
|
140
|
-
handler.gc!()
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
rescue Exception, StandardError => e
|
145
|
-
$log.error pp_exception(e)
|
146
|
-
end
|
147
|
-
}
|
148
|
-
end
|
149
|
-
|
150
|
-
def end_monitor
|
151
|
-
Thread.kill(@monitor)
|
152
|
-
end
|
153
|
-
|
154
|
-
# ------------------------------------------------------------------
|
155
|
-
|
156
|
-
def send(cmd, handler)
|
157
|
-
handler.write(cmd)
|
158
|
-
end
|
159
|
-
|
160
|
-
def broadcast(cmd)
|
161
|
-
for handler in @handlers
|
162
|
-
handler.write(cmd)
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
end
|
167
|
-
|
168
|
-
if $0 == __FILE__
|
169
|
-
require "n/logger"
|
170
|
-
|
171
|
-
$log = Logger.new(STDERR)
|
172
|
-
Server.new().exec()
|
173
|
-
end
|
174
|
-
|
175
|
-
end; end #modules
|
176
|
-
|
data/lib/p/README
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Add Web Application Framework parts in this directory
|