frame 0.0.3 → 0.0.4
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/Gemfile.lock +229 -1
- data/README.md +36 -0
- data/lib/generators/frame.rb +8 -0
- data/lib/generators/frame/admin/USAGE +11 -0
- data/lib/generators/frame/admin/admin_generator.rb +66 -0
- data/lib/generators/frame/admin/templates/pages.rb +15 -0
- data/lib/generators/frame/admin/templates/pages_controller.rb +25 -0
- data/lib/generators/frame/admin/templates/show.html.erb +7 -0
- data/lib/generators/frame/all/USAGE +11 -0
- data/lib/generators/frame/all/all_generator.rb +24 -0
- data/lib/generators/frame/blueprint/USAGE +11 -0
- data/lib/generators/frame/blueprint/blueprint_generator.rb +41 -0
- data/lib/generators/frame/devise/devise_generator.rb +46 -8
- data/lib/generators/frame/devise/templates/defaults.html.erb +7 -5
- data/lib/generators/frame/layout/layout_generator.rb +19 -4
- data/lib/generators/frame/layout/templates/application_helper.rb +1 -1
- data/lib/generators/frame/layout/templates/defaults.html.erb +2 -2
- data/lib/generators/frame/layout/templates/econ64.gif +0 -0
- data/lib/generators/frame/layout/templates/favicon.ico +0 -0
- data/lib/generators/frame/layout/templates/frame.css +145 -0
- data/lib/generators/frame/mysql/mysql_generator.rb +23 -2
- data/lib/generators/frame/omniauth/USAGE +11 -0
- data/lib/generators/frame/omniauth/omniauth_generator.rb +90 -0
- data/lib/generators/frame/omniauth/templates/defaults.html.erb +47 -0
- data/lib/generators/frame/omniauth/templates/omniauth.rb +6 -0
- data/lib/generators/frame/omniauth/templates/omniauth_callbacks_controller.rb +38 -0
- data/lib/generators/frame/pages/pages_generator.rb +89 -45
- data/lib/generators/frame/pages/templates/_sidebar.html.erb +2 -2
- data/lib/generators/frame/pages/templates/pages.html.erb +0 -3
- metadata +262 -4
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'generators/frame'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
module Frame
|
5
|
+
module Generators
|
6
|
+
class BlueprintGenerator < Base
|
7
|
+
#include Rails::Generators::Migration
|
8
|
+
|
9
|
+
desc "Installs Blueprint-CSS."
|
10
|
+
|
11
|
+
def clone_blueprint
|
12
|
+
tmp_dir=File.join(Rails.root, 'tmp/blueprint')
|
13
|
+
dest_dir=File.join(Rails.root, 'app/assets/stylesheets')
|
14
|
+
|
15
|
+
if Dir.exist?(tmp_dir)
|
16
|
+
FileUtils.rm_rf(tmp_dir)
|
17
|
+
end
|
18
|
+
system("git clone git@github.com:joshuaclayton/blueprint-css #{tmp_dir}")
|
19
|
+
Dir.chdir tmp_dir
|
20
|
+
system("git checkout v1.0.1")
|
21
|
+
Dir.chdir File.join(tmp_dir, 'lib')
|
22
|
+
system("bundle install --without test")
|
23
|
+
system("ruby compress.rb -o #{dest_dir}")
|
24
|
+
end
|
25
|
+
|
26
|
+
def adjust_app_css
|
27
|
+
file=destination_path('app/assets/stylesheets/application.css')
|
28
|
+
add_if_missing(file, " *= require screen\n", :after => " *= require_self\n")
|
29
|
+
add_if_missing(file, " *= require ie\n", :after => " *= require_self\n")
|
30
|
+
gsub_file file, / \*\= require_tree \.\n/, ''
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def destination_path(path)
|
36
|
+
File.join(destination_root, path)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -9,22 +9,60 @@ module Frame
|
|
9
9
|
desc "Installs Devise."
|
10
10
|
|
11
11
|
def install_devise
|
12
|
-
gem("rspec-rails", :group => "test")
|
13
|
-
gem("cucumber-rails", :group => "test")
|
12
|
+
gem("rspec-rails", :group => "test, development")
|
13
|
+
gem("cucumber-rails", :group => "test, development")
|
14
14
|
|
15
15
|
if yes?("Would you like to install Devise?")
|
16
16
|
gem("devise")
|
17
|
+
Bundler.with_clean_env do
|
18
|
+
run "bundle"
|
19
|
+
end
|
17
20
|
generate("devise:install")
|
18
|
-
|
19
|
-
model_name = "user
|
21
|
+
default_model = "User"
|
22
|
+
model_name = ask("What would you like the user model to be called? [#{default_model}]")
|
23
|
+
model_name = default_model if model_name.blank?
|
20
24
|
generate("devise", model_name)
|
25
|
+
generate("devise:views")
|
21
26
|
end
|
22
27
|
end
|
23
28
|
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
29
|
+
#def update_initializers
|
30
|
+
# gsub_file 'config/initializers/devise.rb', /config.mailer_sender = "please-change-me-at-config-initializers-devise@example.com"/ do
|
31
|
+
# default_mailer = "webmaster@proj_name.com"
|
32
|
+
# mailer_sender = ask("What is the mail sender address? [#{default_mailer}]")
|
33
|
+
# mailer_sender = default_mailer if mailer_sender.blank?
|
34
|
+
# "config.mailer_sender = \"#{mailer_sender}\""
|
35
|
+
# end
|
36
|
+
#end
|
37
|
+
|
38
|
+
def add_default_layout
|
39
|
+
template 'defaults.html.erb', 'app/views/layouts/defaults.html.erb'
|
40
|
+
end
|
41
|
+
|
42
|
+
def update_db
|
43
|
+
if yes?("Would you like to migrate the database?")
|
44
|
+
rake("db:migrate")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
|
52
|
+
def update_environmentss
|
53
|
+
default_mailer = "proj_name.com"
|
54
|
+
action_mailer = ask("What is the action mailer domain (normally just the domain)? [#{default_mailer}]")
|
55
|
+
action_mailer = default_mailer if action_mailer.blank?
|
56
|
+
application(nil, :env => "production") do
|
57
|
+
"config.action_mailer.default_url_options = { :host => #{action_mailer} }"
|
58
|
+
end
|
59
|
+
application(nil, :env => "test") do
|
60
|
+
"config.action_mailer.default_url_options = { :host => 'localhost:3000' }"
|
61
|
+
end
|
62
|
+
application(nil, :env => "development") do
|
63
|
+
"config.action_mailer.default_url_options = { :host => 'localhost:3000' }"
|
64
|
+
end
|
65
|
+
end
|
28
66
|
|
29
67
|
end
|
30
68
|
end
|
@@ -11,16 +11,16 @@
|
|
11
11
|
<%%= render :partial => "pages/links", :collection => @display_pages.topbar, :as => :page, :locals => {:classes => "left hover"} %>
|
12
12
|
<%% if user_signed_in? %>
|
13
13
|
<%%= link_to '<li class="left hover">Account</li>'.html_safe, edit_user_registration_path %>
|
14
|
-
<%%= link_to '<li class="
|
15
|
-
<li class="right last"
|
14
|
+
<%%= link_to '<li class="right hover">Sign out</li>'.html_safe, destroy_user_session_path, :method => :delete %>
|
15
|
+
<li class="right last lighter"><%%= current_user.email %></li>
|
16
16
|
<%% else %>
|
17
17
|
<%%= link_to '<li class="right hover">Sign in</li>'.html_safe, user_session_path %>
|
18
18
|
<%% end %>
|
19
19
|
</ul>
|
20
20
|
</nav>
|
21
21
|
<banner>
|
22
|
-
<%%= link_to logo, root_path, {:class => "right"} %>
|
23
|
-
<h1 class="left alt
|
22
|
+
<%%= link_to logo, root_path, {:class => "right prepend-1"} %>
|
23
|
+
<h1 class="left alt append-1"><%%= yield(:title) %></h1>
|
24
24
|
<%% flash.each do |key, value| %>
|
25
25
|
<div id="notice" class="left flash <%%= key %>"><%%= value %></div>
|
26
26
|
<%% end %>
|
@@ -33,7 +33,9 @@
|
|
33
33
|
<%% end %>
|
34
34
|
|
35
35
|
<%% content_for :userbar do %>
|
36
|
-
|
36
|
+
<%% if user_signed_in? %>
|
37
|
+
<%%= render 'shared/sidebar', :sidebar => @display_pages.userbar %>
|
38
|
+
<%% end %>
|
37
39
|
<%% end %>
|
38
40
|
|
39
41
|
<%% content_for :footer do %>
|
@@ -10,13 +10,18 @@ module Frame
|
|
10
10
|
|
11
11
|
class_option :force, :type => :boolean, :default => false, :desc => "Force file regeneration"
|
12
12
|
|
13
|
-
def add_gems
|
14
|
-
|
15
|
-
end
|
13
|
+
#def add_gems
|
14
|
+
# add_gem "mysql2"
|
15
|
+
#end
|
16
|
+
#Frame.Generators.PagesGenerator.add_gems
|
16
17
|
|
17
18
|
def remove_index
|
18
|
-
|
19
|
+
filename="public/index.html"
|
20
|
+
if File.exists?("filename") and yes?("Would you like to remove '#{filename}'?")
|
21
|
+
remove_file filename
|
22
|
+
end
|
19
23
|
end
|
24
|
+
#Frame.Generators.PagesGenerator.remove_index
|
20
25
|
|
21
26
|
def add_default_layout
|
22
27
|
template 'defaults.html.erb', 'app/views/layouts/defaults.html.erb'
|
@@ -27,11 +32,21 @@ module Frame
|
|
27
32
|
template 'application_helper.rb', 'app/helpers/application_helper.rb'
|
28
33
|
end
|
29
34
|
|
35
|
+
def add_images
|
36
|
+
template 'econ64.gif', 'app/assets/images/econ64.gif'
|
37
|
+
template 'favicon.ico', 'app/assets/images/favicon.ico'
|
38
|
+
end
|
39
|
+
|
30
40
|
def replace_html_app
|
31
41
|
@title = Rails.application.class.parent_name
|
32
42
|
template 'application.html.erb', 'app/views/layouts/application.html.erb'
|
33
43
|
end
|
34
44
|
|
45
|
+
def copy_css
|
46
|
+
template 'frame.css', 'app/assets/stylesheets/frame.css'
|
47
|
+
add_if_missing('app/assets/stylesheets/application.css', " *= require frame\n", :after => " *= require_self\n")
|
48
|
+
end
|
49
|
+
|
35
50
|
private
|
36
51
|
|
37
52
|
def destination_path(path)
|
@@ -7,6 +7,6 @@ module ApplicationHelper
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def logo
|
10
|
-
image_tag("
|
10
|
+
image_tag("econ64.gif", {:alt => "eContriver", :class => "round", :style => "width: 64px; height: 64px"})
|
11
11
|
end
|
12
12
|
end
|
@@ -13,8 +13,8 @@
|
|
13
13
|
</ul>
|
14
14
|
</nav>
|
15
15
|
<banner>
|
16
|
-
<%%= link_to logo, root_path, {:class => "right"} %>
|
17
|
-
<h1 class="left alt
|
16
|
+
<%%= link_to logo, root_path, {:class => "right prepend-1"} %>
|
17
|
+
<h1 class="left alt append-1"><%%= yield(:title) %></h1>
|
18
18
|
<%% flash.each do |key, value| %>
|
19
19
|
<div id="notice" class="left flash <%%= key %>"><%%= value %></div>
|
20
20
|
<%% end %>
|
Binary file
|
Binary file
|
@@ -0,0 +1,145 @@
|
|
1
|
+
body {
|
2
|
+
}
|
3
|
+
|
4
|
+
a {
|
5
|
+
color: gray;
|
6
|
+
border: none;
|
7
|
+
}
|
8
|
+
|
9
|
+
.box {
|
10
|
+
padding: 1.5em;
|
11
|
+
margin-bottom: 1.5em;
|
12
|
+
background: #f0f0f0;
|
13
|
+
border: 3px outset gray;
|
14
|
+
}
|
15
|
+
|
16
|
+
.ui-icon-grip-solid-horizontal {
|
17
|
+
cursor: move;
|
18
|
+
}
|
19
|
+
|
20
|
+
.debug_dump {
|
21
|
+
clear: both;
|
22
|
+
background-color: #e9967a;
|
23
|
+
border: 2px dashed black;
|
24
|
+
padding: 2em;
|
25
|
+
margin: 2em;
|
26
|
+
}
|
27
|
+
|
28
|
+
.field_with_errors {
|
29
|
+
display: initial;
|
30
|
+
font-style: italic;
|
31
|
+
color: #8A1F11;
|
32
|
+
}
|
33
|
+
|
34
|
+
.list {
|
35
|
+
background-color: #EEE;
|
36
|
+
border-top: 2px dotted #888;
|
37
|
+
padding: 1px 3px;
|
38
|
+
}
|
39
|
+
|
40
|
+
li.ui-state-highlight {
|
41
|
+
display: block;
|
42
|
+
height: 2em;
|
43
|
+
list-style-type: none;
|
44
|
+
}
|
45
|
+
|
46
|
+
.item {
|
47
|
+
list-style-type: none;
|
48
|
+
padding: 3px;
|
49
|
+
margin-bottom: 1px;
|
50
|
+
}
|
51
|
+
|
52
|
+
.list-action {
|
53
|
+
margin: 3px 5px;
|
54
|
+
top: 0;
|
55
|
+
}
|
56
|
+
|
57
|
+
.lighter {
|
58
|
+
font-weight: lighter;
|
59
|
+
}
|
60
|
+
|
61
|
+
select {
|
62
|
+
max-width: 40em;
|
63
|
+
}
|
64
|
+
|
65
|
+
nav ul {
|
66
|
+
margin: 0;
|
67
|
+
padding: 0 0.5em;
|
68
|
+
}
|
69
|
+
|
70
|
+
h1 {
|
71
|
+
/*font-family: Livory-RegularItalic;*/
|
72
|
+
/*font-family: Georgia,Palatino,Times,"MS Serif",serif;*/
|
73
|
+
}
|
74
|
+
|
75
|
+
aside nav ul li {
|
76
|
+
list-style-type: none;
|
77
|
+
color: black;
|
78
|
+
text-transform:uppercase;
|
79
|
+
font-weight: bolder;
|
80
|
+
}
|
81
|
+
|
82
|
+
aside nav ul li:hover {
|
83
|
+
text-decoration: underline;
|
84
|
+
color: #ff7f50;
|
85
|
+
}
|
86
|
+
|
87
|
+
header nav ul li {
|
88
|
+
list-style-type: none;
|
89
|
+
padding: 0.5em;
|
90
|
+
border-bottom: 2px solid black;
|
91
|
+
color: white;
|
92
|
+
font-weight: bolder;
|
93
|
+
}
|
94
|
+
|
95
|
+
footer nav ul li {
|
96
|
+
list-style-type: none;
|
97
|
+
padding: 0.5em;
|
98
|
+
border-top: 2px solid black;
|
99
|
+
color: white;
|
100
|
+
font-weight: bolder;
|
101
|
+
}
|
102
|
+
|
103
|
+
nav a {
|
104
|
+
color: #ffffff;
|
105
|
+
text-decoration: none;
|
106
|
+
}
|
107
|
+
|
108
|
+
header nav {
|
109
|
+
background-color: black;
|
110
|
+
border-bottom: 2px solid lightgray;
|
111
|
+
}
|
112
|
+
|
113
|
+
footer nav {
|
114
|
+
background-color: black;
|
115
|
+
border-top: 2px solid lightgray;
|
116
|
+
}
|
117
|
+
|
118
|
+
header nav ul li.hover:hover, nav ul li.selected {
|
119
|
+
color: #ff7f50;
|
120
|
+
border-bottom: 2px solid #F58400;
|
121
|
+
}
|
122
|
+
|
123
|
+
footer nav ul li.hover:hover, nav ul li.selected {
|
124
|
+
color: #ff7f50;
|
125
|
+
border-top: 2px solid #F58400;
|
126
|
+
}
|
127
|
+
|
128
|
+
.authentication {
|
129
|
+
border: 1px solid black;
|
130
|
+
margin: 1em;
|
131
|
+
padding: 0.5em;
|
132
|
+
background: #EEE;
|
133
|
+
}
|
134
|
+
|
135
|
+
.auth_provider img {
|
136
|
+
display: block;
|
137
|
+
}
|
138
|
+
|
139
|
+
.auth_provider {
|
140
|
+
float: left;
|
141
|
+
text-decoration: none;
|
142
|
+
margin-right: 20px;
|
143
|
+
text-align: center;
|
144
|
+
margin-bottom: 10px;
|
145
|
+
}
|
@@ -8,6 +8,23 @@ module Frame
|
|
8
8
|
|
9
9
|
desc "Update MySQL with user priveleges."
|
10
10
|
|
11
|
+
def add_gems
|
12
|
+
gem("mysql2")
|
13
|
+
comment_lines 'Gemfile', /gem 'sqlite3'/
|
14
|
+
Bundler.with_clean_env do
|
15
|
+
run "bundle"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def drop_db
|
20
|
+
config = YAML.load_file('config/database.yml')
|
21
|
+
db = config[Rails.env]["database"]
|
22
|
+
puts "database: #{db}"
|
23
|
+
output = create_file 'tmp/drop_db.sql', "DROP DATABASE IF EXISTS #{db};"
|
24
|
+
puts "output: #{output}\nEnter mysql root password"
|
25
|
+
system "mysql -u root -p < #{output}"
|
26
|
+
end
|
27
|
+
|
11
28
|
def add_user
|
12
29
|
config = YAML.load_file('config/database.yml')
|
13
30
|
user = config[Rails.env]["username"]
|
@@ -15,7 +32,7 @@ module Frame
|
|
15
32
|
puts "creating user: #{user}"
|
16
33
|
puts "using pw: #{pw}"
|
17
34
|
output = create_file 'tmp/create_user.sql', "CREATE USER '#{user}'@localhost IDENTIFIED BY '#{pw}';"
|
18
|
-
puts "output: #{output}"
|
35
|
+
puts "output: #{output}\nEnter mysql root password"
|
19
36
|
system "mysql -u root -p < #{output}"
|
20
37
|
end
|
21
38
|
|
@@ -26,10 +43,14 @@ module Frame
|
|
26
43
|
puts "granting user: #{user}"
|
27
44
|
puts "all on db: #{db}"
|
28
45
|
output = create_file 'tmp/grant_user.sql', "GRANT ALL PRIVILEGES ON #{db}.* TO '#{user}'@localhost;"
|
29
|
-
puts "output: #{output}"
|
46
|
+
puts "output: #{output}\nEnter mysql root password"
|
30
47
|
system "mysql -u root -p < #{output}"
|
31
48
|
end
|
32
49
|
|
50
|
+
def create_db
|
51
|
+
rake("db:setup")
|
52
|
+
end
|
53
|
+
|
33
54
|
end
|
34
55
|
end
|
35
56
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Description:
|
2
|
+
Generates devise omniauth installation.
|
3
|
+
|
4
|
+
Usage:
|
5
|
+
Use to generate install and setup devise omniauth for a project.
|
6
|
+
|
7
|
+
Examples:
|
8
|
+
rails generate frame:devise
|
9
|
+
|
10
|
+
Methods:
|
11
|
+
There are several methods generated which you can use in your application.
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'generators/frame'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
#require "omniauth-twitter"
|
4
|
+
|
5
|
+
module Frame
|
6
|
+
module Generators
|
7
|
+
class OmniauthGenerator < Base
|
8
|
+
include Rails::Generators::Migration
|
9
|
+
|
10
|
+
desc "Installs Devises Omniauth."
|
11
|
+
|
12
|
+
def install_omniauth
|
13
|
+
gem 'omniauth'
|
14
|
+
gem 'oauth2'
|
15
|
+
gem 'omniauth-twitter'
|
16
|
+
gem 'omniauth-google-oauth2'
|
17
|
+
|
18
|
+
Bundler.with_clean_env do
|
19
|
+
run "bundle"
|
20
|
+
end
|
21
|
+
|
22
|
+
generate("migration AddColumnsToUsers provider:string uid:string")
|
23
|
+
uncomment_lines('config/initializers/session_store.rb', "Tester::Application.config.session_store :active_record_store")
|
24
|
+
generate("session_migration")
|
25
|
+
rake("db:migrate")
|
26
|
+
|
27
|
+
add_if_missing('app/models/user.rb', ":provider, :uid,", :after => " attr_accessible ")
|
28
|
+
add_if_missing('app/models/user.rb', ":omniauthable, ", :after => " devise ")
|
29
|
+
|
30
|
+
add_if_missing('config/routes.rb', ", :controllers => { :omniauth_callbacks => \"users/omniauth_callbacks\" }", :after => " devise_for :users")
|
31
|
+
|
32
|
+
template 'omniauth.rb', 'config/initializers/omniauth.rb'
|
33
|
+
template 'omniauth_callbacks_controller.rb', 'app/controllers/users/omniauth_callbacks_controller.rb'
|
34
|
+
|
35
|
+
add_if_missing('app/models/user.rb', '
|
36
|
+
def self.find_for_twitter_oauth(auth, signed_in_resource=nil)
|
37
|
+
Rails.logger.debug "(DEBUG) auth: #{auth.to_yaml}"
|
38
|
+
user = User.where(:provider => auth.provider, :uid => auth.uid).first
|
39
|
+
unless user
|
40
|
+
#name:auth.extra.raw_info.name,
|
41
|
+
user = User.create(
|
42
|
+
provider:auth.provider,
|
43
|
+
uid:auth.uid,
|
44
|
+
email:auth.info.email,
|
45
|
+
password:Devise.friendly_token[0,20]
|
46
|
+
)
|
47
|
+
end
|
48
|
+
user
|
49
|
+
end', :before => "\nend")
|
50
|
+
|
51
|
+
add_if_missing('app/models/user.rb', '
|
52
|
+
def self.find_for_google_oauth(auth, signed_in_resource=nil)
|
53
|
+
Rails.logger.debug "(DEBUG) auth: #{auth.to_yaml}"
|
54
|
+
user = User.where(:provider => auth.provider, :uid => auth.uid).first
|
55
|
+
unless user
|
56
|
+
#name:auth.extra.raw_info.name,
|
57
|
+
user = User.create(
|
58
|
+
provider:auth.provider,
|
59
|
+
uid:auth.uid,
|
60
|
+
email:auth.info.email,
|
61
|
+
password:Devise.friendly_token[0,20]
|
62
|
+
)
|
63
|
+
end
|
64
|
+
user
|
65
|
+
end', :before => "\nend")
|
66
|
+
|
67
|
+
add_if_missing('Rakefile', "
|
68
|
+
files = ['config/initializers/omniauth.rb','config/database.yml','config/initializers/secret_token.rb']
|
69
|
+
|
70
|
+
domain = \"#{Rails.application.class.parent_name.downcase}.econtriver.com\"
|
71
|
+
set :user, \"root\" # The server's user for deploys
|
72
|
+
set :deploy_to, \"/srv/www/\#{domain}\"
|
73
|
+
|
74
|
+
task :put_secret do
|
75
|
+
files.each do |f|
|
76
|
+
system(\"scp \#{f} \#{user}@\#{domain}:\#{File.join(deploy_to,'private',f)}\")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
task :get_secret do
|
81
|
+
files.each do |f|
|
82
|
+
system(\"scp \#{user}@\#{domain}:\#{File.join(deploy_to,'private',f)} \#{f}\")
|
83
|
+
end
|
84
|
+
end", :after => "Tester::Application.load_tasks\n")
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|