merb_datamapper 0.9.2 → 0.9.3
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/History.txt +1 -0
- data/Manifest.txt +33 -0
- data/README.txt +13 -0
- data/Rakefile +47 -35
- data/TODO +10 -4
- data/datamapper_generators/migration/USAGE +2 -3
- data/datamapper_generators/migration/migration_generator.rb +6 -6
- data/datamapper_generators/migration/templates/new_migration.erb +3 -3
- data/datamapper_generators/model/model_generator.rb +17 -10
- data/datamapper_generators/model/templates/app/models/%model_file_name%.rb +7 -5
- data/datamapper_generators/resource_controller/resource_controller_generator.rb +62 -27
- data/datamapper_generators/resource_controller/templates/app/controllers/%controller_file_name%.rb +6 -6
- data/datamapper_generators/resource_controller/templates/app/helpers/%controller_file_name%_helper.rb +1 -1
- data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/edit.html.erb +19 -1
- data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/index.html.erb +22 -1
- data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/new.html.erb +18 -1
- data/datamapper_generators/resource_controller/templates/app/views/%controller_file_name%/show.html.erb +12 -1
- data/datamapper_generators/resource_migration/USAGE +4 -0
- data/datamapper_generators/resource_migration/resource_migration_generator.rb +122 -0
- data/datamapper_generators/resource_migration/templates/class_migration.erb +13 -0
- data/lib/merb/orms/data_mapper/connection.rb +61 -26
- data/lib/merb/orms/data_mapper/database.yml.sample +32 -12
- data/lib/merb/orms/data_mapper/resource.rb +12 -0
- data/lib/merb/session/data_mapper_session.rb +47 -40
- data/lib/merb_datamapper.rb +15 -11
- data/lib/merb_datamapper/merbtasks.rb +42 -13
- data/lib/merb_datamapper/version.rb +5 -0
- data/spec/connection_spec.rb +67 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +15 -0
- metadata +58 -45
- data/README +0 -10
- data/lib/merb/orms/data_mapper/base.rb +0 -6
- data/specs/merb_sequel_spec.rb +0 -0
- data/specs/spec_helper.rb +0 -2
@@ -1,3 +1,21 @@
|
|
1
1
|
<h1><%= full_controller_const %> controller, edit action</h1>
|
2
2
|
|
3
|
-
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/edit.html.erb</tt></p>
|
3
|
+
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/edit.html.erb</tt></p>
|
4
|
+
|
5
|
+
<%%= error_messages_for :<%= singular_model %> %>
|
6
|
+
|
7
|
+
<%% form_for(@<%= singular_model %>, :action => url(:<%= singular_model %>, @<%= singular_model %>)) do %>
|
8
|
+
<% for property in properties.select{|p| !p.key?} -%>
|
9
|
+
<p>
|
10
|
+
<b><%= Extlib::Inflection.humanize(property.field) %></b><br />
|
11
|
+
<%%= <%= field_from_type(property.type) %> :<%= property.getter %> %>
|
12
|
+
</p>
|
13
|
+
|
14
|
+
<% end -%>
|
15
|
+
<p>
|
16
|
+
<%%= submit_button "Update" %>
|
17
|
+
</p>
|
18
|
+
<%% end %>
|
19
|
+
|
20
|
+
<%%= link_to 'Show', url(:<%= singular_model %>, @<%= singular_model %>) %> |
|
21
|
+
<%%= link_to 'Back', url(:<%= plural_model %>) %>
|
@@ -1,3 +1,24 @@
|
|
1
1
|
<h1><%= full_controller_const %> controller, index action</h1>
|
2
2
|
|
3
|
-
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/index.html.erb</tt></p>
|
3
|
+
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/index.html.erb</tt></p>
|
4
|
+
|
5
|
+
<table>
|
6
|
+
<tr>
|
7
|
+
<% for property in properties.reject{|p| p.lazy?} -%>
|
8
|
+
<th><%= Extlib::Inflection.humanize(property.field) %></th>
|
9
|
+
<% end -%>
|
10
|
+
</tr>
|
11
|
+
|
12
|
+
<%% for <%= singular_model %> in @<%= plural_model %> %>
|
13
|
+
<tr>
|
14
|
+
<% for property in properties.reject{|p| p.lazy?} -%>
|
15
|
+
<td><%%=h <%= singular_model %>.<%= property.getter %> %></td>
|
16
|
+
<% end -%>
|
17
|
+
<td><%%= link_to 'Show', url(:<%= singular_model %>, <%= singular_model %>) %></td>
|
18
|
+
<td><%%= link_to 'Edit', url(:edit_<%= singular_model %>, <%= singular_model %>) %></td>
|
19
|
+
<td><%%= delete_button :<%= singular_model %>, <%= singular_model %> %></td>
|
20
|
+
</tr>
|
21
|
+
<%% end %>
|
22
|
+
</table>
|
23
|
+
|
24
|
+
<%%= link_to 'New', url(:new_<%= singular_model %>) %>
|
@@ -1,3 +1,20 @@
|
|
1
1
|
<h1><%= full_controller_const %> controller, new action</h1>
|
2
2
|
|
3
|
-
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/new.html.erb</tt></p>
|
3
|
+
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/new.html.erb</tt></p>
|
4
|
+
|
5
|
+
<%%= error_messages_for :<%= singular_model %> %>
|
6
|
+
|
7
|
+
<%% form_for(@<%= singular_model %>, :action => url(:<%= plural_model %>) ) do |f| %>
|
8
|
+
<% for property in properties.select{|p| !p.key?} -%>
|
9
|
+
<p>
|
10
|
+
<b><%= Extlib::Inflection.humanize(property.field) %></b><br />
|
11
|
+
<%%= <%= field_from_type(property.type) %> :<%= property.getter %> %>
|
12
|
+
</p>
|
13
|
+
|
14
|
+
<% end -%>
|
15
|
+
<p>
|
16
|
+
<%%= submit_button "Create" %>
|
17
|
+
</p>
|
18
|
+
<%% end %>
|
19
|
+
|
20
|
+
<%%= link_to 'Back', url(:<%= plural_model %>) %>
|
@@ -1,3 +1,14 @@
|
|
1
1
|
<h1><%= full_controller_const %> controller, show action</h1>
|
2
2
|
|
3
|
-
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/show.html.erb</tt></p>
|
3
|
+
<p>Edit this file in <tt>app/views/<%= controller_file_name %>/show.html.erb</tt></p>
|
4
|
+
|
5
|
+
<% for property in properties -%>
|
6
|
+
<p>
|
7
|
+
<b><%= Extlib::Inflection.humanize(property.field) %>:</b>
|
8
|
+
<%%=h @<%= singular_model %>.<%= property.getter %> %>
|
9
|
+
</p>
|
10
|
+
|
11
|
+
<% end -%>
|
12
|
+
|
13
|
+
<%%= link_to 'Edit', url(:edit_<%= singular_model %>, @<%= singular_model %>) %> |
|
14
|
+
<%%= link_to 'Back', url(:<%= plural_model %>) %>
|
@@ -0,0 +1,122 @@
|
|
1
|
+
# require 'merb'
|
2
|
+
class ResourceMigrationGenerator < RubiGen::Base
|
3
|
+
|
4
|
+
# these define datamapper specific properties, not general database concepts
|
5
|
+
UNWANTED_PROPERTIES = [:public, :protected, :private, :accessor,
|
6
|
+
:reader, :writer, :lazy, :lock, :field, :ordinal,
|
7
|
+
:track, :auto_validation, :validates]
|
8
|
+
|
9
|
+
default_options :author => nil
|
10
|
+
|
11
|
+
attr_reader :name, :klass
|
12
|
+
|
13
|
+
def initialize(runtime_args, runtime_options = {})
|
14
|
+
super
|
15
|
+
usage if args.empty?
|
16
|
+
@name = args.shift
|
17
|
+
extract_options
|
18
|
+
end
|
19
|
+
|
20
|
+
def manifest
|
21
|
+
unless @name
|
22
|
+
puts banner
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
|
26
|
+
# first see if we can find our model file where it should be!
|
27
|
+
model_file = File.join(Dir.pwd, "app/models","#{@name.snake_case}.rb")
|
28
|
+
unless File.exist?(model_file)
|
29
|
+
puts "Couldn't find the model file for #{@name}"
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
|
33
|
+
# next, check we actually have a class!
|
34
|
+
require model_file
|
35
|
+
@klass = Module.const_get(@name.camel_case)
|
36
|
+
if @klass.nil?
|
37
|
+
puts "File didn't seem to include the model #{@name.camel_case}"
|
38
|
+
exit 1
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
record do |m|
|
45
|
+
# Ensure appropriate folders exists
|
46
|
+
m.directory 'schema/migrations'
|
47
|
+
|
48
|
+
@migration_name = "create_%s_table" % @name.snake_case.pluralize
|
49
|
+
|
50
|
+
filename = format("%03d_%s", (highest_migration+1), @migration_name)
|
51
|
+
|
52
|
+
m.template "class_migration.erb", "schema/migrations/#{filename}.rb",
|
53
|
+
:assigns => {
|
54
|
+
:migration_name => @migration_name ,
|
55
|
+
:number => (highest_migration+1),
|
56
|
+
:klass_name => klass.storage_name,
|
57
|
+
:properties => properties_as_strings
|
58
|
+
}
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
def banner
|
65
|
+
<<-EOS
|
66
|
+
Creates a new migration for merb using DataMapper
|
67
|
+
|
68
|
+
USAGE: #{$0} #{spec.name} ResourceClass
|
69
|
+
|
70
|
+
Example:
|
71
|
+
#{$0} #{spec.name} Post
|
72
|
+
|
73
|
+
If you already have 3 migrations, this will create the Post migration in
|
74
|
+
schema/migration/004_create_posts_table.rb
|
75
|
+
|
76
|
+
NB: Currently the generator doesn't make any columns for 'belongs_to'-type
|
77
|
+
associations.
|
78
|
+
EOS
|
79
|
+
end
|
80
|
+
|
81
|
+
def add_options!(opts)
|
82
|
+
# opts.separator ''
|
83
|
+
# opts.separator 'Options:'
|
84
|
+
# For each option below, place the default
|
85
|
+
# at the top of the file next to "default_options"
|
86
|
+
# opts.on("-a", "--author=\"Your Name\"", String,
|
87
|
+
# "Some comment about this option",
|
88
|
+
# "Default: none") { |options[:author]| }
|
89
|
+
# opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
|
90
|
+
end
|
91
|
+
|
92
|
+
def extract_options
|
93
|
+
# for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
|
94
|
+
# Templates can access these value via the attr_reader-generated methods, but not the
|
95
|
+
# raw instance variable value.
|
96
|
+
# @author = options[:author]
|
97
|
+
end
|
98
|
+
|
99
|
+
def highest_migration
|
100
|
+
@highest_migration ||= Dir[Dir.pwd+'/schema/migrations/*'].map{ |f|
|
101
|
+
File.basename(f) =~ /^(\d+)/
|
102
|
+
$1}.max.to_i
|
103
|
+
end
|
104
|
+
|
105
|
+
def property_as_string(p)
|
106
|
+
name = p.field
|
107
|
+
type = p.type.to_s
|
108
|
+
# clear out non-db related properties
|
109
|
+
options = p.options.reject { |key, value| UNWANTED_PROPERTIES.include? key }
|
110
|
+
options_as_array = []
|
111
|
+
options.each do |key, value|
|
112
|
+
options_as_array << ":#{key} => #{value}"
|
113
|
+
end
|
114
|
+
|
115
|
+
(options_as_array.empty?) ? ":#{name}, #{type}" :
|
116
|
+
":#{name}, #{type}, #{options_as_array.join(', ')}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def properties_as_strings
|
120
|
+
@properties_as_strings ||= klass.properties.map {|p| property_as_string(p) }
|
121
|
+
end
|
122
|
+
end
|
@@ -1,40 +1,33 @@
|
|
1
1
|
require 'fileutils'
|
2
|
-
require 'data_mapper'
|
3
2
|
|
4
3
|
module Merb
|
5
4
|
module Orms
|
6
5
|
module DataMapper
|
7
6
|
class << self
|
8
|
-
def config_file() Merb.
|
9
|
-
def sample_dest() Merb.
|
7
|
+
def config_file() Merb.dir_for(:config) / "database.yml" end
|
8
|
+
def sample_dest() Merb.dir_for(:config) / "database.yml.sample" end
|
10
9
|
def sample_source() File.dirname(__FILE__) / "database.yml.sample" end
|
11
|
-
|
10
|
+
|
12
11
|
def copy_sample_config
|
13
12
|
FileUtils.cp sample_source, sample_dest unless File.exists?(sample_dest)
|
14
13
|
end
|
15
|
-
|
14
|
+
|
15
|
+
def full_config
|
16
|
+
@full_config ||= Erubis.load_yaml_file(config_file)
|
17
|
+
end
|
18
|
+
|
16
19
|
def config
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
config = (Merb::Plugins.config[:merb_datamapper] = {})
|
22
|
-
(full_config[Merb.environment.to_sym] || full_config[Merb.environment]).each do |k, v|
|
23
|
-
if k == 'port'
|
24
|
-
config[k.to_sym] = v.to_i
|
25
|
-
else
|
26
|
-
config[k.to_sym] = v
|
27
|
-
end
|
28
|
-
end
|
29
|
-
config
|
30
|
-
end
|
20
|
+
if !Merb::Plugins.config[:merb_datamapper].nil? && Merb::Plugins.config[:merb_datamapper].empty?
|
21
|
+
Merb::Plugins.config[:merb_datamapper] = get_config_for_environment
|
22
|
+
end
|
23
|
+
@config ||= Merb::Plugins.config[:merb_datamapper] ||= get_config_for_environment
|
31
24
|
end
|
32
|
-
|
25
|
+
|
33
26
|
# Database connects as soon as the gem is loaded
|
34
27
|
def connect
|
35
28
|
if File.exists?(config_file)
|
36
|
-
|
37
|
-
|
29
|
+
start_logging
|
30
|
+
setup_connections
|
38
31
|
else
|
39
32
|
copy_sample_config
|
40
33
|
Merb.logger.error! "No database.yml file found in #{Merb.root}/config."
|
@@ -42,15 +35,57 @@ module Merb
|
|
42
35
|
exit(1)
|
43
36
|
end
|
44
37
|
end
|
45
|
-
|
38
|
+
|
39
|
+
def start_logging
|
40
|
+
::DataMapper.logger = Merb.logger
|
41
|
+
::DataMapper.logger.info("Connecting to database...")
|
42
|
+
end
|
43
|
+
|
44
|
+
def setup_connections
|
45
|
+
conf = config.dup
|
46
|
+
repositories = conf.delete(:repositories)
|
47
|
+
::DataMapper.setup(:default, conf) unless conf.empty?
|
48
|
+
repositories.each { |name, opts| ::DataMapper.setup(name, opts) } if repositories
|
49
|
+
end
|
50
|
+
|
46
51
|
# Registering this ORM lets the user choose DataMapper as a session store
|
47
52
|
# in merb.yml's session_store: option.
|
48
53
|
def register_session_type
|
49
54
|
Merb.register_session_type("datamapper",
|
50
|
-
|
51
|
-
|
55
|
+
"merb/session/data_mapper_session",
|
56
|
+
"Using DataMapper database sessions")
|
57
|
+
end
|
58
|
+
|
59
|
+
def symbolize_keys(h)
|
60
|
+
config = {}
|
61
|
+
|
62
|
+
h.each do |k, v|
|
63
|
+
if k == 'port'
|
64
|
+
config[k.to_sym] = v.to_i
|
65
|
+
elsif k == 'adapter' && v == 'postgresql'
|
66
|
+
config[k.to_sym] = 'postgres'
|
67
|
+
elsif v.is_a?(Hash)
|
68
|
+
config[k.to_sym] = symbolize_keys(v)
|
69
|
+
else
|
70
|
+
config[k.to_sym] = v
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
config
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def get_config_for_environment
|
80
|
+
if hash = full_config[Merb.environment]
|
81
|
+
symbolize_keys(hash)
|
82
|
+
elsif hash = full_config[Merb.environment.to_sym]
|
83
|
+
hash
|
84
|
+
else
|
85
|
+
raise ArgumentError, "missing environment '#{Merb.environment}' in config file #{config_file}"
|
86
|
+
end
|
52
87
|
end
|
53
88
|
end
|
54
89
|
end
|
55
90
|
end
|
56
|
-
end
|
91
|
+
end
|
@@ -1,16 +1,36 @@
|
|
1
1
|
---
|
2
2
|
# This is a sample database file for the DataMapper ORM
|
3
|
-
|
4
|
-
:
|
5
|
-
:
|
6
|
-
:
|
7
|
-
:
|
8
|
-
:
|
3
|
+
development: &defaults
|
4
|
+
# These are the settings for repository :default
|
5
|
+
adapter: postgres
|
6
|
+
database: sample_development
|
7
|
+
username: the_user
|
8
|
+
password: secrets
|
9
|
+
host: localhost
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
:
|
11
|
+
# Add more repositories
|
12
|
+
# repositories:
|
13
|
+
# repo1:
|
14
|
+
# adapter: postgresql
|
15
|
+
# database: sample_development
|
16
|
+
# username: the_user
|
17
|
+
# password: secrets
|
18
|
+
# host: localhost
|
19
|
+
# repo2:
|
20
|
+
# ...
|
13
21
|
|
14
|
-
:
|
15
|
-
<<:
|
16
|
-
|
22
|
+
test:
|
23
|
+
<<: *defaults
|
24
|
+
database: sample_test
|
25
|
+
|
26
|
+
# repositories:
|
27
|
+
# repo1:
|
28
|
+
# database: sample_development
|
29
|
+
|
30
|
+
production:
|
31
|
+
<<: *defaults
|
32
|
+
database: sample_production
|
33
|
+
|
34
|
+
# repositories:
|
35
|
+
# repo1:
|
36
|
+
# database: sample_development
|
@@ -1,4 +1,10 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
gem 'dm-core', '=0.9.3'
|
3
|
+
require 'dm-core'
|
4
|
+
rescue LoadError => e
|
5
|
+
require 'data_mapper'
|
6
|
+
end
|
7
|
+
|
2
8
|
require 'base64'
|
3
9
|
module Merb
|
4
10
|
module SessionMixin
|
@@ -20,27 +26,31 @@ module Merb
|
|
20
26
|
end
|
21
27
|
|
22
28
|
table_name = (Merb::Plugins.config[:merb_datamapper][:session_table_name] || "sessions")
|
23
|
-
|
24
|
-
class DataMapperSession
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
property :
|
29
|
-
property :
|
30
|
-
|
29
|
+
|
30
|
+
class DataMapperSession
|
31
|
+
include DataMapper::Resource
|
32
|
+
|
33
|
+
storage_names[:default] = "sessions"
|
34
|
+
property :session_id, String, :length => 255, :lazy => false, :key => true
|
35
|
+
property :data, Text, :lazy => false
|
36
|
+
property :updated_at, DateTime
|
37
|
+
|
31
38
|
attr_accessor :needs_new_cookie
|
32
|
-
|
39
|
+
|
33
40
|
class << self
|
34
41
|
# Generates a new session ID and creates a row for the new session in the database.
|
35
42
|
def generate
|
36
|
-
|
43
|
+
new_session = self.new(:data =>{})
|
44
|
+
new_session.session_id = Merb::SessionMixin::rand_uuid
|
45
|
+
new_session.save
|
46
|
+
new_session
|
37
47
|
end
|
38
|
-
|
48
|
+
|
39
49
|
# Gets the existing session based on the <tt>session_id</tt> available in cookies.
|
40
50
|
# If none is found, generates a new session.
|
41
51
|
def persist(session_id)
|
42
|
-
if session_id
|
43
|
-
session = self
|
52
|
+
if !session_id.blank?
|
53
|
+
session = self.first :session_id => session_id
|
44
54
|
end
|
45
55
|
unless session
|
46
56
|
session = generate
|
@@ -51,62 +61,59 @@ module Merb
|
|
51
61
|
def marshal(data) Base64.encode64(Marshal.dump(data)) if data end
|
52
62
|
def unmarshal(data) Marshal.load(Base64.decode64(data)) if data end
|
53
63
|
end
|
54
|
-
|
64
|
+
|
55
65
|
# Regenerate the Session ID
|
56
66
|
def regenerate
|
57
67
|
self.session_id = Merb::SessionMixin::rand_uuid
|
58
68
|
self.needs_new_cookie = true
|
59
69
|
self.save
|
60
|
-
end
|
61
|
-
|
62
|
-
# Recreates the cookie with the default expiration time
|
63
|
-
# Useful during log in for pushing back the expiration date
|
70
|
+
end
|
71
|
+
|
72
|
+
# Recreates the cookie with the default expiration time
|
73
|
+
# Useful during log in for pushing back the expiration date
|
64
74
|
def refresh_expiration
|
65
75
|
self.needs_new_cookie = true
|
66
76
|
end
|
67
|
-
|
68
|
-
# Lazy-delete of session data
|
77
|
+
|
78
|
+
# Lazy-delete of session data
|
69
79
|
def delete(key = nil)
|
70
80
|
key ? self.data.delete(key) : self.data.clear
|
71
81
|
end
|
72
|
-
|
82
|
+
|
73
83
|
def empty?
|
74
84
|
data.empty?
|
75
85
|
end
|
76
|
-
|
86
|
+
|
77
87
|
def each(&b)
|
78
88
|
data.each(&b)
|
79
89
|
end
|
80
|
-
|
90
|
+
|
91
|
+
def each_with_index(&b)
|
92
|
+
data.each_with_index(&b)
|
93
|
+
end
|
94
|
+
|
81
95
|
def [](key)
|
82
96
|
data[key]
|
83
97
|
end
|
84
|
-
|
98
|
+
|
85
99
|
def []=(key, val)
|
86
100
|
data[key] = val
|
87
101
|
end
|
88
|
-
|
102
|
+
|
89
103
|
def data
|
90
|
-
@unmarshalled_data
|
104
|
+
@unmarshalled_data ||= self.class.unmarshal(@data) || {}
|
91
105
|
end
|
92
|
-
|
106
|
+
|
93
107
|
def data=(data)
|
94
108
|
@data, @unmarshalled_data = data, data
|
95
109
|
end
|
96
|
-
|
110
|
+
|
97
111
|
private
|
98
|
-
|
99
|
-
|
100
|
-
|
112
|
+
|
113
|
+
before :save, :serialize_data
|
114
|
+
|
101
115
|
def serialize_data
|
102
|
-
|
116
|
+
attribute_set :data, self.class.marshal(self.data)
|
103
117
|
end
|
104
118
|
end
|
105
|
-
|
106
|
-
|
107
|
-
unless DataMapper.database.table_exists?(table_name)
|
108
|
-
puts "Warning: The database did not contain a '#{table_name}' table for sessions."
|
109
|
-
DataMapperSession.auto_migrate!
|
110
|
-
puts "Created sessions table."
|
111
|
-
end
|
112
119
|
end
|