source: branches/0.4/web/addons/job_monarch/libtoga.php @ 769

Last change on this file since 769 was 767, checked in by ramonb, 11 years ago
  • also parse grid for header
  • Property svn:keywords set to Id
File size: 73.0 KB
Line 
1<?php
2/*
3 *
4 * This file is part of Jobmonarch
5 *
6 * Copyright (C) 2006-2013  Ramon Bastiaans
7 *
8 * Jobmonarch is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Jobmonarch is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 * SVN $Id: libtoga.php 767 2013-03-28 15:06:37Z ramonb $
23 *
24 */
25
26
27class HTTPVariables
28{
29    var $clustername, $metricname;
30    var $restvars, $httpvars;
31
32    function HTTPVariables( $httpvars, $getvars )
33    {
34        $this->restvars        = array();
35
36        $this->clustername    = isset( $httpvars["c"] ) ? $httpvars["c"] : $getvars["c"];
37        $this->metricname    = isset( $httpvars["m"] ) ? $httpvars["m"] : $getvars["m"];
38
39        if( count( $httpvars ) > 0 )
40        {
41            foreach( $httpvars as $httpvar => $httpval )
42            {
43                if( $httpval )
44                {
45                    $this->restvars[$httpvar] = $httpval;
46                }
47            }
48        }
49
50        if( count( $getvars ) > 0 )
51        {
52            foreach( $getvars as $getvar => $getval )
53            {
54                if( $getval )
55                {
56                    $this->restvars[$getvar] = $getval;
57                }
58            }
59        }
60    }
61
62    function getClusterName()
63    {
64        return $this->clustername;
65    }
66
67    function getMetricName()
68    {
69        return $this->metricname;
70    }
71
72    function getHttpVar( $var )
73    {
74        if( isset( $this->restvars[$var] ) )
75        {
76            return $this->restvars[$var];
77        }
78        else
79        {
80            return null;
81        }
82    }
83}
84
85$CLUSTER_CONFS    = array();
86
87ini_set("memory_limit","500M");
88set_time_limit(0);
89
90// Monarch's conf
91//
92include_once "./conf.php";
93include_once "./version.php";
94
95global $GANGLIA_PATH;
96global $RRDTOOL;
97global $JOB_ARCHIVE_DIR;
98global $JOB_ARCHIVE_DBASE;
99global $skan_str;
100global $x_first, $y_first;
101global $CLUSTER_CONFS;
102
103$my_dir = getcwd();
104
105// Load Ganglia's PHP
106chdir( $GANGLIA_PATH );
107
108include_once "./eval_conf.php";
109include_once "./functions.php";
110include_once "./get_context.php";
111
112global $GLOBALS, $conf, $metrics, $version, $rrdtool_version, $context;
113
114// ganglia start
115$metrics = array();
116$version = array();
117
118$version["webfrontend"] = $GLOBALS["ganglia_version"];
119
120# Get rrdtool version
121$rrdtool_version = array();
122exec($conf['rrdtool'], $rrdtool_version);
123$rrdtool_version = explode(" ", $rrdtool_version[0]);
124$rrdtool_version = $rrdtool_version[1];
125$version["rrdtool"] = "$rrdtool_version";
126
127// ganglia end
128
129$context = 'cluster';
130
131// Back to our PHP
132chdir( $my_dir );
133
134global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH, $DATA_SOURCE, $HTTP_GET_VARS, $_GET;
135$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
136
137// Set cluster context so that Ganglia will
138// provide us with the correct metrics array
139//
140global $context, $clustername, $reports;
141
142global $default_metric;
143
144// Ganglia's array of host metrics
145//
146global $hosts_up;
147global $start;
148
149global $DATETIME_FORMAT;
150
151function makeDate( $time )
152{
153    global $DATETIME_FORMAT;
154    return strftime( $DATETIME_FORMAT, $time );
155}
156
157
158class TarchDbase
159{
160    var $ip, $dbase, $conn;
161
162    function TarchDbase( $ip = null, $dbase = null )
163    {
164        global $CLUSTER_CONFS, $clustername;
165        global $JOB_ARCHIVE_DBASE;
166
167        // Import cluster specific settings
168        //
169        foreach( $CLUSTER_CONFS as $confcluster => $conffile )
170        {
171            if( strtolower( trim($this->clustername) ) == strtolower(trim($confcluster)) )
172            {
173                include_once $conffile;
174            }
175        }
176
177        $db_fields = explode( '/', $JOB_ARCHIVE_DBASE );
178
179        $this->ip    = $db_fields[0];
180        $this->dbase    = $db_fields[1];
181        $this->conn    = null;
182    }
183
184    function connect()
185    {
186        if( $this->ip == null )
187            $this->conn = pg_connect( "dbname=".$this->dbase );
188        else
189            $this->conn = pg_connect( "host=".$this->ip." dbname=".$this->dbase );
190    }
191
192    function searchDbase( $id = null, $queue = null, $owner = null, $name = null, $start_from_time = null, $start_to_time = null, $end_from_time = null, $end_to_time = null )
193    {
194        global $SEARCH_RESULT_LIMIT;
195
196        if( $id )
197        {
198            $select_query = "SELECT job_id FROM jobs WHERE job_id = '$id' AND job_status = 'F'";
199            $this->resultcount = 1;
200        }
201        else
202        {
203            $query_args = array();
204           
205            if( $queue )
206            {
207                $query_args[] = "job_queue ='$queue'";
208            }
209            if( $owner )
210            {
211                $query_args[] = "job_owner ='$owner'";
212            }
213            if( $name )
214            {
215                $query_args[] = "job_name = '$name'";
216            }
217            if( $start_from_time )
218            {
219                $query_args[] = "job_start_timestamp >= $start_from_time";
220            }
221            if( $start_to_time )
222            {
223                $query_args[] = "job_start_timestamp <= $start_to_time";
224            }
225            if( $end_from_time )
226            {
227                $query_args[] = "job_stop_timestamp >= $end_from_time";
228            }
229            if( $end_to_time )
230            {
231                $query_args[] = "job_stop_timestamp <= $end_to_time";
232            }
233
234            $query = "FROM jobs WHERE job_status = 'F' AND ";
235            $extra_query_args = '';
236
237            foreach( $query_args as $myquery )
238            {
239                if( $extra_query_args == '' )
240                {
241                    $extra_query_args = $myquery;
242                }
243                else
244                {
245                    $extra_query_args .= " AND ".$myquery;
246                }
247            }
248            $query .= $extra_query_args;
249
250            $count_result_idname = "COUNT(job_id)";
251            $select_result_idname = "job_id";
252
253            $count_query = "SELECT " . $count_result_idname . " " . $query;
254
255            $count_result = $this->queryDbase( $count_query );
256            $this->resultcount = (int) $count_result[0]['count'];
257
258            $select_query = "SELECT " . $select_result_idname . " " . $query . " ORDER BY job_id DESC LIMIT " . $SEARCH_RESULT_LIMIT;
259        }
260
261        $ids = $this->queryDbase( $select_query );
262
263        $ret = array();
264
265        foreach( $ids as $crow)
266        {
267            $ret[] = $crow['job_id'];
268        }
269
270        return $ret;
271    }
272
273    function getNodesForJob( $jobid )
274    {
275        $result = $this->queryDbase( "SELECT node_id FROM job_nodes WHERE job_id = '$jobid'" );
276
277        $nodes = array();
278
279        foreach( $result as $result_row ) 
280        {
281            $nodes[] = $this->getNodeArray( $result_row['node_id'] );
282        }
283
284        return $nodes;
285    }
286
287    function getJobsForNode( $nodeid )
288    {
289        $result = $this->queryDbase( "SELECT job_id FROM job_nodes WHERE node_id = '$nodeid'" );
290
291        $jobs = array();
292
293        foreach( $result as $result_row )
294        {
295            $jobs[] = $this->getJobArray( $result_row['job_id'] );
296        }
297        return $jobs;
298    }
299
300    function getJobArray( $id )
301    {
302        $result = $this->queryDbase( "SELECT * FROM jobs WHERE job_id = '$id'" );
303
304        return ( $this->makeArray( $result[0] ) );
305    }
306
307    function getNodeArray( $id )
308    {
309        $result = $this->queryDbase( "SELECT * FROM nodes WHERE node_id = '$id'" );
310
311        return ( $this->makeArray( $result[0] ) );
312    }
313
314    function makeArray( $result_row )
315    {
316        $myar = array();
317
318        foreach( $result_row as $mykey => $myval )
319        {
320            $map_key = explode( '_', $mykey );
321
322            $rmap_key = array_reverse( $map_key );
323            array_pop( $rmap_key );
324            $map_key = array_reverse( $rmap_key );
325           
326            $newkey = implode( '_', $map_key );
327           
328            $myar[$newkey] = $result_row[$mykey];
329        }
330
331        return $myar;
332    }
333
334    function queryDbase( $query )
335    {
336        $result_rows = array();
337   
338        if( !$this->conn )
339        {
340            $this->connect();
341        }
342
343        $result = pg_query( $this->conn, $query );
344
345        while ($row = pg_fetch_assoc($result))
346        {
347            $result_rows[] = $row;
348        }
349
350        return $result_rows;
351    }
352}
353
354class TarchRrdGraph
355{
356    var $rrdbin, $rrdvalues, $clustername, $hostname, $tempdir, $tarchdir, $metrics;
357
358    function TarchRrdGraph( $clustername, $hostname )
359    {
360        global $conf;
361        global $JOB_ARCHIVE_DIR;
362
363        $this->rrdbin        = $conf['rrdtool'];
364        $this->rrdvalues    = array();
365        $this->tarchdir        = $JOB_ARCHIVE_DIR;
366        $this->clustername    = $clustername;
367        $this->hostname        = $hostname;
368    }
369
370    function doCmd( $command )
371    {
372        $pipe = popen( $command . ' 2>&1', 'r' );
373
374        if (!$pipe)
375        {
376            print "pipe failed.";
377            return "";
378        }
379
380        $output = '';
381
382        while(!feof($pipe))
383        {
384            $output .= fread($pipe, 1024);
385        }
386
387        pclose($pipe);
388
389        $output = explode( "\n", $output );
390
391        return $output;
392    }
393
394    function dirList( $dir )
395    {
396        $dirlist = array();
397
398        if ($handle = opendir( $dir ))
399        {
400            while (false !== ($file = readdir($handle)))
401            {
402                if ($file != "." && $file != "..")
403                {
404                    $dirlist[] = $file;
405                }
406            }
407            closedir($handle);
408        }
409
410        return $dirlist;
411    }
412
413    function getTimePeriods( $start, $end )
414    {
415        $times = array();
416        $dirlist = $this->dirList( $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname );
417
418        $first = 0;
419        $last = 9999999999999;
420
421        foreach( $dirlist as $dir )
422        {
423            if( $dir > $first and $dir <= $start )
424            {
425                $first = $dir;
426            }
427            if( $dir < $last and $dir >= $end )
428            {
429                $last = $dir;
430            }
431        }
432
433        foreach( $dirlist as $dir )
434        {
435            if( $dir >= $first and $dir <= $last and !array_key_exists( $dir, $times ) )
436            {
437                $times[] = $dir;
438            }
439        }
440
441        sort( $times );
442
443        return $times;
444    }
445
446    function getRrdDirs( $start, $stop )
447    {
448        $timess = $this->getTimePeriods( $start, $stop );
449
450        $rrd_files = array();
451
452        foreach( $timess as $time )
453        {
454            $rrd_files[] = $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname. '/'.$time;
455        }
456
457        return $rrd_files;
458    }
459
460    function getRrdFiles( $metric, $start, $stop )
461    {
462        $times = $this->getTimePeriods( $start, $stop );
463
464        $rrd_files = array();
465
466        foreach( $times as $time )
467        {
468            $rrd_files[] = $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname . '/' .$time. '/' . $metric. '.rrd';
469        }
470
471        return $rrd_files;
472    }
473}
474
475class DataSource
476{
477    var $data, $ip, $port;
478
479    function DataSource()
480    {
481        global $DATA_SOURCE, $clustername;
482
483        $ds_fields     = explode( ':', $DATA_SOURCE );
484
485        $ds_ip         = $ds_fields[0];
486        $ds_port       = $ds_fields[1];
487
488        $this->ip       = $ds_ip;
489        $this->port     = $ds_port;
490        $this->clustername = $clustername;
491    }
492
493    function getData()
494    {
495        $errstr        = '';
496        $errno         = 0;
497        $timeout       = 3;
498
499        $fp = fsockopen( $this->ip, $this->port, $errno, $errstr, $timeout );
500
501        if( !$fp )
502        {
503            echo 'Unable to connect to '.$this->ip.':'.$this->port;
504            return;
505        }
506
507        if( $this->port == '8652' )
508        {
509            $request = "/" . $this->clustername . "\n";
510            $rc = fputs($fp, $request);
511            if (!$rc)
512            {
513                $error = "Could not sent request to gmetad: $errstr";
514                if ($debug) print "<br/>DEBUG: $error\n";
515                   return FALSE;
516            }
517        }
518
519        stream_set_timeout( $fp, 30 );
520
521        while ( !feof( $fp ) )
522        {
523            $data .= fread( $fp, 16384 );
524        }
525
526        fclose( $fp );
527
528        return $data;
529    }
530}
531
532class DataGatherer
533{
534    var $xmlhandler, $data, $httpvars;
535
536    function DataGatherer( $cluster )
537    {
538        $this->cluster    = $cluster;
539        $this->httpvars = $httpvars;
540    }
541
542    function parseXML( $data )
543    {
544
545        $this->parser         = xml_parser_create();
546        $this->xmlhandler     = new TorqueXMLHandler( $this->cluster );
547
548        xml_parser_set_option( $this->parser, XML_OPTION_CASE_FOLDING, 0 );
549        xml_set_element_handler( $this->parser, array( &$this->xmlhandler, 'startElement' ), array( &$this->xmlhandler, 'stopElement' ) );
550
551        if ( !xml_parse( $this->parser, $data ) )
552        {
553            $error = sprintf( 'XML error: %s at %d', xml_error_string( xml_get_error_code( $this->parser ) ), xml_get_current_line_number( $this->parser ) );
554        }
555        $handler = &$this->xmlhandler;
556        $handler->finishUp();
557    }
558
559    function printInfo()
560    {
561        $handler = $this->xmlhandler;
562        $handler->printInfo();
563    }
564
565    function getUsingFQDN()
566    {
567        $handler = $this->xmlhandler;
568        return $handler->getUsingFQDN();
569    }
570
571    function getMetrics()
572    {
573        $handler = $this->xmlhandler;
574        return $handler->getMetrics();
575    }
576    function getNodes()
577    {
578        $handler = $this->xmlhandler;
579        return $handler->getNodes();
580    }
581
582    function getNode( $node )
583    {
584        $handler = $this->xmlhandler;
585        return $handler->getNode( $node );
586    }
587
588    function getCpus()
589    {
590        $handler = $this->xmlhandler;
591        return $handler->getCpus();
592    }
593
594    function getJobs()
595    {
596        $handler = $this->xmlhandler;
597        return $handler->getJobs();
598    }
599
600    function getJob( $job )
601    {
602        $handler = $this->xmlhandler;
603        return $handler->getJob( $job );
604    }
605
606    function getHeartbeat()
607    {
608        $handler = $this->xmlhandler;
609        return $handler->getHeartbeat();
610    }
611
612    function isJobmonRunning()
613    {
614        $handler = $this->xmlhandler;
615        return $handler->isJobmonRunning();
616    }
617}
618
619class TorqueXMLHandler
620{
621    var $clusters, $heartbeat, $nodes, $jobs, $clustername, $proc_cluster;
622
623    function TorqueXMLHandler( $clustername )
624    {
625        $this->jobs        = array();
626        $this->clusters     = array();
627        $this->nodes         = array();
628        $this->metrics      = array();
629        $this->heartbeat     = array();
630        $this->down_nodes    = array();
631        $this->offline_nodes    = array();
632        $this->clustername    = $clustername;
633        $this->proc_cluster = null;
634        $this->proc_hostname = null;
635        $this->fqdn        = 1;
636    }
637
638    function getUsingFQDN()
639    {
640        return $this->fqdn;
641    }
642
643    function getCpus()
644    {
645        $cpus = 0;
646
647        if( isset( $this->jobs ) && count( $this->jobs ) > 0 )
648        {
649            foreach( $this->jobs as $jobid=>$jobattrs )
650            {
651                $nodes    = count( $jobattrs['nodes'] );
652                $ppn    = (int) $jobattrs['ppn'] ? $jobattrs['ppn'] : 1;
653                $mycpus    = $nodes * $ppn;
654
655                $cpus    = $cpus + $mycpus;
656            }
657        }
658    }
659
660    function isJobmonRunning()
661    {
662        if (isset( $this->heartbeat['time'] ))
663        {
664            return 1;
665        }
666        else
667        {
668            return 0;
669        }
670    }
671
672    function makeHostname( $thostname, $tdomain=null )
673    {
674        // Should hostname be FQDN or short w/o domain
675        //
676        $nodes = &$this->nodes;
677
678        $fqdn = 1;
679
680        //$tdomain = explode( '.', $thostname );
681        //
682        // TODO?: extract domain from hostname or something?
683
684        if( $tdomain )
685        {
686            $domain_len    = 0 - strlen( $tdomain );
687
688            // Let's see if Ganglia use's FQDN or short hostnames
689            //
690            foreach( $nodes as $hostname => $nimage )
691            {
692                if( strpos( $hostname, $tomdain ) !== false )
693                {
694                    $fqdn    = 0;
695                }
696            }
697        }
698        else
699        {
700            $fqdn    = 0;
701        }
702   
703        if( $tdomain && $fqdn )
704        {
705            if( strpos( $thostname, $tdomain ) !== false )
706            {
707                $thostname = $thostname . '.'.$tdomain;
708            } 
709            else
710            {
711                $thostname = $thostname;
712            }
713        }
714
715        return $thostname;
716    }
717
718    function startElement( $parser, $name, $attrs )
719    {
720        global $cluster, $metrics, $self, $grid;
721
722        $jobid = null;
723
724        if( $name == 'GRID' )
725        {
726            $self = $attrs['NAME'];
727            $grid = $attrs;
728
729            return null;
730        }
731
732        if( $name == 'CLUSTER' )
733        {
734            // ganglia start
735            $cluster = $attrs;
736            // ganglia end
737
738            $this->proc_cluster = $attrs['NAME'];
739            //printf("set proc cluster to %s\n", $attrs['NAME'] );
740            return null;
741        }
742        if( $this->proc_cluster != $this->clustername )
743        {
744            //printf("cluster does not match: %s\n", $this->clustername );
745            return null;
746        }
747
748        if( $name == 'HOST' )
749        {
750            // ganglia start
751            $hostname = $attrs['NAME'];
752            $this->proc_hostname = $hostname;
753
754            # Pseudo metrics - add useful HOST attributes like gmond_started & last_reported to the metrics list:
755            $metrics[$hostname]['gmond_started']['NAME'] = "GMOND_STARTED";
756            $metrics[$hostname]['gmond_started']['VAL'] = $attrs['GMOND_STARTED'];
757            $metrics[$hostname]['gmond_started']['TYPE'] = "timestamp";
758            $metrics[$hostname]['last_reported']['NAME'] = "REPORTED";
759            $metrics[$hostname]['last_reported']['VAL'] = $attrs['REPORTED'];
760            $metrics[$hostname]['last_reported']['TYPE'] = "string";
761            $metrics[$hostname]['ip_address']['NAME'] = "IP";
762            $metrics[$hostname]['ip_address']['VAL'] = $attrs['IP'];
763            $metrics[$hostname]['ip_address']['TYPE'] = "string";
764            $metrics[$hostname]['location']['NAME'] = "LOCATION";
765            $metrics[$hostname]['location']['VAL'] = $attrs['LOCATION'];
766            $metrics[$hostname]['location']['TYPE'] = "string";
767            // ganglia end
768
769            //printf( "host %s\n", $hostname );
770            //$location = $attrs['LOCATION'];
771
772            if( !isset( $this->nodes[$hostname] ) )
773            {
774                $this->nodes[$hostname] = new NodeImage( $this->proc_cluster, $hostname );
775            }
776            return null;
777        }
778
779        if( $name == 'METRIC' )
780        {
781            $hostname = $this->proc_hostname;
782
783            // ganglia start
784            $metricname = rawurlencode($attrs['NAME']);
785            $metrics[$hostname][$metricname] = $attrs;
786            // ganglia end
787
788            if ( strpos( $attrs['NAME'], 'zplugin_monarch' ) === false )
789            {
790                return null;
791            }
792
793            if( strpos( $attrs['NAME'], 'zplugin_monarch_heartbeat' ) !== false )
794            {
795                $this->heartbeat['time'] = $attrs['VAL'];
796                return;
797            }
798            else if( strpos( $attrs['NAME'], 'zplugin_monarch_down' ) !== false )
799            {
800                $fields        = explode( ' ', $attrs['VAL'] );
801
802                $nodes_down    = array();
803                $down_domain    = null;
804
805                foreach( $fields as $f )
806                {
807                    $togavalues    = explode( '=', $f );
808
809                    $toganame    = $togavalues[0];
810                    $togavalue    = $togavalues[1];
811
812                    if( $toganame == 'nodes' )
813                    {
814                        $mynodes = explode( ';', $togavalue );
815
816                        foreach( $mynodes as $node )
817                        {
818                            $nodes_down[] = $node;
819                        }
820                    }
821                    else if( $toganame == 'domain' )
822                    {
823                        $down_domain = $togavalue;
824                    }
825                    else if( $toganame == 'reported' )
826                    {
827                        if( !isset( $this->down_nodes['heartbeat'] ) )
828                        {
829                            $this->down_nodes[$togavalue]    = array( $nodes_down, $down_domain );
830                        }
831                    }
832                }
833                return;
834            }
835            else if( strpos( $attrs['NAME'], 'zplugin_monarch_offline' ) !== false )
836            {
837                $fields        = explode( ' ', $attrs['VAL'] );
838
839                $nodes_offline    = array();
840                $offline_domain    = null;
841
842                foreach( $fields as $f )
843                {
844                    $togavalues    = explode( '=', $f );
845
846                    $toganame    = $togavalues[0];
847                    $togavalue    = $togavalues[1];
848
849                    if( $toganame == 'nodes' )
850                    {
851                        $mynodes = explode( ';', $togavalue );
852
853                        foreach( $mynodes as $node )
854                        {
855                            $nodes_offline[] = $node;
856                        }
857                    }
858                    else if( $toganame == 'domain' )
859                    {
860                        $offline_domain = $togavalue;
861                    }
862                    else if( $toganame == 'reported' )
863                    {
864                        if( !isset( $this->offline_nodes['heartbeat'] ) )
865                        {
866                            $this->offline_nodes[$togavalue] = array( $nodes_offline, $offline_domain );
867                        }
868                    }
869                }
870                return;
871            }
872            else if( strpos( $attrs['NAME'], 'zplugin_monarch_job' ) !== false )
873            {
874                sscanf( $attrs['NAME'], 'zplugin_monarch_job_%d_%s$', $monincr, $jobid );
875
876                if( !isset( $this->jobs[$jobid] ) )
877                {
878                    $this->jobs[$jobid] = array();
879                }
880
881                $fields = explode( ' ', $attrs['VAL'] );
882
883                foreach( $fields as $f )
884                {
885                    $togavalues = explode( '=', $f );
886
887                    $toganame = $togavalues[0];
888                    $togavalue = $togavalues[1];
889
890                    if( $toganame == 'nodes' )
891                    {
892                        if( $this->jobs[$jobid]['status'] == 'R' )
893                        {
894                            if( !isset( $this->jobs[$jobid][$toganame] ) )
895                            {
896                                $this->jobs[$jobid][$toganame] = array();
897                            }
898
899                            $mynodes = explode( ';', $togavalue );
900
901                            foreach( $mynodes as $node )
902                            {
903                                if( !in_array( $node, $this->jobs[$jobid][$toganame] ) )
904                                {
905                                    array_push( $this->jobs[$jobid][$toganame], $node );
906                                }
907                            }
908
909                        }
910                        else if( $this->jobs[$jobid]['status'] == 'Q' )
911                        {
912                            $this->jobs[$jobid][$toganame] = $togavalue;
913                        }
914                    }
915                    else
916                    {
917                        $this->jobs[$jobid][$toganame] = $togavalue;
918                    }
919                }
920
921                if( isset( $this->jobs[$jobid]['nodes'] ) )
922                {
923                    $nr_nodes = count( $this->jobs[$jobid]['nodes'] );
924       
925                    if( $this->jobs[$jobid]['status'] == 'R' )
926                    {
927
928                        if( isset( $this->jobs[$jobid]['domain'] ) )
929                        {
930                            $domain        = $this->jobs[$jobid]['domain'];
931                            $domain_len    = 0 - strlen( $domain );
932
933                            $first_host    = key( array_slice($this->nodes, 0, 1, true) );
934
935                            // Let's see if Ganglia use's FQDN or short hostnames
936                            //
937                            if( strpos( $first_host, $domain ) === false )
938                            {
939                                $this->fqdn    = 0;
940                            }
941                        }
942                        else
943                        {
944                            $this->fqdn    = 0;
945                        }
946
947                        foreach( $this->jobs[$jobid]['nodes'] as $node )
948                        {
949
950                            // Only add domain name to the hostname if Ganglia is doing that too
951                            //
952                            if( $this->fqdn && isset( $this->jobs[$jobid]['domain'] ) )
953                            {
954                                if( strpos( $node, $domain ) === false )
955                                {
956                                    $host = $node. '.'.$domain;
957                                } else
958                                {
959                                    $host = $node;
960                                }
961                            }
962                            else
963                            {
964                                $host    = $node;
965                            }
966
967                            if( !isset( $this->nodes[$host] ) )
968                            {
969                                $my_node = new NodeImage( $this->proc_cluster, $host );
970                            }
971                            else
972                            {
973                                $my_node = $this->nodes[$host];
974                            }
975
976                            if( !$my_node->hasJob( $jobid ) )
977                            {
978                                if( isset( $jobs[$jobid]['ppn'] ) )
979                                {
980                                    $my_node->addJob( $jobid, ((int) $jobs[$jobid]['ppn']) );
981                                }
982                                else
983                                {
984                                    $my_node->addJob( $jobid, 1 );
985                                }
986                            }
987
988                            $this->nodes[$host] = $my_node;
989                        }
990                    }
991                }
992            }
993            return;
994        }
995    }
996
997    function finishUp( )
998    {
999        $nodes    = $this->nodes;
1000
1001        if( sizeof( $this->down_nodes ) > 0 )
1002        {
1003            foreach( $this->down_nodes as $reported => $dnodes )
1004            {
1005                if( $reported == $this->heartbeat['time'] )
1006                {
1007                    $domain = $dnodes[1];
1008
1009                    foreach( $dnodes[0] as $downhost )
1010                    {
1011                        $downhost = $this->makeHostname( $downhost, $domain );
1012
1013                        if( isset( $nodes[$downhost] ) )
1014                        {
1015                            // OMG PHP4 is fking stupid!
1016                            // $nodes[$downhost]->setDown( 1 ) won't work here..
1017                            //
1018                            $mynode = $nodes[$downhost];
1019                            $mynode->setDown( 1 );
1020                            $nodes[$downhost] = $mynode;
1021                        }
1022                    }
1023                }
1024            }
1025        }
1026
1027        if( sizeof( $this->offline_nodes ) > 0 )
1028        {
1029            foreach( $this->offline_nodes as $reported => $onodes )
1030            {
1031                if( $reported == $this->heartbeat['time'] )
1032                {
1033                    $domain = $onodes[1];
1034
1035                    foreach( $onodes[0] as $offlinehost )
1036                    {
1037                        $offlinehost = $this->makeHostname( $offlinehost, $domain );
1038
1039                        if( isset( $nodes[$offlinehost] ) )
1040                        {
1041                            // OMG PHP4 is fking stupid!
1042                            // $nodes[$offlinehost]->setDown( 1 ) won't work here..
1043                            //
1044                            $mynode = $nodes[$offlinehost];
1045                            $mynode->setOffline( 1 );
1046                            $nodes[$offlinehost] = $mynode;
1047                        }
1048                    }
1049                }
1050            }
1051        }
1052
1053        $this->nodes = $nodes;
1054    }
1055
1056    function stopElement( $parser, $name )
1057    {
1058    }
1059
1060    function printInfo()
1061    {
1062        $jobs = &$this->jobs;
1063
1064        printf( "---jobs---\n" );
1065
1066        foreach( $jobs as $jobid => $job )
1067        {
1068            printf( "job %s\n", $jobid );
1069
1070            if( isset( $job['nodes'] ) )
1071            {
1072                foreach( $job['nodes'] as $node )
1073                {
1074                    $mynode = $this->nodes[$node];
1075                    $hostname = $mynode->getHostname();
1076                    $location = $mynode->getLocation();
1077
1078                    printf( "\t- node %s\tlocation %s\n", $hostname, $location );
1079                }
1080            }
1081        }
1082
1083        printf( "---nodes---\n" );
1084
1085        $nodes = &$this->nodes;
1086
1087        foreach( $nodes as $node )
1088        {
1089            $hostname = $node->getHostname();
1090            $location = $node->getLocation();
1091            $jobs = implode( ' ', $node->getJobs() );
1092            printf( "* node %s\tlocation %s\tjobs %s\n", $hostname, $location, $jobs );
1093        }
1094    }
1095
1096    function getNodes()
1097    {
1098        return $this->nodes;
1099    }
1100
1101    function getNode( $node )
1102    {
1103        $nodes = &$this->nodes;
1104
1105        if( isset( $nodes[$node] ) )
1106        {
1107            return $nodes[$node];
1108        }
1109        else
1110        {
1111            return NULL;
1112        }
1113    }
1114
1115    function getJobs()
1116    {
1117        return $this->jobs;
1118    }
1119
1120    function getJob( $job )
1121    {
1122        $jobs = &$this->jobs;
1123
1124        if( isset( $jobs[$job] ) )
1125        {
1126            return $jobs[$job];
1127        }
1128        else
1129        {
1130            return NULL;
1131        }
1132    }
1133
1134    function getHeartbeat()
1135    {
1136        return $this->heartbeat['time'];
1137    }
1138}
1139
1140class NodeImage
1141{
1142    var $image, $x, $y, $hostname, $jobs, $tasks, $showinfo;
1143
1144    function NodeImage( $cluster, $hostname )
1145    {
1146        global $SMALL_CLUSTERIMAGE_NODEWIDTH;
1147
1148        $this->jobs        = array();
1149        $this->tasks        = 0;
1150        $this->hostname        = $hostname;
1151        $this->clustername    = $cluster;
1152        $this->showinfo        = 1;
1153        $this->size        = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1154        $this->down        = 0;
1155        $this->offline        = 0;
1156    }
1157
1158    function addJob( $jobid, $cpus )
1159    {
1160        $jobs        = &$this->jobs;
1161        $jobs[]        = $jobid;
1162        $this->jobs    = $jobs;
1163
1164        $this->addTask( $cpus );
1165    }
1166
1167    function hasJob( $jobid )
1168    {
1169        $jobfound = 0;
1170
1171        if( count( $this->jobs ) > 0 )
1172        {
1173            foreach( $this->jobs as $job )
1174            {
1175                if( $job == $jobid )
1176                {
1177                    $jobfound = 1;
1178                }
1179            }
1180        }
1181
1182        return $jobfound;
1183    }
1184
1185    function addTask( $cpus )
1186    {
1187        $this->tasks = $this->tasks + $cpus;
1188    }
1189    function setDown( $down )
1190    {
1191        $this->down = $down;
1192    }
1193    function isDown()
1194    {
1195        return $this->down;
1196    }
1197    function setOffline( $offline )
1198    {
1199        $this->offline = $offline;
1200    }
1201    function isOffline()
1202    {
1203        return $this->offline;
1204    }
1205    function setImage( $image )
1206    {
1207        $this->image = $image;
1208    }
1209    function setCoords( $x, $y )
1210    {
1211        $this->x = $x;
1212        $this->y = $y;
1213    }
1214    function getX()
1215    {
1216        return $this->x;
1217    }
1218    function getY()
1219    {
1220        return $this->y;
1221    }
1222
1223    function getImagemapArea()
1224    {
1225        $area_topleft        = $this->x . "," . $this->y;
1226        $area_bottomright    = ($this->x + $this->size) . "," . ($this->y + $this->size);
1227        $area_coords        = $area_topleft . "," . $area_bottomright;
1228
1229        $area_href        = "./?c=" . $this->clustername . "&h=" . $this->hostname;
1230
1231        $area_tooltip        = $this->hostname;
1232
1233        if( $this->down)
1234        {
1235            $area_tooltip        = $area_tooltip . ": DOWN";
1236        }
1237        else if( $this->offline )
1238        {
1239            $area_tooltip        = $area_tooltip . ": OFFLINE";
1240        }
1241
1242        $area_tooltip        = $area_tooltip . ": " . implode( " ", $this->jobs );
1243
1244        $tag_href        = "HREF=\"" . $area_href . "\"";
1245        $tag_coords        = "COORDS=\"" . $area_coords . "\"";
1246        $tag_tooltip1        = "ALT=\"" . $area_tooltip . "\"";
1247        $tag_tooltip2        = "TITLE=\"" . $area_tooltip . "\"";
1248
1249        return ("<AREA SHAPE=\"RECT\" " . $tag_coords . " " . $tag_href . " " . $tag_tooltip1 . " " . $tag_tooltip2 . ">");
1250    }
1251
1252    function colorHex( $color )
1253    {
1254        $my_color = imageColorAllocate( $this->image, hexdec( substr( $color, 0, 2 )), hexdec( substr( $color, 2, 2 )), hexdec( substr( $color, 4, 2 )) );
1255
1256        return $my_color;
1257    }
1258
1259    function setLoad( $load )
1260    {
1261        $this->load = $load;
1262    }
1263
1264    function setHostname( $hostname )
1265    {
1266        $this->hostname = $hostname;
1267    }
1268
1269    function getHostname()
1270    {
1271        return $this->hostname;
1272    }
1273
1274    function getJobs()
1275    {
1276        return $this->jobs;
1277    }
1278
1279    function setShowinfo( $showinfo )
1280    {
1281        $this->showinfo = $showinfo;
1282    }
1283
1284    function drawSmall()
1285    {
1286        global $SMALL_CLUSTERIMAGE_NODEWIDTH;
1287
1288        $this->size    = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1289
1290        $this->draw();
1291    }
1292
1293    function drawBig()
1294    {
1295        global $BIG_CLUSTERIMAGE_NODEWIDTH;
1296
1297        $this->size    = $BIG_CLUSTERIMAGE_NODEWIDTH;
1298
1299        $this->drawShadow();
1300        $this->draw();
1301    }
1302
1303    function drawShadow()
1304    {
1305        // offset of drop shadow from top left
1306        //
1307        $ds_offset  = 5;
1308
1309        // number of steps from black to background color
1310        //
1311        $ds_steps   = 15;
1312
1313        // distance between steps
1314        //
1315        $ds_spread = 1;
1316
1317        // define the background color
1318        //
1319        $background = array("r" => 255, "g" => 255, "b" => 255);
1320
1321        // create a new canvas.  New canvas dimensions should be larger than the original's
1322        //
1323        $width  = $this->size + $ds_offset;
1324        $height = $this->size + $ds_offset;
1325
1326        // determine the offset between colors
1327        //
1328        $step_offset = array("r" => ($background['r'] / $ds_steps), "g" => ($background['g'] / $ds_steps), "b" => ($background['b'] / $ds_steps));
1329
1330        // calculate and allocate the needed colors
1331        //
1332        $current_color = $background;
1333
1334        for ($i = 0; $i <= $ds_steps ; $i++)
1335        {
1336            $colors[$i] = imagecolorallocate($this->image, round($current_color['r']), round($current_color['g']), round($current_color['b']));
1337
1338            $current_color['r'] -= $step_offset['r'];
1339            $current_color['g'] -= $step_offset['g'];
1340            $current_color['b'] -= $step_offset['b'];
1341        }
1342
1343        // draw overlapping rectangles to create a drop shadow effect
1344        //
1345        for ($i = 3; $i < count($colors); $i++)
1346        {
1347            imagefilledrectangle( $this->image, ($this->x + $ds_offset), ($this->y + $ds_offset), ($this->x + $width), ($this->y + $height), $colors[$i] );
1348            $width -= $ds_spread;
1349            $height -= $ds_spread;
1350        }
1351    }
1352
1353    function draw()
1354    {
1355        global $JOB_NODE_MARKING, $NODE_DOWN_MARKING, $NODE_OFFLINE_MARKING;
1356
1357        $black_color = imageColorAllocate( $this->image, 0, 0, 0 );
1358        $size = $this->size;
1359
1360        imageFilledRectangle( $this->image, $this->x, $this->y, $this->x+($size), $this->y+($size), $black_color );
1361
1362        if( $this->showinfo)
1363        {
1364            $this->load = $this->determineLoad();
1365
1366            if( !isset( $this->image ) or !isset( $this->x ) or !isset( $this->y ) )
1367            {
1368                printf( "aborting\n" );
1369                printf( "x %d y %d load %f\n", $this->x, $this->y, $load );
1370                return;
1371            }
1372
1373            // Convert Ganglias Hexadecimal load color to a Decimal one
1374            //
1375            $load = $this->determineLoad();   
1376            $usecolor = $this->colorHex( load_color($load) );
1377            imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
1378            if( $this->down )
1379            {
1380                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $NODE_DOWN_MARKING, $black_color );
1381            }
1382            else if( $this->offline )
1383            {
1384                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $NODE_OFFLINE_MARKING, $black_color );
1385            }
1386            else if( count( $this->jobs ) > 0 )
1387            {
1388                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $JOB_NODE_MARKING, $black_color );
1389            }
1390        }
1391        else
1392        {
1393            // White
1394            $usecolor = imageColorAllocate( $this->image, 255, 255, 255 );
1395            imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
1396        }
1397    }
1398
1399    function determineLoad()
1400    {
1401        global $metrics;
1402
1403        $cpus = $metrics[$this->hostname]['cpu_num']['VAL'];
1404        if (!$cpus)
1405        {
1406            $cpus=1;
1407        }
1408
1409        $load_one    = $metrics[$this->hostname]['load_one']['VAL'];
1410        $load        = ((float) $load_one)/$cpus;
1411
1412        return $load;
1413    }
1414}
1415
1416class ClusterImage
1417{
1418    var $dataget, $image, $clustername;
1419    var $filtername, $filters;
1420
1421    function ClusterImage( $data, $clustername )
1422    {
1423        $this->dataget      = new DataGatherer( $clustername );
1424        $this->data         = $data;
1425        $this->clustername  = $clustername;
1426        $this->filters      = array();
1427        $this->size         = 's';
1428        $this->width        = 0;
1429        $this->height       = 0;
1430        $this->output       = 1;
1431        $this->jobs         = null;
1432        $this->nodes        = null;
1433        $this->parsed       = false;
1434    }
1435
1436    function getWidth()
1437    {
1438        return $this->width;
1439    }
1440    function getHeight()
1441    {
1442        return $this->height;
1443    }
1444    function setSmall()
1445    {
1446        $this->size    = 's';
1447    }
1448    function setBig()
1449    {
1450        $this->size    = 'b';
1451    }
1452    function setNoimage()
1453    {
1454        $this->output    = 0;
1455    }
1456    function checkParse()
1457    {
1458        if( $this->parsed == false )
1459        {
1460            $this->dataget->parseXML( $this->data );
1461            $this->parsed = true;
1462        }
1463    }
1464    function getJobs()
1465    {
1466        if( $this->jobs == null )
1467        {
1468            $this->checkParse();
1469            $mydatag = $this->dataget;
1470            $this->jobs = $mydatag->getJobs();
1471        }
1472
1473        return $this->jobs;
1474    }
1475    function setJobs($jobs)
1476    {
1477        $this->jobs   = &$jobs;
1478    }
1479    function getNodes()
1480    {
1481        if( $this->nodes== null )
1482        {
1483            $this->checkParse();
1484            $mydatag = $this->dataget;
1485            $this->nodes = $mydatag->getNodes();
1486        }
1487
1488        return $this->nodes;
1489    }
1490    function setNodes($nodes)
1491    {
1492        $this->nodes    = &$nodes;
1493    }
1494    function isSmall()
1495    {
1496        return ($this->size == 's');
1497    }
1498    function isBig()
1499    {
1500        return ($this->size == 'b');
1501    }
1502    function setFilter( $filtername, $filtervalue )
1503    {
1504        $this->filters[$filtername] = $filtervalue;
1505    }
1506
1507    function filterNodes( $jobs, $nodes )
1508    {
1509        $filtered_nodes = array();
1510
1511        //print_r( $nodes );
1512
1513        foreach( $nodes as $node )
1514        {
1515            $hostname = $node->getHostname();
1516
1517            $addhost = 1;
1518
1519            if( count( $this->filters ) > 0 )
1520            {
1521                $mynjobs = $node->getJobs();
1522
1523                if( count( $mynjobs ) > 0 )
1524                {
1525                    foreach( $mynjobs as $myjob )
1526                    {
1527                        foreach( $this->filters as $filtername => $filtervalue )
1528                        {
1529                            if( $filtername!=null && $filtername!='' )
1530                            {
1531                                if( $filtername == 'jobid' && !$node->hasJob( $filtervalue) )
1532                                {
1533                                    $addhost = 0;
1534                                }
1535                                else if( $filtername != 'jobid' )
1536                                {
1537                                    if( $jobs[$myjob][$filtername] != $filtervalue )
1538                                    {
1539                                        $addhost = 0;
1540                                    }
1541                                }
1542                            }
1543                        }
1544                    }
1545                }
1546                else
1547                {
1548                    $addhost = 0;
1549                }
1550            }
1551
1552            if( $addhost )
1553            {
1554                $filtered_nodes[] = $hostname;
1555            }
1556        }
1557
1558        return $filtered_nodes;
1559    }
1560
1561    function draw()
1562    {
1563        global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH;
1564        global $BIG_CLUSTERIMAGE_MAXWIDTH, $BIG_CLUSTERIMAGE_NODEWIDTH;
1565        global $CLUSTER_CONFS, $confcluster, $SHOW_EMPTY_COLUMN, $SHOW_EMPTY_ROW;
1566
1567        global $SORTBY_HOSTNAME, $SORT_ORDER, $skan_str;
1568        global $x_first, $y_first;
1569
1570        foreach( $CLUSTER_CONFS as $confcluster => $conffile )
1571        {
1572            if( strtolower( trim($this->clustername) ) == strtolower(trim($confcluster)) )
1573            {
1574                include_once $conffile;
1575            }
1576        }
1577
1578        if( $this->isSmall() )
1579        {
1580            $max_width    = $SMALL_CLUSTERIMAGE_MAXWIDTH;
1581            $node_width    = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1582        }
1583        else if( $this->isBig() )
1584        {
1585            $max_width    = $BIG_CLUSTERIMAGE_MAXWIDTH;
1586            $node_width    = $BIG_CLUSTERIMAGE_NODEWIDTH;
1587        }
1588
1589        $nodes        = $this->getNodes();
1590        $nodes_hosts    = array_keys( $nodes );
1591
1592        $nodes_nr    = count( $nodes );
1593
1594        $nodes_size    = $nodes_nr*$node_width;
1595        $node_rows    = 0;
1596
1597        if( $nodes_size > $max_width )
1598        {
1599            $nodes_per_row = ( (int) ($max_width/$node_width) );
1600        }
1601        else
1602        {
1603            $nodes_per_row = $nodes_size;
1604            $node_rows = 1;
1605        }
1606
1607        if( $nodes_per_row < $nodes_nr )
1608        {
1609            $node_rows = ( (int) ($nodes_nr/$nodes_per_row) );
1610            $node_rest = fmod( $nodes_nr, $nodes_per_row );
1611
1612            if( $node_rest > 0 )
1613            {
1614                $node_rows++;
1615            }
1616        }
1617
1618        $y_offset    = 0;
1619        $font         = 2;
1620        $fontwidth    = ImageFontWidth( $font );
1621        $fontheight    = ImageFontHeight( $font );
1622        $fontspaceing    = 2;
1623        $y_offset    = $fontheight + (2 * $fontspaceing);
1624
1625        $this->width    = $max_width;
1626        $this->height    = ($y_offset + (($node_rows*$node_width)+1) );
1627
1628        $jobs = $this->getJobs();
1629        $filtered_nodes = $this->filterNodes( $jobs, $nodes );
1630
1631        if( $SORTBY_HOSTNAME != "" )
1632        {
1633                $sorted     = array();
1634
1635            $x_first    = 0;
1636            $y_first    = 0;
1637
1638            $skan_str    = $SORTBY_HOSTNAME;
1639
1640            global $x_present, $y_present;
1641            $x_present    = false;
1642            $y_present    = false;
1643
1644            // Should we scan by X, Y or both
1645            //
1646            if(strpos( $SORTBY_HOSTNAME, "{x}" ) != false )
1647            {
1648                $x_str        = "{x}";
1649                $x_present    = true;
1650            }
1651            else if(strpos( $SORTBY_HOSTNAME, "{X}" ) != false )
1652            {
1653                $x_str        = "{X}";
1654                $x_present    = true;
1655            }
1656            if(strpos( $SORTBY_HOSTNAME, "{y}" ) != false )
1657            {
1658                $y_str        = "{y}";
1659                $y_present    = true;
1660            }
1661            else if(strpos( $SORTBY_HOSTNAME, "{Y}" ) != false )
1662            {
1663                $y_str        = "{Y}";
1664                $y_present    = true;
1665            }
1666
1667            // If we should scan for both X and Y: see which one is first
1668            //
1669            if(( strpos( $SORTBY_HOSTNAME, $x_str ) < strpos( $SORTBY_HOSTNAME, $y_str ) ) && ( $x_present && $y_present ))
1670            {
1671                $x_first    = 1;
1672            }
1673            else if(( strpos( $SORTBY_HOSTNAME, $x_str ) > strpos( $SORTBY_HOSTNAME, $y_str ) ) && ( $x_present && $y_present ))
1674            {
1675                $y_first    = 1;
1676       
1677            }
1678            else if( $x_present )
1679            {
1680                $x_first    = 1;
1681            }
1682            else if( $y_present )
1683            {
1684                $y_first    = 1;
1685            }
1686
1687            // Now replace our {x} and {y} with %d for sscanf parsing
1688            //
1689            if(( $x_first ) && ( $x_present && $y_present ) )
1690            {
1691                $skan_str    = str_replace( $x_str, "%d", $skan_str );
1692                $skan_str    = str_replace( $y_str, "%d", $skan_str );
1693            } 
1694            else if( $x_present)
1695            {
1696                $skan_str    = str_replace( $x_str, "%d", $skan_str );
1697            }
1698            else if( $y_present)
1699            {
1700                $skan_str    = str_replace( $y_str, "%d", $skan_str );
1701            }
1702
1703            $x_min        = null;
1704            $x_max        = null;
1705            $y_min        = null;
1706            $y_max        = null;
1707
1708            $x_columns    = array();
1709            $y_rows        = array();
1710
1711            // Now let's walk through all our nodes and see which one are valid for our scan pattern
1712            //
1713            foreach( $nodes as $hostname => $node )
1714            {
1715                $x    = null;
1716                $y    = null;
1717
1718                if( $x_present && $y_present )
1719                {
1720                    if( $x_first )
1721                    {
1722                        $n = sscanf( $hostname, $skan_str, $x, $y );
1723                    }
1724                    else if( $y_first )
1725                    {
1726                        $n = sscanf( $hostname, $skan_str, $y, $x );
1727                    }
1728
1729                    // Remove nodes that don't match
1730                    //
1731                    if( $n < 2 )
1732                    {
1733                        // This node hostname has no match for: {x} and {y}
1734                        //
1735                        unset( $nodes[$hostname] );
1736                    }
1737                }
1738                else if( $x_present && !$y_present )
1739                {
1740                    $n = sscanf( $hostname, $skan_str, $x );
1741
1742                    // Remove nodes that don't match
1743                    //
1744                    if( $n < 1 )
1745                    {
1746                        // This node hostname has no match for: {x}
1747                        //
1748                        unset( $nodes[$hostname] );
1749                    }
1750                    $y    = 1;
1751                }
1752                else if( $y_present && !$x_present )
1753                {
1754                    $n = sscanf( $hostname, $skan_str, $y );
1755
1756                    // Remove nodes that don't match
1757                    //
1758                    if( $n < 1 )
1759                    {
1760                        // This node hostname has no match for: {y}
1761                        //
1762                        unset( $nodes[$hostname] );
1763                    }
1764                    $x    = 1;
1765                }
1766
1767                // Determine the lowest value of {x} that exists in all node hostnames
1768                //
1769                if( !$x_min && $x != null )
1770                {
1771                    $x_min    = $x;
1772                }
1773                else if( $x < $x_min && $x != null )
1774                {
1775                    $x_min    = $x;
1776                }
1777
1778                // Determine the highest value of {x} that exists in all node hostnames
1779                //
1780                if( !$x_max && $x != null )
1781                {
1782                    $x_max    = $x;
1783                }
1784                else if( $x > $x_max && $x != null )
1785                {
1786                    $x_max    = $x;
1787                }
1788
1789                // Determine the lowest value of {y} that exists in all node hostnames
1790                //
1791                if( !$y_min && $y != null )
1792                {
1793                    $y_min    = $y;
1794                }
1795                else if( $y < $y_min && $y != null )
1796                {
1797                    $y_min    = $y;
1798                }
1799
1800                // Determine the highest value of {y} that exists in all node hostnames
1801                //
1802                if( !$y_max && $y != null )
1803                {
1804                    $y_max    = $y;
1805                }
1806                else if( $y > $y_max && $y != null )
1807                {
1808                    $y_max    = $y;
1809                }
1810
1811                // Store which non-empty columns and rows we found
1812                //
1813                if( !in_array( $x, $x_columns ) )
1814                {
1815                    $x_columns[] = $x;
1816                }
1817                if( !in_array( $y, $y_rows ) )
1818                {
1819                    $y_rows[] = $y;
1820                }
1821            }
1822
1823            // Sort all the nodes (alpha and numerically)
1824            // 1: gb-r1n1, 2: gb-r1n2, 3: gb-r2n1, etc
1825            //
1826            $sorted_nodes    = usort( $nodes, "cmp" );
1827
1828            //print_r( $x_columns ) ;
1829
1830            $cur_node    = 0;
1831
1832            $x_offset    = 0;
1833            $y_offset    = 0;
1834            $font         = 2;
1835            $fontwidth    = ImageFontWidth( $font );
1836            $fontheight    = ImageFontHeight( $font );
1837            $fontspaceing    = 2;
1838
1839            if( $this->isSmall() ) 
1840            {
1841                $y_offset    = $y_offset + (2 * $fontspaceing) + $fontheight;
1842            }
1843
1844            if( $this->isBig() ) 
1845            {
1846                $y_offset    = ($fontheight * (1 + strlen( $x_max) ) ) + ((2 + strlen( $x_max)) * $fontspaceing);
1847                $x_offset    = ($fontwidth * (1 + strlen( $y_max) ) ) + ((2 + strlen( $y_max)) * $fontspaceing);
1848            }
1849
1850            $image_width    = $x_offset + ($node_width * ($x_max-$x_min+2));
1851
1852            if( $this->isSmall() ) 
1853            {
1854                $image_width    = $max_width;
1855            }
1856            else if( $this->isBig() ) 
1857            {
1858                $image_width    = ($image_width < $max_width) ? $image_width : $max_width;
1859            }
1860            $image_height    = $y_offset + ($node_width * ($y_max-$y_min+2));
1861
1862            $this->width    = $image_width;
1863            $this->heigth    = $image_heigth;
1864
1865            $image        = imageCreateTrueColor( $image_width, $image_height );
1866            $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
1867
1868            imageFill( $image, 0, 0, $colorwhite );
1869
1870            if( $this->isSmall() )
1871            {
1872                // Draw a fancy little header text to explain what it is
1873                //
1874                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1875
1876                imageString( $image, $font, 2, 2, "Monarch Joblist - cluster: ".$this->clustername, $colorblue );
1877            }
1878
1879            if( $this->isBig() && ( isset( $SORT_XLABEL ) || isset( $SORT_YLABEL ) ) )
1880            {
1881                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1882
1883                if( isset( $SORT_XLABEL ) )
1884                {
1885                    // Print the {x} label: rack
1886                    //
1887                    imageString( $image, $font, $x_offset, $fontspaceing, $SORT_XLABEL, $colorblue );
1888                }
1889
1890                if( isset( $SORT_YLABEL ) )
1891                {
1892                    // Stupid php without imageStringDown function... we'll make one ourself
1893                    //
1894
1895                    // Print the {y} label: node
1896                    //
1897                    imageStringDown( $image, $font, $fontspaceing, $y_offset, $SORT_YLABEL, $colorblue );
1898                }
1899            }
1900
1901            $previous_n    = 0;
1902            $previous_m    = 0;
1903            $x_empty_count    = 0;
1904            $y_empty_count    = 0;
1905
1906            // Let's start assigning x,y coordinates now
1907            //
1908            for( $n = $x_min; $n <= $x_max; $n++ )
1909            {
1910                for( $m = $y_min; $m <= $y_max; $m++ )
1911                {
1912                    if( $x_min > 0 )
1913                    {
1914                        $x    = $x_offset + ( ($n-$x_min) * $node_width ) - ($x_empty_count * $node_width);
1915                    }
1916                    if( $y_min > 0 )
1917                    {
1918                        $y    = $y_offset + ( ($m-$y_min) * $node_width ) - ($y_empty_count * $node_width);
1919                    }
1920
1921                    // Don't show empty rows/columns if option enabled
1922                    //
1923                    if( !in_array( $n, $x_columns ) && !$SHOW_EMPTY_COLUMN )
1924                    {
1925                        // Skip to next iteration: we don't want a empty column
1926                        //
1927                        if( $n > $previous_n )
1928                        {
1929                            $previous_n = $n;
1930                            $x_empty_count++;
1931                        }
1932                        continue;
1933                    }
1934                    if( !in_array( $m, $y_rows ) && !$SHOW_EMPTY_ROW )
1935
1936                    {
1937                        // Skip to next iteration: we don't want a empty column
1938                        //
1939                        if( $m > $previous_m )
1940                        {
1941                            $previous_m = $m;
1942                            $y_empty_count++;
1943                        }
1944                        continue;
1945                    }
1946
1947                    if( $this->isBig() ) 
1948                    {
1949                        // Draw y(node) column number header
1950                        //
1951                        if(( $n == $x_min ) && ( isset($SORT_YLABEL) ) )
1952                        {
1953                            $mfontspacing    = 1;
1954
1955                            $ylabel_x    = $x - ( $fontwidth * strlen( $y_max ) ) - $mfontspacing;
1956                            $ylabel_y    = $y;
1957
1958                            imageString( $image, $font, $ylabel_x, $ylabel_y, strval( $m ), $colorblue );
1959
1960                            $xmin_hit[$n]    = true;
1961                        }
1962
1963                        // Draw x(rack) column number header
1964                        //
1965                        if(( $m == $y_min ) && ( isset($SORT_XLABEL) ) )
1966                        {
1967                            $mfontspacing    = 2;
1968                            $xlabel_y    = $y - ( $fontheight * strlen( $x_max ) );
1969                            $xlabel_x    = $x + $mfontspacing; 
1970
1971                            imageStringDown( $image, $font, $xlabel_x, $xlabel_y, strval( $n ), $colorblue );
1972                        }
1973                    }
1974
1975                    if( isset( $nodes[$cur_node] ) ) 
1976                    {
1977                        $host    = $nodes[$cur_node]->getHostname();
1978
1979                        if( $x_present && $y_present )
1980                        {
1981                            if( $x_first )
1982                            {
1983                                $nn = sscanf( $host, $skan_str, $rx, $ry );
1984                            }
1985                            else if( $y_first )
1986                            {
1987                                $nn = sscanf( $host, $skan_str, $ry, $rx );
1988                            }
1989                            if ( $nn < 2 )
1990                            {
1991                                //printf( "skipping node %s - y present & x present + <2 x,y matchs\n", $host);
1992                                continue;
1993                            }
1994                            if( intval( $rx ) > $n )
1995                            {
1996                                // If x(rack) is higher than current x, skip to next x(rack)
1997                                //
1998                                $m        = $y_max + 1;
1999
2000                                continue;
2001                            }
2002                            if( intval( $ry ) > $m )
2003                            {
2004                                // If y(node) is higher than current y, skip to next y(node)
2005                                //
2006                                continue;
2007                            }
2008                        }
2009                        else if( $x_present )
2010                        {
2011                            $nn = sscanf( $host, $skan_str, $rx );
2012                        }
2013                        else if( $y_present )
2014                        {
2015                            $nn = sscanf( $host, $skan_str, $ry );
2016                        }
2017
2018                        if( !in_array( $host, $filtered_nodes ) )
2019                        {
2020                            // This node has been filtered out: we only want to see certain nodes
2021                            //
2022                            $nodes[$cur_node]->setShowinfo( 0 );
2023                        }
2024
2025                        $nodes[$cur_node]->setCoords( $x, $y );
2026                        $nodes[$cur_node]->setImage( $image );
2027
2028                        if( $this->isSmall() )
2029                        {
2030                            $nodes[$cur_node]->drawSmall();
2031                        }
2032                        else if( $this->isBig() )
2033                        {
2034                            $nodes[$cur_node]->drawBig();
2035                        }
2036
2037                        $cur_node++;
2038                    }
2039                }
2040            }
2041
2042        }
2043        else
2044        {
2045            if( $this->isSmall() )
2046            {
2047                $image        = imageCreateTrueColor( $max_width, ($y_offset + (($node_rows*$node_width)+1) ) );
2048            }
2049            else if( $this->isBig() )
2050            {
2051                $image_width    = ($node_width * $nodes_nr) + 2;
2052                $image_width    = ($image_width < $max_width) ? $image_width : $max_width;
2053                $image        = imageCreateTrueColor( $image_width, ($y_offset + (($node_rows*$node_width)+1) ) );
2054            }
2055            $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
2056
2057            imageFill( $image, 0, 0, $colorwhite );
2058
2059            if( $this->isSmall() )
2060            {
2061                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
2062
2063                imageString( $image, $font, 2, 2, "Monarch Joblist - cluster: ".$this->clustername, $colorblue );
2064            }
2065
2066            for( $n = 0; $n < $node_rows; $n++ )
2067            {
2068                for( $m = 0; $m < $nodes_per_row; $m++ )
2069                {
2070                    $x = ($m * $node_width);
2071                    $y = $y_offset + ($n * $node_width);
2072
2073                    $cur_node = ($n * $nodes_per_row) + ($m);
2074                    $host = isset( $nodes_hosts[$cur_node] ) ? $nodes_hosts[$cur_node] : '';
2075
2076                    if( isset( $nodes[$host] ) )
2077                    {
2078                        $nodes[$host]->setCoords( $x, $y );
2079                        $nodes[$host]->setImage( $image );
2080
2081                        if( !in_array( $host, $filtered_nodes ) )
2082                        {
2083                            $nodes[$host]->setShowinfo( 0 );
2084                        }
2085
2086                        if( $this->isSmall() )
2087                        {
2088                            $nodes[$host]->drawSmall();
2089                        }
2090                        else if( $this->isBig() )
2091                        {
2092                            $nodes[$host]->drawBig();
2093                        }
2094                    }
2095                }
2096            }
2097        }
2098   
2099        $this->nodes    = &$nodes;
2100
2101        if ($this->output)
2102        {
2103            header( 'Content-type: image/png' );
2104            imagePNG( $image );
2105            imageDestroy( $image );
2106        }
2107    }
2108
2109    function getImagemapArea()
2110    {
2111        $clusterimage_map    = "";
2112
2113        $nodes = &$this->getNodes();
2114
2115        foreach( $nodes as $node )
2116        {
2117            $node_map          = $node->getImagemapArea();
2118            $clusterimage_map .= $node_map;
2119        }
2120
2121        return $clusterimage_map;
2122    }
2123}
2124
2125class EmptyImage
2126{
2127    function draw()
2128    {
2129        $image        = imageCreateTrueColor( 1, 1 );
2130        $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
2131        imageFill( $image, 0, 0, $colorwhite );                         
2132
2133        header( 'Content-type: image/png' );
2134        imagePNG( $image );
2135        imageDestroy( $image );
2136    }
2137}
2138
2139class HostImage
2140{
2141    var $data_gather, $cluster, $host, $node, $image;
2142    var $headerstrlen;
2143
2144    function HostImage( $data_gather, $cluster, $host )
2145    {
2146        $this->data_gather     = $data_gather;
2147        $this->cluster        = $cluster;
2148        $this->host        = $host;
2149        $this->y_offset        = 0;
2150        $this->font        = 2;
2151        $this->fontspaceing    = 2;
2152        $this->headerstrlen    = array();
2153
2154        $this->fontheight    = ImageFontHeight( $this->font );
2155        $this->fontwidth    = ImageFontWidth( $this->font );
2156
2157        $dg            = &$this->data_gather;
2158        $this->node        = &$dg->getNode( $this->host );
2159        $n            = &$this->node;
2160        $this->njobs        = $n->getJobs();
2161    }
2162
2163    function drawJobs()
2164    {
2165        $dg                     = &$this->data_gather;
2166        $colorblack        = imageColorAllocate( $this->image, 0, 0, 0 );
2167
2168        for( $n = 0; $n < count( $this->njobs ); $n++ )
2169        {
2170            $jobid            = $this->njobs[$n];
2171            $jobinfo        = $dg->getJob( $jobid );
2172
2173            $xoffset        = 5;
2174            imageString( $this->image, $this->font, $xoffset, $this->y_offset, strval( $jobid ), $colorblack );
2175
2176            foreach( $this->headerstrlen as $headername => $headerlen )
2177            {
2178                if( $headername == 'nodes' )
2179                {
2180                    $attrval    = strval( count( $jobinfo['nodes'] ) );
2181                }
2182                else if( $headername == 'cpus' )
2183                {
2184                    if( !isset( $jobinfo['ppn'] ) )
2185                    {
2186                        $jobinfo['ppn'] = 1;
2187                    }
2188
2189                    $attrval    = strval( count( $jobinfo['nodes'] ) * intval( $jobinfo['ppn'] ) );
2190                }
2191                else if( $headername == 'runningtime' )
2192                {
2193                    $attrval    = makeTime( intval( $jobinfo['reported'] ) - intval( $jobinfo['start_timestamp'] ) );
2194                }
2195                else
2196                {
2197                    $attrval    = strval( $jobinfo[$headername] );
2198                }
2199
2200                imageString( $this->image, $this->font, $xoffset, $this->y_offset, $attrval, $colorblack );
2201       
2202                $xoffset    = $xoffset + ($this->fontwidth * ( $headerlen + 1 ) );
2203            }
2204           
2205            $this->newLineOffset();
2206        }
2207    }
2208
2209    function drawHeader()
2210    {
2211        $dg                     = &$this->data_gather;
2212
2213        for( $n = 0; $n < count( $this->njobs ); $n++ )
2214        {
2215            $jobid            = $this->njobs[$n];
2216            $jobinfo        = $dg->getJob( $jobid );
2217
2218            if( !isset( $this->headerstrlen['id'] ) )
2219            {
2220                $this->headerstrlen['id']    = strlen( strval( $jobid ) );
2221            }
2222            else if( strlen( strval( $jobid ) ) > $this->headerstrlen['id'] )
2223            {
2224                $this->headerstrlen['id']    = strlen( strval( $jobid ) );
2225            }
2226
2227            if( !isset( $this->headerstrlen['owner'] ) )
2228            {
2229                $this->headerstrlen['owner']    = strlen( strval( $jobinfo['owner'] ) );
2230            }
2231            else if( strlen( strval( $jobinfo['owner'] ) ) > $this->headerstrlen['owner'] )
2232            {
2233                $this->headerstrlen['owner']    = strlen( strval( $jobinfo['owner'] ) );
2234            }
2235
2236            if( !isset( $this->headerstrlen['queue'] ) )
2237            {
2238                $this->headerstrlen['queue']    = strlen( strval( $jobinfo['queue'] ) );
2239            }
2240            else if( strlen( strval( $jobinfo['queue'] ) ) > $this->headerstrlen['queue'] )
2241            {
2242                $this->headerstrlen['queue']    = strlen( strval( $jobinfo['queue'] ) );
2243            }
2244
2245            if( !isset( $jobinfo['ppn'] ) )
2246            {
2247                $jobinfo['ppn'] = 1;
2248            }
2249
2250            $cpus            = count( $jobinfo['nodes'] ) * intval( $jobinfo['ppn'] );
2251
2252            if( !isset( $this->headerstrlen['cpus'] ) )
2253            {
2254                $this->headerstrlen['cpus']    = strlen( strval( $cpus ) );
2255            }
2256            else if( strlen( strval( $cpus ) ) > $this->headerstrlen['cpus'] )
2257            {
2258                $this->headerstrlen['cpus']    = strlen( strval( $cpus ) );
2259            }
2260
2261            $nodes            = count( $jobinfo['nodes'] );
2262
2263            if( !isset( $this->headerstrlen['nodes'] ) )
2264            {
2265                $this->headerstrlen['nodes']    = strlen( strval( $nodes ) );
2266            }
2267            else if( strlen( strval( $nodes) ) > $this->headerstrlen['nodes'] )
2268            {
2269                $this->headerstrlen['nodes']    = strlen( strval( $nodes ) );
2270            }
2271
2272            $runningtime        = makeTime( intval( $jobinfo[reported] ) - intval( $jobinfo['start_timestamp'] ) );
2273
2274            if( !isset( $this->headerstrlen['runningtime'] ) )
2275            {
2276                $this->headerstrlen['runningtime']    = strlen( strval( $runningtime) );
2277            }
2278            else if( strlen( strval( $runningtime) ) > $this->headerstrlen['runningtime'] )
2279            {
2280                $this->headerstrlen['runningtime']    = strlen( strval( $runningtime) );
2281            }
2282
2283            if( !isset( $this->headerstrlen['name'] ) )
2284            {
2285                $this->headerstrlen['name']    = strlen( strval( $jobinfo['name'] ) );
2286            }
2287            else if( strlen( strval( $jobinfo['name'] ) ) > $this->headerstrlen['name'] )
2288            {
2289                $this->headerstrlen['name']    = strlen( strval( $jobinfo['name'] ) );
2290            }
2291        }
2292
2293        $xoffset    = 5;
2294
2295        foreach( $this->headerstrlen as $headername => $headerlen )
2296        {
2297            $colorgreen    = imageColorAllocate( $this->image, 0, 200, 0 );
2298
2299            if( $headerlen < strlen( $headername ) )
2300            {
2301                $this->headerstrlen[$headername]    = strlen( $headername );
2302            }
2303
2304            imageString( $this->image, $this->font, $xoffset, $this->y_offset, ucfirst( $headername ), $colorgreen );
2305
2306            $xoffset    = $xoffset + ($this->fontwidth * ( $this->headerstrlen[$headername] + 1 ) );
2307        }
2308        $this->newLineOffset();
2309    }
2310
2311    function newLineOffset()
2312    {
2313        $this->y_offset        = $this->y_offset + $this->fontheight + $this->fontspaceing;
2314    }
2315
2316    function draw()
2317    {
2318        $xlen        = 450;
2319        $ylen        = ( count( $this->njobs ) * ( $this->fontheight + $this->fontspaceing ) ) + (3 * $this->fontheight);
2320
2321        $this->image    = imageCreateTrueColor( $xlen, $ylen );
2322        $colorwhite    = imageColorAllocate( $this->image, 255, 255, 255 );
2323        imageFill( $this->image, 0, 0, $colorwhite );                         
2324
2325        $colorblue    = imageColorAllocate( $this->image, 0, 0, 255 );
2326
2327        imageString( $this->image, $this->font, 1, $this->y_offset, "Monarch Joblist - host: ".$this->host, $colorblue );
2328        $this->newLineOffset();
2329
2330        $this->drawHeader();
2331        $this->drawJobs();
2332
2333        header( 'Content-type: image/png' );
2334        imagePNG( $this->image );
2335        imageDestroy( $this->image );
2336    }
2337}
2338
2339function imageStringDown( &$image, $font, $x, $y, &$s, &$col )
2340{
2341    $fw    = imagefontwidth( $font);
2342    $fh    = imagefontheight( $font);
2343   
2344    $fontspacing = 0;
2345
2346    $fx    = $x;
2347    $fy    = $y;
2348
2349    for( $n=0; $n<strlen( $s ); $n++ )
2350    {
2351        $myc    = $s{$n};
2352
2353        imagestring( $image, $font, $fx, $fy, $myc, $col );
2354
2355        $fy    += ($fontspacing + $fh );
2356    }
2357}
2358
2359function array_rem( $val, &$arr )
2360{
2361    // Delete val from arr
2362    //
2363    $i    = array_search( $val, $arr );
2364
2365    if( $i == false ) return false;
2366
2367    $arr    = array_merge( array_slice( $arr, 0, $i ), array_slice( $arr, $i+1, count( $arr ) ) );
2368
2369    return true;
2370}
2371
2372function cmp( $a, $b ) 
2373{
2374    global $SORT_ORDER;
2375    global $skan_str;
2376    global $x_first, $y_first;
2377    global $x_present, $y_present;
2378
2379    $a_node        = $a;
2380    $b_node        = $b;
2381    $a        = $a_node->getHostname();
2382    $b        = $b_node->getHostname();
2383
2384    if( $a == $b ) return 0;
2385
2386    $a_x        = 0;
2387    $b_x        = 0;
2388    $a_y        = 0;
2389    $b_y        = 0;
2390
2391    if( $x_present && $y_present )
2392    {
2393        if( $x_first )
2394        {
2395            $n = sscanf( $a, $skan_str, $a_x, $a_y );
2396            $n = sscanf( $b, $skan_str, $b_x, $b_y );
2397        }
2398        else if( $y_first )
2399        {
2400            $n = sscanf( $a, $skan_str, $a_y, $a_x );
2401            $n = sscanf( $b, $skan_str, $b_y, $b_x );
2402        }
2403    } 
2404    else if( $x_present && !$y_present )
2405    {
2406        $n = sscanf( $a, $skan_str, $a_x );
2407        $n = sscanf( $b, $skan_str, $b_x );
2408    }
2409    else if( $y_present && !$x_present )
2410    {
2411        $n = sscanf( $a, $skan_str, $a_y );
2412        $n = sscanf( $b, $skan_str, $b_y );
2413    }
2414
2415    if ( $SORT_ORDER=="desc" )
2416    {
2417
2418        if( $x_present && $y_present )
2419        {
2420            // 1  = a < b
2421            // -1 = a > b
2422            //
2423            if ($a_x == $b_x)
2424            {
2425                if ($a_y < $b_y)
2426                {
2427                    return 1;
2428                }
2429                else if ($a_y > $b_y)
2430                {
2431                    return -1;
2432                }
2433            }
2434            else if ($a_x < $b_x)
2435            {
2436                return 1;
2437            }
2438            else if ($a_x > $b_x)
2439            {
2440                return -1;
2441            }
2442        } 
2443        else if( $x_present && !$y_present )
2444        {
2445            if ($a_x < $b_x)
2446            {
2447                return 1;
2448            }
2449            else if ($a_x > $b_x)
2450            {
2451                return -1;
2452            }
2453        }
2454        else if( $y_present && !$x_present )
2455        {
2456            if ($a_y < $b_y)
2457            {
2458                return 1;
2459            }
2460            else if ($a_y > $b_y)
2461            {
2462                return -1;
2463            }
2464        }
2465    }
2466    else if ( $SORT_ORDER == "asc" )
2467    {
2468
2469        if( $x_present && $y_present )
2470        {
2471            // 1  = a > b
2472            // -1 = a < b
2473            //
2474            if ($a_x == $b_x)
2475            {
2476                if ($a_y > $b_y)
2477                {
2478                    return 1;
2479                }
2480                else if ($a_y < $b_y)
2481                {
2482                    return -1;
2483                }
2484            }
2485            else if ($a_x > $b_x)
2486            {
2487                return 1;
2488            }
2489            else if ($a_x < $b_x)
2490            {
2491                return -1;
2492            }
2493        }
2494        else if( $x_present && !$y_present )
2495        {
2496            if ($a_x > $b_x)
2497            {
2498                return 1;
2499            }
2500            else if ($a_x < $b_x)
2501            {
2502                return -1;
2503            }
2504        }
2505        else if( $y_present && !$x_present )
2506        {
2507            if ($a_y > $b_y)
2508            {
2509                return 1;
2510            }
2511            else if ($a_y < $b_y)
2512            {
2513                return -1;
2514            }
2515        }
2516    }
2517}
2518function makeTime( $time )
2519{
2520        $days = intval( $time / 86400 );
2521        $time = ($days>0) ? $time % ($days * 86400) : $time;
2522
2523        $date_str = '';
2524        $day_str = '';
2525
2526        if( $days > 0 )
2527        {
2528            if( $days > 1 )
2529            {
2530                $day_str .= $days . ' days';
2531            }
2532            else
2533            {
2534                $day_str .= $days . ' day';
2535            }
2536        }
2537
2538        $hours = intval( $time / 3600 );
2539        $time = $hours ? $time % ($hours * 3600) : $time;
2540
2541        if( $hours > 0 )
2542        {
2543             $date_str .= $hours . ':';
2544             $date_unit = 'hours'; 
2545        }
2546
2547        $minutes = intval( $time / 60 );
2548        $seconds = $minutes ? $time % ($minutes * 60) : $time;
2549
2550        if( $minutes > 0 )
2551        {
2552            if( $minutes >= 10 )
2553            {
2554                $date_str .= $minutes . ':';
2555            }
2556            else
2557            {
2558                $date_str .= '0' . $minutes . ':';
2559            }
2560                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
2561        }
2562        else
2563        {
2564            if($hours > 0 )
2565            {
2566                $date_str .= '00:';
2567                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
2568            }
2569        }
2570
2571        $date_unit = (!isset($date_unit)) ? 'seconds' : $date_unit;
2572
2573        if( $seconds > 0 )
2574        {
2575            if( $seconds >= 10 )
2576            {
2577                $date_str .= $seconds . ' ' . $date_unit;
2578            }
2579            else
2580            {
2581                $date_str .= '0' . $seconds . ' ' . $date_unit;
2582            }
2583        }
2584        else if ( $hours > 0 or $minutes > 0 )
2585        {
2586            $date_str .= '00 ' . $date_unit;
2587        }
2588
2589        if( $days > 0)
2590        {
2591            if( $hours > 0 or $minutes > 0 or $seconds > 0 )
2592            {
2593                $date_str = $day_str . ' - ' . $date_str;
2594            }
2595            else
2596            {
2597                $date_str = $day_str;
2598            }
2599        }
2600        return $date_str;
2601}
2602?>
Note: See TracBrowser for help on using the repository browser.