pg 0.15.0.pre.454-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.
- data.tar.gz.sig +0 -0
- data/.gemtest +0 -0
- data/BSDL +22 -0
- data/ChangeLog +2945 -0
- data/Contributors.rdoc +46 -0
- data/History.rdoc +205 -0
- data/LICENSE +56 -0
- data/Manifest.txt +53 -0
- data/POSTGRES +23 -0
- data/README-OS_X.rdoc +68 -0
- data/README-Windows.rdoc +67 -0
- data/README.ja.rdoc +14 -0
- data/README.rdoc +111 -0
- data/Rakefile +156 -0
- data/Rakefile.cross +271 -0
- data/ext/extconf.rb +91 -0
- data/ext/gvl_wrappers.c +13 -0
- data/ext/gvl_wrappers.h +185 -0
- data/ext/pg.c +525 -0
- data/ext/pg.h +126 -0
- data/ext/pg_connection.c +3600 -0
- data/ext/pg_result.c +939 -0
- data/ext/vc/pg.sln +26 -0
- data/ext/vc/pg_18/pg.vcproj +216 -0
- data/ext/vc/pg_19/pg_19.vcproj +209 -0
- data/lib/2.0/pg_ext.so +0 -0
- data/lib/pg.rb +52 -0
- data/lib/pg/connection.rb +71 -0
- data/lib/pg/constants.rb +11 -0
- data/lib/pg/exceptions.rb +11 -0
- data/lib/pg/result.rb +16 -0
- data/sample/array_insert.rb +20 -0
- data/sample/async_api.rb +106 -0
- data/sample/async_copyto.rb +39 -0
- data/sample/async_mixed.rb +56 -0
- data/sample/check_conn.rb +21 -0
- data/sample/copyfrom.rb +81 -0
- data/sample/copyto.rb +19 -0
- data/sample/cursor.rb +21 -0
- data/sample/disk_usage_report.rb +186 -0
- data/sample/issue-119.rb +94 -0
- data/sample/losample.rb +69 -0
- data/sample/minimal-testcase.rb +17 -0
- data/sample/notify_wait.rb +72 -0
- data/sample/pg_statistics.rb +294 -0
- data/sample/replication_monitor.rb +231 -0
- data/sample/test_binary_values.rb +33 -0
- data/sample/wal_shipper.rb +434 -0
- data/sample/warehouse_partitions.rb +320 -0
- data/spec/data/expected_trace.out +26 -0
- data/spec/data/random_binary_data +0 -0
- data/spec/lib/helpers.rb +279 -0
- data/spec/pg/connection_spec.rb +1013 -0
- data/spec/pg/result_spec.rb +278 -0
- data/spec/pg_spec.rb +31 -0
- metadata +275 -0
- metadata.gz.sig +0 -0
data/sample/copyto.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
# An example of how to stream data to your local host from the database as CSV.
|
7
|
+
|
8
|
+
$stderr.puts "Opening database connection ..."
|
9
|
+
conn = PG.connect( :dbname => 'test' )
|
10
|
+
|
11
|
+
$stderr.puts "Running COPY command ..."
|
12
|
+
buf = ''
|
13
|
+
conn.transaction do
|
14
|
+
conn.exec( "COPY logs TO STDOUT WITH csv" )
|
15
|
+
$stdout.puts( buf ) while buf = conn.get_copy_data
|
16
|
+
end
|
17
|
+
|
18
|
+
conn.finish
|
19
|
+
|
data/sample/cursor.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
# An example of how to use SQL cursors. This is mostly a straight port of
|
6
|
+
# the cursor portion of testlibpq.c from src/test/examples.
|
7
|
+
|
8
|
+
$stderr.puts "Opening database connection ..."
|
9
|
+
conn = PG.connect( :dbname => 'test' )
|
10
|
+
|
11
|
+
#
|
12
|
+
conn.transaction do
|
13
|
+
conn.exec( "DECLARE myportal CURSOR FOR select * from pg_database" )
|
14
|
+
res = conn.exec( "FETCH ALL IN myportal" )
|
15
|
+
|
16
|
+
puts res.fields.collect {|fname| "%-15s" % [fname] }.join( '' )
|
17
|
+
res.values.collect do |row|
|
18
|
+
puts row.collect {|col| "%-15s" % [col] }.join( '' )
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# vim: set noet nosta sw=4 ts=4 :
|
3
|
+
#
|
4
|
+
# Quickly dump size information for a given database.
|
5
|
+
# Top twenty objects, and size per schema.
|
6
|
+
#
|
7
|
+
# Mahlon E. Smith <mahlon@martini.nu>
|
8
|
+
#
|
9
|
+
# Based on work by Jeff Davis <ruby@j-davis.com>.
|
10
|
+
#
|
11
|
+
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'ostruct'
|
15
|
+
require 'optparse'
|
16
|
+
require 'etc'
|
17
|
+
require 'pg'
|
18
|
+
|
19
|
+
rescue LoadError # 1.8 support
|
20
|
+
unless Object.const_defined?( :Gem )
|
21
|
+
require 'rubygems'
|
22
|
+
retry
|
23
|
+
end
|
24
|
+
raise
|
25
|
+
end
|
26
|
+
|
27
|
+
SCRIPT_VERSION = %q$Id$
|
28
|
+
|
29
|
+
|
30
|
+
### Gather data and output it to $stdout.
|
31
|
+
###
|
32
|
+
def report( opts )
|
33
|
+
db = PG.connect(
|
34
|
+
:dbname => opts.database,
|
35
|
+
:host => opts.host,
|
36
|
+
:port => opts.port,
|
37
|
+
:user => opts.user,
|
38
|
+
:password => opts.pass,
|
39
|
+
:sslmode => 'prefer'
|
40
|
+
)
|
41
|
+
|
42
|
+
# -----------------------------------------
|
43
|
+
|
44
|
+
db_info = db.exec %Q{
|
45
|
+
SELECT
|
46
|
+
count(oid) AS num_relations,
|
47
|
+
pg_size_pretty(pg_database_size('#{opts.database}')) AS dbsize
|
48
|
+
FROM
|
49
|
+
pg_class
|
50
|
+
}
|
51
|
+
|
52
|
+
puts '=' * 70
|
53
|
+
puts "Disk usage information for %s: (%d relations, %s total)" % [
|
54
|
+
opts.database,
|
55
|
+
db_info[0]['num_relations'],
|
56
|
+
db_info[0]['dbsize']
|
57
|
+
]
|
58
|
+
puts '=' * 70
|
59
|
+
|
60
|
+
# -----------------------------------------
|
61
|
+
|
62
|
+
top_twenty = db.exec %q{
|
63
|
+
SELECT
|
64
|
+
relname AS name,
|
65
|
+
relkind AS kind,
|
66
|
+
pg_size_pretty(pg_relation_size(pg_class.oid)) AS size
|
67
|
+
FROM
|
68
|
+
pg_class
|
69
|
+
ORDER BY
|
70
|
+
pg_relation_size(pg_class.oid) DESC
|
71
|
+
LIMIT 20
|
72
|
+
}
|
73
|
+
|
74
|
+
puts 'Top twenty objects by size:'
|
75
|
+
puts '-' * 70
|
76
|
+
top_twenty.each do |row|
|
77
|
+
type = case row['kind']
|
78
|
+
when 'i'; 'index'
|
79
|
+
when 't'; 'toast'
|
80
|
+
when 'r'; 'table'
|
81
|
+
when 'S'; 'sequence'
|
82
|
+
else; '???'
|
83
|
+
end
|
84
|
+
|
85
|
+
puts "%40s %10s (%s)" % [ row['name'], row['size'], type ]
|
86
|
+
end
|
87
|
+
puts '-' * 70
|
88
|
+
|
89
|
+
# -----------------------------------------
|
90
|
+
|
91
|
+
schema_sizes = db.exec %q{
|
92
|
+
SELECT
|
93
|
+
table_schema,
|
94
|
+
pg_size_pretty( CAST( SUM(pg_total_relation_size(table_schema || '.' || table_name)) AS bigint)) AS size
|
95
|
+
FROM
|
96
|
+
information_schema.tables
|
97
|
+
GROUP BY
|
98
|
+
table_schema
|
99
|
+
ORDER BY
|
100
|
+
CAST( SUM(pg_total_relation_size(table_schema || '.' || table_name)) AS bigint ) DESC
|
101
|
+
}
|
102
|
+
|
103
|
+
|
104
|
+
puts 'Size per schema:'
|
105
|
+
puts '-' * 70
|
106
|
+
schema_sizes.each do |row|
|
107
|
+
puts "%20s %10s" % [ row['table_schema'], row['size'] ]
|
108
|
+
end
|
109
|
+
puts '-' * 70
|
110
|
+
puts
|
111
|
+
|
112
|
+
db.finish
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
### Parse command line arguments. Return a struct of global options.
|
117
|
+
###
|
118
|
+
def parse_args( args )
|
119
|
+
options = OpenStruct.new
|
120
|
+
options.database = Etc.getpwuid( Process.uid ).name
|
121
|
+
options.host = '127.0.0.1'
|
122
|
+
options.port = 5432
|
123
|
+
options.user = Etc.getpwuid( Process.uid ).name
|
124
|
+
options.sslmode = 'prefer'
|
125
|
+
options.interval = 5
|
126
|
+
|
127
|
+
opts = OptionParser.new do |opts|
|
128
|
+
opts.banner = "Usage: #{$0} [options]"
|
129
|
+
|
130
|
+
opts.separator ''
|
131
|
+
opts.separator 'Connection options:'
|
132
|
+
|
133
|
+
opts.on( '-d', '--database DBNAME',
|
134
|
+
"specify the database to connect to (default: \"#{options.database}\")" ) do |db|
|
135
|
+
options.database = db
|
136
|
+
end
|
137
|
+
|
138
|
+
opts.on( '-h', '--host HOSTNAME', 'database server host' ) do |host|
|
139
|
+
options.host = host
|
140
|
+
end
|
141
|
+
|
142
|
+
opts.on( '-p', '--port PORT', Integer,
|
143
|
+
"database server port (default: \"#{options.port}\")" ) do |port|
|
144
|
+
options.port = port
|
145
|
+
end
|
146
|
+
|
147
|
+
opts.on( '-U', '--user NAME',
|
148
|
+
"database user name (default: \"#{options.user}\")" ) do |user|
|
149
|
+
options.user = user
|
150
|
+
end
|
151
|
+
|
152
|
+
opts.on( '-W', 'force password prompt' ) do |pw|
|
153
|
+
print 'Password: '
|
154
|
+
begin
|
155
|
+
system 'stty -echo'
|
156
|
+
options.pass = gets.chomp
|
157
|
+
ensure
|
158
|
+
system 'stty echo'
|
159
|
+
puts
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
opts.separator ''
|
164
|
+
opts.separator 'Other options:'
|
165
|
+
|
166
|
+
opts.on_tail( '--help', 'show this help, then exit' ) do
|
167
|
+
$stderr.puts opts
|
168
|
+
exit
|
169
|
+
end
|
170
|
+
|
171
|
+
opts.on_tail( '--version', 'output version information, then exit' ) do
|
172
|
+
puts SCRIPT_VERSION
|
173
|
+
exit
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
opts.parse!( args )
|
178
|
+
return options
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
if __FILE__ == $0
|
183
|
+
opts = parse_args( ARGV )
|
184
|
+
report( opts )
|
185
|
+
end
|
186
|
+
|
data/sample/issue-119.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
# This is another example of how to use COPY FROM, this time as a
|
6
|
+
# minimal test case used to try to figure out what was going on in
|
7
|
+
# an issue submitted from a user:
|
8
|
+
#
|
9
|
+
# https://bitbucket.org/ged/ruby-pg/issue/119
|
10
|
+
#
|
11
|
+
|
12
|
+
conn = PG.connect( dbname: 'test' )
|
13
|
+
table_name = 'issue_119'
|
14
|
+
field_list = %w[name body_weight brain_weight]
|
15
|
+
method = 0
|
16
|
+
options = { truncate: true }
|
17
|
+
sql_parameters = ''
|
18
|
+
|
19
|
+
conn.set_error_verbosity( PG::PQERRORS_VERBOSE )
|
20
|
+
conn.exec( "DROP TABLE IF EXISTS #{table_name}" )
|
21
|
+
conn.exec( "CREATE TABLE #{table_name} ( id SERIAL, name TEXT, body_weight REAL, brain_weight REAL )" )
|
22
|
+
|
23
|
+
text = <<-END_DATA
|
24
|
+
Mountain beaver 1.35 465
|
25
|
+
Cow 465 423
|
26
|
+
Grey wolf 36.33 119.5
|
27
|
+
Goat 27.66 115
|
28
|
+
Guinea pig 1.04 5.5
|
29
|
+
Dipliodocus 11700 50
|
30
|
+
Asian elephant 2547 4603
|
31
|
+
Donkey 187.1 419
|
32
|
+
Horse 521 655
|
33
|
+
Potar monkey 10 115
|
34
|
+
Cat 3.3 25.6
|
35
|
+
Giraffe 529 680
|
36
|
+
Gorilla 207 406
|
37
|
+
Human 62 1320
|
38
|
+
African elephant 6654 5712
|
39
|
+
Triceratops 9400 70
|
40
|
+
Rhesus monkey 6.8 179
|
41
|
+
Kangaroo 35 56
|
42
|
+
Golden hamster 0.12 1
|
43
|
+
Mouse 0.023 0.4
|
44
|
+
Rabbit 2.5 12.1
|
45
|
+
Sheep 55.5 175
|
46
|
+
Jaguar 100 157
|
47
|
+
Chimpanzee 52.16 440
|
48
|
+
Brachiosaurus 87000 154.5
|
49
|
+
Mole 0.122 3
|
50
|
+
Pig 192 18
|
51
|
+
END_DATA
|
52
|
+
|
53
|
+
#ActiveRecord::Base.connection_pool.with_connection do |conn|
|
54
|
+
conn.transaction do
|
55
|
+
rc = conn #.raw_connection
|
56
|
+
rc.exec "TRUNCATE TABLE #{table_name};" if options[:truncate]
|
57
|
+
sql = "COPY #{table_name} (#{field_list.join(',')}) FROM STDIN #{sql_parameters} "
|
58
|
+
p sql
|
59
|
+
rc.exec(sql)
|
60
|
+
errmsg = nil # scope this outside of the rescue below so it's visible later
|
61
|
+
begin
|
62
|
+
if method == 1
|
63
|
+
rc.put_copy_data text + "\\.\n"
|
64
|
+
else
|
65
|
+
text.each_line { |line| rc.put_copy_data(line) }
|
66
|
+
end
|
67
|
+
rescue Errno => err
|
68
|
+
errmsg = "%s while reading copy data: %s" % [err.class.name, err.message]
|
69
|
+
puts "an error occured"
|
70
|
+
end
|
71
|
+
|
72
|
+
if errmsg
|
73
|
+
rc.put_copy_end(errmsg)
|
74
|
+
puts "ERROR #{errmsg}"
|
75
|
+
else
|
76
|
+
rc.put_copy_end
|
77
|
+
end
|
78
|
+
|
79
|
+
while res = rc.get_result
|
80
|
+
st = res.res_status( res.result_status )
|
81
|
+
puts "Result of COPY is: %s" % [ st ]
|
82
|
+
if res.result_status != PG::PGRES_COPY_IN
|
83
|
+
puts res.error_message
|
84
|
+
end
|
85
|
+
end
|
86
|
+
puts "end"
|
87
|
+
end #transaction
|
88
|
+
#end #connection
|
89
|
+
|
90
|
+
conn.exec( "SELECT name, brain_weight FROM #{table_name}" ) do |res|
|
91
|
+
p res.values
|
92
|
+
end
|
93
|
+
|
94
|
+
|
data/sample/losample.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
SAMPLE_WRITE_DATA = 'some sample data'
|
6
|
+
SAMPLE_EXPORT_NAME = 'lowrite.txt'
|
7
|
+
|
8
|
+
conn = PG.connect( :dbname => 'test', :host => 'localhost', :port => 5432 )
|
9
|
+
puts "dbname: " + conn.db + "\thost: " + conn.host + "\tuser: " + conn.user
|
10
|
+
|
11
|
+
# Start a transaction, as all large object functions require one.
|
12
|
+
puts "Beginning transaction"
|
13
|
+
conn.exec( 'BEGIN' )
|
14
|
+
|
15
|
+
# Test importing from a file
|
16
|
+
puts "Import test:"
|
17
|
+
puts " importing %s" % [ __FILE__ ]
|
18
|
+
oid = conn.lo_import( __FILE__ )
|
19
|
+
puts " imported as large object %d" % [ oid ]
|
20
|
+
|
21
|
+
# Read back 50 bytes of the imported data
|
22
|
+
puts "Read test:"
|
23
|
+
fd = conn.lo_open( oid, PG::INV_READ|PG::INV_WRITE )
|
24
|
+
conn.lo_lseek( fd, 0, PG::SEEK_SET )
|
25
|
+
buf = conn.lo_read( fd, 50 )
|
26
|
+
puts " read: %p" % [ buf ]
|
27
|
+
puts " read was ok!" if buf =~ /require 'pg'/
|
28
|
+
|
29
|
+
# Append some test data onto the end of the object
|
30
|
+
puts "Write test:"
|
31
|
+
conn.lo_lseek( fd, 0, PG::SEEK_END )
|
32
|
+
buf = SAMPLE_WRITE_DATA.dup
|
33
|
+
totalbytes = 0
|
34
|
+
until buf.empty?
|
35
|
+
bytes = conn.lo_write( fd, buf )
|
36
|
+
buf.slice!( 0, bytes )
|
37
|
+
totalbytes += bytes
|
38
|
+
end
|
39
|
+
puts " appended %d bytes" % [ totalbytes ]
|
40
|
+
|
41
|
+
# Now export it
|
42
|
+
puts "Export test:"
|
43
|
+
File.unlink( SAMPLE_EXPORT_NAME ) if File.exist?( SAMPLE_EXPORT_NAME )
|
44
|
+
conn.lo_export( oid, SAMPLE_EXPORT_NAME )
|
45
|
+
puts " success!" if File.exist?( SAMPLE_EXPORT_NAME )
|
46
|
+
puts " exported as %s (%d bytes)" % [ SAMPLE_EXPORT_NAME, File.size(SAMPLE_EXPORT_NAME) ]
|
47
|
+
|
48
|
+
conn.exec( 'COMMIT' )
|
49
|
+
puts "End of transaction."
|
50
|
+
|
51
|
+
|
52
|
+
puts 'Testing read and delete from a new transaction:'
|
53
|
+
puts ' starting a new transaction'
|
54
|
+
conn.exec( 'BEGIN' )
|
55
|
+
|
56
|
+
fd = conn.lo_open( oid, PG::INV_READ )
|
57
|
+
puts ' reopened okay.'
|
58
|
+
conn.lo_lseek( fd, 50, PG::SEEK_END )
|
59
|
+
buf = conn.lo_read( fd, 50 )
|
60
|
+
puts ' read okay.' if buf == SAMPLE_WRITE_DATA
|
61
|
+
|
62
|
+
puts 'Closing and unlinking:'
|
63
|
+
conn.lo_close( fd )
|
64
|
+
puts ' closed.'
|
65
|
+
conn.lo_unlink( oid )
|
66
|
+
puts ' unlinked.'
|
67
|
+
conn.exec( 'COMMIT' )
|
68
|
+
puts 'Done.'
|
69
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'pg'
|
4
|
+
|
5
|
+
conn = PG.connect( :dbname => 'test' )
|
6
|
+
$stderr.puts '---',
|
7
|
+
RUBY_DESCRIPTION,
|
8
|
+
PG.version_string( true ),
|
9
|
+
"Server version: #{conn.server_version}",
|
10
|
+
"Client version: #{PG.respond_to?( :library_version ) ? PG.library_version : 'unknown'}",
|
11
|
+
'---'
|
12
|
+
|
13
|
+
result = conn.exec( "SELECT * from pg_stat_activity" )
|
14
|
+
|
15
|
+
$stderr.puts %Q{Expected this to return: ["select * from pg_stat_activity"]}
|
16
|
+
p result.field_values( 'current_query' )
|
17
|
+
|
@@ -0,0 +1,72 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# Test script, demonstrating a non-poll notification for a table event.
|
4
|
+
#
|
5
|
+
|
6
|
+
BEGIN {
|
7
|
+
require 'pathname'
|
8
|
+
basedir = Pathname.new( __FILE__ ).expand_path.dirname.parent
|
9
|
+
libdir = basedir + 'lib'
|
10
|
+
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
11
|
+
}
|
12
|
+
|
13
|
+
require 'pg'
|
14
|
+
|
15
|
+
TRIGGER_TABLE = %{
|
16
|
+
CREATE TABLE IF NOT EXISTS test ( message text );
|
17
|
+
}
|
18
|
+
|
19
|
+
TRIGGER_FUNCTION = %{
|
20
|
+
CREATE OR REPLACE FUNCTION notify_test()
|
21
|
+
RETURNS TRIGGER
|
22
|
+
LANGUAGE plpgsql
|
23
|
+
AS $$
|
24
|
+
BEGIN
|
25
|
+
NOTIFY woo;
|
26
|
+
RETURN NULL;
|
27
|
+
END
|
28
|
+
$$
|
29
|
+
}
|
30
|
+
|
31
|
+
DROP_TRIGGER = %{
|
32
|
+
DROP TRIGGER IF EXISTS notify_trigger ON test
|
33
|
+
}
|
34
|
+
|
35
|
+
|
36
|
+
TRIGGER = %{
|
37
|
+
CREATE TRIGGER notify_trigger
|
38
|
+
AFTER UPDATE OR INSERT OR DELETE
|
39
|
+
ON test
|
40
|
+
FOR EACH STATEMENT
|
41
|
+
EXECUTE PROCEDURE notify_test();
|
42
|
+
}
|
43
|
+
|
44
|
+
conn = PG.connect( :dbname => 'test' )
|
45
|
+
|
46
|
+
conn.exec( TRIGGER_TABLE )
|
47
|
+
conn.exec( TRIGGER_FUNCTION )
|
48
|
+
conn.exec( DROP_TRIGGER )
|
49
|
+
conn.exec( TRIGGER )
|
50
|
+
|
51
|
+
conn.exec( 'LISTEN woo' ) # register interest in the 'woo' event
|
52
|
+
|
53
|
+
notifications = []
|
54
|
+
|
55
|
+
puts "Now switch to a different term and run:",
|
56
|
+
'',
|
57
|
+
%{ psql test -c "insert into test values ('A message.')"},
|
58
|
+
''
|
59
|
+
|
60
|
+
puts "Waiting up to 30 seconds for for an event!"
|
61
|
+
conn.wait_for_notify( 30 ) do |notify, pid|
|
62
|
+
notifications << [ pid, notify ]
|
63
|
+
end
|
64
|
+
|
65
|
+
if notifications.empty?
|
66
|
+
puts "Awww, I didn't see any events."
|
67
|
+
else
|
68
|
+
puts "I got one from pid %d: %s" % notifications.first
|
69
|
+
end
|
70
|
+
|
71
|
+
|
72
|
+
|