waitress-core 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +4 -4
- data/LICENSE +21 -21
- data/Rakefile +17 -17
- data/bin/waitress +22 -22
- data/ext/Thanks.md +1 -1
- data/ext/waitress_http11/ext_help.h +15 -15
- data/ext/waitress_http11/extconf.rb +6 -6
- data/ext/waitress_http11/http11.c +532 -532
- data/ext/waitress_http11/http11_parser.c +1216 -1216
- data/ext/waitress_http11/http11_parser.h +49 -49
- data/ext/waitress_http11/http11_parser.java.rl +171 -171
- data/ext/waitress_http11/http11_parser.rl +165 -165
- data/ext/waitress_http11/http11_parser_common.rl +55 -55
- data/ext/waitress_http11/http11_wrb_parser.h +91 -91
- data/lib/waitress.rb +100 -99
- data/lib/waitress/chef.rb +113 -113
- data/lib/waitress/configure.rb +127 -121
- data/lib/waitress/evalbind.rb +9 -9
- data/lib/waitress/handlers/dirhandler.rb +39 -39
- data/lib/waitress/handlers/handler.rb +57 -57
- data/lib/waitress/handlers/handler404.rb +25 -25
- data/lib/waitress/handlers/libhandler.rb +135 -58
- data/lib/waitress/kernel.rb +189 -189
- data/lib/waitress/parse/query.rb +60 -60
- data/lib/waitress/request.rb +45 -45
- data/lib/waitress/resources/default_config.rb +52 -52
- data/lib/waitress/resources/default_less.yml +7 -0
- data/lib/waitress/resources/http/404.html +18 -18
- data/lib/waitress/resources/http/css/hack.css +37 -37
- data/lib/waitress/resources/http/css/waitress.css +57 -57
- data/lib/waitress/resources/http/fonts/eot/latin/hack-bold-latin-webfont.eot +0 -0
- data/lib/waitress/resources/http/fonts/eot/latin/hack-bolditalic-latin-webfont.eot +0 -0
- data/lib/waitress/resources/http/fonts/eot/latin/hack-italic-latin-webfont.eot +0 -0
- data/lib/waitress/resources/http/fonts/eot/latin/hack-regular-latin-webfont.eot +0 -0
- data/lib/waitress/resources/http/fonts/svg/latin/hack-bold-latin-webfont.svg +240 -240
- data/lib/waitress/resources/http/fonts/svg/latin/hack-bolditalic-latin-webfont.svg +240 -240
- data/lib/waitress/resources/http/fonts/svg/latin/hack-italic-latin-webfont.svg +240 -240
- data/lib/waitress/resources/http/fonts/svg/latin/hack-regular-latin-webfont.svg +240 -240
- data/lib/waitress/resources/http/fonts/web-ttf/latin/hack-bold-latin-webfont.ttf +0 -0
- data/lib/waitress/resources/http/fonts/web-ttf/latin/hack-bolditalic-latin-webfont.ttf +0 -0
- data/lib/waitress/resources/http/fonts/web-ttf/latin/hack-italic-latin-webfont.ttf +0 -0
- data/lib/waitress/resources/http/fonts/web-ttf/latin/hack-regular-latin-webfont.ttf +0 -0
- data/lib/waitress/resources/http/fonts/woff/latin/hack-bold-latin-webfont.woff +0 -0
- data/lib/waitress/resources/http/fonts/woff/latin/hack-bolditalic-latin-webfont.woff +0 -0
- data/lib/waitress/resources/http/fonts/woff/latin/hack-italic-latin-webfont.woff +0 -0
- data/lib/waitress/resources/http/fonts/woff/latin/hack-regular-latin-webfont.woff +0 -0
- data/lib/waitress/resources/http/fonts/woff2/latin/hack-bold-latin-webfont.woff2 +0 -0
- data/lib/waitress/resources/http/fonts/woff2/latin/hack-bolditalic-latin-webfont.woff2 +0 -0
- data/lib/waitress/resources/http/fonts/woff2/latin/hack-italic-latin-webfont.woff2 +0 -0
- data/lib/waitress/resources/http/fonts/woff2/latin/hack-regular-latin-webfont.woff2 +0 -0
- data/lib/waitress/resources/http/img/404.png +0 -0
- data/lib/waitress/resources/http/index.html +15 -15
- data/lib/waitress/response.rb +105 -105
- data/lib/waitress/server.rb +160 -160
- data/lib/waitress/util/less_watcher.rb +56 -0
- data/lib/waitress/{util.rb → util/util.rb} +707 -707
- data/lib/waitress/version.rb +3 -3
- data/lib/waitress/vhost.rb +229 -227
- data/lib/waitress_http11.so +0 -0
- data/waitress-core.gemspec +32 -29
- metadata +48 -4
- data/lib/waitress_http11.bundle +0 -0
data/lib/waitress/evalbind.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
module Waitress
|
2
|
-
class EvalBindings
|
3
|
-
|
4
|
-
def context
|
5
|
-
binding()
|
6
|
-
end
|
7
|
-
|
8
|
-
end
|
9
|
-
end
|
1
|
+
module Waitress
|
2
|
+
class EvalBindings
|
3
|
+
|
4
|
+
def context
|
5
|
+
binding()
|
6
|
+
end
|
7
|
+
|
8
|
+
end
|
9
|
+
end
|
@@ -1,39 +1,39 @@
|
|
1
|
-
module Waitress
|
2
|
-
|
3
|
-
# The DirHandler class is an instance of +Waitress::Handler+ that is responsible
|
4
|
-
# for loading files from the filesystem and serving them if they exist in the VHost's
|
5
|
-
# root. It automatically handles mimetypes, evaluation and almost everything about
|
6
|
-
# the serving process for files in the FileSystem.
|
7
|
-
class DirHandler < Handler
|
8
|
-
|
9
|
-
attr_accessor :priority
|
10
|
-
attr_accessor :directory
|
11
|
-
|
12
|
-
# Get the instance of DirHandler that will load Waitress' resources
|
13
|
-
# such as the default 404 and index pages, as well as CSS and JS
|
14
|
-
def self.resources_handler
|
15
|
-
@@resources_handler ||= Waitress::DirHandler.new(Waitress::Chef.resources_http, -1000)
|
16
|
-
@@resources_handler
|
17
|
-
end
|
18
|
-
|
19
|
-
# Create a new DirHandler, with the given FileSystem directory as a root
|
20
|
-
# and priority.
|
21
|
-
def initialize directory, priority=50
|
22
|
-
@directory = File.absolute_path(directory)
|
23
|
-
@priority = priority
|
24
|
-
end
|
25
|
-
|
26
|
-
def respond? request, vhost
|
27
|
-
path = File.expand_path File.join("#{directory}", request.path)
|
28
|
-
res = Waitress::Chef.find_file(path)[:result]
|
29
|
-
path.include?(directory) && (res == :ok)
|
30
|
-
end
|
31
|
-
|
32
|
-
def serve request, response, client, vhost
|
33
|
-
path = File.expand_path File.join("#{directory}", request.path)
|
34
|
-
file = Waitress::Chef.find_file(path)[:file]
|
35
|
-
Waitress::Chef.serve_file request, response, client, vhost, file
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
1
|
+
module Waitress
|
2
|
+
|
3
|
+
# The DirHandler class is an instance of +Waitress::Handler+ that is responsible
|
4
|
+
# for loading files from the filesystem and serving them if they exist in the VHost's
|
5
|
+
# root. It automatically handles mimetypes, evaluation and almost everything about
|
6
|
+
# the serving process for files in the FileSystem.
|
7
|
+
class DirHandler < Handler
|
8
|
+
|
9
|
+
attr_accessor :priority
|
10
|
+
attr_accessor :directory
|
11
|
+
|
12
|
+
# Get the instance of DirHandler that will load Waitress' resources
|
13
|
+
# such as the default 404 and index pages, as well as CSS and JS
|
14
|
+
def self.resources_handler
|
15
|
+
@@resources_handler ||= Waitress::DirHandler.new(Waitress::Chef.resources_http, -1000)
|
16
|
+
@@resources_handler
|
17
|
+
end
|
18
|
+
|
19
|
+
# Create a new DirHandler, with the given FileSystem directory as a root
|
20
|
+
# and priority.
|
21
|
+
def initialize directory, priority=50
|
22
|
+
@directory = File.absolute_path(directory)
|
23
|
+
@priority = priority
|
24
|
+
end
|
25
|
+
|
26
|
+
def respond? request, vhost
|
27
|
+
path = File.expand_path File.join("#{directory}", request.path)
|
28
|
+
res = Waitress::Chef.find_file(path)[:result]
|
29
|
+
path.include?(directory) && (res == :ok)
|
30
|
+
end
|
31
|
+
|
32
|
+
def serve request, response, client, vhost
|
33
|
+
path = File.expand_path File.join("#{directory}", request.path)
|
34
|
+
file = Waitress::Chef.find_file(path)[:file]
|
35
|
+
Waitress::Chef.serve_file request, response, client, vhost, file
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -1,57 +1,57 @@
|
|
1
|
-
module Waitress
|
2
|
-
|
3
|
-
# The Handler class is responsible for handling incoming HTTP requests for a
|
4
|
-
# given URL Path. This default class works by matching a regular expression to
|
5
|
-
# the request path, however subclasses may choose to use their own matching
|
6
|
-
# methods (see +Waitress::DirHandler+).
|
7
|
-
#
|
8
|
-
# Each Handler acts off of a priority system, where if multiple handlers
|
9
|
-
# can respond to the request, the one with the highest priority will be chosen.
|
10
|
-
class Handler
|
11
|
-
|
12
|
-
attr_accessor :priority
|
13
|
-
|
14
|
-
# Create a new Regex-Based Handler
|
15
|
-
# Params:
|
16
|
-
# +regex+:: The regex pattern to match against the request path
|
17
|
-
# +priority+:: Priority of the handler. Default: 50
|
18
|
-
# +action+:: The block to call when a match is reached. Should take args
|
19
|
-
# request, response, client and vhost.
|
20
|
-
def initialize regex=nil, priority=50, &action
|
21
|
-
@regex = regex
|
22
|
-
@action = action
|
23
|
-
@priority = priority
|
24
|
-
end
|
25
|
-
|
26
|
-
# Returns true if this handler is valid for the given request
|
27
|
-
def respond? request, vhost
|
28
|
-
(request.path =~ @regex) != nil
|
29
|
-
end
|
30
|
-
|
31
|
-
# Don't touch this -- this adds Kernel bindings
|
32
|
-
def serve! request, response, client, vhost
|
33
|
-
kernel_prepare
|
34
|
-
serve request, response, client, vhost
|
35
|
-
end
|
36
|
-
|
37
|
-
# If we can respond to the request, this method is called to
|
38
|
-
# serve a response based on this handler. Do your response logic here.
|
39
|
-
# Params:
|
40
|
-
# +request+:: The +Waitress::Request+ object
|
41
|
-
# +response+:: The +Waitress::Response+ object
|
42
|
-
# +client+:: The client socket
|
43
|
-
# +vhost+:: The Virtual Host responsible for the connection
|
44
|
-
def serve request, response, client, vhost
|
45
|
-
@action.call(request, response, client, vhost) unless @action.nil?
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
# The ErrorHandler has the lowest priority, as it shouldn't be triggered
|
51
|
-
# unless there is an error (i.e. 404, 500)
|
52
|
-
class ErrorHandler < Handler
|
53
|
-
def initialize
|
54
|
-
@priority = -65536
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
1
|
+
module Waitress
|
2
|
+
|
3
|
+
# The Handler class is responsible for handling incoming HTTP requests for a
|
4
|
+
# given URL Path. This default class works by matching a regular expression to
|
5
|
+
# the request path, however subclasses may choose to use their own matching
|
6
|
+
# methods (see +Waitress::DirHandler+).
|
7
|
+
#
|
8
|
+
# Each Handler acts off of a priority system, where if multiple handlers
|
9
|
+
# can respond to the request, the one with the highest priority will be chosen.
|
10
|
+
class Handler
|
11
|
+
|
12
|
+
attr_accessor :priority
|
13
|
+
|
14
|
+
# Create a new Regex-Based Handler
|
15
|
+
# Params:
|
16
|
+
# +regex+:: The regex pattern to match against the request path
|
17
|
+
# +priority+:: Priority of the handler. Default: 50
|
18
|
+
# +action+:: The block to call when a match is reached. Should take args
|
19
|
+
# request, response, client and vhost.
|
20
|
+
def initialize regex=nil, priority=50, &action
|
21
|
+
@regex = regex
|
22
|
+
@action = action
|
23
|
+
@priority = priority
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns true if this handler is valid for the given request
|
27
|
+
def respond? request, vhost
|
28
|
+
(request.path =~ @regex) != nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# Don't touch this -- this adds Kernel bindings
|
32
|
+
def serve! request, response, client, vhost
|
33
|
+
kernel_prepare
|
34
|
+
serve request, response, client, vhost
|
35
|
+
end
|
36
|
+
|
37
|
+
# If we can respond to the request, this method is called to
|
38
|
+
# serve a response based on this handler. Do your response logic here.
|
39
|
+
# Params:
|
40
|
+
# +request+:: The +Waitress::Request+ object
|
41
|
+
# +response+:: The +Waitress::Response+ object
|
42
|
+
# +client+:: The client socket
|
43
|
+
# +vhost+:: The Virtual Host responsible for the connection
|
44
|
+
def serve request, response, client, vhost
|
45
|
+
@action.call(request, response, client, vhost) unless @action.nil?
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
# The ErrorHandler has the lowest priority, as it shouldn't be triggered
|
51
|
+
# unless there is an error (i.e. 404, 500)
|
52
|
+
class ErrorHandler < Handler
|
53
|
+
def initialize
|
54
|
+
@priority = -65536
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,25 +1,25 @@
|
|
1
|
-
module Waitress
|
2
|
-
|
3
|
-
# The 404 Handler is a simple "Catch-All" handler which will be triggered if
|
4
|
-
# a valid handler is not found for the page, and will show an error page
|
5
|
-
# telling the user the page cannot be found
|
6
|
-
class Handler404 < ErrorHandler
|
7
|
-
|
8
|
-
def serve request, response, client, vhost
|
9
|
-
response.status 404
|
10
|
-
e404page = vhost.get_404
|
11
|
-
if !e404page.nil? && (Waitress::Chef.find_file(e404page)[:result]==:ok)
|
12
|
-
Waitress::Chef.serve_file request, response, client, vhost, e404page
|
13
|
-
else
|
14
|
-
if vhost.resources?
|
15
|
-
h = File.join Waitress::Chef.resources_http, "404.html"
|
16
|
-
Waitress::Chef.serve_file request, response, client, vhost, h
|
17
|
-
else
|
18
|
-
response.mime ".html"
|
19
|
-
response.body "<h1> 404 - Not Found </h1> <p> The page you have requested is not here </p>"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
end
|
1
|
+
module Waitress
|
2
|
+
|
3
|
+
# The 404 Handler is a simple "Catch-All" handler which will be triggered if
|
4
|
+
# a valid handler is not found for the page, and will show an error page
|
5
|
+
# telling the user the page cannot be found
|
6
|
+
class Handler404 < ErrorHandler
|
7
|
+
|
8
|
+
def serve request, response, client, vhost
|
9
|
+
response.status 404
|
10
|
+
e404page = vhost.get_404
|
11
|
+
if !e404page.nil? && (Waitress::Chef.find_file(e404page)[:result]==:ok)
|
12
|
+
Waitress::Chef.serve_file request, response, client, vhost, e404page
|
13
|
+
else
|
14
|
+
if vhost.resources?
|
15
|
+
h = File.join Waitress::Chef.resources_http, "404.html"
|
16
|
+
Waitress::Chef.serve_file request, response, client, vhost, h
|
17
|
+
else
|
18
|
+
response.mime ".html"
|
19
|
+
response.body "<h1> 404 - Not Found </h1> <p> The page you have requested is not here </p>"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -1,58 +1,135 @@
|
|
1
|
-
module Waitress
|
2
|
-
|
3
|
-
# The LibraryHandler is used to handle requests to the VHost regarding the
|
4
|
-
# libraries to be loaded by other Handlers and .wrb files. This will take any
|
5
|
-
# requests to /libraries (or whatever the user has set it to) to load libraries
|
6
|
-
class LibraryHandler < Handler
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
38
|
-
|
39
|
-
def
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
1
|
+
module Waitress
|
2
|
+
|
3
|
+
# The LibraryHandler is used to handle requests to the VHost regarding the
|
4
|
+
# libraries to be loaded by other Handlers and .wrb files. This will take any
|
5
|
+
# requests to /libraries (or whatever the user has set it to) to load libraries
|
6
|
+
class LibraryHandler < Handler
|
7
|
+
|
8
|
+
require 'json'
|
9
|
+
require 'less'
|
10
|
+
require 'digest'
|
11
|
+
|
12
|
+
attr_accessor :priority
|
13
|
+
|
14
|
+
def initialize libraries, libdir, liburi, vhost
|
15
|
+
@priority = 150
|
16
|
+
@vhost = vhost
|
17
|
+
@libraries, @libdir, @liburi = libraries, File.expand_path(libdir), liburi
|
18
|
+
@cachedir = File.join(@libdir, ".libcache")
|
19
|
+
@lesscache = File.join(@cachedir, "less_compile")
|
20
|
+
FileUtils.mkdir_p(@libdir) unless File.exist?(@libdir)
|
21
|
+
parse_libraries
|
22
|
+
basic_libs
|
23
|
+
compiler_libs
|
24
|
+
|
25
|
+
setup_bower
|
26
|
+
end
|
27
|
+
|
28
|
+
def compile_less main_file, path
|
29
|
+
parser = Less::Parser.new :paths => [path].flatten, :filename => main_file
|
30
|
+
tree = parser.parse(File.read(main_file))
|
31
|
+
|
32
|
+
FileUtils.mkdir_p(@lesscache) unless File.exist?(@lesscache)
|
33
|
+
output = File.join(@lesscache, "#{Digest::MD5.hexdigest(main_file)}.min.css")
|
34
|
+
File.write(output, tree.to_css(:compress => true))
|
35
|
+
|
36
|
+
{:file => output, :type => :css}
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_libraries
|
40
|
+
@libraries.each do |name, lib|
|
41
|
+
l = {}
|
42
|
+
d = dirType(lib[:bindtype])
|
43
|
+
matches = Dir["#{d}/**/*.#{lib[:bindtype].to_s}"].select { |x| (x =~ lib[:pattern]) != nil }
|
44
|
+
if matches.length > 0
|
45
|
+
l[:file] = matches[0]
|
46
|
+
l[:type] = lib[:bindtype]
|
47
|
+
else
|
48
|
+
l = nil
|
49
|
+
end
|
50
|
+
@libraries[name] = l
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def basic_libs
|
55
|
+
[:css, :js].each do |k|
|
56
|
+
d = dirType k
|
57
|
+
FileUtils.mkdir_p(d) unless File.exist?(d)
|
58
|
+
|
59
|
+
Dir["#{d}/**/*.#{k.to_s}"].each do |fl|
|
60
|
+
@libraries[File.basename(fl).to_sym] = { :file => fl, :type => k }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def compiler_libs
|
66
|
+
lessdir = dirType :less
|
67
|
+
FileUtils.mkdir_p(lessdir) unless File.exist?(lessdir)
|
68
|
+
entry = File.join(lessdir, "less.yml")
|
69
|
+
if File.exist? entry
|
70
|
+
conf = YAML.load(File.read(entry))
|
71
|
+
unless conf["libs"].nil?
|
72
|
+
conf["libs"].each do |libname, lib|
|
73
|
+
@libraries[libname.to_sym] = compile_less File.expand_path(lib, lessdir), lessdir
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
unless conf["watch"].nil? || (conf["watch"].length == 0)
|
78
|
+
map = conf["watch"].map { |x| File.expand_path(x, lessdir) }
|
79
|
+
Waitress::LESSWatcher.new(map) { |file| compile_less(file, lessdir) }
|
80
|
+
end
|
81
|
+
else
|
82
|
+
File.write(entry, File.join(Waitress::Chef.resources, "default_less.yml"))
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def setup_bower
|
87
|
+
bowerdir = File.join(@libdir, "bower_components")
|
88
|
+
Dir["#{bowerdir}/**"].each do |component|
|
89
|
+
bowerfile = JSON.parse File.read(File.join(component, "bower.json"))
|
90
|
+
loadfiles = [bowerfile["main"]].flatten
|
91
|
+
loadfiles.each { |x| loadBower(x, bowerfile["name"], component, loadfiles.length > 1) }
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def loadBower main, libname, home, append_type=false
|
96
|
+
ext = File.extname(main)
|
97
|
+
lib = {}
|
98
|
+
|
99
|
+
main = File.expand_path(main, home)
|
100
|
+
|
101
|
+
if ext == ".css"
|
102
|
+
lib[:file] = main
|
103
|
+
lib[:type] = :css
|
104
|
+
elsif ext == ".js"
|
105
|
+
lib[:file] = main
|
106
|
+
lib[:type] = :js
|
107
|
+
elsif ext == ".less"
|
108
|
+
lib = compile_less main, File.dirname(libname)
|
109
|
+
end
|
110
|
+
|
111
|
+
libname = libname + "_#{lib[:type].to_s}" if append_type
|
112
|
+
libname = libname.to_sym
|
113
|
+
@libraries[libname] = lib
|
114
|
+
end
|
115
|
+
|
116
|
+
def dirType k
|
117
|
+
File.join(@libdir, k.to_s)
|
118
|
+
end
|
119
|
+
|
120
|
+
def respond? request, vhost
|
121
|
+
path = request.path
|
122
|
+
return false unless path.start_with?("/#{@liburi}/")
|
123
|
+
name = path.sub("/#{@liburi}/", "").to_sym
|
124
|
+
@libraries.include?(name)
|
125
|
+
end
|
126
|
+
|
127
|
+
def serve request, response, client, vhost
|
128
|
+
path = request.path
|
129
|
+
name = path.sub("/#{@liburi}/", "").to_sym
|
130
|
+
lib = @libraries[name]
|
131
|
+
Waitress::Chef.serve_file request, response, client, vhost, lib[:file]
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|