1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
// This file is part of BOINC. |
4
|
|
|
// http://boinc.berkeley.edu |
5
|
|
|
// Copyright (C) 2011 University of California |
6
|
|
|
// |
7
|
|
|
// BOINC is free software; you can redistribute it and/or modify it |
8
|
|
|
// under the terms of the GNU Lesser General Public License |
9
|
|
|
// as published by the Free Software Foundation, |
10
|
|
|
// either version 3 of the License, or (at your option) any later version. |
11
|
|
|
// |
12
|
|
|
// BOINC is distributed in the hope that it will be useful, |
13
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
14
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
15
|
|
|
// See the GNU Lesser General Public License for more details. |
16
|
|
|
// |
17
|
|
|
// You should have received a copy of the GNU Lesser General Public License |
18
|
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>. |
19
|
|
|
|
20
|
|
|
// example of a web interface to remote job submission |
21
|
|
|
// |
22
|
|
|
// Although the architecture is intended to support remote portals, |
23
|
|
|
// this example must run on the BOINC project server. |
24
|
|
|
// In particular: |
25
|
|
|
// - It assumes cookie-based authentication, |
26
|
|
|
// as is done by the BOINC code. |
27
|
|
|
// You'll need to adapt/extend this considerably to run this |
28
|
|
|
// on a server other than the BOINC project server. |
29
|
|
|
// - It uses some functions from BOINC (page_head() etc.). |
30
|
|
|
// When you adapt this to your own purposes, |
31
|
|
|
// you can strip out this stuff if the web site doesn't use BOINC |
32
|
|
|
|
33
|
|
|
// THIS IS PRETTY MUCH USELESS |
34
|
|
|
|
35
|
|
|
require_once("../inc/submit.inc"); |
36
|
|
|
require_once("../inc/common_defs.inc"); |
37
|
|
|
require_once("../inc/submit_db.inc"); |
38
|
|
|
require_once("../inc/submit_util.inc"); |
39
|
|
|
// needed for access control stuff |
40
|
|
|
require_once("../inc/util.inc"); |
41
|
|
|
require_once("../project/project.inc"); |
42
|
|
|
|
43
|
|
|
display_errors(); |
44
|
|
|
|
45
|
|
|
// hardwired app name for now |
46
|
|
|
define('APP_NAME', 'remote_test'); |
47
|
|
|
|
48
|
|
|
$project = master_url(); |
49
|
|
|
$user = get_logged_in_user(); |
|
|
|
|
50
|
|
|
$auth = $user->authenticator; |
51
|
|
|
|
52
|
|
|
// the job submission "home page": |
53
|
|
|
// show the user's in-progress and completed batches, |
54
|
|
|
// and a button for creating a new batch |
55
|
|
|
// |
56
|
|
|
function handle_main() { |
57
|
|
|
global $project, $auth; |
58
|
|
|
$req = new StdClass; |
59
|
|
|
$req->project = $project; |
60
|
|
|
$req->authenticator = $auth; |
61
|
|
|
list($batches, $errmsg) = boinc_query_batches($req); |
62
|
|
|
if ($errmsg) error_page(htmlentities($errmsg)); |
63
|
|
|
|
64
|
|
|
page_head("Job submission and control"); |
65
|
|
|
|
66
|
|
|
echo " |
67
|
|
|
This is an example of a web interface |
68
|
|
|
for remote submission of BOINC jobs. |
69
|
|
|
It lets you |
70
|
|
|
<ul> |
71
|
|
|
<li> Upload files |
72
|
|
|
<li> submit batches of jobs, |
73
|
|
|
<li> see the status of in-progress and completed batches. |
74
|
|
|
</ul> |
75
|
|
|
<p> |
76
|
|
|
To use this, you must be logged in as a user |
77
|
|
|
with permission to submit jobs. |
78
|
|
|
<p> |
79
|
|
|
"; |
80
|
|
|
show_button("submit_example.php?action=create_form", "Create new batch"); |
81
|
|
|
|
82
|
|
|
$first = true; |
83
|
|
|
foreach ($batches as $batch) { |
84
|
|
|
if ($batch->state != BATCH_STATE_IN_PROGRESS) continue; |
85
|
|
|
if ($first) { |
86
|
|
|
$first = false; |
87
|
|
|
echo "<h2>Batches in progress</h2>\n"; |
88
|
|
|
start_table(); |
89
|
|
|
table_header("name", "ID", "app", "# jobs", "progress", "submitted"); |
90
|
|
|
} |
91
|
|
|
$pct_done = (int)($batch->fraction_done*100); |
92
|
|
|
table_row( |
93
|
|
|
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>", |
94
|
|
|
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>", |
95
|
|
|
$batch->app_name, |
96
|
|
|
$batch->njobs, |
97
|
|
|
"$pct_done%", |
98
|
|
|
local_time_str($batch->create_time) |
99
|
|
|
); |
100
|
|
|
} |
101
|
|
|
if ($first) { |
102
|
|
|
echo "<p>You have no in-progress batches.\n"; |
103
|
|
|
} else { |
104
|
|
|
end_table(); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
$first = true; |
108
|
|
|
foreach ($batches as $batch) { |
109
|
|
|
if ($batch->state != BATCH_STATE_COMPLETE) continue; |
110
|
|
|
if ($first) { |
111
|
|
|
$first = false; |
112
|
|
|
echo "<h2>Completed batches</h2>\n"; |
113
|
|
|
start_table(); |
114
|
|
|
table_header("name", "ID", "# jobs", "submitted"); |
115
|
|
|
} |
116
|
|
|
table_row( |
117
|
|
|
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>", |
118
|
|
|
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>", |
119
|
|
|
$batch->njobs, |
120
|
|
|
local_time_str($batch->create_time) |
121
|
|
|
); |
122
|
|
|
} |
123
|
|
|
if ($first) { |
124
|
|
|
echo "<p>You have no completed batches.\n"; |
125
|
|
|
} else { |
126
|
|
|
end_table(); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
$first = true; |
130
|
|
|
foreach ($batches as $batch) { |
131
|
|
|
if ($batch->state != BATCH_STATE_ABORTED) continue; |
132
|
|
|
if ($first) { |
133
|
|
|
$first = false; |
134
|
|
|
echo "<h2>Aborted batches</h2>\n"; |
135
|
|
|
start_table(); |
136
|
|
|
table_header("name", "ID", "# jobs", "submitted"); |
137
|
|
|
} |
138
|
|
|
table_row( |
139
|
|
|
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->name</a>", |
140
|
|
|
"<a href=submit_example.php?action=query_batch&batch_id=$batch->id>$batch->id</a>", |
141
|
|
|
$batch->njobs, |
142
|
|
|
local_time_str($batch->create_time) |
143
|
|
|
); |
144
|
|
|
} |
145
|
|
|
if (!$first) { |
146
|
|
|
end_table(); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
150
|
|
|
page_tail(); |
151
|
|
|
} |
152
|
|
|
|
153
|
|
|
// return an array of the apps this user is allowed to submit jobs for |
154
|
|
|
// |
155
|
|
|
function eligible_apps() { |
156
|
|
|
global $user; |
157
|
|
|
$apps = BoincApp::enum("deprecated = 0"); |
158
|
|
|
$user_submit = BoincUserSubmit::lookup_userid($user->id); |
159
|
|
|
if (!$user_submit) return null; |
160
|
|
|
$a = array(); |
161
|
|
|
foreach($apps as $app) { |
162
|
|
|
if ($user_submit->submit_all) { |
163
|
|
|
$a[] = $app; |
164
|
|
|
} else { |
165
|
|
|
if (BoincUserSubmitApp::lookup("user_id=$user->id and app_id=$app->id")) { |
166
|
|
|
$a[] = $app; |
167
|
|
|
} |
168
|
|
|
} |
169
|
|
|
} |
170
|
|
|
return $a; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
// return HTML for a popup menu of apps |
174
|
|
|
// |
175
|
|
|
function app_select($apps) { |
176
|
|
|
$x = '<select class="form-control" name="app_name">\n'; |
177
|
|
|
foreach ($apps as $app) { |
178
|
|
|
$x .= "<option value=$app->name>$app->user_friendly_name</option>\n"; |
179
|
|
|
} |
180
|
|
|
$x .= "</select>\n"; |
181
|
|
|
return $x; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
// show a form for creating a batch. |
185
|
|
|
// |
186
|
|
|
function handle_create_form() { |
187
|
|
|
global $project, $auth; |
188
|
|
|
|
189
|
|
|
$apps = eligible_apps(); |
190
|
|
|
if (!$apps) error_page("You are not allowed to submit jobs"); |
191
|
|
|
page_head("Create batch"); |
192
|
|
|
echo " |
193
|
|
|
This form lets you specify a batch of jobs, |
194
|
|
|
and either submit it or get and estimate of its completion time. |
195
|
|
|
<p> |
196
|
|
|
The job runs an application that |
197
|
|
|
<ul> |
198
|
|
|
<li> Reads an input file, converts it to upper case, |
199
|
|
|
and writes this to an output file. |
200
|
|
|
You give a URL from which this file can be read. |
201
|
|
|
<li> Takes a command-line parameter, and uses that |
202
|
|
|
number of seconds of CPU time |
203
|
|
|
You can specify a range of values for the parameter; |
204
|
|
|
this determines the number of jobs in the batch. |
205
|
|
|
</ul> |
206
|
|
|
|
207
|
|
|
<p> |
208
|
|
|
<form action=submit_example.php> |
209
|
|
|
<input type=hidden name=action value=create_action> |
210
|
|
|
"; |
211
|
|
|
start_table(); |
212
|
|
|
row2("Batch name", "<input name=batch_name value=\"enter name\">"); |
213
|
|
|
// row2("Application", app_select($apps)); |
214
|
|
|
row2("Input file URL", "<input name=input_url size=60 value=\"https://google.com/\">"); |
215
|
|
|
row2("Parameter low value (0..60)", "<input name=param_lo value=10>"); |
216
|
|
|
row2("Parameter high value (0..60)", "<input name=param_hi value=20>"); |
217
|
|
|
row2("Parameter increment (>= 1)", "<input name=param_inc value=1>"); |
218
|
|
|
row2("", |
219
|
|
|
"<input class=\"btn btn-default\" type=submit name=get_estimate value=\"Get completion time estimate\">" |
220
|
|
|
); |
221
|
|
|
row2("", |
222
|
|
|
"<input class=\"btn btn-primary\" type=submit name=submit value=Submit>" |
223
|
|
|
); |
224
|
|
|
end_table(); |
225
|
|
|
echo "</form>\n"; |
226
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
227
|
|
|
page_tail(); |
228
|
|
|
} |
229
|
|
|
|
230
|
|
|
// build a request object for boinc_*_batch() from form variables |
231
|
|
|
// |
232
|
|
|
function form_to_request() { |
233
|
|
|
global $project, $auth; |
234
|
|
|
|
235
|
|
|
$input_url = get_str('input_url'); |
236
|
|
|
if (!$input_url) error_page("missing input URL"); |
237
|
|
|
$param_lo = (double)get_str('param_lo'); |
238
|
|
|
if ($param_lo<0 || $param_lo>60) error_page("param lo must be in 0..60"); |
239
|
|
|
$param_hi = (double)get_str('param_hi'); |
240
|
|
|
if ($param_hi<0 || $param_hi>60 || $param_hi <= $param_lo) { |
241
|
|
|
error_page("param hi must be in 0..60 and > param lo"); |
242
|
|
|
} |
243
|
|
|
$param_inc = (double)get_str('param_inc'); |
244
|
|
|
if ($param_inc < 1) error_page("param inc must be >= 1"); |
245
|
|
|
|
246
|
|
|
$req = new StdClass; |
247
|
|
|
$req->project = $project; |
248
|
|
|
$req->authenticator = $auth; |
249
|
|
|
$req->app_name = APP_NAME; |
250
|
|
|
$req->batch_name = get_str('batch_name'); |
251
|
|
|
$req->jobs = array(); |
252
|
|
|
|
253
|
|
|
$f = new StdClass; |
254
|
|
|
$f->source = $input_url; |
255
|
|
|
$f->mode = 'semilocal'; |
256
|
|
|
|
257
|
|
|
for ($x=$param_lo; $x<$param_hi; $x += $param_inc) { |
258
|
|
|
$job = new StdClass; |
259
|
|
|
$job->rsc_fpops_est = $x*1e9; |
260
|
|
|
$job->command_line = "--t $x"; |
261
|
|
|
$job->input_files = array($f); |
262
|
|
|
$req->jobs[] = $job; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
return $req; |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
// create and submit a batch |
269
|
|
|
// |
270
|
|
|
function handle_create_action() { |
271
|
|
|
global $project, $auth; |
272
|
|
|
|
273
|
|
|
$get_estimate = get_str('get_estimate', true); |
274
|
|
|
if ($get_estimate) { |
275
|
|
|
$req = form_to_request($project, $auth); |
|
|
|
|
276
|
|
|
list($e, $errmsg) = boinc_estimate_batch($req); |
277
|
|
|
if ($errmsg) error_page(htmlentities($errmsg)); |
278
|
|
|
page_head("Batch estimate"); |
279
|
|
|
echo sprintf("Estimate: %.0f seconds", $e); |
280
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
281
|
|
|
page_tail(); |
282
|
|
|
} else { |
283
|
|
|
$req = form_to_request($project, $auth); |
284
|
|
|
list($id, $errmsg) = boinc_submit_batch($req); |
285
|
|
|
if ($errmsg) error_page(htmlentities($errmsg)); |
286
|
|
|
page_head("Batch submitted"); |
287
|
|
|
echo "Batch created, ID: $id\n"; |
288
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
289
|
|
|
page_tail(); |
290
|
|
|
} |
291
|
|
|
} |
292
|
|
|
|
293
|
|
|
// show the details of an existing batch |
294
|
|
|
// |
295
|
|
|
function handle_query_batch() { |
296
|
|
|
global $project, $auth; |
297
|
|
|
$req = (object)array( |
298
|
|
|
'project' => $project, |
299
|
|
|
'authenticator' => $auth, |
300
|
|
|
'batch_id' => get_int('batch_id'), |
301
|
|
|
); |
302
|
|
|
list($batch, $errmsg) = boinc_query_batch($req); |
303
|
|
|
if ($errmsg) error_page(htmlentities($errmsg)); |
304
|
|
|
|
305
|
|
|
page_head("Batch $req->batch_id"); |
306
|
|
|
start_table(); |
307
|
|
|
row2("name", $batch->name); |
308
|
|
|
row2("application", $batch->app_name); |
309
|
|
|
row2("state", batch_state_string($batch->state)); |
310
|
|
|
row2("# jobs", $batch->njobs); |
311
|
|
|
row2("# error jobs", $batch->nerror_jobs); |
312
|
|
|
row2("progress", sprintf("%.0f%%", $batch->fraction_done*100)); |
313
|
|
|
if ($batch->completion_time) { |
314
|
|
|
row2("completed", local_time_str($batch->completion_time)); |
315
|
|
|
} |
316
|
|
|
row2("GFLOP/hours, estimated", number_format(credit_to_gflop_hours($batch->credit_estimate), 2)); |
317
|
|
|
row2("GFLOP/hours, actual", number_format(credit_to_gflop_hours($batch->credit_canonical), 2)); |
318
|
|
|
end_table(); |
319
|
|
|
echo "<p>"; |
320
|
|
|
$url = boinc_get_output_files($req); |
321
|
|
|
show_button($url, "Get zipped output files"); |
322
|
|
|
echo "<p>"; |
323
|
|
|
switch ($batch->state) { |
324
|
|
|
case BATCH_STATE_IN_PROGRESS: |
325
|
|
|
show_button( |
326
|
|
|
"submit_example.php?action=abort_batch_confirm&batch_id=$req->batch_id", |
327
|
|
|
"Abort batch" |
328
|
|
|
); |
329
|
|
|
break; |
330
|
|
|
case BATCH_STATE_COMPLETE: |
331
|
|
|
case BATCH_STATE_ABORTED: |
332
|
|
|
show_button( |
333
|
|
|
"submit_example.php?action=retire_batch_confirm&batch_id=$req->batch_id", |
334
|
|
|
"Retire batch" |
335
|
|
|
); |
336
|
|
|
break; |
337
|
|
|
} |
338
|
|
|
|
339
|
|
|
echo "<h2>Jobs</h2>\n"; |
340
|
|
|
start_table(); |
341
|
|
|
table_header( |
342
|
|
|
"Job ID<br><p class=\"text-muted\">click for details or to get output files</p>", |
343
|
|
|
"status", |
344
|
|
|
"Canonical instance<br><p class=\"text-muted\">click to see result page on BOINC server</p>" |
345
|
|
|
); |
346
|
|
|
foreach($batch->jobs as $job) { |
347
|
|
|
$id = (int)$job->id; |
348
|
|
|
$resultid = (int)$job->canonical_instance_id; |
349
|
|
|
if ($resultid) { |
350
|
|
|
$x = "<a href=result.php?resultid=$resultid>$resultid</a>"; |
351
|
|
|
$y = "completed"; |
352
|
|
|
} else { |
353
|
|
|
$x = "---"; |
354
|
|
|
$y = "in progress"; |
355
|
|
|
} |
356
|
|
|
|
357
|
|
|
echo "<tr> |
358
|
|
|
<td><a href=submit_example.php?action=query_job&job_id=$id>$id</a></td> |
359
|
|
|
<td>$y</td> |
360
|
|
|
<td>$x</td> |
361
|
|
|
</tr> |
362
|
|
|
"; |
363
|
|
|
} |
364
|
|
|
end_table(); |
365
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
366
|
|
|
page_tail(); |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
// show the details of a job, including links to see the output files |
370
|
|
|
// |
371
|
|
|
function handle_query_job() { |
372
|
|
|
global $project, $auth; |
373
|
|
|
$req = new StdClass; |
374
|
|
|
$req->project = $project; |
375
|
|
|
$req->authenticator = $auth; |
376
|
|
|
$req->job_id = get_int('job_id'); |
377
|
|
|
|
378
|
|
|
list($reply, $errmsg) = boinc_query_job($req); |
379
|
|
|
if ($errmsg) error_page(htmlentities($errmsg)); |
380
|
|
|
|
381
|
|
|
page_head("Job $req->job_id"); |
382
|
|
|
echo "<a href=$project/workunit.php?wuid=$req->job_id>View workunit page on BOINC server</a>\n"; |
383
|
|
|
echo "<h2>Instances</h2>\n"; |
384
|
|
|
start_table(); |
385
|
|
|
table_header( |
386
|
|
|
"Instance ID<br><p class=\"text-muted\">click for result page on BOINC server</p>", |
387
|
|
|
"State", "Output files" |
388
|
|
|
); |
389
|
|
|
foreach($reply->instances as $inst) { |
390
|
|
|
echo "<tr> |
391
|
|
|
<td><a href=result.php?resultid=$inst->id>$inst->id</a></td> |
392
|
|
|
<td>$inst->state</td> |
393
|
|
|
<td> |
394
|
|
|
"; |
395
|
|
|
$i = 0; |
396
|
|
|
foreach ($inst->outfiles as $outfile) { |
397
|
|
|
$req->instance_name = $inst->name; |
398
|
|
|
$req->file_num = $i; |
399
|
|
|
$url = boinc_get_output_file($req); |
400
|
|
|
echo "<a href=$url>$outfile->size bytes</a>"; |
401
|
|
|
$i++; |
402
|
|
|
} |
403
|
|
|
echo "</td></tr>\n"; |
404
|
|
|
} |
405
|
|
|
end_table(); |
406
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
407
|
|
|
page_tail(); |
408
|
|
|
} |
409
|
|
|
|
410
|
|
|
function handle_abort_batch_confirm() { |
411
|
|
|
$batch_id = get_int('batch_id'); |
412
|
|
|
page_head("Confirm abort batch"); |
413
|
|
|
echo " |
414
|
|
|
Aborting a batch will cancel all unstarted jobs. |
415
|
|
|
Are you sure you want to do this? |
416
|
|
|
<p> |
417
|
|
|
"; |
418
|
|
|
show_button( |
419
|
|
|
"submit_example.php?action=abort_batch&batch_id=$batch_id", |
420
|
|
|
"Yes - abort batch" |
421
|
|
|
); |
422
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
423
|
|
|
page_tail(); |
424
|
|
|
} |
425
|
|
|
|
426
|
|
|
function handle_abort_batch() { |
427
|
|
|
global $project, $auth; |
428
|
|
|
$req->project = $project; |
|
|
|
|
429
|
|
|
$req->authenticator = $auth; |
430
|
|
|
$req->batch_id = get_int('batch_id'); |
431
|
|
|
$errmsg = boinc_abort_batch($req); |
432
|
|
|
if ($errmsg) error_page(htmlentities($errmsg)); |
433
|
|
|
page_head("Batch aborted"); |
434
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
435
|
|
|
page_tail(); |
436
|
|
|
} |
437
|
|
|
|
438
|
|
|
function handle_retire_batch_confirm() { |
439
|
|
|
$batch_id = get_int('batch_id'); |
440
|
|
|
page_head("Confirm retire batch"); |
441
|
|
|
echo " |
442
|
|
|
Retiring a batch will remove all of its output files. |
443
|
|
|
Are you sure you want to do this? |
444
|
|
|
<p> |
445
|
|
|
"; |
446
|
|
|
show_button( |
447
|
|
|
"submit_example.php?action=retire_batch&batch_id=$batch_id", |
448
|
|
|
"Yes - retire batch" |
449
|
|
|
); |
450
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
451
|
|
|
page_tail(); |
452
|
|
|
} |
453
|
|
|
|
454
|
|
|
function handle_retire_batch() { |
455
|
|
|
global $project, $auth; |
456
|
|
|
$req->project = $project; |
|
|
|
|
457
|
|
|
$req->authenticator = $auth; |
458
|
|
|
$req->batch_id = get_int('batch_id'); |
459
|
|
|
$errmsg = boinc_retire_batch($req); |
460
|
|
|
if ($errmsg) error_page(htmlentities($errmsg)); |
461
|
|
|
page_head("Batch retired"); |
462
|
|
|
echo "<p><a href=submit_example.php>Return to job control page</a>\n"; |
463
|
|
|
page_tail(); |
464
|
|
|
} |
465
|
|
|
|
466
|
|
|
$action = get_str('action', true); |
467
|
|
|
switch ($action) { |
468
|
|
|
case '': handle_main(); break; |
469
|
|
|
case 'abort_batch': handle_abort_batch(); break; |
|
|
|
|
470
|
|
|
case 'abort_batch_confirm': handle_abort_batch_confirm(); break; |
471
|
|
|
case 'create_action': handle_create_action(); break; |
472
|
|
|
case 'create_form': handle_create_form(); break; |
473
|
|
|
case 'query_batch': handle_query_batch(); break; |
|
|
|
|
474
|
|
|
case 'query_job': handle_query_job(); break; |
|
|
|
|
475
|
|
|
case 'retire_batch': handle_retire_batch(); break; |
|
|
|
|
476
|
|
|
case 'retire_batch_confirm': handle_retire_batch_confirm(); break; |
477
|
|
|
default: |
|
|
|
|
478
|
|
|
error_page('no such action'); |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
?> |
482
|
|
|
|
This check looks for function or method calls that always return null and whose return value is assigned to a variable.
The method
getObject()
can return nothing but null, so it makes no sense to assign that value to a variable.The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.