ruby_mvc 0.0.1 → 0.0.2
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/README.md +14 -0
- data/lib/ruby_mvc.rb +3 -1
- data/lib/ruby_mvc/application.rb +52 -2
- data/lib/ruby_mvc/controllers.rb +28 -0
- data/lib/ruby_mvc/controllers/action.rb +93 -0
- data/lib/ruby_mvc/controllers/action_group.rb +70 -0
- data/lib/ruby_mvc/controllers/app_controller.rb +4 -2
- data/lib/ruby_mvc/controllers/rails_controller.rb +2 -0
- data/lib/ruby_mvc/models.rb +2 -0
- data/lib/ruby_mvc/models/ar_table_model.rb +133 -0
- data/lib/ruby_mvc/models/array_table_model.rb +81 -13
- data/lib/ruby_mvc/models/keyed_array_table_model.rb +1 -1
- data/lib/ruby_mvc/models/model.rb +129 -0
- data/lib/ruby_mvc/models/table_model.rb +107 -10
- data/lib/ruby_mvc/models/view_model_template.rb +140 -0
- data/lib/ruby_mvc/renderers.rb +1 -0
- data/lib/ruby_mvc/renderers/html4_table_model_renderer.rb +7 -6
- data/lib/ruby_mvc/renderers/hyperlink_cell_renderer.rb +47 -0
- data/lib/ruby_mvc/toolkit.rb +5 -1
- data/lib/ruby_mvc/toolkit/browser_history.rb +115 -0
- data/lib/ruby_mvc/toolkit/dialog.rb +12 -1
- data/lib/ruby_mvc/toolkit/frame.rb +3 -1
- data/lib/ruby_mvc/toolkit/grid_view.rb +46 -0
- data/lib/ruby_mvc/toolkit/messagebox.rb +32 -0
- data/lib/ruby_mvc/toolkit/peers/wxruby.rb +5 -0
- data/lib/ruby_mvc/toolkit/peers/wxruby/app.rb +23 -2
- data/lib/ruby_mvc/toolkit/peers/wxruby/common.rb +11 -1
- data/lib/ruby_mvc/toolkit/peers/wxruby/dialog.rb +82 -0
- data/lib/ruby_mvc/toolkit/peers/wxruby/form_builder.rb +108 -0
- data/lib/ruby_mvc/toolkit/peers/wxruby/frame.rb +85 -1
- data/lib/ruby_mvc/toolkit/peers/wxruby/grid_model.rb +79 -0
- data/lib/ruby_mvc/toolkit/peers/wxruby/grid_view.rb +117 -0
- data/lib/ruby_mvc/toolkit/peers/wxruby/messagebox.rb +58 -0
- data/lib/ruby_mvc/toolkit/peers/wxruby/web_view.rb +40 -10
- data/lib/ruby_mvc/toolkit/property_change_notifier.rb +46 -0
- data/lib/ruby_mvc/toolkit/signal_handler.rb +149 -0
- data/lib/ruby_mvc/toolkit/web_view.rb +1 -1
- data/lib/ruby_mvc/toolkit/widget.rb +13 -6
- data/lib/ruby_mvc/views.rb +8 -59
- data/lib/ruby_mvc/views/{ar_type_list.rb → ar_form_view.rb} +10 -13
- data/lib/ruby_mvc/views/ar_support.rb +29 -0
- data/lib/ruby_mvc/views/ar_type_editor.rb +17 -28
- data/lib/ruby_mvc/views/ar_web_model_view.rb +59 -0
- data/lib/ruby_mvc/views/ar_web_type_list.rb +44 -0
- data/lib/ruby_mvc/views/browser_view.rb +185 -0
- data/lib/ruby_mvc/views/form_view.rb +111 -0
- data/lib/ruby_mvc/views/grid_table_view.rb +96 -0
- data/lib/ruby_mvc/views/table_view.rb +0 -39
- data/lib/ruby_mvc/views/view.rb +121 -0
- data/lib/ruby_mvc/views/web_content_table_view.rb +40 -0
- data/lib/ruby_mvc/views/{web_view.rb → web_content_view.rb} +17 -28
- data/lib/ruby_mvc/views/web_model_view.rb +67 -0
- data/ruby_mvc.gemspec +1 -1
- data/sample/browser_view.rb +57 -0
- data/sample/form.rb +59 -0
- data/sample/form2.rb +63 -0
- data/sample/grid_table_view.rb +68 -0
- data/sample/grid_view.rb +44 -0
- data/sample/grid_view2.rb +57 -0
- data/sample/test.html +1 -0
- data/sample/test2.html +33 -0
- data/sample/web_view.rb +4 -0
- data/test/unit/models/test_array_table_model.rb +19 -3
- data/test/unit/models/test_keyed_array_table_model.rb +3 -2
- data/test/unit/models/test_model.rb +88 -0
- metadata +39 -20
- data/lib/ruby_mvc/toolkit/notification.rb +0 -202
- data/lib/ruby_mvc/views/ar_model_editor.rb +0 -84
@@ -38,29 +38,32 @@ module RubyMVC
|
|
38
38
|
evt_html_link_clicked self, :on_link_clicked
|
39
39
|
#evt_html_cell_hover self, :on_hover
|
40
40
|
end
|
41
|
+
@history = BrowserHistory.new
|
41
42
|
end
|
42
43
|
|
43
|
-
|
44
|
+
def location
|
45
|
+
@history.current
|
46
|
+
end
|
44
47
|
|
45
48
|
def can_go_back?
|
46
|
-
|
49
|
+
@history.has_prev?
|
47
50
|
end
|
48
51
|
|
49
52
|
def can_go_forward?
|
50
|
-
|
53
|
+
@history.has_next?
|
51
54
|
end
|
52
55
|
|
53
56
|
def go_back
|
54
|
-
|
57
|
+
load_entry @history.prev
|
55
58
|
end
|
56
59
|
|
57
60
|
def go_forward
|
58
|
-
|
61
|
+
load_entry @history.next
|
59
62
|
end
|
60
63
|
|
61
64
|
def open(uri)
|
62
|
-
@
|
63
|
-
|
65
|
+
@history << { :uri => uri }
|
66
|
+
load_entry(@history.current)
|
64
67
|
end
|
65
68
|
|
66
69
|
def stop_loading
|
@@ -68,13 +71,30 @@ module RubyMVC
|
|
68
71
|
end
|
69
72
|
|
70
73
|
def reload
|
71
|
-
|
74
|
+
load_entry(@history.current)
|
72
75
|
end
|
73
76
|
|
74
77
|
def load_html(html, base_uri = nil)
|
75
78
|
# FIXME: this isn't quite right...
|
76
|
-
|
77
|
-
|
79
|
+
if base_uri
|
80
|
+
if base_uri != @history.current[:uri]
|
81
|
+
@history << { :uri => base_uri, :content => html }
|
82
|
+
else
|
83
|
+
@history.current[:content] = html
|
84
|
+
end
|
85
|
+
else
|
86
|
+
@history << { :uri => base_uri, :content => html }
|
87
|
+
end
|
88
|
+
load_entry(@history.current)
|
89
|
+
end
|
90
|
+
|
91
|
+
def append_html(html = "", &block)
|
92
|
+
# FIXME: not sure if I want to keep this API as it
|
93
|
+
# seems kinda clunky...
|
94
|
+
h = html || ""
|
95
|
+
h << block.call if block
|
96
|
+
@history.current[:content] << h
|
97
|
+
append_to_page(h)
|
78
98
|
end
|
79
99
|
|
80
100
|
#--
|
@@ -89,6 +109,16 @@ module RubyMVC
|
|
89
109
|
signal_emit("navigation-requested", self, link.href, link.target)
|
90
110
|
end
|
91
111
|
|
112
|
+
protected
|
113
|
+
def load_entry(entry)
|
114
|
+
if html = entry[:content]
|
115
|
+
set_page(html)
|
116
|
+
else
|
117
|
+
load_page(entry[:uri])
|
118
|
+
end
|
119
|
+
signal_emit("load-finished", self, entry[:uri])
|
120
|
+
end
|
121
|
+
|
92
122
|
end
|
93
123
|
end
|
94
124
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
#--
|
2
|
+
######################################################################
|
3
|
+
#
|
4
|
+
# Copyright 2011-2012 Andrew S. Townley
|
5
|
+
#
|
6
|
+
# Permission to use, copy, modify, and disribute this software for
|
7
|
+
# any purpose with or without fee is hereby granted, provided that
|
8
|
+
# the above copyright notices and this permission notice appear in
|
9
|
+
# all copies.
|
10
|
+
#
|
11
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
|
12
|
+
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
13
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
14
|
+
# AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
|
15
|
+
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
16
|
+
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
17
|
+
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
18
|
+
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
19
|
+
#
|
20
|
+
# File: property_change_notifier.rb
|
21
|
+
# Created: Mon 2 Jan 2012 12:52:02 CET
|
22
|
+
#
|
23
|
+
#####################################################################
|
24
|
+
#++
|
25
|
+
|
26
|
+
module RubyMVC
|
27
|
+
module Toolkit
|
28
|
+
|
29
|
+
module PropertyChangeNotifier
|
30
|
+
include Toolkit::SignalHandler
|
31
|
+
extend Toolkit::SignalHandler::ClassMethods
|
32
|
+
|
33
|
+
# this signal is emitted when any property is changed on
|
34
|
+
# the model. The arguments are the sender, the old and
|
35
|
+
# the new values
|
36
|
+
|
37
|
+
signal "property-changed"
|
38
|
+
|
39
|
+
protected
|
40
|
+
def property_changed(key, old, val)
|
41
|
+
signal_emit("property-changed", self, key, old, val)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,149 @@
|
|
1
|
+
#--
|
2
|
+
######################################################################
|
3
|
+
#
|
4
|
+
# Copyright 2008, Andrew S. Townley
|
5
|
+
#
|
6
|
+
# Permission to use, copy, modify, and disribute this software for
|
7
|
+
# any purpose with or without fee is hereby granted, provided that
|
8
|
+
# the above copyright notices and this permission notice appear in
|
9
|
+
# all copies.
|
10
|
+
#
|
11
|
+
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL
|
12
|
+
# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
13
|
+
# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
14
|
+
# AUTHORS BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT OR
|
15
|
+
# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
16
|
+
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
17
|
+
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
18
|
+
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
19
|
+
#
|
20
|
+
# File: signal_handler.rb
|
21
|
+
# Author: Andrew S. Townley
|
22
|
+
# Created: Sat Nov 1 14:27:10 GMT 2008
|
23
|
+
# Borrowed: Wed 23 Nov 2011 22:29:22 GMT
|
24
|
+
#
|
25
|
+
######################################################################
|
26
|
+
#++
|
27
|
+
|
28
|
+
module RubyMVC
|
29
|
+
module Toolkit
|
30
|
+
|
31
|
+
# This module provides an implementation of signal handlers
|
32
|
+
# originally modelled on the GTK+ 2.x mechanisms. While it
|
33
|
+
# is similar to GTK+, it may not behave in exactly the same
|
34
|
+
# way.
|
35
|
+
#
|
36
|
+
# This module also defines some useful class methods to
|
37
|
+
# expand the meta-programming of Ruby objects to support
|
38
|
+
# signal handling. To use these methods, you follow the
|
39
|
+
# following idiom in the derived class:
|
40
|
+
#
|
41
|
+
# class SignalSource
|
42
|
+
# incude RubyMVC::Toolkit::SignalHandler
|
43
|
+
# extend RubyMVC::Toolkit::SignalHandler::ClassMethods
|
44
|
+
# ...
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# Once the class has been defined as per above, valid
|
48
|
+
# signals for the signal source may be defined using the
|
49
|
+
# class method #signal as follows:
|
50
|
+
#
|
51
|
+
# class SignalSource
|
52
|
+
# ...
|
53
|
+
#
|
54
|
+
# signal "sig1", :description => "A test signal",
|
55
|
+
# signal "sig2", :description => "A vetoable signal", :vetoable => true
|
56
|
+
# ...
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# To register for signal notification, use the
|
60
|
+
# #signal_connect method of the signal source instance as
|
61
|
+
# follows:
|
62
|
+
#
|
63
|
+
# src = SignalSource.new
|
64
|
+
# src.signal_connect "sig1" do |sender|
|
65
|
+
# ...
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# Internally to the signal source instance, the signal can
|
69
|
+
# be triggered using the #signal_emit method as follows
|
70
|
+
#
|
71
|
+
# class SignalSource
|
72
|
+
# def send_sig1
|
73
|
+
# ...
|
74
|
+
# signal_emit("sig1", self)
|
75
|
+
# ...
|
76
|
+
# end
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# Planned Areas of Improvement
|
80
|
+
# ============================
|
81
|
+
#
|
82
|
+
# Currently, there's not a really good way to document the
|
83
|
+
# signals so that they're clear. I'm not sure how these are
|
84
|
+
# represented in rdoc, but there should be a method/way to
|
85
|
+
# specify the arguments in order and what they should be so
|
86
|
+
# that they live with the signal definition within the class
|
87
|
+
# itself so things are self-documenting.
|
88
|
+
|
89
|
+
module SignalHandler
|
90
|
+
module ClassMethods
|
91
|
+
def signals
|
92
|
+
@signals ||= {}
|
93
|
+
end
|
94
|
+
|
95
|
+
def signal(signal, options = { :vetoable => false })
|
96
|
+
signals[signal] = options
|
97
|
+
end
|
98
|
+
|
99
|
+
def valid_signal?(signal)
|
100
|
+
# puts "#{self}#signals.keys: #{signals.keys.inspect}"
|
101
|
+
# puts "#{self}#signals.has_key? #{signal}: #{signals.has_key?(signal)}"
|
102
|
+
# if self.superclass.respond_to?(:valid_signal?)
|
103
|
+
# puts "#{self.superclass}#signals.keys: #{self.superclass.signals.keys.inspect}"
|
104
|
+
# puts "#{self.superclass}#valid_signal? #{signal}: #{self.superclass.valid_signal?(signal)}"
|
105
|
+
# end
|
106
|
+
|
107
|
+
return true if signals.has_key? signal
|
108
|
+
|
109
|
+
if self.superclass.respond_to? :valid_signal?
|
110
|
+
self.superclass.valid_signal? signal
|
111
|
+
else
|
112
|
+
false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def valid_signal!(signal)
|
117
|
+
if !valid_signal? (signal)
|
118
|
+
raise ArgumentError, "class #{self} does not support signal '#{signal}'"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def signal_connect(signal, &block)
|
124
|
+
self.class.valid_signal! signal if self.class.respond_to? :signals
|
125
|
+
signals = (@signals ||= {})
|
126
|
+
sigs = (signals[signal] ||= [])
|
127
|
+
if !sigs.include? block
|
128
|
+
sigs << block
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def signal_disconnect(signal, &block)
|
133
|
+
self.class.valid_signal! signal if self.class.respond_to? :signals
|
134
|
+
signals = (@signals ||= {})
|
135
|
+
sigs = (signals[signal] ||= [])
|
136
|
+
sigs.delete(block)
|
137
|
+
end
|
138
|
+
|
139
|
+
def signal_emit(signal, *args)
|
140
|
+
self.class.valid_signal! signal if self.class.respond_to? :signals
|
141
|
+
signals = (@signals ||= {})
|
142
|
+
(signals[signal] ||= []).each do |proc|
|
143
|
+
proc.call(*args) if !proc.nil?
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
149
|
+
end
|
@@ -30,7 +30,7 @@ module RubyMVC
|
|
30
30
|
# modelled on WebKit
|
31
31
|
|
32
32
|
class WebView < Widget
|
33
|
-
|
33
|
+
api_methods :load_html, :append_html
|
34
34
|
api_methods :can_go_back?, :go_back
|
35
35
|
api_methods :can_go_forward?, :go_forward
|
36
36
|
api_methods :open, :reload, :go_home, :location
|
@@ -25,15 +25,22 @@
|
|
25
25
|
|
26
26
|
module RubyMVC
|
27
27
|
module Toolkit
|
28
|
-
|
29
|
-
# This class defines the base toolkit widget class. Each
|
30
|
-
# widget has one - and only one - UI peer that is
|
31
|
-
# registered automatically when the UI peer is loaded.
|
32
28
|
|
33
|
-
class
|
29
|
+
# This class provides an un-peered abstract widget, mostly
|
30
|
+
# related to signal handling capabilities so that
|
31
|
+
# abstract, non-peer views can be created with built-in
|
32
|
+
# signal handling.
|
33
|
+
|
34
|
+
class AbstractWidget
|
34
35
|
include SignalHandler
|
35
36
|
extend SignalHandler::ClassMethods
|
37
|
+
end
|
38
|
+
|
39
|
+
# This class defines the base toolkit widget class. Each
|
40
|
+
# widget has one - and only one - UI peer that is
|
41
|
+
# registered automatically when the UI peer is loaded.
|
36
42
|
|
43
|
+
class Widget < AbstractWidget
|
37
44
|
class << self
|
38
45
|
attr_accessor :peer_class
|
39
46
|
|
@@ -96,7 +103,7 @@ module RubyMVC
|
|
96
103
|
|
97
104
|
def connect_peer_signals
|
98
105
|
self.class.signals.each do |s, opts|
|
99
|
-
puts "connecting signal '#{s}' to #{
|
106
|
+
puts "connecting signal '#{peer}##{s}' to #{self}"
|
100
107
|
peer.signal_connect(s) do |*args|
|
101
108
|
args[0] = self
|
102
109
|
signal_emit(s, *args)
|
data/lib/ruby_mvc/views.rb
CHANGED
@@ -23,63 +23,12 @@
|
|
23
23
|
#####################################################################
|
24
24
|
#++
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
else
|
34
|
-
if (x = targ.widget_def).nil?
|
35
|
-
if targ != RubyMVC::Views::View
|
36
|
-
self.widget_def(targ.superclass)
|
37
|
-
end
|
38
|
-
else
|
39
|
-
x
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.create_widget(klass)
|
45
|
-
w = self.widget_def(klass)
|
46
|
-
args = w[:args]
|
47
|
-
block = w[:block]
|
48
|
-
args[0].new(*args[1..-1], &block)
|
49
|
-
end
|
50
|
-
|
51
|
-
class << self
|
52
|
-
# This method is used to define the primary widget
|
53
|
-
# class through which this view may be added to other
|
54
|
-
# widgets.
|
55
|
-
|
56
|
-
def widget(*args, &block)
|
57
|
-
puts "Set widget for #{self}: #{args.inspect}"
|
58
|
-
@widget_def = { :args => args, :block => block }
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def peer
|
63
|
-
@widget.peer
|
64
|
-
end
|
65
|
-
|
66
|
-
attr_accessor :controller, :widget
|
67
|
-
def initialize(*args)
|
68
|
-
@widget = View.create_widget(self.class)
|
69
|
-
if(options = args.last).is_a? Hash
|
70
|
-
self.controller = options[:controller]
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
def method_missing(m, *a, &b)
|
75
|
-
@widget.send(m, *a, &b)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
26
|
+
require 'ruby_mvc/views/view'
|
27
|
+
require 'ruby_mvc/views/web_content_view'
|
28
|
+
require 'ruby_mvc/views/web_model_view'
|
29
|
+
require 'ruby_mvc/views/web_content_table_view'
|
30
|
+
require 'ruby_mvc/views/form_view'
|
31
|
+
require 'ruby_mvc/views/grid_table_view'
|
32
|
+
require 'ruby_mvc/views/browser_view'
|
81
33
|
#require 'ruby_mvc/views/table_view'
|
82
|
-
#require 'ruby_mvc/views/
|
83
|
-
#require 'ruby_mvc/views/ar_type_list'
|
84
|
-
#require 'ruby_mvc/views/ar_type_editor'
|
85
|
-
require 'ruby_mvc/views/web_view'
|
34
|
+
#require 'ruby_mvc/views/web_table_view'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#--
|
2
2
|
######################################################################
|
3
3
|
#
|
4
|
-
# Copyright 2011 Andrew S. Townley
|
4
|
+
# Copyright 2011-2012 Andrew S. Townley
|
5
5
|
#
|
6
6
|
# Permission to use, copy, modify, and disribute this software for
|
7
7
|
# any purpose with or without fee is hereby granted, provided that
|
@@ -17,8 +17,8 @@
|
|
17
17
|
# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
18
18
|
# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
19
19
|
#
|
20
|
-
# File:
|
21
|
-
# Created:
|
20
|
+
# File: ar_form_view.rb
|
21
|
+
# Created: Sat 19 Nov 2011 11:26:37 GMT
|
22
22
|
#
|
23
23
|
#####################################################################
|
24
24
|
#++
|
@@ -26,18 +26,15 @@
|
|
26
26
|
module RubyMVC
|
27
27
|
module Views
|
28
28
|
|
29
|
-
class
|
30
|
-
|
31
|
-
@entity_type = model
|
32
|
-
super(model.find(options[:query] || :all), options, &block)
|
33
|
-
end
|
29
|
+
# This class is responsible for building a form for the
|
30
|
+
# given ActiveRecord model
|
34
31
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
32
|
+
class ActiveRecordFormView < FormView
|
33
|
+
def initialize(model, &block)
|
34
|
+
super
|
35
|
+
signal_connect("form-submit") do |f, m|
|
36
|
+
m.save!
|
39
37
|
end
|
40
|
-
cols
|
41
38
|
end
|
42
39
|
end
|
43
40
|
|