savant-scenes 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/scenes +18 -0
- data/bin/src/SceneManager.rb +444 -0
- data/bin/src/glade/SceneManager.glade +429 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9143eeadd43302951c43db507ed5340b094970ee
|
4
|
+
data.tar.gz: 1ca8e91f8272abb8e11b9663d0c7e7f647d63b3a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1761df1a223088982ebca964a65875b3e055c967c2d28de0afca2a116f4aa369fa12f460e72c1a0a5f753a295588db33b110e2b941ab321a510844d6b72d296e
|
7
|
+
data.tar.gz: d86688aa22863e33de2248cb2a8013989900ced5ef20c88cef5ccc3d5cbaf29f7af0af4629068343a63a4e80f03c3ebd171c6e310f384d7a3e95533bf53bddb5
|
data/bin/scenes
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require "vrlib"
|
5
|
+
require 'net/http'
|
6
|
+
require 'uri'
|
7
|
+
require 'net/scp'
|
8
|
+
require 'socket'
|
9
|
+
require 'timeout'
|
10
|
+
require 'ipaddress'
|
11
|
+
require 'sqlite3'
|
12
|
+
|
13
|
+
# from require_all gem:
|
14
|
+
require_rel 'src/'
|
15
|
+
|
16
|
+
|
17
|
+
SceneManager.new.show_glade()
|
18
|
+
|
@@ -0,0 +1,444 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'net/http'
|
3
|
+
require 'net/scp'
|
4
|
+
require 'uri'
|
5
|
+
require 'socket'
|
6
|
+
require 'timeout'
|
7
|
+
require 'ipaddress'
|
8
|
+
require 'sqlite3'
|
9
|
+
|
10
|
+
|
11
|
+
class SceneManager
|
12
|
+
|
13
|
+
attr_accessor :ftv
|
14
|
+
include GladeGUI
|
15
|
+
|
16
|
+
def initialize
|
17
|
+
#Initialize the Scenes List view
|
18
|
+
@listviewSavantScenes = VR::ListView.new(:modify => TrueClass, :scene => String, :user => String, :id => String, :image => String, :isGlobal => String, :isActive => String, :isScheduled => String, :hasCustomImage => String, :userSceneOrder => String, :tags => String)
|
19
|
+
@listviewSavantScenes.col_sortable(true)
|
20
|
+
@listviewSavantScenes.col_sort_column_id(:scene => @listviewSavantScenes.id(:scene), :user => @listviewSavantScenes.id(:user))
|
21
|
+
@listviewSavantScenes.col_title(:modify => "", :scene => "Scene Name", :tags => "Zones Affected", :isGlobal => "Global", :isActive => "Active", :isScheduled => "Scheduled", :hasCustomImage => "Custom Image", :userSceneOrder => "User Order")
|
22
|
+
@listviewSavantScenes.col_xalign(:isGlobal => 0.5, :isActive => 0.5, :isScheduled => 0.5, :hasCustomImage => 0.5, :userSceneOrder => 0.5)
|
23
|
+
@listviewSavantScenes.col_width(:tags => 100, :image => 100)
|
24
|
+
@listviewSavantScenes.ren_editable(:scene => true, :isActive => true, :user => true, :id => true)
|
25
|
+
|
26
|
+
row = @listviewSavantScenes.add_row
|
27
|
+
row[:scene] = ""
|
28
|
+
@listviewSavantScenes.visible = true
|
29
|
+
|
30
|
+
#Validate user name change to email address (checks for text before and after @ symbol, as well as 3 chars after the last ".""
|
31
|
+
@listviewSavantScenes.renderer(:user).validate_block = Proc.new { |text, model_sym, row, view|
|
32
|
+
x = text.length
|
33
|
+
suffix = text[x-4..x]
|
34
|
+
if text.include?("@") && text.include?(".") && text.split(/[@,.]/).length == 3 && suffix.chr == "."
|
35
|
+
true
|
36
|
+
else
|
37
|
+
false
|
38
|
+
alert("Please enter a valid email address.", :parent => self)
|
39
|
+
end
|
40
|
+
text.include?("@") && text.include?(".") && text.split(/[@,.]/).length == 3 && suffix.chr == "."
|
41
|
+
}
|
42
|
+
|
43
|
+
#Validate id change to allow it to be copied for Bluepritn entry, but not actually changed
|
44
|
+
@listviewSavantScenes.renderer(:id).validate_block = Proc.new { |text, model_sym, row, view|
|
45
|
+
text == "this is never going to validate"
|
46
|
+
}
|
47
|
+
|
48
|
+
#Validate ACtively Scheduled to only be a 0 or 1
|
49
|
+
@listviewSavantScenes.renderer(:isActive).validate_block = Proc.new { |text, model_sym, row, view|
|
50
|
+
text == "0" || text == "1"
|
51
|
+
}
|
52
|
+
|
53
|
+
# Capture user name change, save to SQL, and transfer SQL to host
|
54
|
+
# @listviewSavantScenes.renderer(:user).edited_callback = Proc.new { |model_sym, row, view |
|
55
|
+
# alert "User email changed to : " + row[:user].to_s
|
56
|
+
# }
|
57
|
+
#
|
58
|
+
# Capture scene name change, save to SQL, and transfer SQL to host
|
59
|
+
# @listviewSavantScenes.renderer(:scene).edited_callback = Proc.new { |model_sym, row, view |
|
60
|
+
# alert "Scene name changed to : " + row[:scene].to_s
|
61
|
+
# }
|
62
|
+
#
|
63
|
+
# @listviewSavantScenes.renderer(:isActive).edited_callback = Proc.new { |model_sym, row, view |
|
64
|
+
# alert "Scene is scheduled changed to : " + row[:isScheduled].to_s
|
65
|
+
# }
|
66
|
+
end
|
67
|
+
|
68
|
+
#####Set variables before windows load#####
|
69
|
+
def before_show()
|
70
|
+
@savantURL = "192.168.77.40"
|
71
|
+
@login = 'RPM'
|
72
|
+
@password = 'RPM'
|
73
|
+
|
74
|
+
@ftv = VR::FileTreeView.new(Dir.home, File.join(File.dirname(__FILE__), "/../img"), glob = "*", validate_block = nil)
|
75
|
+
@builder["scrolledwindow_BackupRestore"].add(@ftv)
|
76
|
+
@ftv.set_show_expanders(true)
|
77
|
+
end
|
78
|
+
|
79
|
+
#####Check to see if Racepoint and SCLI bridge ports are open on host#####
|
80
|
+
def is_port_open?(ip, port)
|
81
|
+
if IPAddress.valid? ip
|
82
|
+
begin
|
83
|
+
Timeout::timeout(1) do
|
84
|
+
begin
|
85
|
+
s = TCPSocket.new(ip, port)
|
86
|
+
s.close
|
87
|
+
return true
|
88
|
+
rescue StandardError
|
89
|
+
return false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
rescue Timeout::Error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
#####Checks to see if Savant version is greater than 8.3 to support scene features.
|
98
|
+
def savantVersion?(ip)
|
99
|
+
begin
|
100
|
+
@builder["labelHostInfo"].label = ""
|
101
|
+
Net::SSH.start(ip, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
|
102
|
+
#Check host type and update sclibridge location for reference, though only Pro Host is supported
|
103
|
+
ssh.open_channel do |ch, success|
|
104
|
+
ch.exec("uname")
|
105
|
+
ch.on_data do |ch, data|
|
106
|
+
if data.to_s.include? 'Darwin'
|
107
|
+
@scliBridge = "~/Applications/RacePointMedia/sclibridge "
|
108
|
+
@dis = "/Users/RPM/Library/Application Support/RacePointMedia/statusfiles/dis/dashboard.sqlite"
|
109
|
+
else
|
110
|
+
@scliBridge = "/usr/local/bin/sclibridge "
|
111
|
+
@dis = "GNUstep/Library/ApplicationSupport/RacePointMedia/statusfiles/dis/dashboard.sqlite"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
ssh.loop
|
116
|
+
#parse the rpmSystemInfo.plist form the pro host to get host name
|
117
|
+
if @scliBridge == "~/Applications/RacePointMedia/sclibridge "
|
118
|
+
ssh.open_channel do |ch, success|
|
119
|
+
|
120
|
+
ch.exec("plutil -p 'library/application support/racepointmedia/userconfig.rpmconfig/rpmSystemInfo.plist'")
|
121
|
+
ch.on_data do |ch, data|
|
122
|
+
if data.to_s.include? 'module'
|
123
|
+
x = data.split("\"RPMSystemName\" => ")
|
124
|
+
x = x[1].split("\n")
|
125
|
+
@savantHostName = x[0][1..-2]
|
126
|
+
@str = @scliBridge + "readstate \"" + @savantHostName + ".SoftwareVersion\""
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
ssh.loop
|
131
|
+
#parse the rpmSystemInfo.plist from the smart host to get host name
|
132
|
+
elsif @scliBridge == "/usr/local/bin/sclibridge "
|
133
|
+
ssh.open_channel do |ch, success|
|
134
|
+
ch.exec("strings 'GNUstep/Library/ApplicationSupport/RacePointMedia/userConfig.rpmConfig/rpmSystemInfo.plist'")
|
135
|
+
ch.on_data do |ch, data|
|
136
|
+
if data.to_s.include? 'DOCTYPE'
|
137
|
+
x = data.split("RPMUserDefinedName</key><string>")
|
138
|
+
y = x[1].split("</string>")
|
139
|
+
x = x[1].split("VERSION</key><integer>")
|
140
|
+
x = x[1].split("</integer>")
|
141
|
+
alert("Instant host found at specified IP address. Instant hosts are not supported (even by Savant!)", :parent => self)
|
142
|
+
return false
|
143
|
+
@instantHost = true
|
144
|
+
elsif data.to_s.include? 'module'
|
145
|
+
x = data.split('module')
|
146
|
+
x = x[1].split("\n")
|
147
|
+
@savantHostName = x[0][1..-1]
|
148
|
+
@str = @scliBridge + "readstate \"" + @savantHostName + ".SoftwareVersion\""
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
ssh.loop
|
153
|
+
end
|
154
|
+
#Use host name to query SoftwareVersion state from host
|
155
|
+
ssh.open_channel do |ch, success|
|
156
|
+
ch.exec(@str)
|
157
|
+
ch.on_data do |ch, data|
|
158
|
+
@savantHostVersion = data
|
159
|
+
end
|
160
|
+
end
|
161
|
+
ssh.loop
|
162
|
+
end
|
163
|
+
@builder["labelHostInfo"].text = @savantHostName + " Version : " + @savantHostVersion
|
164
|
+
|
165
|
+
#return true if version is 8.3 or later
|
166
|
+
if @savantHostVersion.to_r > 8.2 && !@savantHostVersion.empty?
|
167
|
+
return true
|
168
|
+
else
|
169
|
+
return false
|
170
|
+
end
|
171
|
+
|
172
|
+
rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
#Enter key scans for hsot from IP address field
|
178
|
+
def savantURL__key_press_event(view, evt)
|
179
|
+
return unless evt.keyval == 65293
|
180
|
+
buttonScanHost__clicked()
|
181
|
+
end
|
182
|
+
|
183
|
+
#Rebuild listview window
|
184
|
+
def repaint
|
185
|
+
@builder["listviewSavantScenes"].hide
|
186
|
+
@builder["window1"].show_all
|
187
|
+
unless savantVersion?(@savantURL)
|
188
|
+
@builder["buttonActivateScene"].hide
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
#Scan the specified IP for scenes
|
193
|
+
def buttonScanHost__clicked(*argv)
|
194
|
+
@savantURL = @builder["savantURL"].text
|
195
|
+
if is_port_open?(@savantURL,"11263") || is_port_open?(@savantURL,"48664") || is_port_open?(@savantURL,"1124")
|
196
|
+
unless savantVersion?(@savantURL)
|
197
|
+
@builder["buttonActivateScene"].hide
|
198
|
+
end
|
199
|
+
begin
|
200
|
+
@listviewSavantScenes.model.clear
|
201
|
+
Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
|
202
|
+
# test to see if remote files exist and transfer them if they do
|
203
|
+
fileExists = ssh.exec!("[ -f #{@dis} ] && echo 'true' || echo 'false'")
|
204
|
+
unless fileExists == 'false'
|
205
|
+
ssh.scp.download!(@dis, '/tmp/')
|
206
|
+
#read from sqlite database and add to listview
|
207
|
+
@db = SQLite3::Database.open('/tmp/dashboard.sqlite')
|
208
|
+
@db.execute( "select * from scenes" ) do |rowData|
|
209
|
+
row = @listviewSavantScenes.add_row
|
210
|
+
row[:modify] = false
|
211
|
+
row[:id] = rowData.shift
|
212
|
+
row[:scene] = rowData.shift
|
213
|
+
row[:image] = rowData.shift
|
214
|
+
row[:tags] = rowData.shift
|
215
|
+
row[:isGlobal] = rowData.shift.to_s
|
216
|
+
row[:isActive] = rowData.shift.to_s
|
217
|
+
row[:isScheduled] = rowData.shift.to_s
|
218
|
+
row[:hasCustomImage] = rowData.shift.to_s
|
219
|
+
|
220
|
+
stm = @db.prepare( "select * from sceneusermap where sceneIdentifier=?" )
|
221
|
+
stm.bind_param 1, row[:id]
|
222
|
+
rs = stm.execute.next
|
223
|
+
row[:user] = rs[2]
|
224
|
+
row[:userSceneOrder] = rs[3].to_s
|
225
|
+
stm.close
|
226
|
+
end
|
227
|
+
repaint
|
228
|
+
end
|
229
|
+
end
|
230
|
+
rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
|
231
|
+
alert("Host not reached.", :parent => self)
|
232
|
+
end
|
233
|
+
else
|
234
|
+
alert("A Savant host was not found at the specified IP address.", :parent => self)
|
235
|
+
@listviewSavantScenes.model.clear
|
236
|
+
repaint
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
#Transfer database from tmp folder to remote host
|
241
|
+
def updateDatabase()
|
242
|
+
begin
|
243
|
+
Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
|
244
|
+
fileExists = ssh.exec!("[ -f #{@dis} ] && echo 'true' || echo 'false'")
|
245
|
+
unless fileExists == 'false'
|
246
|
+
ssh.scp.upload!('/tmp/dashboard.sqlite', @dis.chomp("dashboard.sqlite"))
|
247
|
+
alert("Please re-open the Savant Pro app to reflect changes.", :parent => self)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
|
251
|
+
alert("Host not reached.", :parent => self)
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
# #
|
256
|
+
# SCENE ACTIONS #
|
257
|
+
# #
|
258
|
+
|
259
|
+
#Activate the selected scene
|
260
|
+
def buttonActivateScene__clicked(*argv)
|
261
|
+
get_glade_variables()
|
262
|
+
activateScenes = []
|
263
|
+
activateIDs = []
|
264
|
+
activateUsers = []
|
265
|
+
@listviewSavantScenes.each_row do |row|
|
266
|
+
if row[:modify]
|
267
|
+
@str = @scliBridge + "activateScene \'" + row[:scene] + "\' \'" + row[:id] + "\' \'" + row[:user] + "\'"
|
268
|
+
begin
|
269
|
+
Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
|
270
|
+
ssh.exec!(@str)
|
271
|
+
alert("Scene activated: #{row[:scene]}", :parent => self)
|
272
|
+
end
|
273
|
+
rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
|
274
|
+
alert("Host not reached.", :parent => self)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
#Edit the selected scenes
|
281
|
+
def buttonApplyEdits__clicked(*argv)
|
282
|
+
get_glade_variables()
|
283
|
+
editScenes = []
|
284
|
+
editIDs = []
|
285
|
+
editUsers = []
|
286
|
+
editActive = []
|
287
|
+
count = 0
|
288
|
+
@listviewSavantScenes.each_row do |row|
|
289
|
+
if row[:modify]
|
290
|
+
count += 1
|
291
|
+
editScenes << row[:scene]
|
292
|
+
editIDs << row[:id]
|
293
|
+
editUsers << row[:user]
|
294
|
+
editActive << row[:isActive]
|
295
|
+
end
|
296
|
+
end
|
297
|
+
#make sure a scene was selected, else alert the user
|
298
|
+
if count > 0
|
299
|
+
#confirm the edits should be made
|
300
|
+
strAlert = "Do you want to apply changes to the following scenes on the Savant host?\n\n" + editScenes.join("\n")
|
301
|
+
if alert(strAlert, :headline => "Edit Scenes?", :button_yes => "Apply Changes", :button_cancel => "Cancel", :parent => self)
|
302
|
+
count = 0
|
303
|
+
#edit the database with the updated info
|
304
|
+
editIDs.each do |id|
|
305
|
+
stm = @db.prepare( "update sceneusermap set user=? where sceneIdentifier=?" )
|
306
|
+
stm.bind_param 1, editUsers[count]
|
307
|
+
stm.bind_param 2, id
|
308
|
+
stm.execute
|
309
|
+
stm.close
|
310
|
+
stm = @db.prepare( "update scenes set name=?, isActive=? where identifier=?" )
|
311
|
+
stm.bind_param 1, editScenes[count]
|
312
|
+
stm.bind_param 2, editActive[count]
|
313
|
+
stm.bind_param 3, id
|
314
|
+
stm.execute
|
315
|
+
stm.close
|
316
|
+
|
317
|
+
count += 1
|
318
|
+
end
|
319
|
+
updateDatabase()
|
320
|
+
buttonScanHost__clicked()
|
321
|
+
end
|
322
|
+
else
|
323
|
+
alert("Please select at least 1 row to modify.", :parent => self)
|
324
|
+
end
|
325
|
+
end
|
326
|
+
|
327
|
+
#Delete the selected scenes
|
328
|
+
def buttonDeleteScene__clicked(*argv)
|
329
|
+
get_glade_variables()
|
330
|
+
deleteScenes = []
|
331
|
+
deleteIDs = []
|
332
|
+
count = 0
|
333
|
+
@listviewSavantScenes.each_row do |row|
|
334
|
+
if row[:modify]
|
335
|
+
count += 1
|
336
|
+
deleteScenes << row[:scene]
|
337
|
+
deleteIDs << row[:id]
|
338
|
+
end
|
339
|
+
end
|
340
|
+
#make sure a scene was selected, else alert the user
|
341
|
+
if count > 0
|
342
|
+
#confirm the edits should be made
|
343
|
+
strAlert = "Do you want to delete the following scenes from the Savant host?\n\n" + deleteScenes.join("\n")
|
344
|
+
if alert(strAlert, :headline => "Delete Scenes?", :button_yes => "Delete", :button_cancel => "Cancel", :parent => self)
|
345
|
+
#edit the database with the updated info
|
346
|
+
deleteIDs.each do |id|
|
347
|
+
stm = @db.prepare( "delete from sceneusermap where sceneIdentifier=?" )
|
348
|
+
stm.bind_param 1, id
|
349
|
+
stm.execute
|
350
|
+
stm.close
|
351
|
+
stm = @db.prepare( "delete from scenes where identifier=?" )
|
352
|
+
stm.bind_param 1, id
|
353
|
+
stm.execute
|
354
|
+
stm.close
|
355
|
+
stm = @db.prepare( "delete from scenedefinitions where sceneIdentifier=?" )
|
356
|
+
stm.bind_param 1, id
|
357
|
+
stm.execute
|
358
|
+
stm.close
|
359
|
+
end
|
360
|
+
updateDatabase()
|
361
|
+
buttonScanHost__clicked()
|
362
|
+
end
|
363
|
+
else
|
364
|
+
alert("Please select at least 1 row to modify.", :parent => self)
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# #
|
369
|
+
# BACKUP AND RESTORE #
|
370
|
+
# #
|
371
|
+
|
372
|
+
#FileTreeView expand and collapse for file backup and restore
|
373
|
+
def ftv__row_activated(_self, path, col)
|
374
|
+
@ftv.expand_or_collapse_folder()
|
375
|
+
end
|
376
|
+
|
377
|
+
#Restore files from local filesystem to remote host
|
378
|
+
def buttonRestore__clicked(*a)
|
379
|
+
return unless row = @ftv.selected_rows.first
|
380
|
+
backupDir = row[:path]
|
381
|
+
#Get folder name if a file is selected.
|
382
|
+
if File.file?(backupDir)
|
383
|
+
backupDir = File.dirname(backupDir)
|
384
|
+
end
|
385
|
+
#Check that folder contains correct files
|
386
|
+
if File.file?(backupDir + "/dashboard.sqlite")
|
387
|
+
begin
|
388
|
+
Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
|
389
|
+
# test to see if remote folder exists, if so, transfer files and restart harbridge
|
390
|
+
dirExists = ssh.exec!("[ -d #{@dis.chomp("dashboard.sqlite")} ] && echo 'true' || echo 'false'")
|
391
|
+
if dirExists
|
392
|
+
ssh.scp.upload!(backupDir + "/dashboard.sqlite", @dis.chomp("dashboard.sqlite"))
|
393
|
+
alert("File has been restored from " + row[:path] + "\n\nPlease re-open the Savant Pro app to reflect changes.", :parent => self)
|
394
|
+
@builder["windowBackupRestore"].hide
|
395
|
+
buttonScanHost__clicked()
|
396
|
+
else
|
397
|
+
alert("Users/RPM/habridge/data folder not found on remote host.", :parent => self)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
else
|
402
|
+
alert("Selected directory does not contain dashboard.sqlite.", :parent => self)
|
403
|
+
end
|
404
|
+
end
|
405
|
+
|
406
|
+
#Backup files from remote host to local filesystem
|
407
|
+
def buttonBackup__clicked(*a)
|
408
|
+
return unless row = @ftv.selected_rows.first
|
409
|
+
backupDir = row[:path]
|
410
|
+
#Get folder name if a file is selected.
|
411
|
+
if File.file?(backupDir)
|
412
|
+
backupDir = File.dirname(backupDir)
|
413
|
+
end
|
414
|
+
begin
|
415
|
+
Net::SSH.start(@savantURL, @login, :password => @password, :paranoid => false, :timeout => 3) do |ssh|
|
416
|
+
# test to see if remote files exist and transfer them if they do
|
417
|
+
fileExists = ssh.exec!("[ -f #{@dis} ] && echo 'true' || echo 'false'")
|
418
|
+
unless fileExists == 'false'
|
419
|
+
ssh.scp.download!(@dis, backupDir)
|
420
|
+
end
|
421
|
+
repaint
|
422
|
+
end
|
423
|
+
rescue Net::SSH::ConnectionTimeout, SocketError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EHOSTDOWN
|
424
|
+
alert("Host not reached.", :parent => self)
|
425
|
+
end
|
426
|
+
alert("File backed up to " + row[:path], :parent => self)
|
427
|
+
@builder["windowBackupRestore"].hide
|
428
|
+
buttonScanHost__clicked()
|
429
|
+
|
430
|
+
end
|
431
|
+
|
432
|
+
def buttonBackupRestore__clicked(*argv)
|
433
|
+
@builder["windowBackupRestore"].show
|
434
|
+
end
|
435
|
+
|
436
|
+
def buttonBackupRestoreCancel__clicked(*argv)
|
437
|
+
@builder["windowBackupRestore"].hide
|
438
|
+
end
|
439
|
+
|
440
|
+
def buttonExit__clicked(*args)
|
441
|
+
@builder["window1"].destroy
|
442
|
+
end
|
443
|
+
|
444
|
+
end
|
@@ -0,0 +1,429 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<!-- Generated with glade 3.20.0 -->
|
3
|
+
<interface>
|
4
|
+
<requires lib="gtk+" version="3.0"/>
|
5
|
+
<object class="GtkWindow" id="window1">
|
6
|
+
<property name="can_focus">False</property>
|
7
|
+
<property name="has_focus">True</property>
|
8
|
+
<property name="hexpand">True</property>
|
9
|
+
<property name="vexpand">True</property>
|
10
|
+
<property name="window_position">center</property>
|
11
|
+
<property name="default_width">1200</property>
|
12
|
+
<child>
|
13
|
+
<object class="GtkGrid">
|
14
|
+
<property name="visible">True</property>
|
15
|
+
<property name="can_focus">False</property>
|
16
|
+
<property name="margin_left">12</property>
|
17
|
+
<property name="margin_right">12</property>
|
18
|
+
<property name="hexpand">True</property>
|
19
|
+
<property name="vexpand">False</property>
|
20
|
+
<child>
|
21
|
+
<object class="GtkLabel">
|
22
|
+
<property name="visible">True</property>
|
23
|
+
<property name="can_focus">False</property>
|
24
|
+
<property name="margin_top">12</property>
|
25
|
+
<property name="margin_bottom">12</property>
|
26
|
+
<property name="label" translatable="yes"><big><b>Savant Scene Manager</b></big></property>
|
27
|
+
<property name="use_markup">True</property>
|
28
|
+
</object>
|
29
|
+
<packing>
|
30
|
+
<property name="left_attach">0</property>
|
31
|
+
<property name="top_attach">0</property>
|
32
|
+
</packing>
|
33
|
+
</child>
|
34
|
+
<child>
|
35
|
+
<object class="GtkGrid">
|
36
|
+
<property name="visible">True</property>
|
37
|
+
<property name="can_focus">False</property>
|
38
|
+
<property name="margin_left">12</property>
|
39
|
+
<property name="margin_right">12</property>
|
40
|
+
<property name="column_homogeneous">True</property>
|
41
|
+
<child>
|
42
|
+
<object class="GtkButtonBox">
|
43
|
+
<property name="visible">True</property>
|
44
|
+
<property name="can_focus">False</property>
|
45
|
+
<property name="margin_right">12</property>
|
46
|
+
<property name="margin_top">12</property>
|
47
|
+
<property name="margin_bottom">12</property>
|
48
|
+
<property name="spacing">7</property>
|
49
|
+
<property name="layout_style">end</property>
|
50
|
+
<child>
|
51
|
+
<object class="GtkButton" id="buttonBackupRestore">
|
52
|
+
<property name="label" translatable="yes">Backup/Restore</property>
|
53
|
+
<property name="visible">True</property>
|
54
|
+
<property name="can_focus">True</property>
|
55
|
+
<property name="receives_default">True</property>
|
56
|
+
</object>
|
57
|
+
<packing>
|
58
|
+
<property name="expand">True</property>
|
59
|
+
<property name="fill">True</property>
|
60
|
+
<property name="position">1</property>
|
61
|
+
</packing>
|
62
|
+
</child>
|
63
|
+
<child>
|
64
|
+
<object class="GtkButton" id="buttonExit">
|
65
|
+
<property name="label" translatable="yes">Exit</property>
|
66
|
+
<property name="visible">True</property>
|
67
|
+
<property name="can_focus">True</property>
|
68
|
+
<property name="receives_default">True</property>
|
69
|
+
</object>
|
70
|
+
<packing>
|
71
|
+
<property name="expand">True</property>
|
72
|
+
<property name="fill">True</property>
|
73
|
+
<property name="position">2</property>
|
74
|
+
</packing>
|
75
|
+
</child>
|
76
|
+
</object>
|
77
|
+
<packing>
|
78
|
+
<property name="left_attach">1</property>
|
79
|
+
<property name="top_attach">0</property>
|
80
|
+
</packing>
|
81
|
+
</child>
|
82
|
+
<child>
|
83
|
+
<object class="GtkButtonBox">
|
84
|
+
<property name="visible">True</property>
|
85
|
+
<property name="can_focus">False</property>
|
86
|
+
<property name="margin_left">12</property>
|
87
|
+
<property name="spacing">9</property>
|
88
|
+
<property name="homogeneous">True</property>
|
89
|
+
<property name="layout_style">start</property>
|
90
|
+
<child>
|
91
|
+
<object class="GtkButton" id="buttonApplyEdits">
|
92
|
+
<property name="label" translatable="yes">Apply Edits</property>
|
93
|
+
<property name="visible">True</property>
|
94
|
+
<property name="can_focus">True</property>
|
95
|
+
<property name="receives_default">True</property>
|
96
|
+
</object>
|
97
|
+
<packing>
|
98
|
+
<property name="expand">True</property>
|
99
|
+
<property name="fill">True</property>
|
100
|
+
<property name="position">0</property>
|
101
|
+
</packing>
|
102
|
+
</child>
|
103
|
+
<child>
|
104
|
+
<object class="GtkButton" id="buttonDeleteScene">
|
105
|
+
<property name="label" translatable="yes">Delete Scene</property>
|
106
|
+
<property name="visible">True</property>
|
107
|
+
<property name="can_focus">True</property>
|
108
|
+
<property name="receives_default">True</property>
|
109
|
+
</object>
|
110
|
+
<packing>
|
111
|
+
<property name="expand">True</property>
|
112
|
+
<property name="fill">True</property>
|
113
|
+
<property name="position">1</property>
|
114
|
+
</packing>
|
115
|
+
</child>
|
116
|
+
<child>
|
117
|
+
<object class="GtkButton" id="buttonActivateScene">
|
118
|
+
<property name="label" translatable="yes">Activate Scene</property>
|
119
|
+
<property name="visible">True</property>
|
120
|
+
<property name="can_focus">True</property>
|
121
|
+
<property name="receives_default">True</property>
|
122
|
+
</object>
|
123
|
+
<packing>
|
124
|
+
<property name="expand">True</property>
|
125
|
+
<property name="fill">True</property>
|
126
|
+
<property name="position">2</property>
|
127
|
+
</packing>
|
128
|
+
</child>
|
129
|
+
</object>
|
130
|
+
<packing>
|
131
|
+
<property name="left_attach">0</property>
|
132
|
+
<property name="top_attach">0</property>
|
133
|
+
</packing>
|
134
|
+
</child>
|
135
|
+
</object>
|
136
|
+
<packing>
|
137
|
+
<property name="left_attach">0</property>
|
138
|
+
<property name="top_attach">3</property>
|
139
|
+
</packing>
|
140
|
+
</child>
|
141
|
+
<child>
|
142
|
+
<object class="GtkGrid">
|
143
|
+
<property name="visible">True</property>
|
144
|
+
<property name="can_focus">False</property>
|
145
|
+
<property name="margin_left">12</property>
|
146
|
+
<property name="margin_right">12</property>
|
147
|
+
<property name="hexpand">True</property>
|
148
|
+
<property name="vexpand">True</property>
|
149
|
+
<child>
|
150
|
+
<object class="GtkScrolledWindow" id="listviewSavantScenes">
|
151
|
+
<property name="visible">True</property>
|
152
|
+
<property name="can_focus">True</property>
|
153
|
+
<property name="margin_bottom">12</property>
|
154
|
+
<property name="hexpand">True</property>
|
155
|
+
<property name="vexpand">True</property>
|
156
|
+
<property name="hscrollbar_policy">always</property>
|
157
|
+
<property name="vscrollbar_policy">always</property>
|
158
|
+
<property name="shadow_type">in</property>
|
159
|
+
<property name="min_content_height">200</property>
|
160
|
+
<property name="max_content_height">800</property>
|
161
|
+
<child>
|
162
|
+
<placeholder/>
|
163
|
+
</child>
|
164
|
+
</object>
|
165
|
+
<packing>
|
166
|
+
<property name="left_attach">0</property>
|
167
|
+
<property name="top_attach">1</property>
|
168
|
+
</packing>
|
169
|
+
</child>
|
170
|
+
<child>
|
171
|
+
<object class="GtkGrid">
|
172
|
+
<property name="name">30</property>
|
173
|
+
<property name="visible">True</property>
|
174
|
+
<property name="can_focus">False</property>
|
175
|
+
<property name="margin_left">240</property>
|
176
|
+
<property name="margin_top">12</property>
|
177
|
+
<property name="margin_bottom">12</property>
|
178
|
+
<property name="column_spacing">3</property>
|
179
|
+
<child>
|
180
|
+
<object class="GtkEntry" id="savantURL">
|
181
|
+
<property name="visible">True</property>
|
182
|
+
<property name="can_focus">True</property>
|
183
|
+
<property name="has_focus">True</property>
|
184
|
+
<property name="is_focus">True</property>
|
185
|
+
<property name="events">GDK_KEY_PRESS_MASK | GDK_STRUCTURE_MASK</property>
|
186
|
+
<property name="halign">start</property>
|
187
|
+
<property name="activates_default">True</property>
|
188
|
+
<property name="width_chars">50</property>
|
189
|
+
</object>
|
190
|
+
<packing>
|
191
|
+
<property name="left_attach">1</property>
|
192
|
+
<property name="top_attach">0</property>
|
193
|
+
</packing>
|
194
|
+
</child>
|
195
|
+
<child>
|
196
|
+
<object class="GtkAlignment">
|
197
|
+
<property name="visible">True</property>
|
198
|
+
<property name="can_focus">False</property>
|
199
|
+
<child>
|
200
|
+
<object class="GtkLabel">
|
201
|
+
<property name="visible">True</property>
|
202
|
+
<property name="can_focus">False</property>
|
203
|
+
<property name="halign">end</property>
|
204
|
+
<property name="label" translatable="yes">Savant Host IP Address: </property>
|
205
|
+
<property name="justify">right</property>
|
206
|
+
</object>
|
207
|
+
</child>
|
208
|
+
</object>
|
209
|
+
<packing>
|
210
|
+
<property name="left_attach">0</property>
|
211
|
+
<property name="top_attach">0</property>
|
212
|
+
</packing>
|
213
|
+
</child>
|
214
|
+
<child>
|
215
|
+
<object class="GtkButton" id="buttonScanHost">
|
216
|
+
<property name="label" translatable="yes">Scan</property>
|
217
|
+
<property name="visible">True</property>
|
218
|
+
<property name="can_focus">True</property>
|
219
|
+
<property name="can_default">True</property>
|
220
|
+
<property name="has_default">True</property>
|
221
|
+
<property name="receives_default">True</property>
|
222
|
+
</object>
|
223
|
+
<packing>
|
224
|
+
<property name="left_attach">2</property>
|
225
|
+
<property name="top_attach">0</property>
|
226
|
+
</packing>
|
227
|
+
</child>
|
228
|
+
<child>
|
229
|
+
<object class="GtkAlignment">
|
230
|
+
<property name="visible">True</property>
|
231
|
+
<property name="can_focus">False</property>
|
232
|
+
<property name="halign">end</property>
|
233
|
+
<property name="margin_top">20</property>
|
234
|
+
<property name="hexpand">True</property>
|
235
|
+
<child>
|
236
|
+
<object class="GtkLabel" id="labelHostInfo">
|
237
|
+
<property name="visible">True</property>
|
238
|
+
<property name="can_focus">False</property>
|
239
|
+
<property name="margin_left">12</property>
|
240
|
+
<property name="justify">center</property>
|
241
|
+
</object>
|
242
|
+
</child>
|
243
|
+
</object>
|
244
|
+
<packing>
|
245
|
+
<property name="left_attach">3</property>
|
246
|
+
<property name="top_attach">0</property>
|
247
|
+
</packing>
|
248
|
+
</child>
|
249
|
+
</object>
|
250
|
+
<packing>
|
251
|
+
<property name="left_attach">0</property>
|
252
|
+
<property name="top_attach">0</property>
|
253
|
+
</packing>
|
254
|
+
</child>
|
255
|
+
<child>
|
256
|
+
<object class="GtkLabel">
|
257
|
+
<property name="visible">True</property>
|
258
|
+
<property name="can_focus">False</property>
|
259
|
+
<property name="halign">start</property>
|
260
|
+
<property name="margin_left">35</property>
|
261
|
+
<property name="margin_bottom">5</property>
|
262
|
+
<property name="label" translatable="yes">Check the box next to a scene and choose on option below.</property>
|
263
|
+
<property name="use_markup">True</property>
|
264
|
+
</object>
|
265
|
+
<packing>
|
266
|
+
<property name="left_attach">0</property>
|
267
|
+
<property name="top_attach">2</property>
|
268
|
+
</packing>
|
269
|
+
</child>
|
270
|
+
</object>
|
271
|
+
<packing>
|
272
|
+
<property name="left_attach">0</property>
|
273
|
+
<property name="top_attach">2</property>
|
274
|
+
</packing>
|
275
|
+
</child>
|
276
|
+
<child>
|
277
|
+
<object class="GtkLabel" id="labelDescription">
|
278
|
+
<property name="visible">True</property>
|
279
|
+
<property name="can_focus">False</property>
|
280
|
+
<property name="margin_top">12</property>
|
281
|
+
<property name="margin_bottom">12</property>
|
282
|
+
<property name="label" translatable="yes"> Savant scene manager copies the dashboard.sqlite file from the host to a temporary folder and lists all scenes from all users on that host.
|
283
|
+
You can backup and restore this database, as well as delete scenes or edit certain properties: Scene Name, user email, and whether or not the scene is actively scheduled.
|
284
|
+
|
285
|
+
If the host is running at least 8.3, you can also activate scenes.</property>
|
286
|
+
<property name="justify">center</property>
|
287
|
+
<property name="wrap">True</property>
|
288
|
+
<property name="wrap_mode">word-char</property>
|
289
|
+
<property name="width_chars">60</property>
|
290
|
+
<property name="max_width_chars">60</property>
|
291
|
+
</object>
|
292
|
+
<packing>
|
293
|
+
<property name="left_attach">0</property>
|
294
|
+
<property name="top_attach">1</property>
|
295
|
+
</packing>
|
296
|
+
</child>
|
297
|
+
</object>
|
298
|
+
</child>
|
299
|
+
</object>
|
300
|
+
<object class="GtkWindow" id="windowBackupRestore">
|
301
|
+
<property name="width_request">300</property>
|
302
|
+
<property name="height_request">300</property>
|
303
|
+
<property name="can_focus">False</property>
|
304
|
+
<property name="modal">True</property>
|
305
|
+
<property name="window_position">center-on-parent</property>
|
306
|
+
<property name="gravity">center</property>
|
307
|
+
<property name="transient_for">window1</property>
|
308
|
+
<property name="has_resize_grip">True</property>
|
309
|
+
<child>
|
310
|
+
<object class="GtkBox">
|
311
|
+
<property name="visible">True</property>
|
312
|
+
<property name="can_focus">False</property>
|
313
|
+
<property name="orientation">vertical</property>
|
314
|
+
<child>
|
315
|
+
<object class="GtkLabel">
|
316
|
+
<property name="visible">True</property>
|
317
|
+
<property name="can_focus">False</property>
|
318
|
+
<property name="margin_top">20</property>
|
319
|
+
<property name="margin_bottom">20</property>
|
320
|
+
<property name="label" translatable="yes"><big><b>Backup and Restore</b></big></property>
|
321
|
+
<property name="use_markup">True</property>
|
322
|
+
</object>
|
323
|
+
<packing>
|
324
|
+
<property name="expand">False</property>
|
325
|
+
<property name="fill">True</property>
|
326
|
+
<property name="position">0</property>
|
327
|
+
</packing>
|
328
|
+
</child>
|
329
|
+
<child>
|
330
|
+
<object class="GtkLabel">
|
331
|
+
<property name="visible">True</property>
|
332
|
+
<property name="can_focus">False</property>
|
333
|
+
<property name="margin_left">20</property>
|
334
|
+
<property name="margin_right">20</property>
|
335
|
+
<property name="margin_bottom">12</property>
|
336
|
+
<property name="label" translatable="yes"> This will backup or restore the dashboard.sqlite file.
|
337
|
+
|
338
|
+
To backup the file, select a destination folder.
|
339
|
+
|
340
|
+
To restore the backed up file, select the folder that contains the file. </property>
|
341
|
+
<property name="wrap">True</property>
|
342
|
+
</object>
|
343
|
+
<packing>
|
344
|
+
<property name="expand">False</property>
|
345
|
+
<property name="fill">False</property>
|
346
|
+
<property name="position">1</property>
|
347
|
+
</packing>
|
348
|
+
</child>
|
349
|
+
<child>
|
350
|
+
<object class="GtkScrolledWindow" id="scrolledwindow_BackupRestore">
|
351
|
+
<property name="width_request">300</property>
|
352
|
+
<property name="height_request">300</property>
|
353
|
+
<property name="visible">True</property>
|
354
|
+
<property name="can_focus">True</property>
|
355
|
+
<property name="margin_left">20</property>
|
356
|
+
<property name="margin_right">20</property>
|
357
|
+
<property name="shadow_type">in</property>
|
358
|
+
<property name="min_content_width">300</property>
|
359
|
+
<property name="min_content_height">300</property>
|
360
|
+
<property name="max_content_width">300</property>
|
361
|
+
<property name="max_content_height">300</property>
|
362
|
+
<child>
|
363
|
+
<placeholder/>
|
364
|
+
</child>
|
365
|
+
</object>
|
366
|
+
<packing>
|
367
|
+
<property name="expand">False</property>
|
368
|
+
<property name="fill">False</property>
|
369
|
+
<property name="position">2</property>
|
370
|
+
</packing>
|
371
|
+
</child>
|
372
|
+
<child>
|
373
|
+
<object class="GtkButtonBox">
|
374
|
+
<property name="visible">True</property>
|
375
|
+
<property name="can_focus">False</property>
|
376
|
+
<property name="margin_top">20</property>
|
377
|
+
<property name="margin_bottom">12</property>
|
378
|
+
<property name="layout_style">spread</property>
|
379
|
+
<child>
|
380
|
+
<object class="GtkButton" id="buttonBackup">
|
381
|
+
<property name="label" translatable="yes">Backup</property>
|
382
|
+
<property name="visible">True</property>
|
383
|
+
<property name="can_focus">True</property>
|
384
|
+
<property name="receives_default">True</property>
|
385
|
+
</object>
|
386
|
+
<packing>
|
387
|
+
<property name="expand">True</property>
|
388
|
+
<property name="fill">True</property>
|
389
|
+
<property name="position">0</property>
|
390
|
+
</packing>
|
391
|
+
</child>
|
392
|
+
<child>
|
393
|
+
<object class="GtkButton" id="buttonRestore">
|
394
|
+
<property name="label" translatable="yes">Restore</property>
|
395
|
+
<property name="visible">True</property>
|
396
|
+
<property name="can_focus">True</property>
|
397
|
+
<property name="receives_default">True</property>
|
398
|
+
</object>
|
399
|
+
<packing>
|
400
|
+
<property name="expand">True</property>
|
401
|
+
<property name="fill">True</property>
|
402
|
+
<property name="position">1</property>
|
403
|
+
</packing>
|
404
|
+
</child>
|
405
|
+
<child>
|
406
|
+
<object class="GtkButton" id="buttonBackupRestoreCancel">
|
407
|
+
<property name="label" translatable="yes">Cancel</property>
|
408
|
+
<property name="visible">True</property>
|
409
|
+
<property name="can_focus">True</property>
|
410
|
+
<property name="receives_default">True</property>
|
411
|
+
</object>
|
412
|
+
<packing>
|
413
|
+
<property name="expand">True</property>
|
414
|
+
<property name="fill">True</property>
|
415
|
+
<property name="position">2</property>
|
416
|
+
</packing>
|
417
|
+
</child>
|
418
|
+
</object>
|
419
|
+
<packing>
|
420
|
+
<property name="expand">True</property>
|
421
|
+
<property name="fill">True</property>
|
422
|
+
<property name="pack_type">end</property>
|
423
|
+
<property name="position">3</property>
|
424
|
+
</packing>
|
425
|
+
</child>
|
426
|
+
</object>
|
427
|
+
</child>
|
428
|
+
</object>
|
429
|
+
</interface>
|
metadata
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: savant-scenes
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Corey Miller
|
8
|
+
autorequire:
|
9
|
+
bindir:
|
10
|
+
- bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-04-28 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: sqlite3
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '1.3'
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.3.13
|
24
|
+
type: :runtime
|
25
|
+
prerelease: false
|
26
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
|
+
requirements:
|
28
|
+
- - "~>"
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: '1.3'
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.3.13
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: net-scp
|
36
|
+
requirement: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.2'
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.2.1
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: !ruby/object:Gem::Requirement
|
47
|
+
requirements:
|
48
|
+
- - "~>"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '1.2'
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.2.1
|
54
|
+
- !ruby/object:Gem::Dependency
|
55
|
+
name: ipaddress
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '0.8'
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: 0.8.3
|
64
|
+
type: :runtime
|
65
|
+
prerelease: false
|
66
|
+
version_requirements: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - "~>"
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0.8'
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 0.8.3
|
74
|
+
- !ruby/object:Gem::Dependency
|
75
|
+
name: visualruby
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - "~>"
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: '3.0'
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: 3.0.23
|
84
|
+
type: :runtime
|
85
|
+
prerelease: false
|
86
|
+
version_requirements: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '3.0'
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 3.0.23
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: require_all
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - "~>"
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '1.2'
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.2.0
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.2'
|
111
|
+
- - ">="
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: 1.2.0
|
114
|
+
description: Savant Scene Management
|
115
|
+
email: cmiller@premieresystems.com
|
116
|
+
executables:
|
117
|
+
- scenes
|
118
|
+
extensions: []
|
119
|
+
extra_rdoc_files: []
|
120
|
+
files:
|
121
|
+
- bin/scenes
|
122
|
+
- bin/src/SceneManager.rb
|
123
|
+
- bin/src/glade/SceneManager.glade
|
124
|
+
homepage: http://www.yoursite.org/
|
125
|
+
licenses: []
|
126
|
+
metadata: {}
|
127
|
+
post_install_message:
|
128
|
+
rdoc_options: []
|
129
|
+
require_paths:
|
130
|
+
- lib
|
131
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
|
+
requirements:
|
133
|
+
- - ">="
|
134
|
+
- !ruby/object:Gem::Version
|
135
|
+
version: '2.0'
|
136
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
|
+
requirements:
|
138
|
+
- - ">="
|
139
|
+
- !ruby/object:Gem::Version
|
140
|
+
version: '0'
|
141
|
+
requirements: []
|
142
|
+
rubyforge_project: nowarning
|
143
|
+
rubygems_version: 2.4.8
|
144
|
+
signing_key:
|
145
|
+
specification_version: 4
|
146
|
+
summary: Savant Scene Manager
|
147
|
+
test_files: []
|