awestruct 0.5.6.beta8 → 0.5.6.beta9
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.
- checksums.yaml +4 -4
- data/Gemfile +2 -4
- data/Rakefile +1 -1
- data/awestruct.gemspec +22 -18
- data/lib/awestruct/cli/auto.rb +25 -21
- data/lib/awestruct/cli/generate.rb +3 -2
- data/lib/awestruct/cli/init.rb +2 -1
- data/lib/awestruct/cli/invoker.rb +4 -3
- data/lib/awestruct/cli/manifest.rb +41 -0
- data/lib/awestruct/cli/options.rb +10 -1
- data/lib/awestruct/cli/server.rb +36 -6
- data/lib/awestruct/config/default-site.yml +3 -0
- data/lib/awestruct/context.rb +17 -0
- data/lib/awestruct/context_helper.rb +25 -21
- data/lib/awestruct/deploy/s3_deploy.rb +41 -3
- data/lib/awestruct/engine.rb +64 -33
- data/lib/awestruct/extensions/disqus.rb +2 -2
- data/lib/awestruct/extensions/flattr.rb +1 -1
- data/lib/awestruct/extensions/pipeline.rb +30 -8
- data/lib/awestruct/extensions/relative.rb +3 -1
- data/lib/awestruct/extensions/sitemap.rb +6 -0
- data/lib/awestruct/extensions/sitemap.xml.haml +2 -1
- data/lib/awestruct/extensions/tagger.rb +7 -6
- data/lib/awestruct/extensions/template.atom.haml +1 -1
- data/lib/awestruct/frameworks/base_Gemfile +12 -1
- data/lib/awestruct/frameworks/bootstrap/base_index.html.haml +22 -20
- data/lib/awestruct/frameworks/bootstrap/base_layout.html.haml +9 -7
- data/lib/awestruct/handlers/asciidoctor_handler.rb +1 -1
- data/lib/awestruct/handlers/base_tilt_handler.rb +3 -1
- data/lib/awestruct/pipeline.rb +57 -7
- data/lib/awestruct/rack/generate.rb +43 -0
- data/lib/awestruct/util/exception_helper.rb +3 -0
- data/lib/awestruct/version.rb +1 -1
- data/spec/awestruct/cli/invoker_spec.rb +1 -1
- data/spec/awestruct/cli/options_spec.rb +14 -13
- data/spec/awestruct/cli/server_spec.rb +15 -0
- data/spec/awestruct/context_helper_spec.rb +5 -5
- data/spec/awestruct/engine_spec.rb +110 -1
- data/spec/awestruct/extensions/relative_spec.rb +22 -0
- data/spec/awestruct/handlers/asciidoc_handler_spec.rb +7 -1
- data/spec/awestruct/handlers/layout_handler_spec.rb +7 -7
- data/spec/awestruct/handlers/tilt_handler_spec.rb +1 -1
- data/spec/awestruct/pipeline_spec.rb +27 -2
- data/spec/awestruct/scm/git_spec.rb +4 -4
- data/spec/spec_helper.rb +6 -1
- data/spec/support/emmet_matchers.rb +1 -1
- data/spec/support/nokogiri_matchers.rb +1 -1
- data/spec/support/shared_handler_example.rb +66 -71
- data/spec/support/test-data/engine-generate-no-errors/_config/site.yml +26 -0
- data/spec/support/test-data/engine-generate-no-errors/_ext/pipeline.rb +8 -0
- data/spec/support/test-data/engine-generate-no-errors/_layouts/base.html.slim +6 -0
- data/spec/support/test-data/engine-generate-no-errors/index.html.slim +5 -0
- data/spec/support/test-data/engine-generate-with-errors/_config/site.yml +26 -0
- data/spec/support/test-data/engine-generate-with-errors/_ext/pipeline.rb +8 -0
- data/spec/support/test-data/engine-generate-with-errors/_layouts/base.html.slim +6 -0
- data/spec/support/test-data/engine-generate-with-errors/index.html.slim +6 -0
- data/spec/support/test-data/engine-yaml/_config/site.yml +9 -0
- data/spec/support/test-data/pipeline/_ext/extensions.rb +26 -0
- data/spec/support/test-data/pipeline/_ext/pipeline.rb +12 -0
- metadata +229 -72
@@ -24,6 +24,11 @@ module Awestruct
|
|
24
24
|
if site.sitemap["excluded_extensions"]
|
25
25
|
@excluded_extensions.merge(site.sitemap.excluded_extensions)
|
26
26
|
end
|
27
|
+
|
28
|
+
# Check for a specified stylesheet for the sitemap
|
29
|
+
if site.sitemap["stylesheet_url"]
|
30
|
+
stylesheet_url = site.sitemap["stylesheet_url"]
|
31
|
+
end
|
27
32
|
end
|
28
33
|
|
29
34
|
# Go through all of the site's pages and add sitemap metadata
|
@@ -50,6 +55,7 @@ module Awestruct
|
|
50
55
|
page.output_path = 'sitemap.xml'
|
51
56
|
page.sitemap_entries = sitemap_pages
|
52
57
|
page.do_not_track_dependencies = true
|
58
|
+
page.stylesheet_url = stylesheet_url || nil
|
53
59
|
|
54
60
|
# Add the sitemap to our site
|
55
61
|
site.pages << page
|
@@ -1,7 +1,8 @@
|
|
1
1
|
---
|
2
2
|
---
|
3
3
|
!!! XML
|
4
|
-
|
4
|
+
- if !page.stylesheet_url.nil?
|
5
|
+
<?xml-stylesheet type='text/xsl' href='#{site.baseurl}#{page.stylesheet_url}'?>
|
5
6
|
%urlset{ :xmlns=>'http://www.sitemaps.org/schemas/sitemap/0.9' }
|
6
7
|
- unless page.sitemap_entries.empty?
|
7
8
|
- for entry in page.sitemap_entries
|
@@ -20,7 +20,11 @@ module Awestruct
|
|
20
20
|
module TagLinker
|
21
21
|
def tag_links(delimiter = ', ', style_class = nil)
|
22
22
|
class_attr = (style_class ? ' class="' + style_class + '"' : '')
|
23
|
-
tags.map
|
23
|
+
tags.map do |tag|
|
24
|
+
url = tag.primary_page.url
|
25
|
+
url << '/' unless (url.include?('.htm') || url.end_with?('/'))
|
26
|
+
%Q{<a#{class_attr} href="#{url}">#{tag}</a>}
|
27
|
+
end.join(delimiter)
|
24
28
|
end
|
25
29
|
end
|
26
30
|
|
@@ -45,14 +49,11 @@ module Awestruct
|
|
45
49
|
@tags[tag] ||= TagStat.new( tag, [] )
|
46
50
|
@tags[tag].pages << page
|
47
51
|
end
|
52
|
+
page.tags = (page.tags || []).collect{|t| @tags[t]}
|
53
|
+
page.extend( TagLinker )
|
48
54
|
end
|
49
55
|
end
|
50
56
|
|
51
|
-
all.each do |page|
|
52
|
-
page.tags = (page.tags||[]).collect{|t| @tags[t]}
|
53
|
-
page.extend( TagLinker )
|
54
|
-
end
|
55
|
-
|
56
57
|
ordered_tags = @tags.values
|
57
58
|
ordered_tags.sort!{|l,r| -(l.pages.size <=> r.pages.size)}
|
58
59
|
#ordered_tags = ordered_tags[0,100]
|
@@ -36,7 +36,7 @@
|
|
36
36
|
- for tag in entry.tags
|
37
37
|
%category{:term=>"#{tag}"}
|
38
38
|
%summary
|
39
|
-
#{summarize( html_to_text( entry.content ), 100 )}
|
39
|
+
#{summarize( html_to_text( entry.content ).strip, 100 )}
|
40
40
|
%content{:type=>'html'}
|
41
41
|
= clean_html( html_escape( fully_qualify_urls( site.base_url, find_and_preserve( entry.content ) ) ) )
|
42
42
|
|
@@ -24,9 +24,20 @@
|
|
24
24
|
|
25
25
|
source 'https://rubygems.org' # This tells Bundler where to look for gems
|
26
26
|
|
27
|
-
gem 'awestruct', '
|
27
|
+
gem 'awestruct', '>= <%= awestruct_version %>' # Goes without saying
|
28
28
|
gem 'webrick', '~> 1.3.1' # The rack webserver to use in dev mode
|
29
29
|
|
30
|
+
gem 'compass', '<%= dependencies['compass'].requirement %>'
|
31
|
+
<% if framework.eql? 'bootstrap' %>
|
32
|
+
gem 'bootstrap-sass', '<%= dependencies['bootstrap-sass'].requirement %>'
|
33
|
+
<% end %>
|
34
|
+
<% if framework.eql? 'foundation' %>
|
35
|
+
gem 'zurb-foundation', '<%= dependencies['zurb-foundation'].requirement %>'
|
36
|
+
<% end %>
|
37
|
+
<% if framework.eql? '960' %>
|
38
|
+
gem 'compass-960-plugin', '<%= dependencies['compass-960-plugin'].requirement %>'
|
39
|
+
<% end %>
|
40
|
+
|
30
41
|
# FIXME
|
31
42
|
# gem 'rake', '>= 0.9.2' # Needed for the Rakefile to work
|
32
43
|
# gem 'coffee-script', '>= 2.2.0' # If using coffee-script or to remove the warning
|
@@ -1,27 +1,29 @@
|
|
1
1
|
---
|
2
2
|
layout: base
|
3
3
|
---
|
4
|
-
.
|
4
|
+
.jumbotron
|
5
5
|
%h1 You're awestruct!
|
6
|
-
%p This site is all setup to use Bootstrap
|
6
|
+
%p This site is all setup to use Bootstrap 3 with Awestruct.
|
7
7
|
%p
|
8
|
-
%a.btn.btn-primary.btn-
|
8
|
+
%a.btn.btn-primary.btn-lg{ :href=>'http://awestruct.org', :role=>"button" }
|
9
9
|
%i.icon-info-sign.icon-white
|
10
10
|
Learn more »
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
%
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
%
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
%
|
11
|
+
|
12
|
+
.container-fluid
|
13
|
+
.row
|
14
|
+
.col-md-4
|
15
|
+
%h2 About
|
16
|
+
%p Awestruct is a framework for creating static HTML sites. It's inspired by the awesome Jekyll utility in the same genre.
|
17
|
+
%p Additionally, Awestruct integrates technologies such as Compass, Markdown and Haml.
|
18
|
+
%p
|
19
|
+
%a.btn{ :href=>'http://awestruct.org' } View details »
|
20
|
+
.col-md-4
|
21
|
+
%h2 Goal
|
22
|
+
%p The goal of Awestruct is to make it trivially easy to bake out non-trivial static websites. In addition to providing template-driven site creation (using Haml), Awestruct provides facilities for easily priming the site creation with additional non-page data.
|
23
|
+
%p
|
24
|
+
%a.btn{ :href=>'http://awestruct.org' } View details »
|
25
|
+
.col-md-4
|
26
|
+
%h2 Concept
|
27
|
+
%p The core concept of Awestruct is that of structures, specifically Ruby OpenStruct structures. The struct aspect allows arbitrary, schema-less data to be associated with a specific page or the entire site.
|
28
|
+
%p
|
29
|
+
%a.btn{ :href=>'http://awestruct.org' } View details »
|
@@ -12,13 +12,15 @@
|
|
12
12
|
/[if lt IE 9]
|
13
13
|
%script{ :type=>'text/javascript', :src=>'//html5shim.googlecode.com/svn/trunk/html5.js' }
|
14
14
|
%body
|
15
|
-
.navbar.navbar-fixed-top
|
16
|
-
.
|
17
|
-
.
|
18
|
-
%a.brand{ :href=>"#{site.base_url}" } #{site.name}
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
%nav.navbar.navbar-default.navbar-fixed-top{:role=>'navigation'}
|
16
|
+
.container-fluid
|
17
|
+
.navbar-header
|
18
|
+
%a.navbar-brand{ :href=>"#{site.base_url}" } #{site.name}
|
19
|
+
|
20
|
+
%ul.nav.navbar-nav.navbar-right
|
21
|
+
%li
|
22
|
+
%a{ :href=>"#{site.base_url}" } Home
|
23
|
+
|
22
24
|
.container
|
23
25
|
~ content
|
24
26
|
%hr
|
@@ -137,12 +137,14 @@ module Awestruct
|
|
137
137
|
ExceptionHelper.log_message "Could not load template library required for rendering #{File.join site.dir, error_page.source_path}."
|
138
138
|
ExceptionHelper.log_message "Please see #{File.join site.dir, error_page.output_path} for more information"
|
139
139
|
return ExceptionHelper.html_error_report e, error_page.source_path
|
140
|
-
rescue
|
140
|
+
rescue => e
|
141
141
|
error_page = context[:page]
|
142
142
|
if error_page[:__is_layout] == true
|
143
143
|
ExceptionHelper.log_message "An error during rendering layout file #{File.join site.dir, error_page.source_path} occurred."
|
144
|
+
ExceptionHelper.log_building_error e, error_page.source_path
|
144
145
|
else
|
145
146
|
ExceptionHelper.log_message "An error during rendering #{File.join site.dir, error_page.source_path} occurred."
|
147
|
+
ExceptionHelper.log_building_error e, error_page.source_path
|
146
148
|
end
|
147
149
|
ExceptionHelper.log_message "Please see #{File.join site.dir, error_page.output_path} for more information"
|
148
150
|
return ExceptionHelper.html_error_report e, error_page.source_path
|
data/lib/awestruct/pipeline.rb
CHANGED
@@ -6,18 +6,35 @@ module Awestruct
|
|
6
6
|
class Pipeline
|
7
7
|
|
8
8
|
attr_reader :handler_chains
|
9
|
+
attr_reader :before_all_extensions
|
10
|
+
attr_reader :extensions
|
11
|
+
attr_reader :after_all_extensions
|
12
|
+
attr_reader :helpers
|
13
|
+
attr_reader :transformers
|
14
|
+
attr_reader :after_generation_extensions
|
9
15
|
|
10
16
|
def initialize()
|
11
17
|
@handler_chains = HandlerChains.new
|
12
|
-
@
|
13
|
-
@
|
14
|
-
@
|
18
|
+
@before_all_extensions = []
|
19
|
+
@extensions = []
|
20
|
+
@helpers = []
|
21
|
+
@transformers = []
|
22
|
+
@after_all_extensions = []
|
23
|
+
@after_generation_extensions = []
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_before_extension(e)
|
27
|
+
@before_all_extensions << e
|
15
28
|
end
|
16
29
|
|
17
30
|
def extension(e)
|
18
31
|
@extensions << e
|
19
32
|
# TC: why? transformer and extension?
|
20
|
-
e.transform(@transformers) if e.respond_to?(
|
33
|
+
e.transform(@transformers) if e.respond_to?(:transform)
|
34
|
+
end
|
35
|
+
|
36
|
+
def add_after_extension(e)
|
37
|
+
@after_all_extensions << e
|
21
38
|
end
|
22
39
|
|
23
40
|
def helper(h)
|
@@ -28,14 +45,37 @@ module Awestruct
|
|
28
45
|
@transformers << t
|
29
46
|
end
|
30
47
|
|
31
|
-
def
|
32
|
-
|
48
|
+
def add_after_generation_extension(e)
|
49
|
+
@after_generation_extensions << e
|
33
50
|
end
|
34
51
|
|
35
|
-
def
|
52
|
+
def execute(site, on_reload = false)
|
53
|
+
execute_extensions(site, on_reload)
|
54
|
+
end
|
55
|
+
|
56
|
+
def execute_extensions(site, on_reload)
|
57
|
+
@before_all_extensions.each do |e|
|
58
|
+
e.on_reload(site) if (on_reload && e.respond_to?(:on_reload))
|
59
|
+
if (e.respond_to? :execute)
|
60
|
+
e.execute(site)
|
61
|
+
else
|
62
|
+
e.before_extensions(site)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
36
66
|
@extensions.each do |e|
|
67
|
+
e.on_reload(site) if (on_reload && e.respond_to?(:on_reload))
|
37
68
|
e.execute(site)
|
38
69
|
end
|
70
|
+
|
71
|
+
@after_all_extensions.each do |e|
|
72
|
+
e.on_reload(site) if (on_reload && e.respond_to?(:on_reload))
|
73
|
+
if e.respond_to? :execute
|
74
|
+
e.execute(site)
|
75
|
+
else
|
76
|
+
e.after_generation(site)
|
77
|
+
end
|
78
|
+
end
|
39
79
|
end
|
40
80
|
|
41
81
|
def apply_transformers(site, page, rendered)
|
@@ -45,6 +85,16 @@ module Awestruct
|
|
45
85
|
rendered
|
46
86
|
end
|
47
87
|
|
88
|
+
def execute_after_generation(site)
|
89
|
+
@after_generation_extensions.each do |e|
|
90
|
+
if e.respond_to? :execute
|
91
|
+
e.execute(site)
|
92
|
+
else
|
93
|
+
e.after_generation(site)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
48
98
|
def mixin_helpers(context)
|
49
99
|
context.extend( Awestruct::ContextHelper )
|
50
100
|
@helpers.each do |h|
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
module Awestruct
|
3
|
+
module Rack
|
4
|
+
|
5
|
+
class GenerateOnAccess
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
engine = ::Awestruct::Engine.instance
|
12
|
+
|
13
|
+
generate = false
|
14
|
+
|
15
|
+
req_path = env['REQUEST_PATH']
|
16
|
+
path = req_path
|
17
|
+
path = req_path + "index.html" if req_path.end_with? '/'
|
18
|
+
|
19
|
+
page = engine.site.pages_by_output_path[path]
|
20
|
+
if page.nil? and !req_path.end_with? '/'
|
21
|
+
path = req_path + "/index.html"
|
22
|
+
page = engine.site.pages_by_output_path[path]
|
23
|
+
end
|
24
|
+
|
25
|
+
if !page.nil?
|
26
|
+
generate_path = File.join( engine.site.config.output_dir, page.output_path )
|
27
|
+
|
28
|
+
generate = true if page.stale_output? generate_path
|
29
|
+
generate = true if path.end_with? '.html'
|
30
|
+
end
|
31
|
+
|
32
|
+
if generate
|
33
|
+
puts "Regenerate #{page.source_path}"
|
34
|
+
|
35
|
+
engine.generate_page page, true
|
36
|
+
end
|
37
|
+
|
38
|
+
@app.call(env)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/lib/awestruct/version.rb
CHANGED
@@ -76,7 +76,7 @@ describe Awestruct::CLI::Invoker do
|
|
76
76
|
generator = double
|
77
77
|
Awestruct::CLI::Generate.should_receive( :new ).and_return( generator )
|
78
78
|
generator.should_receive( :run ).and_return( false )
|
79
|
-
Awestruct::CLI::Invoker.new( %w(--source-dir spec/support/test-config --generate) ).invoke
|
79
|
+
expect(Awestruct::CLI::Invoker.new( %w(--source-dir spec/support/test-config --generate) ).invoke!).to be_falsey
|
80
80
|
end
|
81
81
|
|
82
82
|
|
@@ -63,37 +63,38 @@ describe Awestruct::CLI::Options do
|
|
63
63
|
parse!( '--auto' ).auto.should == true
|
64
64
|
end
|
65
65
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
66
|
+
# I'm not sure if we'll ever do this
|
67
|
+
# it 'should parse script-related args' do
|
68
|
+
# pending 'Not yet implemented. See issue #248.'
|
69
|
+
# #parse!( '--run', 'puts "hi"' ).script.should == 'puts "hi"'
|
70
|
+
# end
|
70
71
|
|
71
72
|
it 'should turn off generate when doing a --deploy' do
|
72
73
|
result = parse!( '--deploy' )
|
73
|
-
result.deploy.should
|
74
|
-
result.generate.should
|
74
|
+
result.deploy.should be_truthy
|
75
|
+
result.generate.should be_falsey
|
75
76
|
end
|
76
77
|
|
77
78
|
it 'should turn off generate when doing a --deploy unless explicitly turned back on' do
|
78
79
|
result = parse!( '--deploy', '--generate' )
|
79
|
-
result.deploy.should
|
80
|
-
result.generate.should
|
80
|
+
result.deploy.should be_truthy
|
81
|
+
result.generate.should be_truthy
|
81
82
|
|
82
83
|
result = parse!( '--generate', '--deploy' )
|
83
|
-
result.deploy.should
|
84
|
-
result.generate.should
|
84
|
+
result.deploy.should be_truthy
|
85
|
+
result.generate.should be_truthy
|
85
86
|
end
|
86
87
|
|
87
88
|
it 'should turn on verbose when -w or --verbose is explicitly turned back on' do
|
88
89
|
result = parse!( '-w' )
|
89
|
-
result.verbose.should
|
90
|
+
result.verbose.should be_truthy
|
90
91
|
|
91
92
|
result = parse!( '--verbose' )
|
92
|
-
result.verbose.should
|
93
|
+
result.verbose.should be_truthy
|
93
94
|
end
|
94
95
|
|
95
96
|
it 'should generate by default' do
|
96
|
-
parse!().generate.should
|
97
|
+
parse!().generate.should be_truthy
|
97
98
|
end
|
98
99
|
|
99
100
|
it 'should parse directory options' do
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'awestruct/cli/server'
|
2
|
+
require 'awestruct/cli/options'
|
3
|
+
require 'socket'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
describe Awestruct::CLI::Server do
|
7
|
+
|
8
|
+
let(:subject) { Awestruct::CLI::Server.new('./')}
|
9
|
+
|
10
|
+
it 'should abort if the port is already in use' do
|
11
|
+
server = class_double(TCPServer).as_stubbed_const(:transfer_nested_constants => true)
|
12
|
+
expect(server).to receive(:new).and_raise(Errno::EADDRINUSE)
|
13
|
+
expect(lambda { Timeout.timeout(0.2) { subject.run } }).to raise_error(SystemExit)
|
14
|
+
end
|
15
|
+
end
|
@@ -76,21 +76,21 @@ describe Awestruct::ContextHelper do
|
|
76
76
|
describe "fully_qualify_urls" do
|
77
77
|
it "should fix anchor tags" do
|
78
78
|
str = "<a href='/foo'>foobar</a>"
|
79
|
-
@tester.fully_qualify_urls('http://foobar.com', str).should ==
|
79
|
+
@tester.fully_qualify_urls('http://foobar.com', str).should == %q(<a href="http://foobar.com/foo">foobar</a>)
|
80
80
|
end
|
81
81
|
|
82
82
|
it "should fix link tags" do
|
83
|
-
str = "<link href='/foo'
|
84
|
-
@tester.fully_qualify_urls('http://foobar.com', str).should ==
|
83
|
+
str = "<link href='/foo'>"
|
84
|
+
@tester.fully_qualify_urls('http://foobar.com', str).should == %q(<link href="http://foobar.com/foo" />)
|
85
85
|
end
|
86
86
|
|
87
87
|
it "should fix image tags" do
|
88
88
|
str = "<img src='/foo' />"
|
89
|
-
@tester.fully_qualify_urls('http://foobar.com', str).should ==
|
89
|
+
@tester.fully_qualify_urls('http://foobar.com', str).should == %q(<img src="http://foobar.com/foo" />)
|
90
90
|
end
|
91
91
|
|
92
92
|
it "should leave anchor tags with no href attribute (for page anchors) unchanged" do
|
93
|
-
str =
|
93
|
+
str = %q(<a target="#foo">foobar</a>)
|
94
94
|
@tester.fully_qualify_urls('http://foobar.com', str).should == str
|
95
95
|
end
|
96
96
|
end
|