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