rename nodes to slivers
[raven.git] / apps / gacksadmin / gacks_functions.php
1 <?php
2
3 require_once 'form.php';
4
5 define(INFINITY, 2147483647);
6
7 define(STATE_PENDING, 0);
8 define(STATE_APPLY, 1);
9 define(STATE_APPLIED, 2);
10 define(STATE_INVOICED, 3);
11
12 define(KIND_CYCLE_CHARGE, 0);
13 define(KIND_SLOT_CHARGE, 1);
14 define(KIND_CYCLE_AGGREGATE, 2);
15 define(KIND_INVOICE, 10);
16 define(KIND_INVOICE_BEST_EFFORT, 11);
17 define(KIND_INVOICE_RESV, 12);
18 define(KIND_ADJUSTMENT, 20);
19 define(KIND_PAYMENT, 30);
20
21 function l_gacks_accounts ()       { return "/db/gacks/accounts.php"; }
22 function l_gacks_add_account ()    { return "/db/gacks/add_account.php"; }
23 function l_gacks_actions ()        { return "/db/gacks/action.php"; }
24 function l_gacks_account ($acctname, $acctkind)    { return "/db/gacks/account.php?account_name=$acctname&account_kind=$acctkind"; }
25 function l_gacks_reservations ()   { return "/db/gacks/reservations.php"; }
26 function l_gacks_reservation_set ()    { return "/db/gacks/reservation_set.php"; }
27 function l_gacks_invoice($name, $token, $state, $start_date, $end_date, $parent) { return "/db/gacks/invoices.php?account_name=$name&account_token=$token&state=$state&start_date=$start_date&end_date=$end_date&parent_id=$parent"; }
28 function l_gacks_all_invoices ()   { return l_gacks_invoice(NULL, NULL, STATE_INVOICED, time() - 30*24*60*60, NULL, NULL); }
29 function l_gacks_weekly ($y=NULL, $m=NULL, $d=NULL)         { return "/db/gacks/weekly.php?invoiceyear=$y&invoicemonth=$m&invoiceday=$d"; }
30 function l_gacks_node_status ()    { return "/db/gacks/nodestatus.php"; }
31 function l_gacks_wizard ()         { return "/db/gacks/wizard.php"; }
32 function l_gacks_nodelist ()         { return "/db/gacks/user_nodelist.php"; }
33 function l_gacks_nodelist_download ($acctname) { return "/db/gacks/action.php?action=download-nodelist&account_name=$acctname&format=CSV"; }
34 function l_gacks_image ()         { return "/db/gacks/user_image.php"; }
35 function l_gacks_user_reservations() { return "/db/gacks/user_reservations.php"; }
36 function l_gacks_edit($item)       { return "/db/gacks/edit.php"; }
37 function l_gacks_delete($item)     { $timeStart=$item['timeStart']; $timeStop=$item['timeStop']; $id=$item['id']; $lastAllocator=end($item['allocatorHRNs']); return "/db/gacks/action.php?action=delete-reservation&timeStart=$timeStart&timeStop=$timeStop&resource_id=$id&lastAllocator=$lastAllocator"; }
38 function l_gacks_service_level()   { return "/db/gacks/user_service_level.php"; }
39 function l_gacks_confirm_service($acct, $level, $autoRenew, $enableBestEffort) { return "/db/gacks/user_confirm_service.php?account_name=$acct&level=$level&autoRenew=$autoRenew&enableBestEffort=$enableBestEffort"; }
40 function l_gacks_add_reservation() { return "/db/gacks/user_add_reservation.php"; }
41 function l_gacks_persons()         { return "/db/gacks/user_persons.php"; }
42 function l_gacks_advanced($value, $url)        { $eurl=urlencode($url); return "/db/gacks/action.php?action=set-advanced&value=$value&url=$eurl"; }
43 function l_gacks_summary()         { return "/db/gacks/user_summary.php"; }
44
45 function gacksid($x) { return "gacksid:" . $x; }
46
47 function gackshrn($x) { return "hrn:" . $x; }
48
49 function slice_to_hrn($slice)
50 {
51    $slice = str_replace("_", ".", $slice);
52    $hrn = "plc.vicci." . $slice;
53    return $hrn;
54 }
55
56 function is_time_unimportant($x)
57 {
58     if (($x==KIND_CYCLE_CHARGE) || ($x==KIND_SLOT_CHARGE)) {
59         return FALSE;
60     } else {
61         return TRUE;
62     }
63 }
64
65 function gacks_config()
66 {
67     return parse_ini_file("/etc/gacks/gacks.conf", true);     // see also in gacksclient.php
68 }
69
70 function handle_as_string($handle)
71 {
72     $id = $handle['id'];
73     $unitStart = $handle['unitStart'];
74     $unitStop = $handle['unitStop'];
75     $timeStart = $handle['timeStart'];
76     $timeStop = $handle['timeStop'];
77
78     return "$id#$unitStart-$unitStop#$timeStart-$timeStop";
79 }
80
81 function verify_account_token($account_name, $account_token) {
82     //$handle = fopen("/root/gacks_account_secret.txt", "r");
83     //$secret = fgets($handle, 4096);
84     //fclose($handle);
85
86     $config = gacks_config();
87     $secret = $config['gacks']['account_secret'];
88
89     $secret = trim($secret);
90     $token = sha1($secret . $account_name);
91     $token = substr($token, 0, 8);
92
93     //print $secret . " " . $token . " " . $account_name . " " . $account_token;
94
95     return ($token == $account_token);
96 }
97
98 function gacksid_guess_prefix($x) {
99     if ((strpos($x, ".") !== false) and (strpos($x, "_") == false)) {
100         return "hrn:" . $x;
101     } else if ((strpos($x, ".") == false) and (strpos($x, "_") == true)) {
102         return "slice:" . $x;
103     } else {
104         // XXX this doesn't display an error to the user
105         throw new Exception("unable to guess whether name is a slice or hrn");
106     }
107 }
108
109 function level_selectors($value)
110 {
111     $level_selectors = array();
112     $level_selectors []= array("display"=>"Default", "value"=>"default");
113     $level_selectors []= array("display"=>"Silver", "value"=>"silver");
114     $level_selectors []= array("display"=>"Gold", "value"=>"gold");
115
116     foreach ($level_selectors as &$sel) {
117         if ($sel["value"] == $value) {
118             $sel["selected"] = True;
119         }
120     }
121
122     return $level_selectors;
123 }
124
125 function charge_kind_selectors($value)
126 {
127     $kind_selectors = array();
128     $kind_selectors []= array("display"=>"Cycle Charge", "value"=>"0");
129     $kind_selectors []= array("display"=>"Slot Charge", "value"=>"1");
130     $kind_selectors []= array("display"=>"Invoice Charge", "value"=>"10");
131     $kind_selectors []= array("display"=>"Adjustment", "value"=>"20");
132     $kind_selectors []= array("display"=>"Payment", "value"=>"30");
133
134     foreach ($kind_selectors as &$sel) {
135         if ($sel["value"] == $value) {
136             $sel["selected"] = True;
137         }
138     }
139
140     return $kind_selectors;
141 }
142
143 function bool_text($value, $true, $false)
144 {
145     if ($value) {
146         return $true;
147     } else {
148         return $false;
149     }
150 }
151
152 function bool_selectors($value)
153 {
154     if ($value) {
155         $value = 1;
156     } else {
157         $value = 0;
158     }
159
160     $bool_selectors = array();
161     $bool_selectors []= array("display"=>"Yes", "value"=>"1");
162     $bool_selectors []= array("display"=>"No", "value"=>"0");
163
164     foreach ($bool_selectors as &$sel) {
165         if ($sel["value"] == $value) {
166             $sel["selected"] = True;
167         }
168     }
169
170     return $bool_selectors;
171 }
172
173 function aggregate_records($records)
174 {
175    $aggs = array();
176
177    foreach ($records as $rec) {
178        $rec['key'] = $rec['id'] + '#' + $rec['timeStart'] + "-" + $rec['timeStop'] + ":" + implode(",", $rec['allocatorHRNs']) + ">" + $rec['consumerHRN'];
179        $rec['qty'] = $rec['unitStop'] - $rec['unitStart'];
180
181        $found = False;
182        foreach ($aggs as &$agg) {
183            if ($agg['key'] == $rec['key']) {
184                $agg['qty'] = $agg['qty'] + $rec['qty'];
185                $found = True;
186            }
187        }
188        if (!$found) {
189            $aggs []= $rec;
190        }
191    }
192
193    return $aggs;
194 }
195
196 function record_table($records, $timezone_seconds)
197 {
198     $headers=array();
199     $headers["id"] = "string";
200     $headers["start"] = "string";
201     $headers["stop"] = "string";
202     $headers["lastAllocator"] = "string";
203     $headers["consumer"] = "string";
204     $headers["qty"] = "int";
205     $headers["actions"] = "string";
206
207     $sort_column = 1;
208     $table = new PlekitTable("reservations", $headers, $sort_column);
209     $table->start();
210
211     $aggs = aggregate_records($records);
212
213     foreach ( $aggs as $item ) {
214             $table->row_start();
215             $table->cell($item['id']);
216             $table->cell(strftime("%Y-%m-%d %H:%M:%S", $item['timeStart']+$timezone_seconds));
217             $table->cell(strftime("%Y-%m-%d %H:%M:%S", $item['timeStop']+$timezone_seconds));
218             $table->cell(end($item['allocatorHRNs']));
219             $table->cell($item['consumerHRN']);
220             $table->cell($item['qty']);
221             $table->cell(href(l_gacks_delete($item), "delete")); // href(l_gacks_edit($item), "edit") . " "
222             $table->row_end();
223     }
224
225     $table->end();
226 }
227
228 function charge_detail($charge)
229 {
230     $details = new PlekitDetails(False);
231
232     $details->start();
233
234     $details->form_start(l_gacks_actions(), array());
235
236     $details->th_td("id", $charge["id"]);
237     $details->th_td("object/desc", $charge["object_desc"]);
238     $details->th_td("kind", $charge["kind_id"]);
239     $details->th_td("date", $charge["date"]);
240     $details->th_td("amount", $charge["amount"]);
241     $details->th_td("state", $charge["state"]);
242     $details->th_td("parent_id", $charge["parent_id"]);
243     $details->th_td("account_name", $charge["account_name"]);
244
245     $details->end();
246     $details->form_end();
247 }
248
249 function dollars($amount)
250 {
251     return "$ " . number_format($amount, 2);
252 }
253
254 function invoice_table($invoice, $account_name, $account_token, $options)
255 {
256     $invoice_kind = array();
257     $invoice_kind[KIND_CYCLE_CHARGE] = "best effort";
258     $invoice_kind[KIND_SLOT_CHARGE] = "reservation";
259     $invoice_kind[KIND_CYCLE_AGGREGATE] = "best effort";
260     $invoice_kind[KIND_INVOICE] = "daily invoice";
261     $invoice_kind[KIND_INVOICE_BEST_EFFORT] = "daily invoice";
262     $invoice_kind[KIND_INVOICE_RESV] = "daily invoice";
263     $invoice_kind[KIND_ADJUSTMENT] = "adjustment";
264     $invoice_kind[KIND_PAYMENT] = "payment";
265
266     $headers=array();
267     $headers["id"] = "string";
268     $headers["account_name"] = "string";
269     $headers["date"] = "string";
270     $headers["kind"] = "string";
271     $headers["description"] = "string";
272     $headers["amount"] = "int";
273
274     // ideally it would be nice if we could sort by 3 columns,
275     //    account_name, date, description
276     if ($account_name) {
277         $sort_column = 2; // date
278     } else {
279         $sort_column = 1; // account name
280     }
281
282     $table = new PlekitTable("invoices", $headers, $sort_column);
283     $table->start();
284
285     $charges = $invoice['charges'];
286
287     foreach ( $charges as $item ) {
288             //if ($options['date_only']) {
289             if (is_time_unimportant($item['kind_id'])) {
290                 $date = explode(' ', $item['date']);
291                 $date = $date[0];
292             } else {
293                 $date = $item['date'];
294             }
295             $table->row_start();
296             $table->cell(href(l_gacks_invoice($account_name, $account_token, NULL, NULL, NULL, $item['id']), $item['id']));
297             $table->cell($item['account_name']);
298             $table->cell($date);
299             $table->cell($invoice_kind[$item['kind_id']]);
300             $table->cell($item['object_desc']);
301             $table->cell(dollars($item['amount']), array("align"=>"right"));
302             $table->row_end();
303     }
304
305     $table->end();
306 }
307
308 # from http://cool-php-tutorials.blogspot.com/2010/02/easy-php-date-picker.html
309 function date_picker($name, $y, $m, $d)
310 {
311     $startyear = 2012;
312     $endyear = date("Y");
313
314     $months=array('','January','February','March','April','May',
315     'June','July','August', 'September','October','November','December');
316
317     // Month dropdown
318     $html="<select name=\"".$name."month\">";
319
320     for($i=1;$i<=12;$i++)
321     {
322        $html.="<option value='$i'";
323        if ($i==$m) {
324            $html.=" selected=true";
325        }
326        $html.=">$months[$i]</option>";
327     }
328     $html.="</select> ";
329
330     // Day dropdown
331     $html.="<select name=\"".$name."day\">";
332     for($i=1;$i<=31;$i++)
333     {
334        $html.="<option value='$i'";
335        if ($i==$d) {
336            $html.=" selected=true";
337        }
338        $html.=">$i</option>";
339     }
340     $html.="</select> ";
341
342     // Year dropdown
343     $html.="<select name=\"".$name."year\">";
344
345     for($i=$startyear;$i<=$endyear;$i++)
346     {
347       $html.="<option value='$i'";
348       if ($i==$y) {
349           $html.=" selected=true";
350       }
351       $html.=">$i</option>";
352     }
353     $html.="</select> ";
354
355     return $html;
356 }
357
358 function get_slices($plcapi, $person_id, $fields)
359 {
360     if (!in_array("name", $fields)) {
361         $fields []= "name";
362     }
363
364     $persons = $plcapi->GetPersons(array('person_id'=>$person_id),array('person_id','email','slice_ids','role_ids','site_ids'));
365     $person=$persons[0];
366     $slice_filter=array('slice_id' => $person['slice_ids']);
367     $user_slices=$plcapi->GetSlices($slice_filter,$fields);
368
369     $slices = array();
370     foreach ($user_slices as $slice) {
371         $slices[$slice['name']] = $slice;
372     }
373
374     $is_pi = in_array( 20, $person['role_ids']);
375     if ($is_pi) {
376         $slice_filter=array('site_id'=>$person['site_ids'][0]);
377         $pi_slices = $plcapi->GetSlices($slice_filter, $fields);
378
379         foreach ($pi_slices as $slice) {
380             if (!array_key_exists($slice['name'], $slices)) {
381                 $slices[$slice['name']] = $slice;
382             }
383         }
384     }
385
386     return $slices;
387 }
388
389 function get_account_names($plcapi, $person_id)
390 {
391     $slices = get_slices($plcapi, $person_id, array("name"));
392     $slicenames = array();
393     foreach ($slices as $name => $slice) {
394         $slicenames []= $name;
395     }
396
397     return $slicenames;
398 }
399
400 function account_selectors($plcapi, $person_id, $account_name)
401 {
402     $slicenames = get_account_names($plcapi, $person_id);
403
404     $selectors = array();
405     foreach ($slicenames as $slicename) {
406         if ($slicename == $account_name) {
407             $selectors []= array("display"=>$slicename, "value"=>$slicename, "selected"=>True);
408         } else {
409             $selectors []= array("display"=>$slicename, "value"=>$slicename);
410         }
411     }
412
413     return $selectors;
414 }
415
416 function &find_selector($needle, &$selectors)
417 {
418     foreach ($selectors as &$selector) {
419         if ($selector['value']==$needle) {
420             return $selector;
421         }
422     }
423     return NULL;
424 }
425
426 function select_selector($needle, &$selectors)
427 {
428     $selector = &find_selector($needle, $selectors);
429     if ($selector) {
430         $selector["selected"] = True;
431     }
432 }
433
434 function get_gacks_session()
435 {
436     if (!array_key_exists("gacks", $_SESSION)) {
437         return array("account_name" => NULL);
438     }
439     return $_SESSION['gacks'];
440 }
441
442 function update_gacks_session($updated_session)
443 {
444     $session = get_gacks_session();
445
446     foreach ($updated_session as $key => $value) {
447         $session[$key] = $value;
448     }
449
450     $_SESSION['gacks'] = $session;
451 }
452
453 function get_account_name($api, $_person_id, $form=NULL, $url=NULL)
454 {
455     $session = get_gacks_session();
456     $account_name = $session['account_name'];
457
458 // this would be if we want to do it like how plc does loging...
459 //    if ($account_name == NULL) {
460 //        Header("Location: /db/gacks/set_account.php?url=" . urlencode($url));
461 //        exit();
462 //    }
463
464     drupal_add_js("misc/popup.js");
465
466     if ($form == NULL) {
467         $form = new PlekitForm(l_gacks_actions(), array("action"=>"set-account",
468                                                         "url"=>$_SERVER['REQUEST_URI']));
469         $form->start();
470         $needFormEnd = TRUE;
471     } else {
472         $needFormEnd = FALSE;
473     }
474
475     $selectors = account_selectors($api, $_person_id, $account_name);
476
477     if (($account_name != NULL) && (!find_selector($account_name, $selectors))) {
478         $account_name = NULL;
479     }
480
481     if ($account_name == NULL) {
482         print "Slice name:<br>";
483         print $form->select_html("account_name", $selectors);
484         print $form->submit_html("submit", "submit");
485     } else {
486         print "Slice name:<br>";
487         if ($url != NULL) {
488             $onChange = "PopupMessage(); this.form.action=\"$url\"; this.form.submit();";
489         } else {
490             $onChange = "PopupMessage(); this.form.submit();";
491         }
492         print $form->select_html("account_name", $selectors, array("onChange"=> $onChange));
493     }
494
495     if ($needFormEnd) {
496         $form->end();
497     }
498
499     return $account_name;
500 }
501
502 // This makes a combobox that when it is changed, it will pop up a "Please Wait"
503 // message and refresh the page.
504 //
505 // &$value is passed by reference, so that it will automatically be set to the
506 // first item in the combobox if it is NULL.
507
508 function auto_refresh_combo($form, $name, $selectors, &$value, $url)
509 {
510     foreach ($selectors as &$sel) {
511         if ($sel["value"] == $value) {
512             $sel["selected"] = True;
513         } else {
514             $sel["selected"] = False;
515         }
516     }
517
518     if (($value!=NULL) && (!find_selector($value, $selectors))) {
519         $value = NULL;
520     }
521
522     if ($value==NULL) {
523         if (count($selectors)>=1) {
524             $value = $selectors[0]['value'];
525         }
526     }
527
528     $onChange = "PopupMessage(); this.form.action=\"$url\"; this.form.method=\"get\"; this.form.submit();";
529     return $form->select_html($name, $selectors, array("onChange"=> $onChange));
530 }
531
532 // Combobox for Gacks account names. In addition to the features supported by
533 // auto_refresh_combo, it automatically populates the selectors with the slices
534 // that the user has access to, and gets and sets the account_name in the
535 // session variables.
536
537 function account_name_combo($api, $_person_id, $form, &$account_name, $url)
538 {
539     $session = get_gacks_session();
540     if ($account_name==NULL) {
541         $account_name = $session['account_name'];
542     } else {
543         // If a new $account_name was passed in, then update the session
544         // variable.
545         if ($account_name!=$session['account_name']) {
546              update_gacks_session(array("account_name" => $account_name));
547         }
548     }
549
550     $selectors = account_selectors($api, $_person_id, $account_name);
551
552     return auto_refresh_combo($form, "account_name", $selectors, $account_name, $url);
553 }
554
555 function timezone_combo($form, &$timezone, $url)
556 {
557     $session = get_gacks_session();
558     if ($timezone==NULL) {
559         $timezone = $session['timezone'];
560     } else {
561         // If a new $timezone was passed in, then update the session
562         // variable.
563         if ($timezone!=$session['timezone']) {
564              update_gacks_session(array("timezone" => $timezone));
565         }
566     }
567
568     $selectors = array();
569     for($i=-12;$i<=14;$i++) {
570         if ($i<0) {
571             $selectors []= array("display" => "GMT" . $i, "value" => $i);
572         } else {
573             $selectors []= array("display" => "GMT+" . $i, "value" => $i);
574         }
575     }
576
577     return auto_refresh_combo($form, "timezone", $selectors, $timezone, $url);
578 }
579
580 function account_table($plcapi, $gacksapi, $person_id)
581 {
582     $slices = get_slices($plcapi, $person_id, array("name","person_ids","node_ids"));
583
584     $accounts = array();
585     foreach ($slices as $slicename => $slice) {
586          $accounts[$slicename] = $gacksapi->get_account(gacksid($slicename), "user");
587     }
588
589     $headers=array();
590     $headers["name"] = "string";
591     $headers["level"] = "string";
592     $headers["be"] = "string";
593     $headers["users"] = "integer";
594     $headers["slivers"] = "integer";
595     $headers["billingContacts"] = "string";
596
597     $table = new PlekitTable("accounts", $headers, 0);
598     $table->start();
599
600     foreach ($accounts as $name => $account) {
601         $slice = $slices[$name];
602         $table->row_start();
603         $table->cell($name);
604         $table->cell($account["level"]);
605         $table->cell(bool_text(!$account["freezeUnreserved"], "enabled", "disabled"));
606         $table->cell(count($slice["person_ids"]));
607         $table->cell(count($slice["node_ids"]));
608         $table->cell($account["billingContacts"]);
609
610         $table->row_end();
611     }
612
613     $table->end();
614
615 }
616
617 function date_combo($form, $name, &$y, &$m, &$d, $url)
618 {
619     $month_selectors = array();
620     $month_selectors []= array("display" => "Jan", "value" => 1);
621     $month_selectors []= array("display" => "Feb", "value" => 2);
622     $month_selectors []= array("display" => "Mar", "value" => 3);
623     $month_selectors []= array("display" => "Apr", "value" => 4);
624     $month_selectors []= array("display" => "May", "value" => 5);
625     $month_selectors []= array("display" => "Jun", "value" => 6);
626     $month_selectors []= array("display" => "Jul", "value" => 7);
627     $month_selectors []= array("display" => "Aug", "value" => 8);
628     $month_selectors []= array("display" => "Sep", "value" => 9);
629     $month_selectors []= array("display" => "Oct", "value" => 10);
630     $month_selectors []= array("display" => "Nov", "value" => 11);
631     $month_selectors []= array("display" => "Dec", "value" => 12);
632
633     $year_selectors = array();
634     for($i=2012;$i<=2022;$i++) {
635         $year_selectors []= array("display" => $i, "value" => $i);
636     }
637
638     $day_selectors = array();
639     for($i=1;$i<=31;$i++) {
640         $day_selectors []= array("display" => $i, "value" => $i);
641     }
642
643     $m_combo = auto_refresh_combo($form, $name . "_m", $month_selectors, $m, $url);
644     $d_combo = auto_refresh_combo($form, $name . "_d", $day_selectors, $d, $url);
645     $y_combo = auto_refresh_combo($form, $name . "_y", $year_selectors, $y, $url);
646
647     return $m_combo . $d_combo . $y_combo;
648 }
649
650 function get_slice_image($api, $slicename)
651 {
652     $image_tags = $api->GetSliceTags(array("tagname" => "vref", "name" => $slicename));
653     if (count($image_tags) > 0) {
654         return $image_tags[0]['value'];
655     } else {
656         return NULL;
657     }
658 }
659
660 function set_slice_image($api, $slicename, $value)
661 {
662     $tags = $api->GetSliceTags(array("tagname" => "vref", "name" => $slicename));
663     if (count($tags) > 0) {
664         if (!$value) {
665             $api->DeleteSliceTag($tags[0]['slice_tag_id']);
666         } else if ($tags[0]['slice_tag_id'] != $value) {
667             $api->UpdateSliceTag($tags[0]['slice_tag_id'], $value);
668         }
669     } else {
670         $api->AddSliceTag($slicename, "vref", $value);
671     }
672 }
673
674 function get_slice_headnode($api, $slicename)
675 {
676     $ipList_tags = $api->GetSliceTags(array("tagname" => "vsys_ipList", "name" => $slicename));
677     if (count($ipList_tags) > 0) {
678         $ipList = $ipList_tags[0]['value'];
679         $ips = explode(",", $ipList);
680         if (count($ips)>0) {
681             return $ips[0];
682         } else {
683             return NULL;
684         }
685     } else {
686         return NULL;
687     }
688 }
689
690 function time_selectors($start_date, $min_date)
691 {
692     for($i=0;$i<24;$i++) {
693         if ($start_date+$i*60*60 >= $min_date) {
694             $selectors []= array("display" => "$i:00:00", "value"=>$i);
695         }
696     }
697
698     return $selectors;
699 }
700
701 function get_timezone()
702 {
703     if (isset($_GET['timezone_offset_minutes'])) {
704         $minutes = $_GET['timezone_offset_minutes'];
705 /*        echo "GMT offset (in minutes, from the browser): ". $minutes ."<br />\n";
706         echo "GMT: ". gmdate("Y-m-d H:i:s") ."<br />\n";
707
708         $local = gmmktime(gmdate("H"),gmdate("i")-$minutes); // adjust GMT by client's offset
709
710         echo "Calculated client's date/time: ". gmdate("Y-m-d h:i:s a",$local) ."<br />\n";*/
711
712         return $minutes;
713     } else {
714         if  (!strchr($_SERVER['REQUEST_URI'], "?")) {
715             $url = $_SERVER['REQUEST_URI'] . "?";
716         } else {
717             $url = $_SERVER['REQUEST_URI'] . "&";
718         }
719
720         echo "<script language='javascript'>\n";
721         echo "var d = new Date();\n";
722         echo "location.href=\"${url}timezone_offset_minutes=\" + (-d.getTimezoneOffset());\n";
723         echo "</script>\n";
724         exit();
725     }
726 }
727
728 function manage_slivers_tabs()
729 {
730     $tabs = array();
731
732     $tabs['Show Slivers'] = array('method'=>'GET',
733                                'url'=>l_gacks_nodelist(),
734                                'bubble'=>"Show slivers (also known as nodes or VMs) in your slice");
735
736     $tabs['Add Slivers'] = array('method'=>'GET',
737                                'url'=>l_gacks_wizard(),
738                                'bubble'=>"Add slivers (also known as nodes or VMs) to your slice");
739
740     $tabs['Select Image'] = array('method'=>'GET',
741                                'url'=>l_gacks_image(),
742                                'bubble'=>"Select image to use in this slice");
743
744     return $tabs;
745 }