experiment 0.0.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,11 +5,15 @@ Rakefile
5
5
  lib/experiment.rb
6
6
  lib/experiment/config.rb
7
7
  lib/experiment/stats.rb
8
+ lib/experiment/runner.rb
8
9
  lib/experiment/generator/readme_template.txt
9
10
  lib/experiment/generator/experiment_template.rb
10
11
  lib/experiment/generator/Rakefile
11
12
  lib/experiment/base.rb
12
13
  lib/experiment/notify.rb
14
+ lib/experiment/work_server.rb
15
+ lib/experiment/distributed.rb
13
16
  test/test_experiment.rb
14
17
  test/test_helper.rb
15
- bin/experiment
18
+ bin/experiment
19
+ bin/growl.sh
@@ -27,7 +27,7 @@ Experiments are set up in the experiments directory. The first thing you need to
27
27
 
28
28
  For a typical experiment you will need to do some setup work (eg. initialize your classes, calculate parametres, etc.), run the experiment and maybe do cleanup (remove temp. files).
29
29
 
30
- You do all this work in the `run_the_experiment` method. Remember to pass the raw output via `<<` to the `output` variable and wrap the experiment in a benchmark block. This will be automatically saved to the results directory for further analysis.
30
+ You do all this work in the `run_the_experiment` method. Use the `measure` method to wrap your measurements. These will be autmatically benchmarked and their ouput will be automatically saved to the results directory for further analysis.
31
31
 
32
32
  The `test_data` method lets you specify an array of data points that you want split for cross-validation (see below). This will be passed to in `run_the_experiment` in the input variable.
33
33
 
@@ -102,7 +102,7 @@ Then your final config will look like this:
102
102
  :master_dir => "/Users/kubowo/Desktop/points-vals/s015",
103
103
  :alpha => 0.6 }
104
104
 
105
- Flexible, eh?
105
+ Flexible, eh? **NEW** Check out the *get* method. It has features like interpolation and defaults.
106
106
 
107
107
  == Cross Validation
108
108
 
@@ -116,8 +116,17 @@ Surprise, surprise. This will create two files in your `report` directory (BTW,
116
116
 
117
117
  The second file created is the `data.csv` file which contains the data from all your experiments. It should be importable to Numbers, Excel even Matlab for further analysis and charting.
118
118
 
119
+
120
+ == Distributed computing support
121
+
122
+ Newly this library supports a simple distributed model of running experiments. Setup worker computers with the
123
+
124
+ $ experiment worker --address IP_OF_COMPUTER_WHERE_YOU_RUN_EXPERIMENTS
125
+
126
+ and then run experiments with --distributed flag.
127
+
119
128
  == Misc
120
129
 
121
- So that's pretty much the gist of experiment. There's a few other features (and a few soon to come to a gem near you ;-)
130
+ So that's pretty much the gist of experiment. There's a few other features (and a few soon to come to a gem near you ;-) Growl notifications are now supported. Turn them of by setting growl_notifications to false in your config file.
122
131
 
123
132
  Also check out the RDocs: http://rdoc.info/github/gampleman/Experiment/master/frames
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ $hoe = Hoe.spec 'experiment' do
14
14
  self.developer 'Jakub Hampl', 'honitom@seznam.cz'
15
15
  #self.post_install_message = 'PostInstall.txt' # TODO remove if post-install message not required
16
16
  self.rubyforge_name = self.name # TODO this is default value
17
- # self.extra_deps = [['activesupport','>= 2.0.2']]
17
+ #self.extra_deps = [['ruby-growl','>= 1.0']]
18
18
 
19
19
  end
20
20
 
@@ -1,47 +1,14 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- # == Synopsis
4
- # This program will run an experimental batch or generate files
5
- # for a new experiment
6
- #
7
- # == Examples
8
- # Running an experiment
9
- # experiment --env dice experiment1 experiment2 ...
10
- #
11
- # Generating a new experiment with 2 cross validations
12
- # experiment new experiment_name --cv 2
13
- #
14
- # List all available experiments
15
- # experiment list
16
- #
17
- #
18
- # == Usage
19
- # experiment command [options]
20
- #
21
- # For help use: experiment -h
22
- #
23
- # == Options
24
- # -h, --help Displays help message
25
- # -v, --version Display the version, then exit
26
- # -q, --quiet Output as little as possible, overrides verbose
27
- # -V, --verbose Verbose output
28
- # -e, --env Sets the environment to run in
29
- # Defaults to development
30
- # -c, --cv Number of Cross validations to run
31
- # -m, --description A description of the current experiment
32
- #
33
- # == Author
34
- # Jakub Hampl
35
- #
36
-
37
- #require "rubygems"
38
3
  require 'optparse'
39
- #require 'rdoc/usage'
40
4
  require 'ostruct'
41
- #require File.dirname(__FILE__) + "/experiment"
5
+ require "rdoc"
6
+ require "rdoc/rdoc"
7
+
8
+ require File.dirname(__FILE__) + "/../lib/experiment/runner"
42
9
 
43
10
  class App
44
- VERSION = '1.0'
11
+ VERSION = '0.2.0'
45
12
 
46
13
  attr_reader :options
47
14
 
@@ -55,11 +22,10 @@ class App
55
22
  @options.quiet = false
56
23
  @options.env = :development
57
24
  @options.cv = 5
58
- @options.n_classes = 10
59
- @options.kind = "d"
60
25
  @options.description = ""
61
- @options.opts = {}
62
-
26
+ @options.opts = ""
27
+ @options.distributed = false
28
+ @options.master = "localhost"
63
29
  end
64
30
 
65
31
  # Parse options, check arguments, then process the command
@@ -69,10 +35,7 @@ class App
69
35
 
70
36
  puts "Start at #{DateTime.now}\n\n" if @options.verbose
71
37
 
72
- output_options if @options.verbose # [Optional]
73
- require File.dirname(__FILE__) + "/vendor/backports/backports" if @options.env == :dice
74
-
75
- process_arguments
38
+ output_options if @options.verbose # [Optional]
76
39
  process_command
77
40
 
78
41
  puts "\nFinished at #{DateTime.now}" if @options.verbose
@@ -88,20 +51,20 @@ class App
88
51
  def parsed_options?
89
52
 
90
53
  # Specify options
91
- opts = OptionParser.new
92
- opts.on('-v', '--version') { output_version ; exit 0 }
93
- opts.on('-h', '--help') { output_help }
94
- opts.on('-V', '--verbose') { @options.verbose = true }
95
- opts.on('-q', '--quiet') { @options.quiet = true }
96
- opts.on('-e', '--env [ENV]', [:development, :dice]) { |v| @options.env = v }
97
- opts.on('-c', '--cv CV', Integer) { |v| @options.cv = v }
98
- opts.on('-n', '--number NUMBER', Integer) { |v| @options.n_classes = v }
99
- opts.on('-k', '--kind KIND', String) { |v| @options.kind = v }
100
- opts.on('-m', '--description M', String) { |v| @options.description = v }
101
- opts.on('-o', '--options OPTSTRING', String) do |v|
54
+ @opts = OptionParser.new
55
+ @opts.on('-v', '--version') { output_version ; exit 0 }
56
+ @opts.on('-h', '--help') { output_help }
57
+ @opts.on('-V', '--verbose') { @options.verbose = true }
58
+ @opts.on('-q', '--quiet') { @options.quiet = true }
59
+ @opts.on('-e', '--env [ENV]', [:development, :compute], "Sets the environment to run in.") { |v| @options.env = v }
60
+ @opts.on('-c', '--cv CV', Integer, "The number of cross validations to run.") { |v| @options.cv = v }
61
+ @opts.on('-m', '--description M', String, "Description or hypothesis for the condition being generated.") { |v| @options.description = v }
62
+ @opts.on('-o', '--options OPTSTRING', String, "Options to override config with. key1:val1,key2:val2") do |v|
102
63
  @options.opts = v
103
64
  end
104
- opts.parse!(@arguments) rescue return false
65
+ @opts.on('-D', '--distributed', "Run with a distributed computing mode. This will be the master server/work cue.") { @options.distributed = true }
66
+ @opts.on('-a', '--address MODE', String, "Address to the master machine.") { |v| @options.master = v }
67
+ @opts.parse!(@arguments) #rescue return false
105
68
 
106
69
  process_options
107
70
  true
@@ -122,21 +85,45 @@ class App
122
85
 
123
86
  # True if required arguments were provided
124
87
  def arguments_valid?
125
- true if @arguments.length > 0
126
- end
127
-
128
- # Setup the arguments
129
- def process_arguments
130
- # TO DO - place in local vars, etc
88
+ true #if @arguments.length > 0
131
89
  end
132
90
 
133
91
  def output_help
134
92
  output_version
135
- RDoc::usage() #exits app
93
+ puts "= Synopsis
94
+ This program will run an experimental batch or generate files
95
+ for a new experiment"
96
+ puts
97
+ output_usage
98
+ puts
99
+ puts "= Options"
100
+ puts @opts.help
101
+ puts
102
+ puts "= Commands"
103
+ # Bizzare hax to make RDoc parse the files
104
+ top_level = RDoc::TopLevel.new File.dirname(__FILE__) + "/../lib/experiment/runner.rb"
105
+ opts = RDoc::Options.new
106
+ stats = RDoc::Stats.new 1
107
+ parser = RDoc::Parser.for top_level, File.dirname(__FILE__) + "/../lib/experiment/runner.rb", File.read(File.dirname(__FILE__) + "/../lib/experiment/runner.rb"), opts, stats
108
+ d = parser.scan
109
+ d.modules.first.classes.first.method_list.each do |m|
110
+ if m.comment != ""
111
+ puts "== #{m.name == 'new_project' ? 'new' : m.name}"
112
+ puts m.comment
113
+ puts
114
+ end
115
+ end
116
+
117
+ puts "----"
118
+ exit 0
136
119
  end
137
120
 
138
121
  def output_usage
139
- RDoc::usage('usage') # gets usage from comments above
122
+ puts "= Usage
123
+ experiment command [options]
124
+
125
+ For help use: experiment -h"
126
+
140
127
  end
141
128
 
142
129
  def output_version
@@ -144,130 +131,19 @@ class App
144
131
  end
145
132
 
146
133
  def process_command
147
- if @arguments.first == 'generate'
148
- dir = "./experiments/" + @arguments[1]
149
- Dir.mkdir(dir)
150
- File.open(dir + "/" + @arguments[1] + ".rb", "w") do |req_file|
151
- req_file.puts "# ## #{as_human_name @arguments[1]} ##"
152
- req_file.puts "# "+@options.description.split("\n").join("\n# ")
153
- req_file.puts
154
- req_file.puts
155
- req_file.puts "# The first contious block of comment will be included in your report."
156
- req_file.puts "# This includes the reference implementation."
157
- req_file.puts "# Override any desired files in this directory."
158
- Dir["./app/**/*.rb"].each do |f|
159
- p = f.split("/") - File.expand_path(".").split("/")
160
- req_file.puts "require File.dirname(__FILE__) + \"/../../#{p.join("/")}\""
161
- end
162
- req_file.puts "\nclass #{as_class_name @arguments[1]} < MyExperiment\n\t\nend"
163
- end
164
- File.open(dir + "/config.yaml", "w") do |f|
165
- f << "---\nexperiment:\n development:\n compute:\n"
166
- end
167
-
168
- elsif @arguments.first == "new" # generate a new project
169
- require 'fileutils'
170
- dir = "./" + @arguments[1]
171
- Dir.mkdir(dir)
172
- %w[app config experiments report results test tmp vendor].each do |d|
173
- Dir.mkdir(dir + "/" + d)
174
- end
175
- basedir = File.dirname(__FILE__) + "/.."
176
- File.open(File.join(dir, "config", "config.yaml"), "w") do |f|
177
- f << "---\nenvironments:\n development:\n compute:\n"
178
- end
179
- File.open(File.join(dir, ".gitignore"), "w") do |f|
180
- f << "tmp/*"
181
- end
182
- FileUtils::cp File.join(basedir, "lib/experiment/generator/readme_template.txt"), File.join(dir, "README")
183
- FileUtils::cp File.join(basedir, "lib/experiment/generator/Rakefile"), File.join(dir, "Rakefile")
184
- FileUtils::cp File.join(basedir, "lib/experiment/generator/experiment_template.rb"), File.join(dir, "experiments", "experiment.rb")
185
- elsif @arguments.first == "list"
186
- puts "Available experiments:"
187
- puts " " + Dir["./experiments/*"].map{|a| File.basename(a) }.join(", ")
188
- elsif @arguments.first == "report"
189
- dir = "./report/"
190
- File.open(dir + "method.mmd", "w") do |f|
191
- f.puts "# Methods #"
192
- Dir["./experiments/*/*.rb"].each do |desc|
193
- if File.basename(desc) == File.basename(File.dirname(desc)) + ".rb"
194
- File.read(desc).split("\n").each do |line|
195
- if m = line.match(/^\# (.+)/)
196
- f.puts m[1]
197
- else
198
- break
199
- end
200
- end
201
- f.puts
202
- f.puts
203
- end
204
- end
205
- end
206
- require 'csv'
207
- require "yaml"
208
- require File.dirname(__FILE__)+"/../lib/experiment/stats"
209
- CSV.open(dir + "/data.csv", "w") do |csv|
210
- data = {}
211
- Dir["./results/*/results.yaml"].each do |res|
212
- d = YAML::load_file(res)
213
- da = {}
214
- d.each do |k, vals|
215
- da[k.to_s + " mean"], da[k.to_s + " sd"] = Stats::mean(vals), Stats::standard_deviation(vals)
216
- vals.each_with_index do |v, i|
217
- da[k.to_s + " cv:" + i.to_s] = v
218
- end
219
- end
220
- array_merge(data, da)
221
- end
222
- data.keys.map do |key|
223
- # calculate stats
224
- a = data[key]
225
- [key] + a
226
- end.transpose.each do |row|
227
- csv << row
228
- end
229
- end
230
- elsif @arguments.shift == "run"
231
- require File.dirname(__FILE__) + "/../lib/experiment/base"
232
- require "experiments/experiment"
233
- @arguments.each do |exp|
234
- require "./experiments/#{exp}/#{exp}"
235
- cla = eval(as_class_name(exp))
236
- experiment = cla.new exp, @options.opts, @options.env
237
- experiment.run! @options.cv
238
- end
239
- else
240
- output_usage
241
- end
242
-
243
- end
244
-
245
-
246
- private
247
- def array_merge(h1, h2)
248
- h2.each do |key, value|
249
- h1[key] ||= []
250
- h1[key] << value
251
- end
252
- end
253
-
254
- def as_class_name(str)
255
- str.split(/[\_\-]+/).map(&:capitalize).join
256
- end
257
-
258
- def as_human_name(str)
259
- str.split(/[\_\-]+/).map(&:capitalize).join(" ")
134
+ command = @arguments.shift
135
+ runner = Experiment::Runner.new @arguments, options
136
+ command = "new_project" if command == 'new'
137
+ #begin
138
+ runner.send command.to_sym
139
+ #rescue NoMethodError => e
140
+ # puts "Wrong input #{e.inspect}"
141
+ # output_usage
142
+ #end
260
143
  end
261
144
 
262
145
  def process_standard_input
263
146
  input = @stdin.read
264
- # TO DO - process input
265
-
266
- # [Optional]
267
- # @stdin.each do |line|
268
- # # TO DO - process each line
269
- #end
270
-
271
147
  end
272
148
  end
273
149
 
@@ -0,0 +1,241 @@
1
+ #!/bin/sh
2
+ #-----------------------------------------------------------------------------
3
+ # growl - Send the a message to Mac OS X Growl <http://growl.info> via a
4
+ # Unix shell script.
5
+ #
6
+ # And if this is a Linux or Windows_NT box, use ssh to forward the
7
+ # growl notice to my Mac OS X workstation (taking advantage of
8
+ # previously exchanged ssh so no additional authentication is
9
+ # needed).
10
+ #
11
+ # This script should be somewhere in your PATH. I like to use
12
+ # $HOME/bin for personal scripts, and /usr/local/bin for system
13
+ # wide scripts, with appropriate entries added to PATH. The script
14
+ # needs to be executable:
15
+ #
16
+ # chmod +x $HOME/bin/growl
17
+ #
18
+ # The basics for the Growl Applescript came from the Growl
19
+ # documentation at:
20
+ # <http://growl.info/documentation/applescript-support.php>
21
+ #-----------------------------------------------------------------------------
22
+ # Bob Harris - 2-Jun-2007
23
+ #-----------------------------------------------------------------------------
24
+
25
+
26
+ #--- usage -------------------------------------------------------------------
27
+ usage()
28
+ {
29
+ echo 1>&2 ""
30
+ echo 1>&2 "Usage: growl [options] \"message to display\""
31
+ echo 1>&2 ""
32
+ echo 1>&2 " -sticky - Stays on screen until dismissed [Default]."
33
+ echo 1>&2 " -nosticky - Goes away after several seconds."
34
+ echo 1>&2 " -priority n - Priority -2,-1,0,1,2 [Default: 0]"
35
+ echo 1>&2 " -verylow - priority [-2]"
36
+ echo 1>&2 " -moderate - priority [-1]"
37
+ echo 1>&2 " -normal - priority [0] [Default]"
38
+ echo 1>&2 " -high - priority [1]"
39
+ echo 1>&2 " -emergency - priority [2]"
40
+ echo 1>&2 ""
41
+ echo 1>&2 " Interesting environment variables:"
42
+ echo 1>&2 " G_TITLE - Used as the Growl message title."
43
+ echo 1>&2 " G_APPLICATION_NAME - Used by Growl to manage a set of"
44
+ echo 1>&2 " G_WITH_NAME message configurations."
45
+ echo 1>&2 " See System Preferences -> Growl"
46
+ echo 1>&2 " G_ALL_NAMES - Used to specify 'ALL' the possible"
47
+ echo 1>&2 " G_WITH_NAME values this"
48
+ echo 1>&2 " G_APPLICATION_NAME will ever use."
49
+ echo 1>&2 " Specify something like:"
50
+ echo 1>&2 " G_ALL_NAMES='\"class1\",\"class2\"'"
51
+ echo 1>&2 " export G_ALL_NAMES"
52
+ echo 1>&2 " G_WITH_NAME - Used by Growl to associate a"
53
+ echo 1>&2 " message with a set of Growl"
54
+ echo 1>&2 " notification settings, such as"
55
+ echo 1>&2 " message style and colors associated"
56
+ echo 1>&2 " with different priorities. See"
57
+ echo 1>&2 " System preferences -> Growl"
58
+ echo 1>&2 " Specify something like:"
59
+ echo 1>&2 " G_WITH_NAME='class2'"
60
+ echo 1>&2 " export G_WITH_NAME"
61
+ echo 1>&2 " If G_WITH_NAME is not in"
62
+ echo 1>&2 " G_ALL_NAMES, nothing will be"
63
+ echo 1>&2 " displayed"
64
+ echo 1>&2 " G_APPLICATION_ICON - Display this application's icon in"
65
+ echo 1>&2 " the Growl message (default is"
66
+ echo 1>&2 " Terminal.app, as this is a shell"
67
+ echo 1>&2 " script generated Growl notice)."
68
+ echo 1>&2 ""
69
+ exit 1
70
+ }
71
+
72
+
73
+ #--- defaults ----------------------------------------------------------------
74
+ defaults()
75
+ {
76
+ #
77
+ # These 2 variables are used when this script notices that it is on a Linux
78
+ # or Windows_NT system, then this script uses ssh to forward the request to
79
+ # my Mac OS X workstation. This assumes that ssh keys have been exchanged
80
+ # between the systems so that no passwords are needed. If you don't know
81
+ # what this means, then do a Google search for something like
82
+ # "ssh nopassword key" and you should turn up a number of guides for
83
+ # configuring ssh.
84
+ #
85
+ G_REMOTE="${G_REMOTE:-juggle-mac.us.oracle.com}" # assumes ssh exchanged keys
86
+ G_REMOTE_GROWL="${G_REMOTE_GROWL:-bin/growl}" # growl script remote location
87
+
88
+ #
89
+ # G_APPLICATION_NAME is the name Growl will use in the Growl System
90
+ # Preferences to provide defaults for Display, and to collect each of your
91
+ # notification classes (See G_ALL_NAMES below).
92
+ #
93
+ G_APPLICATION_NAME="${G_APPLICATION_NAME:-Shell Script Growl Message}"
94
+ #
95
+ # G_ALL_NAMES contains a list of all the notification classes to be
96
+ # associated with the G_APPLICATION_NAME. Each notification class can have
97
+ # its own default Display, Priority, and Stickness settings in the Growl
98
+ # System Preferences.
99
+ #
100
+ G_ALL_NAMES="${G_ALL_NAMES:-\"Shell Script Growl Message\",\"Growl Message\"}"
101
+ #
102
+ # The default notification class this message should use, must be in the
103
+ # G_ALL_NAMES list above.
104
+ #
105
+ G_WITH_NAME="${G_WITH_NAME:-Shell Script Growl Message}" # default notification
106
+ #
107
+ G_TITLE="${G_TITLE:-Shell Script Growl Message}" # default title
108
+ G_APPLICATION_ICON="${G_APPLICATION_ICON:-Terminal.app}" # default icon to use
109
+ G_STICKY="${G_STICKY:-yes}" # default sticky setting
110
+ G_PRIORITY="${G_PRIORITY:-0}" # default priority (normal)
111
+ }
112
+
113
+
114
+ #--- growl -------------------------------------------------------------------
115
+ # notify v : Post a notification to be displayed via Growl
116
+ # notify
117
+ # with name string : name of the notification to display
118
+ # title string : title of the notification to display
119
+ # description string : full text of the notification to display
120
+ # application name string : name of the application posting the
121
+ # notification.
122
+ # [image from location location_reference]
123
+ # : Location of the image file to use for this
124
+ # notification. Accepts aliases, paths and
125
+ # file:/// URLs.
126
+ # [icon of file location_reference]
127
+ # : Location of the file whose icon should be
128
+ # used as the image for this notification.
129
+ # Accepts aliases, paths and file:/// URLs.
130
+ # e.g. 'file:///Applications'.
131
+ # [icon of application string]
132
+ # : Name of the application whose icon should
133
+ # be used for this notification. For
134
+ # example, 'Mail.app'.
135
+ # [image Image] : TIFF Image to be used for the
136
+ # notification.
137
+ # [pictImage Picture] : PICT Image to be used for the
138
+ # notification.
139
+ # [sticky boolean] : whether or not the notification displayed
140
+ # should time out. Defaults to 'no'.
141
+ # [priority integer] : The priority of the notification, from -2
142
+ # (low) to 0 (normal) to 2 (emergency).
143
+ #
144
+ growl()
145
+ {
146
+ typeset description="$*"
147
+
148
+ osascript <<EOD
149
+ -- From <http://growl.info/documentation/applescript-support.php>
150
+ --
151
+ tell application "GrowlHelperApp"
152
+ -- Make a list of all the notification types that this script will ever send:
153
+ set the allNotificationsList to {${G_ALL_NAMES}}
154
+
155
+ -- Make a list of the notifications that will be enabled by default.
156
+ -- Those not enabled by default can be enabled later in the 'Applications'
157
+ -- tab of the growl prefpane.
158
+ set the enabledNotificationsList to {"${G_WITH_NAME}"}
159
+
160
+ -- Register our script with growl. You can optionally (as here) set a
161
+ -- default icon for this script's notifications.
162
+ register as application "${G_APPLICATION_NAME}" all notifications allNotificationsList default notifications enabledNotificationsList icon of application "${G_APPLICATION_ICON}"
163
+
164
+ -- Send a Notification...
165
+ notify with name "${G_WITH_NAME}" title "${G_TITLE}" description "${description}" application name "${G_APPLICATION_NAME}" sticky ${G_STICKY} priority ${G_PRIORITY}
166
+
167
+ end tell
168
+ EOD
169
+ }
170
+
171
+
172
+ #--- main --------------------------------------------------------------------
173
+ #{
174
+ if [[ $# = 0 ]]; then
175
+ #
176
+ # No arguments, so give the usage message.
177
+ #
178
+ usage
179
+ exit 1
180
+ fi
181
+ while [[ "X$1" = X-* ]]
182
+ do
183
+ if [[ "X$1" = X-nos* ]]; then
184
+ G_STICKY=no
185
+ elif [[ "X$1" = X-s* ]]; then
186
+ G_STICKY=yes
187
+ elif [[ "X$1" = X-p* ]]; then
188
+ G_PRIORITY="$2"
189
+ G_TITLE="${G_TITLE:-Priority $2}"
190
+ OPTIONS="$OPTIONS $1"
191
+ shift
192
+ elif [[ "X$1" = X-v* ]]; then
193
+ G_PRIORITY="-2"
194
+ G_TITLE="${G_TITLE:-Very Low Priority}"
195
+ elif [[ "X$1" = X-m* ]]; then
196
+ G_PRIORITY="-1"
197
+ G_TITLE="${G_TITLE:-Moderate Priority}"
198
+ elif [[ "X$1" = X-n* ]]; then
199
+ G_PRIORITY="0"
200
+ G_TITLE="${G_TITLE:-Normal Priority}"
201
+ elif [[ "X$1" = X-h* ]]; then
202
+ G_PRIORITY="1"
203
+ G_TITLE="${G_TITLE:-High Priority}"
204
+ elif [[ "X$1" = X-e* ]]; then
205
+ G_PRIORITY="2"
206
+ G_TITLE="${G_TITLE:-Emergency Priority}"
207
+ else
208
+ break;
209
+ fi
210
+ OPTIONS="$OPTIONS $1"
211
+ shift
212
+ done
213
+
214
+ #
215
+ # If any of the option variables have not been set yet, then apply the
216
+ # default values now.
217
+ #
218
+ defaults
219
+
220
+ UNAME=$(uname)
221
+ if [[ "$UNAME" = Darwin ]]; then
222
+ #
223
+ # I'm assuming this is one of my systems where I have Growl
224
+ # installed.
225
+ #
226
+ growl "$*"
227
+ elif [[ "$UNAME" = *Linux* || "$UNAME" = *Windows_NT* ]]; then
228
+ #
229
+ # Must be one of the development systems I work on, so lets ship
230
+ # this request to my Mac OS X workstation.
231
+ #
232
+ ssh ${G_REMOTE} ${G_REMOTE_GROWL} $OPTIONS "$*"
233
+ else
234
+ #
235
+ # I don't know what this is, so I'll just try to Growl anyway. It
236
+ # will most likely fail (no osascript would be my guess), but what
237
+ # do I have to loose at this point!
238
+ #
239
+ growl "$*"
240
+ fi
241
+ #}