source: branches/1.0/web/addons/job_monarch/libtoga.php @ 865

Last change on this file since 865 was 865, checked in by ramonb, 11 years ago

libtoga.php:

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