eventmachine 1.2.0.dev.2-x64-mingw32

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.
Files changed (181) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +105 -0
  3. data/GNU +281 -0
  4. data/LICENSE +60 -0
  5. data/README.md +108 -0
  6. data/docs/DocumentationGuidesIndex.md +27 -0
  7. data/docs/GettingStarted.md +521 -0
  8. data/docs/old/ChangeLog +211 -0
  9. data/docs/old/DEFERRABLES +246 -0
  10. data/docs/old/EPOLL +141 -0
  11. data/docs/old/INSTALL +13 -0
  12. data/docs/old/KEYBOARD +42 -0
  13. data/docs/old/LEGAL +25 -0
  14. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  15. data/docs/old/PURE_RUBY +75 -0
  16. data/docs/old/RELEASE_NOTES +94 -0
  17. data/docs/old/SMTP +4 -0
  18. data/docs/old/SPAWNED_PROCESSES +148 -0
  19. data/docs/old/TODO +8 -0
  20. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  21. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  22. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  23. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  24. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  25. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  26. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  27. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  28. data/examples/old/ex_channel.rb +43 -0
  29. data/examples/old/ex_queue.rb +2 -0
  30. data/examples/old/ex_tick_loop_array.rb +15 -0
  31. data/examples/old/ex_tick_loop_counter.rb +32 -0
  32. data/examples/old/helper.rb +2 -0
  33. data/ext/binder.cpp +124 -0
  34. data/ext/binder.h +46 -0
  35. data/ext/cmain.cpp +988 -0
  36. data/ext/ed.cpp +2111 -0
  37. data/ext/ed.h +442 -0
  38. data/ext/em.cpp +2379 -0
  39. data/ext/em.h +308 -0
  40. data/ext/eventmachine.h +143 -0
  41. data/ext/extconf.rb +270 -0
  42. data/ext/fastfilereader/extconf.rb +110 -0
  43. data/ext/fastfilereader/mapper.cpp +216 -0
  44. data/ext/fastfilereader/mapper.h +59 -0
  45. data/ext/fastfilereader/rubymain.cpp +127 -0
  46. data/ext/kb.cpp +79 -0
  47. data/ext/page.cpp +107 -0
  48. data/ext/page.h +51 -0
  49. data/ext/pipe.cpp +354 -0
  50. data/ext/project.h +176 -0
  51. data/ext/rubymain.cpp +1504 -0
  52. data/ext/ssl.cpp +615 -0
  53. data/ext/ssl.h +103 -0
  54. data/java/.classpath +8 -0
  55. data/java/.project +17 -0
  56. data/java/src/com/rubyeventmachine/EmReactor.java +591 -0
  57. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  58. data/java/src/com/rubyeventmachine/EventableChannel.java +72 -0
  59. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +201 -0
  60. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +415 -0
  61. data/lib/2.0/fastfilereaderext.so +0 -0
  62. data/lib/2.0/rubyeventmachine.so +0 -0
  63. data/lib/2.1/fastfilereaderext.so +0 -0
  64. data/lib/2.1/rubyeventmachine.so +0 -0
  65. data/lib/2.2/fastfilereaderext.so +0 -0
  66. data/lib/2.2/rubyeventmachine.so +0 -0
  67. data/lib/2.3/fastfilereaderext.so +0 -0
  68. data/lib/2.3/rubyeventmachine.so +0 -0
  69. data/lib/em/buftok.rb +59 -0
  70. data/lib/em/callback.rb +58 -0
  71. data/lib/em/channel.rb +69 -0
  72. data/lib/em/completion.rb +304 -0
  73. data/lib/em/connection.rb +770 -0
  74. data/lib/em/deferrable.rb +210 -0
  75. data/lib/em/deferrable/pool.rb +2 -0
  76. data/lib/em/file_watch.rb +73 -0
  77. data/lib/em/future.rb +61 -0
  78. data/lib/em/iterator.rb +252 -0
  79. data/lib/em/messages.rb +66 -0
  80. data/lib/em/pool.rb +151 -0
  81. data/lib/em/process_watch.rb +45 -0
  82. data/lib/em/processes.rb +123 -0
  83. data/lib/em/protocols.rb +37 -0
  84. data/lib/em/protocols/header_and_content.rb +138 -0
  85. data/lib/em/protocols/httpclient.rb +299 -0
  86. data/lib/em/protocols/httpclient2.rb +600 -0
  87. data/lib/em/protocols/line_and_text.rb +125 -0
  88. data/lib/em/protocols/line_protocol.rb +29 -0
  89. data/lib/em/protocols/linetext2.rb +166 -0
  90. data/lib/em/protocols/memcache.rb +331 -0
  91. data/lib/em/protocols/object_protocol.rb +46 -0
  92. data/lib/em/protocols/postgres3.rb +246 -0
  93. data/lib/em/protocols/saslauth.rb +175 -0
  94. data/lib/em/protocols/smtpclient.rb +394 -0
  95. data/lib/em/protocols/smtpserver.rb +666 -0
  96. data/lib/em/protocols/socks4.rb +66 -0
  97. data/lib/em/protocols/stomp.rb +205 -0
  98. data/lib/em/protocols/tcptest.rb +54 -0
  99. data/lib/em/pure_ruby.rb +1022 -0
  100. data/lib/em/queue.rb +80 -0
  101. data/lib/em/resolver.rb +232 -0
  102. data/lib/em/spawnable.rb +84 -0
  103. data/lib/em/streamer.rb +118 -0
  104. data/lib/em/threaded_resource.rb +90 -0
  105. data/lib/em/tick_loop.rb +85 -0
  106. data/lib/em/timers.rb +61 -0
  107. data/lib/em/version.rb +3 -0
  108. data/lib/eventmachine.rb +1584 -0
  109. data/lib/fastfilereaderext.rb +2 -0
  110. data/lib/jeventmachine.rb +301 -0
  111. data/lib/rubyeventmachine.rb +2 -0
  112. data/rakelib/package.rake +120 -0
  113. data/rakelib/test.rake +8 -0
  114. data/tests/client.crt +31 -0
  115. data/tests/client.key +51 -0
  116. data/tests/dhparam.pem +13 -0
  117. data/tests/em_test_helper.rb +151 -0
  118. data/tests/test_attach.rb +151 -0
  119. data/tests/test_basic.rb +283 -0
  120. data/tests/test_channel.rb +75 -0
  121. data/tests/test_completion.rb +178 -0
  122. data/tests/test_connection_count.rb +54 -0
  123. data/tests/test_connection_write.rb +35 -0
  124. data/tests/test_defer.rb +35 -0
  125. data/tests/test_deferrable.rb +35 -0
  126. data/tests/test_epoll.rb +142 -0
  127. data/tests/test_error_handler.rb +38 -0
  128. data/tests/test_exc.rb +28 -0
  129. data/tests/test_file_watch.rb +66 -0
  130. data/tests/test_fork.rb +75 -0
  131. data/tests/test_futures.rb +170 -0
  132. data/tests/test_get_sock_opt.rb +37 -0
  133. data/tests/test_handler_check.rb +35 -0
  134. data/tests/test_hc.rb +155 -0
  135. data/tests/test_httpclient.rb +233 -0
  136. data/tests/test_httpclient2.rb +128 -0
  137. data/tests/test_idle_connection.rb +25 -0
  138. data/tests/test_inactivity_timeout.rb +54 -0
  139. data/tests/test_ipv4.rb +125 -0
  140. data/tests/test_ipv6.rb +131 -0
  141. data/tests/test_iterator.rb +115 -0
  142. data/tests/test_kb.rb +28 -0
  143. data/tests/test_line_protocol.rb +33 -0
  144. data/tests/test_ltp.rb +138 -0
  145. data/tests/test_ltp2.rb +308 -0
  146. data/tests/test_many_fds.rb +22 -0
  147. data/tests/test_next_tick.rb +104 -0
  148. data/tests/test_object_protocol.rb +36 -0
  149. data/tests/test_pause.rb +107 -0
  150. data/tests/test_pending_connect_timeout.rb +52 -0
  151. data/tests/test_pool.rb +196 -0
  152. data/tests/test_process_watch.rb +50 -0
  153. data/tests/test_processes.rb +128 -0
  154. data/tests/test_proxy_connection.rb +180 -0
  155. data/tests/test_pure.rb +88 -0
  156. data/tests/test_queue.rb +64 -0
  157. data/tests/test_resolver.rb +104 -0
  158. data/tests/test_running.rb +14 -0
  159. data/tests/test_sasl.rb +47 -0
  160. data/tests/test_send_file.rb +217 -0
  161. data/tests/test_servers.rb +33 -0
  162. data/tests/test_set_sock_opt.rb +39 -0
  163. data/tests/test_shutdown_hooks.rb +23 -0
  164. data/tests/test_smtpclient.rb +75 -0
  165. data/tests/test_smtpserver.rb +57 -0
  166. data/tests/test_spawn.rb +293 -0
  167. data/tests/test_ssl_args.rb +78 -0
  168. data/tests/test_ssl_dhparam.rb +83 -0
  169. data/tests/test_ssl_ecdh_curve.rb +79 -0
  170. data/tests/test_ssl_extensions.rb +49 -0
  171. data/tests/test_ssl_methods.rb +65 -0
  172. data/tests/test_ssl_protocols.rb +246 -0
  173. data/tests/test_ssl_verify.rb +126 -0
  174. data/tests/test_stomp.rb +37 -0
  175. data/tests/test_system.rb +46 -0
  176. data/tests/test_threaded_resource.rb +61 -0
  177. data/tests/test_tick_loop.rb +59 -0
  178. data/tests/test_timers.rb +123 -0
  179. data/tests/test_ud.rb +8 -0
  180. data/tests/test_unbind_reason.rb +52 -0
  181. metadata +381 -0
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems' # or use Bundler.setup
4
+ require 'eventmachine'
5
+
6
+ class SimpleChatServer < EM::Connection
7
+
8
+ @@connected_clients = Array.new
9
+
10
+
11
+ attr_reader :username
12
+
13
+
14
+ #
15
+ # EventMachine handlers
16
+ #
17
+
18
+ def post_init
19
+ @username = nil
20
+
21
+ puts "A client has connected..."
22
+ ask_username
23
+ end
24
+
25
+ def unbind
26
+ @@connected_clients.delete(self)
27
+ puts "[info] #{@username} has left" if entered_username?
28
+ end
29
+
30
+ def receive_data(data)
31
+ if entered_username?
32
+ handle_chat_message(data.strip)
33
+ else
34
+ handle_username(data.strip)
35
+ end
36
+ end
37
+
38
+
39
+
40
+
41
+ #
42
+ # Username handling
43
+ #
44
+
45
+ def entered_username?
46
+ !@username.nil? && !@username.empty?
47
+ end # entered_username?
48
+
49
+ def handle_username(input)
50
+ if input.empty?
51
+ send_line("Blank usernames are not allowed. Try again.")
52
+ ask_username
53
+ else
54
+ @username = input
55
+ @@connected_clients.push(self)
56
+ self.other_peers.each { |c| c.send_data("#{@username} has joined the room\n") }
57
+ puts "#{@username} has joined"
58
+
59
+ self.send_line("[info] Ohai, #{@username}")
60
+ end
61
+ end # handle_username(input)
62
+
63
+ def ask_username
64
+ self.send_line("[info] Enter your username:")
65
+ end # ask_username
66
+
67
+
68
+
69
+ #
70
+ # Message handling
71
+ #
72
+
73
+ def handle_chat_message(msg)
74
+ if command?(msg)
75
+ self.handle_command(msg)
76
+ else
77
+ self.announce(msg, "#{@username}:")
78
+ end
79
+ end
80
+
81
+
82
+ #
83
+ # Commands handling
84
+ #
85
+
86
+ def command?(input)
87
+ input =~ /exit$/i
88
+ end # command?(input)
89
+
90
+ def handle_command(cmd)
91
+ case cmd
92
+ when /exit$/i then self.close_connection
93
+ end
94
+ end # handle_command(cmd)
95
+
96
+
97
+
98
+ #
99
+ # Helpers
100
+ #
101
+
102
+ def announce(msg = nil, prefix = "[chat server]")
103
+ @@connected_clients.each { |c| c.send_line("#{prefix} #{msg}") } unless msg.empty?
104
+ end # announce(msg)
105
+
106
+ def other_peers
107
+ @@connected_clients.reject { |c| self == c }
108
+ end # other_peers
109
+
110
+ def send_line(line)
111
+ self.send_data("#{line}\n")
112
+ end # send_line(line)
113
+ end
114
+
115
+ EventMachine.run do
116
+ # hit Control + C to stop
117
+ Signal.trap("INT") { EventMachine.stop }
118
+ Signal.trap("TERM") { EventMachine.stop }
119
+
120
+ EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer)
121
+ end
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems' # or use Bundler.setup
4
+ require 'eventmachine'
5
+
6
+ class SimpleChatServer < EM::Connection
7
+
8
+ @@connected_clients = Array.new
9
+ DM_REGEXP = /^@([a-zA-Z0-9]+)\s*:?\s+(.+)/.freeze
10
+
11
+ attr_reader :username
12
+
13
+
14
+ #
15
+ # EventMachine handlers
16
+ #
17
+
18
+ def post_init
19
+ @username = nil
20
+
21
+ puts "A client has connected..."
22
+ ask_username
23
+ end
24
+
25
+ def unbind
26
+ @@connected_clients.delete(self)
27
+ puts "[info] #{@username} has left" if entered_username?
28
+ end
29
+
30
+ def receive_data(data)
31
+ if entered_username?
32
+ handle_chat_message(data.strip)
33
+ else
34
+ handle_username(data.strip)
35
+ end
36
+ end
37
+
38
+
39
+ #
40
+ # Username handling
41
+ #
42
+
43
+ def entered_username?
44
+ !@username.nil? && !@username.empty?
45
+ end # entered_username?
46
+
47
+ def handle_username(input)
48
+ if input.empty?
49
+ send_line("Blank usernames are not allowed. Try again.")
50
+ ask_username
51
+ else
52
+ @username = input
53
+ @@connected_clients.push(self)
54
+ self.other_peers.each { |c| c.send_data("#{@username} has joined the room\n") }
55
+ puts "#{@username} has joined"
56
+
57
+ self.send_line("[info] Ohai, #{@username}")
58
+ end
59
+ end # handle_username(input)
60
+
61
+ def ask_username
62
+ self.send_line("[info] Enter your username:")
63
+ end # ask_username
64
+
65
+
66
+ #
67
+ # Message handling
68
+ #
69
+
70
+ def handle_chat_message(msg)
71
+ if command?(msg)
72
+ self.handle_command(msg)
73
+ else
74
+ if direct_message?(msg)
75
+ self.handle_direct_message(msg)
76
+ else
77
+ self.announce(msg, "#{@username}:")
78
+ end
79
+ end
80
+ end # handle_chat_message(msg)
81
+
82
+ def direct_message?(input)
83
+ input =~ DM_REGEXP
84
+ end # direct_message?(input)
85
+
86
+ def handle_direct_message(input)
87
+ username, message = parse_direct_message(input)
88
+
89
+ if connection = @@connected_clients.find { |c| c.username == username }
90
+ puts "[dm] @#{@username} => @#{username}"
91
+ connection.send_line("[dm] @#{@username}: #{message}")
92
+ else
93
+ send_line "@#{username} is not in the room. Here's who is: #{usernames.join(', ')}"
94
+ end
95
+ end # handle_direct_message(input)
96
+
97
+ def parse_direct_message(input)
98
+ return [$1, $2] if input =~ DM_REGEXP
99
+ end # parse_direct_message(input)
100
+
101
+
102
+ #
103
+ # Commands handling
104
+ #
105
+
106
+ def command?(input)
107
+ input =~ /(exit|status)$/i
108
+ end # command?(input)
109
+
110
+ def handle_command(cmd)
111
+ case cmd
112
+ when /exit$/i then self.close_connection
113
+ when /status$/i then self.send_line("[chat server] It's #{Time.now.strftime('%H:%M')} and there are #{self.number_of_connected_clients} people in the room")
114
+ end
115
+ end # handle_command(cmd)
116
+
117
+
118
+ #
119
+ # Helpers
120
+ #
121
+
122
+ def announce(msg = nil, prefix = "[chat server]")
123
+ @@connected_clients.each { |c| c.send_line("#{prefix} #{msg}") } unless msg.empty?
124
+ end # announce(msg)
125
+
126
+ def other_peers
127
+ @@connected_clients.reject { |c| self == c }
128
+ end # other_peers
129
+
130
+ def send_line(line)
131
+ self.send_data("#{line}\n")
132
+ end # send_line(line)
133
+ end
134
+
135
+ EventMachine.run do
136
+ # hit Control + C to stop
137
+ Signal.trap("INT") { EventMachine.stop }
138
+ Signal.trap("TERM") { EventMachine.stop }
139
+
140
+ EventMachine.start_server("0.0.0.0", 10000, SimpleChatServer)
141
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ EM.run do
4
+
5
+ # Create a channel to push data to, this could be stocks...
6
+ RandChannel = EM::Channel.new
7
+
8
+ # The server simply subscribes client connections to the channel on connect,
9
+ # and unsubscribes them on disconnect.
10
+ class Server < EM::Connection
11
+ def self.start(host = '127.0.0.1', port = 8000)
12
+ EM.start_server(host, port, self)
13
+ end
14
+
15
+ def post_init
16
+ @sid = RandChannel.subscribe { |m| send_data "#{m.inspect}\n" }
17
+ end
18
+
19
+ def unbind
20
+ RandChannel.unsubscribe @sid
21
+ end
22
+ end
23
+ Server.start
24
+
25
+ # Two client connections, that just print what they receive.
26
+ 2.times do
27
+ EM.connect('127.0.0.1', 8000) do |c|
28
+ c.extend EM::P::LineText2
29
+ def c.receive_line(line)
30
+ puts "Subscriber: #{signature} got #{line}"
31
+ end
32
+ EM.add_timer(2) { c.close_connection }
33
+ end
34
+ end
35
+
36
+ # This part of the example is more fake, but imagine sleep was in fact a
37
+ # long running calculation to achieve the value.
38
+ 40.times do
39
+ EM.defer lambda { v = sleep(rand * 2); RandChannel << [Time.now, v] }
40
+ end
41
+
42
+ EM.add_timer(5) { EM.stop }
43
+ end
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
@@ -0,0 +1,15 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ EM.run do
4
+ array = (1..100).to_a
5
+
6
+ tickloop = EM.tick_loop do
7
+ if array.empty?
8
+ :stop
9
+ else
10
+ puts array.shift
11
+ end
12
+ end
13
+
14
+ tickloop.on_stop { EM.stop }
15
+ end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class TickCounter
4
+ attr_reader :start_time, :count
5
+
6
+ def initialize
7
+ reset
8
+ @tick_loop = EM.tick_loop(method(:tick))
9
+ end
10
+
11
+ def reset
12
+ @count = 0
13
+ @start_time = EM.current_time
14
+ end
15
+
16
+ def tick
17
+ @count += 1
18
+ end
19
+
20
+ def rate
21
+ @count / (EM.current_time - @start_time)
22
+ end
23
+ end
24
+
25
+ period = 5
26
+ EM.run do
27
+ counter = TickCounter.new
28
+ EM.add_periodic_timer(period) do
29
+ puts "Ticks per second: #{counter.rate} (mean of last #{period}s)"
30
+ counter.reset
31
+ end
32
+ end
@@ -0,0 +1,2 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__) + '/../lib')
2
+ require 'eventmachine'
@@ -0,0 +1,124 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: binder.cpp
6
+ Date: 07Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+ #include "project.h"
21
+
22
+ #define DEV_URANDOM "/dev/urandom"
23
+
24
+
25
+ map<uintptr_t, Bindable_t*> Bindable_t::BindingBag;
26
+
27
+
28
+ /********************************
29
+ STATIC Bindable_t::CreateBinding
30
+ ********************************/
31
+
32
+ uintptr_t Bindable_t::CreateBinding()
33
+ {
34
+ static uintptr_t num = 0;
35
+ while(BindingBag[++num]) {}
36
+ return num;
37
+ }
38
+
39
+ #if 0
40
+ string Bindable_t::CreateBinding()
41
+ {
42
+ static int index = 0;
43
+ static string seed;
44
+
45
+ if ((index >= 1000000) || (seed.length() == 0)) {
46
+ #ifdef OS_UNIX
47
+ int fd = open (DEV_URANDOM, O_RDONLY);
48
+ if (fd < 0)
49
+ throw std::runtime_error ("No entropy device");
50
+
51
+ unsigned char u[16];
52
+ size_t r = read (fd, u, sizeof(u));
53
+ if (r < sizeof(u))
54
+ throw std::runtime_error ("Unable to read entropy device");
55
+
56
+ unsigned char *u1 = (unsigned char*)u;
57
+ char u2 [sizeof(u) * 2 + 1];
58
+
59
+ for (size_t i=0; i < sizeof(u); i++)
60
+ sprintf (u2 + (i * 2), "%02x", u1[i]);
61
+
62
+ seed = string (u2);
63
+ #endif
64
+
65
+
66
+ #ifdef OS_WIN32
67
+ UUID uuid;
68
+ UuidCreate (&uuid);
69
+ unsigned char *uuidstring = NULL;
70
+ UuidToString (&uuid, &uuidstring);
71
+ if (!uuidstring)
72
+ throw std::runtime_error ("Unable to read uuid");
73
+ seed = string ((const char*)uuidstring);
74
+
75
+ RpcStringFree (&uuidstring);
76
+ #endif
77
+
78
+ index = 0;
79
+
80
+
81
+ }
82
+
83
+ stringstream ss;
84
+ ss << seed << (++index);
85
+ return ss.str();
86
+ }
87
+ #endif
88
+
89
+ /*****************************
90
+ STATIC: Bindable_t::GetObject
91
+ *****************************/
92
+
93
+ Bindable_t *Bindable_t::GetObject (const uintptr_t binding)
94
+ {
95
+ map<uintptr_t, Bindable_t*>::const_iterator i = BindingBag.find (binding);
96
+ if (i != BindingBag.end())
97
+ return i->second;
98
+ else
99
+ return NULL;
100
+ }
101
+
102
+
103
+ /**********************
104
+ Bindable_t::Bindable_t
105
+ **********************/
106
+
107
+ Bindable_t::Bindable_t()
108
+ {
109
+ Binding = Bindable_t::CreateBinding();
110
+ BindingBag [Binding] = this;
111
+ }
112
+
113
+
114
+
115
+ /***********************
116
+ Bindable_t::~Bindable_t
117
+ ***********************/
118
+
119
+ Bindable_t::~Bindable_t()
120
+ {
121
+ BindingBag.erase (Binding);
122
+ }
123
+
124
+