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

Last change on this file since 874 was 874, checked in by ramonb, 8 years ago

libtoga.php:

  • modified XML processor to try and tackle DNS/hostname/FQDN inconsistency issue
  • each individual gangliahost can have different hostname style: short or FQDN
  • determine for each gangliahost if it is FQDN or short hostname during XML HOST processing
  • moved job/node/gangliahost association to finishUp(): first all ganglia hosts must be processed and FQDN detection completed
  • during job/node/gangliahost association use FQDN/short detected hostname as determined during XML processing

overview.php:

  • let XML processor (via data gatherer) decide if to use use FQDN or short hostname
  • Property svn:keywords set to Id
File size: 72.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 874 2013-05-16 19:47:03Z 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 getMetrics()
601    {
602        $handler = $this->xmlhandler;
603        return $handler->getMetrics();
604    }
605    function getNodes()
606    {
607        $handler = $this->xmlhandler;
608        return $handler->getNodes();
609    }
610
611    function getNode( $node )
612    {
613        $handler = $this->xmlhandler;
614        return $handler->getNode( $node );
615    }
616
617    function getCpus()
618    {
619        $handler = $this->xmlhandler;
620        return $handler->getCpus();
621    }
622
623    function getJobs()
624    {
625        $handler = $this->xmlhandler;
626        return $handler->getJobs();
627    }
628
629    function getJob( $job )
630    {
631        $handler = $this->xmlhandler;
632        return $handler->getJob( $job );
633    }
634
635    function getHeartbeat()
636    {
637        $handler = $this->xmlhandler;
638        return $handler->getHeartbeat();
639    }
640
641    function isJobmonRunning()
642    {
643        $handler = $this->xmlhandler;
644        return $handler->isJobmonRunning();
645    }
646
647    function makeHostname( $ahost, $adomain )
648    {
649        $handler = $this->xmlhandler;
650        return $handler->makeHostname( $ahost, $adomain );
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          = array();
671    }
672
673    function getCpus()
674    {
675        $cpus = 0;
676
677        if( isset( $this->jobs ) && count( $this->jobs ) > 0 )
678        {
679            foreach( $this->jobs as $jobid=>$jobattrs )
680            {
681                $nodes    = count( $jobattrs['nodes'] );
682                $ppn    = (int) $jobattrs['ppn'] ? $jobattrs['ppn'] : 1;
683                $mycpus    = $nodes * $ppn;
684
685                $cpus    = $cpus + $mycpus;
686            }
687        }
688    }
689
690    function isJobmonRunning()
691    {
692        if (isset( $this->heartbeat['time'] ))
693        {
694            return 1;
695        }
696        else
697        {
698            return 0;
699        }
700    }
701
702    function isFqdn( $somehost )
703    {
704        $chr_count = count_chars( $somehost );
705        $dot_count = $chr_count[ ord('.') ];
706
707        if( $dot_count > 1 )
708        {
709            return true;
710        }
711        return false;
712    }
713
714    function makeHostname( $thostname, $tdomain )
715    {
716        $mhost = $thostname;
717
718        if( ( $this->fqdn[ $thostname ] === true ) && isset( $tdomain ) && ( $tdomain !== '' ) )
719        {
720            if( strpos( $thostname, $tdomain ) === false )
721            {
722                $mhost = $thostname . '.' . $tdomain;
723            } 
724        }
725
726        return $mhost;
727    }
728
729    function startElement( $parser, $name, $attrs )
730    {
731        global $cluster, $metrics, $self, $grid;
732
733        $jobid = null;
734
735        if( $name == 'GRID' )
736        {
737            $self = $attrs['NAME'];
738            $grid = $attrs;
739
740            return null;
741        }
742
743        if( $name == 'CLUSTER' )
744        {
745            // ganglia start
746            $cluster = $attrs;
747            // ganglia end
748
749            $this->proc_cluster = $attrs['NAME'];
750            //printf("set proc cluster to %s\n", $attrs['NAME'] );
751            return null;
752        }
753        if( $this->proc_cluster != $this->clustername )
754        {
755            //printf("cluster does not match: %s\n", $this->clustername );
756            return null;
757        }
758
759        if( $name == 'HOST' )
760        {
761            // ganglia start
762            $hostname = $attrs['NAME'];
763            $this->proc_hostname = $hostname;
764
765            if( $this->isFqdn( $hostname ) === true )
766            {
767                $host_fields = explode( '.', $hostname );
768                $shorthost   = $host_fields[0];
769
770                $this->fqdn[ $shorthost ] = true;
771            }
772            else
773            {
774                $this->fqdn[ $hostname ] = false;
775            }
776
777            # Pseudo metrics - add useful HOST attributes like gmond_started & last_reported to the metrics list:
778            $metrics[$hostname]['gmond_started']['NAME'] = "GMOND_STARTED";
779            $metrics[$hostname]['gmond_started']['VAL'] = $attrs['GMOND_STARTED'];
780            $metrics[$hostname]['gmond_started']['TYPE'] = "timestamp";
781            $metrics[$hostname]['last_reported']['NAME'] = "REPORTED";
782            $metrics[$hostname]['last_reported']['VAL'] = $attrs['REPORTED'];
783            $metrics[$hostname]['last_reported']['TYPE'] = "string";
784            $metrics[$hostname]['ip_address']['NAME'] = "IP";
785            $metrics[$hostname]['ip_address']['VAL'] = $attrs['IP'];
786            $metrics[$hostname]['ip_address']['TYPE'] = "string";
787            $metrics[$hostname]['location']['NAME'] = "LOCATION";
788            $metrics[$hostname]['location']['VAL'] = $attrs['LOCATION'];
789            $metrics[$hostname]['location']['TYPE'] = "string";
790            // ganglia end
791
792            //printf( "host %s\n", $hostname );
793            //$location = $attrs['LOCATION'];
794
795            if( !isset( $this->nodes[$hostname] ) )
796            {
797                $this->nodes[$hostname] = new NodeImage( $this->proc_cluster, $hostname );
798            }
799            return null;
800        }
801
802        if( $name == 'METRIC' )
803        {
804            $hostname = $this->proc_hostname;
805
806            // ganglia start
807            $metricname = rawurlencode($attrs['NAME']);
808            $metrics[$hostname][$metricname] = $attrs;
809            // ganglia end
810
811            if ( strpos( $attrs['NAME'], 'zplugin_monarch' ) === false )
812            {
813                return null;
814            }
815
816            if( strpos( $attrs['NAME'], 'zplugin_monarch_heartbeat' ) !== false )
817            {
818                $this->heartbeat['time'] = $attrs['VAL'];
819                return null;
820            }
821            else if( strpos( $attrs['NAME'], 'zplugin_monarch_down' ) !== false )
822            {
823                $fields        = explode( ' ', $attrs['VAL'] );
824
825                $nodes_down    = array();
826                $down_domain   = null;
827
828                foreach( $fields as $f )
829                {
830                    $togavalues  = explode( '=', $f );
831
832                    $toganame    = $togavalues[0];
833                    $togavalue   = $togavalues[1];
834
835                    if( $toganame == 'nodes' )
836                    {
837                        $mynodes = explode( ';', $togavalue );
838
839                        foreach( $mynodes as $node )
840                        {
841                            $nodes_down[] = $node;
842                        }
843                    }
844                    else if( $toganame == 'domain' )
845                    {
846                        $down_domain = $togavalue;
847                    }
848                    else if( $toganame == 'reported' )
849                    {
850                        if( !isset( $this->down_nodes['heartbeat'] ) )
851                        {
852                            $this->down_nodes[$togavalue] = array( $nodes_down, $down_domain );
853                        }
854                    }
855                }
856                return;
857            }
858            else if( strpos( $attrs['NAME'], 'zplugin_monarch_offline' ) !== false )
859            {
860                $fields         = explode( ' ', $attrs['VAL'] );
861
862                $nodes_offline  = array();
863                $offline_domain = null;
864
865                foreach( $fields as $f )
866                {
867                    $togavalues = explode( '=', $f );
868
869                    $toganame   = $togavalues[0];
870                    $togavalue  = $togavalues[1];
871
872                    if( $toganame == 'nodes' )
873                    {
874                        $mynodes = explode( ';', $togavalue );
875
876                        foreach( $mynodes as $node )
877                        {
878                            $nodes_offline[] = $node;
879                        }
880                    }
881                    else if( $toganame == 'domain' )
882                    {
883                        $offline_domain = $togavalue;
884                    }
885                    else if( $toganame == 'reported' )
886                    {
887                        if( !isset( $this->offline_nodes['heartbeat'] ) )
888                        {
889                            $this->offline_nodes[$togavalue] = array( $nodes_offline, $offline_domain );
890                        }
891                    }
892                }
893                return;
894            }
895            else if( strpos( $attrs['NAME'], 'zplugin_monarch_job' ) !== false )
896            {
897                sscanf( $attrs['NAME'], 'zplugin_monarch_job_%d_%s$', $monincr, $jobid );
898
899                if( !isset( $this->jobs[$jobid] ) )
900                {
901                    $this->jobs[$jobid] = array();
902                }
903
904                $fields = explode( ' ', $attrs['VAL'] );
905
906                foreach( $fields as $f )
907                {
908                    $togavalues = explode( '=', $f );
909
910                    $toganame   = $togavalues[0];
911                    $togavalue  = $togavalues[1];
912
913                    if( $toganame == 'nodes' )
914                    {
915                        if( $this->jobs[$jobid]['status'] == 'R' )
916                        {
917                            if( !isset( $this->jobs[$jobid][$toganame] ) )
918                            {
919                                $this->jobs[$jobid][$toganame] = array();
920                            }
921
922                            $mynodes = explode( ';', $togavalue );
923
924                            foreach( $mynodes as $node )
925                            {
926                                if( !in_array( $node, $this->jobs[$jobid][$toganame] ) )
927                                {
928                                    array_push( $this->jobs[$jobid][$toganame], $node );
929                                }
930                            }
931
932                        }
933                        else if( $this->jobs[$jobid]['status'] == 'Q' )
934                        {
935                            $this->jobs[$jobid][$toganame] = $togavalue;
936                        }
937                    }
938                    else
939                    {
940                        $this->jobs[$jobid][$toganame] = $togavalue;
941                    }
942                }
943
944            }
945            return;
946        }
947    }
948
949    function finishUp( )
950    {
951        $nodes    = $this->nodes;
952
953        foreach( $this->jobs as $jobid => &$jobattrs )
954        {
955            if( isset( $this->jobs[$jobid]['nodes'] ) )
956            {
957                $nr_nodes = count( $this->jobs[$jobid]['nodes'] );
958       
959                if( $this->jobs[$jobid]['status'] == 'R' )
960                {
961                    foreach( $this->jobs[$jobid]['nodes'] as $node )
962                    {
963                        $domain = $this->jobs[$jobid]['domain'];
964                        $host   = $this->makeHostname( $node, $domain );
965
966                        if( !isset( $nodes[$host] ) )
967                        {
968                            $my_node = new NodeImage( $this->proc_cluster, $host );
969                        }
970                        else
971                        {
972                            $my_node = $nodes[$host];
973                        }
974
975                        if( !$my_node->hasJob( $jobid ) )
976                        {
977                            if( isset( $this->jobs[$jobid]['ppn'] ) )
978                            {
979                                $my_node->addJob( $jobid, ((int) $this->jobs[$jobid]['ppn']) );
980                            }
981                            else
982                            {
983                                $my_node->addJob( $jobid, 1 );
984                            }
985                        }
986
987                        $nodes[$host] = $my_node;
988                    }
989                }
990            }
991        }
992
993        if( sizeof( $this->down_nodes ) > 0 )
994        {
995            foreach( $this->down_nodes as $reported => $dnodes )
996            {
997                if( $reported == $this->heartbeat['time'] )
998                {
999                    $domain = $dnodes[1];
1000
1001                    foreach( $dnodes[0] as $downhost )
1002                    {
1003                        $downhost = $this->makeHostname( $downhost, $domain );
1004
1005                        if( isset( $nodes[$downhost] ) )
1006                        {
1007                            // OMG PHP4 is fking stupid!
1008                            // $nodes[$downhost]->setDown( 1 ) won't work here..
1009                            //
1010                            $mynode = $nodes[$downhost];
1011                            $mynode->setDown( 1 );
1012                            $nodes[$downhost] = $mynode;
1013                        }
1014                    }
1015                }
1016            }
1017        }
1018
1019        if( sizeof( $this->offline_nodes ) > 0 )
1020        {
1021            foreach( $this->offline_nodes as $reported => $onodes )
1022            {
1023                if( $reported == $this->heartbeat['time'] )
1024                {
1025                    $domain = $onodes[1];
1026
1027                    foreach( $onodes[0] as $offlinehost )
1028                    {
1029                        $offlinehost = $this->makeHostname( $offlinehost, $domain );
1030
1031                        if( isset( $nodes[$offlinehost] ) )
1032                        {
1033                            // OMG PHP4 is fking stupid!
1034                            // $nodes[$offlinehost]->setDown( 1 ) won't work here..
1035                            //
1036                            $mynode = $nodes[$offlinehost];
1037                            $mynode->setOffline( 1 );
1038                            $nodes[$offlinehost] = $mynode;
1039                        }
1040                    }
1041                }
1042            }
1043        }
1044
1045        $this->nodes = $nodes;
1046    }
1047
1048    function stopElement( $parser, $name )
1049    {
1050    }
1051
1052    function printInfo()
1053    {
1054        $jobs = &$this->jobs;
1055
1056        printf( "---jobs---\n" );
1057
1058        foreach( $jobs as $jobid => $job )
1059        {
1060            printf( "job %s\n", $jobid );
1061
1062            if( isset( $job['nodes'] ) )
1063            {
1064                foreach( $job['nodes'] as $node )
1065                {
1066                    $mynode = $this->nodes[$node];
1067                    $hostname = $mynode->getHostname();
1068                    $location = $mynode->getLocation();
1069
1070                    printf( "\t- node %s\tlocation %s\n", $hostname, $location );
1071                }
1072            }
1073        }
1074
1075        printf( "---nodes---\n" );
1076
1077        $nodes = &$this->nodes;
1078
1079        foreach( $nodes as $node )
1080        {
1081            $hostname = $node->getHostname();
1082            $location = $node->getLocation();
1083            $jobs = implode( ' ', $node->getJobs() );
1084            printf( "* node %s\tlocation %s\tjobs %s\n", $hostname, $location, $jobs );
1085        }
1086    }
1087
1088    function getNodes()
1089    {
1090        return $this->nodes;
1091    }
1092
1093    function getNode( $node )
1094    {
1095        $nodes = &$this->nodes;
1096
1097        if( isset( $nodes[$node] ) )
1098        {
1099            return $nodes[$node];
1100        }
1101        else
1102        {
1103            return NULL;
1104        }
1105    }
1106
1107    function getJobs()
1108    {
1109        return $this->jobs;
1110    }
1111
1112    function getJob( $job )
1113    {
1114        $jobs = &$this->jobs;
1115
1116        if( isset( $jobs[$job] ) )
1117        {
1118            return $jobs[$job];
1119        }
1120        else
1121        {
1122            return NULL;
1123        }
1124    }
1125
1126    function getHeartbeat()
1127    {
1128        return $this->heartbeat['time'];
1129    }
1130}
1131
1132class NodeImage
1133{
1134    var $image, $x, $y, $hostname, $jobs, $tasks, $showinfo;
1135
1136    function NodeImage( $cluster, $hostname )
1137    {
1138        global $SMALL_CLUSTERIMAGE_NODEWIDTH;
1139
1140        $this->jobs        = array();
1141        $this->tasks        = 0;
1142        $this->hostname        = $hostname;
1143        $this->clustername    = $cluster;
1144        $this->showinfo        = 1;
1145        $this->size        = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1146        $this->down        = 0;
1147        $this->offline        = 0;
1148    }
1149
1150    function addJob( $jobid, $cpus )
1151    {
1152        $jobs        = &$this->jobs;
1153        $jobs[]        = $jobid;
1154        $this->jobs    = $jobs;
1155
1156        $this->addTask( $cpus );
1157    }
1158
1159    function hasJob( $jobid )
1160    {
1161        $jobfound = 0;
1162
1163        if( count( $this->jobs ) > 0 )
1164        {
1165            foreach( $this->jobs as $job )
1166            {
1167                if( $job == $jobid )
1168                {
1169                    $jobfound = 1;
1170                }
1171            }
1172        }
1173
1174        return $jobfound;
1175    }
1176
1177    function addTask( $cpus )
1178    {
1179        $this->tasks = $this->tasks + $cpus;
1180    }
1181    function setDown( $down )
1182    {
1183        $this->down = $down;
1184    }
1185    function isDown()
1186    {
1187        return $this->down;
1188    }
1189    function setOffline( $offline )
1190    {
1191        $this->offline = $offline;
1192    }
1193    function isOffline()
1194    {
1195        return $this->offline;
1196    }
1197    function setImage( $image )
1198    {
1199        $this->image = $image;
1200    }
1201    function setCoords( $x, $y )
1202    {
1203        $this->x = $x;
1204        $this->y = $y;
1205    }
1206    function getX()
1207    {
1208        return $this->x;
1209    }
1210    function getY()
1211    {
1212        return $this->y;
1213    }
1214
1215    function getImagemapArea()
1216    {
1217        $area_topleft        = $this->x . "," . $this->y;
1218        $area_bottomright    = ($this->x + $this->size) . "," . ($this->y + $this->size);
1219        $area_coords        = $area_topleft . "," . $area_bottomright;
1220
1221        $area_href        = "./?c=" . $this->clustername . "&h=" . $this->hostname;
1222
1223        $area_tooltip        = $this->hostname;
1224
1225        if( $this->down)
1226        {
1227            $area_tooltip        = $area_tooltip . ": DOWN";
1228        }
1229        else if( $this->offline )
1230        {
1231            $area_tooltip        = $area_tooltip . ": OFFLINE";
1232        }
1233
1234        $area_tooltip        = $area_tooltip . ": " . implode( " ", $this->jobs );
1235
1236        $tag_href        = "HREF=\"" . $area_href . "\"";
1237        $tag_coords        = "COORDS=\"" . $area_coords . "\"";
1238        $tag_tooltip1        = "ALT=\"" . $area_tooltip . "\"";
1239        $tag_tooltip2        = "TITLE=\"" . $area_tooltip . "\"";
1240
1241        return ("<AREA SHAPE=\"RECT\" " . $tag_coords . " " . $tag_href . " " . $tag_tooltip1 . " " . $tag_tooltip2 . ">");
1242    }
1243
1244    function colorHex( $color )
1245    {
1246        $my_color = imageColorAllocate( $this->image, hexdec( substr( $color, 0, 2 )), hexdec( substr( $color, 2, 2 )), hexdec( substr( $color, 4, 2 )) );
1247
1248        return $my_color;
1249    }
1250
1251    function setLoad( $load )
1252    {
1253        $this->load = $load;
1254    }
1255
1256    function setHostname( $hostname )
1257    {
1258        $this->hostname = $hostname;
1259    }
1260
1261    function getHostname()
1262    {
1263        return $this->hostname;
1264    }
1265
1266    function getJobs()
1267    {
1268        return $this->jobs;
1269    }
1270
1271    function setShowinfo( $showinfo )
1272    {
1273        $this->showinfo = $showinfo;
1274    }
1275
1276    function drawSmall()
1277    {
1278        global $SMALL_CLUSTERIMAGE_NODEWIDTH;
1279
1280        $this->size    = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1281
1282        $this->draw();
1283    }
1284
1285    function drawBig()
1286    {
1287        global $BIG_CLUSTERIMAGE_NODEWIDTH;
1288
1289        $this->size    = $BIG_CLUSTERIMAGE_NODEWIDTH;
1290
1291        $this->drawShadow();
1292        $this->draw();
1293    }
1294
1295    function drawShadow()
1296    {
1297        // offset of drop shadow from top left
1298        //
1299        $ds_offset  = 5;
1300
1301        // number of steps from black to background color
1302        //
1303        $ds_steps   = 15;
1304
1305        // distance between steps
1306        //
1307        $ds_spread = 1;
1308
1309        // define the background color
1310        //
1311        $background = array("r" => 255, "g" => 255, "b" => 255);
1312
1313        // create a new canvas.  New canvas dimensions should be larger than the original's
1314        //
1315        $width  = $this->size + $ds_offset;
1316        $height = $this->size + $ds_offset;
1317
1318        // determine the offset between colors
1319        //
1320        $step_offset = array("r" => ($background['r'] / $ds_steps), "g" => ($background['g'] / $ds_steps), "b" => ($background['b'] / $ds_steps));
1321
1322        // calculate and allocate the needed colors
1323        //
1324        $current_color = $background;
1325
1326        for ($i = 0; $i <= $ds_steps ; $i++)
1327        {
1328            $colors[$i] = imagecolorallocate($this->image, round($current_color['r']), round($current_color['g']), round($current_color['b']));
1329
1330            $current_color['r'] -= $step_offset['r'];
1331            $current_color['g'] -= $step_offset['g'];
1332            $current_color['b'] -= $step_offset['b'];
1333        }
1334
1335        // draw overlapping rectangles to create a drop shadow effect
1336        //
1337        for ($i = 3; $i < count($colors); $i++)
1338        {
1339            imagefilledrectangle( $this->image, ($this->x + $ds_offset), ($this->y + $ds_offset), ($this->x + $width), ($this->y + $height), $colors[$i] );
1340            $width -= $ds_spread;
1341            $height -= $ds_spread;
1342        }
1343    }
1344
1345    function draw()
1346    {
1347        global $JOB_NODE_MARKING, $NODE_DOWN_MARKING, $NODE_OFFLINE_MARKING;
1348
1349        $black_color = imageColorAllocate( $this->image, 0, 0, 0 );
1350        $size = $this->size;
1351
1352        imageFilledRectangle( $this->image, $this->x, $this->y, $this->x+($size), $this->y+($size), $black_color );
1353
1354        if( $this->showinfo)
1355        {
1356            $this->load = $this->determineLoad();
1357
1358            if( !isset( $this->image ) or !isset( $this->x ) or !isset( $this->y ) )
1359            {
1360                printf( "aborting\n" );
1361                printf( "x %d y %d load %f\n", $this->x, $this->y, $load );
1362                return;
1363            }
1364
1365            // Convert Ganglias Hexadecimal load color to a Decimal one
1366            //
1367            $load = $this->determineLoad();   
1368            $usecolor = $this->colorHex( load_color($load) );
1369            imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
1370            if( $this->down )
1371            {
1372                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $NODE_DOWN_MARKING, $black_color );
1373            }
1374            else if( $this->offline )
1375            {
1376                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $NODE_OFFLINE_MARKING, $black_color );
1377            }
1378            else if( count( $this->jobs ) > 0 )
1379            {
1380                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $JOB_NODE_MARKING, $black_color );
1381            }
1382        }
1383        else
1384        {
1385            // White
1386            $usecolor = imageColorAllocate( $this->image, 255, 255, 255 );
1387            imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
1388        }
1389    }
1390
1391    function determineLoad()
1392    {
1393        global $metrics;
1394
1395        $cpus = $metrics[$this->hostname]['cpu_num']['VAL'];
1396        if (!$cpus)
1397        {
1398            $cpus=1;
1399        }
1400
1401        $load_one    = $metrics[$this->hostname]['load_one']['VAL'];
1402        $load        = ((float) $load_one)/$cpus;
1403
1404        return $load;
1405    }
1406}
1407
1408class ClusterImage
1409{
1410    var $dataget, $image, $clustername;
1411    var $filtername, $filters;
1412
1413    function ClusterImage( $data, $clustername )
1414    {
1415        $this->dataget      = new DataGatherer( $clustername );
1416        $this->data         = $data;
1417        $this->clustername  = $clustername;
1418        $this->filters      = array();
1419        $this->size         = 's';
1420        $this->width        = 0;
1421        $this->height       = 0;
1422        $this->output       = 1;
1423        $this->jobs         = null;
1424        $this->nodes        = null;
1425        $this->parsed       = false;
1426    }
1427
1428    function getWidth()
1429    {
1430        return $this->width;
1431    }
1432    function getHeight()
1433    {
1434        return $this->height;
1435    }
1436    function setSmall()
1437    {
1438        $this->size    = 's';
1439    }
1440    function setBig()
1441    {
1442        $this->size    = 'b';
1443    }
1444    function setNoimage()
1445    {
1446        $this->output    = 0;
1447    }
1448    function checkParse()
1449    {
1450        if( $this->parsed == false )
1451        {
1452            $this->dataget->parseXML( $this->data );
1453            $this->parsed = true;
1454        }
1455    }
1456    function getJobs()
1457    {
1458        if( $this->jobs == null )
1459        {
1460            $this->checkParse();
1461            $mydatag = $this->dataget;
1462            $this->jobs = $mydatag->getJobs();
1463        }
1464
1465        return $this->jobs;
1466    }
1467    function setJobs($jobs)
1468    {
1469        $this->jobs   = &$jobs;
1470    }
1471    function getNodes()
1472    {
1473        if( $this->nodes === null )
1474        {
1475            $this->checkParse();
1476            $mydatag = $this->dataget;
1477            $this->nodes = $mydatag->getNodes();
1478        }
1479
1480        return $this->nodes;
1481    }
1482    function setNodes($nodes)
1483    {
1484        $this->nodes    = &$nodes;
1485    }
1486    function isSmall()
1487    {
1488        return ($this->size == 's');
1489    }
1490    function isBig()
1491    {
1492        return ($this->size == 'b');
1493    }
1494    function setFilter( $filtername, $filtervalue )
1495    {
1496        $this->filters[$filtername] = $filtervalue;
1497    }
1498
1499    function filterNodes( $jobs, $nodes )
1500    {
1501        $filtered_nodes = array();
1502
1503        //print_r( $nodes );
1504
1505        foreach( $nodes as $node )
1506        {
1507            $hostname = $node->getHostname();
1508
1509            $addhost = 1;
1510
1511            if( count( $this->filters ) > 0 )
1512            {
1513                $mynjobs = $node->getJobs();
1514
1515                if( count( $mynjobs ) > 0 )
1516                {
1517                    foreach( $mynjobs as $myjob )
1518                    {
1519                        foreach( $this->filters as $filtername => $filtervalue )
1520                        {
1521                            if( $filtername!=null && $filtername!='' )
1522                            {
1523                                if( $filtername == 'jobid' && !$node->hasJob( $filtervalue) )
1524                                {
1525                                    $addhost = 0;
1526                                }
1527                                else if( $filtername != 'jobid' )
1528                                {
1529                                    if( $jobs[$myjob][$filtername] != $filtervalue )
1530                                    {
1531                                        $addhost = 0;
1532                                    }
1533                                }
1534                            }
1535                        }
1536                    }
1537                }
1538                else
1539                {
1540                    $addhost = 0;
1541                }
1542            }
1543
1544            if( $addhost )
1545            {
1546                $filtered_nodes[] = $hostname;
1547            }
1548        }
1549
1550        return $filtered_nodes;
1551    }
1552
1553    function draw()
1554    {
1555        global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH;
1556        global $BIG_CLUSTERIMAGE_MAXWIDTH, $BIG_CLUSTERIMAGE_NODEWIDTH;
1557        global $CLUSTER_CONFS, $confcluster, $SHOW_EMPTY_COLUMN, $SHOW_EMPTY_ROW;
1558
1559        global $SORTBY_HOSTNAME, $SORT_ORDER, $skan_str;
1560        global $x_first, $y_first;
1561
1562        foreach( $CLUSTER_CONFS as $confcluster => $conffile )
1563        {
1564            if( strtolower( trim($this->clustername) ) == strtolower(trim($confcluster)) )
1565            {
1566                include_once $conffile;
1567            }
1568        }
1569
1570        if( $this->isSmall() )
1571        {
1572            $max_width    = $SMALL_CLUSTERIMAGE_MAXWIDTH;
1573            $node_width    = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1574        }
1575        else if( $this->isBig() )
1576        {
1577            $max_width    = $BIG_CLUSTERIMAGE_MAXWIDTH;
1578            $node_width    = $BIG_CLUSTERIMAGE_NODEWIDTH;
1579        }
1580
1581        $nodes        = $this->getNodes();
1582        $nodes_hosts    = array_keys( $nodes );
1583
1584        $nodes_nr    = count( $nodes );
1585
1586        $nodes_size    = $nodes_nr*$node_width;
1587        $node_rows    = 0;
1588
1589        if( $nodes_size > $max_width )
1590        {
1591            $nodes_per_row = ( (int) ($max_width/$node_width) );
1592        }
1593        else
1594        {
1595            $nodes_per_row = $nodes_size;
1596            $node_rows = 1;
1597        }
1598
1599        if( $nodes_per_row < $nodes_nr )
1600        {
1601            $node_rows = ( (int) ($nodes_nr/$nodes_per_row) );
1602            $node_rest = fmod( $nodes_nr, $nodes_per_row );
1603
1604            if( $node_rest > 0 )
1605            {
1606                $node_rows++;
1607            }
1608        }
1609
1610        $y_offset    = 0;
1611        $font         = 2;
1612        $fontwidth    = ImageFontWidth( $font );
1613        $fontheight    = ImageFontHeight( $font );
1614        $fontspaceing    = 2;
1615        $y_offset    = $fontheight + (2 * $fontspaceing);
1616
1617        $this->width    = $max_width;
1618        $this->height    = ($y_offset + (($node_rows*$node_width)+1) );
1619
1620        $jobs = $this->getJobs();
1621        $filtered_nodes = $this->filterNodes( $jobs, $nodes );
1622
1623        if( $SORTBY_HOSTNAME != "" )
1624        {
1625                $sorted     = array();
1626
1627            $x_first    = 0;
1628            $y_first    = 0;
1629
1630            $skan_str    = $SORTBY_HOSTNAME;
1631
1632            global $x_present, $y_present;
1633            $x_present    = false;
1634            $y_present    = false;
1635
1636            // Should we scan by X, Y or both
1637            //
1638            if(strpos( $SORTBY_HOSTNAME, "{x}" ) != false )
1639            {
1640                $x_str        = "{x}";
1641                $x_present    = true;
1642            }
1643            else if(strpos( $SORTBY_HOSTNAME, "{X}" ) != false )
1644            {
1645                $x_str        = "{X}";
1646                $x_present    = true;
1647            }
1648            if(strpos( $SORTBY_HOSTNAME, "{y}" ) != false )
1649            {
1650                $y_str        = "{y}";
1651                $y_present    = true;
1652            }
1653            else if(strpos( $SORTBY_HOSTNAME, "{Y}" ) != false )
1654            {
1655                $y_str        = "{Y}";
1656                $y_present    = true;
1657            }
1658
1659            // If we should scan for both X and Y: see which one is first
1660            //
1661            if(( strpos( $SORTBY_HOSTNAME, $x_str ) < strpos( $SORTBY_HOSTNAME, $y_str ) ) && ( $x_present && $y_present ))
1662            {
1663                $x_first    = 1;
1664            }
1665            else if(( strpos( $SORTBY_HOSTNAME, $x_str ) > strpos( $SORTBY_HOSTNAME, $y_str ) ) && ( $x_present && $y_present ))
1666            {
1667                $y_first    = 1;
1668       
1669            }
1670            else if( $x_present )
1671            {
1672                $x_first    = 1;
1673            }
1674            else if( $y_present )
1675            {
1676                $y_first    = 1;
1677            }
1678
1679            // Now replace our {x} and {y} with %d for sscanf parsing
1680            //
1681            if(( $x_first ) && ( $x_present && $y_present ) )
1682            {
1683                $skan_str    = str_replace( $x_str, "%d", $skan_str );
1684                $skan_str    = str_replace( $y_str, "%d", $skan_str );
1685            } 
1686            else if( $x_present)
1687            {
1688                $skan_str    = str_replace( $x_str, "%d", $skan_str );
1689            }
1690            else if( $y_present)
1691            {
1692                $skan_str    = str_replace( $y_str, "%d", $skan_str );
1693            }
1694
1695            $x_min        = null;
1696            $x_max        = null;
1697            $y_min        = null;
1698            $y_max        = null;
1699
1700            $x_columns    = array();
1701            $y_rows        = array();
1702
1703            // Now let's walk through all our nodes and see which one are valid for our scan pattern
1704            //
1705            foreach( $nodes as $hostname => $node )
1706            {
1707                $x    = null;
1708                $y    = null;
1709
1710                if( $x_present && $y_present )
1711                {
1712                    if( $x_first )
1713                    {
1714                        $n = sscanf( $hostname, $skan_str, $x, $y );
1715                    }
1716                    else if( $y_first )
1717                    {
1718                        $n = sscanf( $hostname, $skan_str, $y, $x );
1719                    }
1720
1721                    // Remove nodes that don't match
1722                    //
1723                    if( $n < 2 )
1724                    {
1725                        // This node hostname has no match for: {x} and {y}
1726                        //
1727                        unset( $nodes[$hostname] );
1728                    }
1729                }
1730                else if( $x_present && !$y_present )
1731                {
1732                    $n = sscanf( $hostname, $skan_str, $x );
1733
1734                    // Remove nodes that don't match
1735                    //
1736                    if( $n < 1 )
1737                    {
1738                        // This node hostname has no match for: {x}
1739                        //
1740                        unset( $nodes[$hostname] );
1741                    }
1742                    $y    = 1;
1743                }
1744                else if( $y_present && !$x_present )
1745                {
1746                    $n = sscanf( $hostname, $skan_str, $y );
1747
1748                    // Remove nodes that don't match
1749                    //
1750                    if( $n < 1 )
1751                    {
1752                        // This node hostname has no match for: {y}
1753                        //
1754                        unset( $nodes[$hostname] );
1755                    }
1756                    $x    = 1;
1757                }
1758
1759                // Determine the lowest value of {x} that exists in all node hostnames
1760                //
1761                if( !$x_min && $x != null )
1762                {
1763                    $x_min    = $x;
1764                }
1765                else if( $x < $x_min && $x != null )
1766                {
1767                    $x_min    = $x;
1768                }
1769
1770                // Determine the highest value of {x} that exists in all node hostnames
1771                //
1772                if( !$x_max && $x != null )
1773                {
1774                    $x_max    = $x;
1775                }
1776                else if( $x > $x_max && $x != null )
1777                {
1778                    $x_max    = $x;
1779                }
1780
1781                // Determine the lowest value of {y} that exists in all node hostnames
1782                //
1783                if( !$y_min && $y != null )
1784                {
1785                    $y_min    = $y;
1786                }
1787                else if( $y < $y_min && $y != null )
1788                {
1789                    $y_min    = $y;
1790                }
1791
1792                // Determine the highest value of {y} that exists in all node hostnames
1793                //
1794                if( !$y_max && $y != null )
1795                {
1796                    $y_max    = $y;
1797                }
1798                else if( $y > $y_max && $y != null )
1799                {
1800                    $y_max    = $y;
1801                }
1802
1803                // Store which non-empty columns and rows we found
1804                //
1805                if( !in_array( $x, $x_columns ) )
1806                {
1807                    $x_columns[] = $x;
1808                }
1809                if( !in_array( $y, $y_rows ) )
1810                {
1811                    $y_rows[] = $y;
1812                }
1813            }
1814
1815            // Sort all the nodes (alpha and numerically)
1816            // 1: gb-r1n1, 2: gb-r1n2, 3: gb-r2n1, etc
1817            //
1818            $sorted_nodes    = usort( $nodes, "cmp" );
1819
1820            //print_r( $x_columns ) ;
1821
1822            $cur_node    = 0;
1823
1824            $x_offset    = 0;
1825            $y_offset    = 0;
1826            $font         = 2;
1827            $fontwidth    = ImageFontWidth( $font );
1828            $fontheight    = ImageFontHeight( $font );
1829            $fontspaceing    = 2;
1830
1831            if( $this->isSmall() ) 
1832            {
1833                $y_offset    = $y_offset + (2 * $fontspaceing) + $fontheight;
1834            }
1835
1836            if( $this->isBig() ) 
1837            {
1838                $y_offset    = ($fontheight * (1 + strlen( $x_max) ) ) + ((2 + strlen( $x_max)) * $fontspaceing);
1839                $x_offset    = ($fontwidth * (1 + strlen( $y_max) ) ) + ((2 + strlen( $y_max)) * $fontspaceing);
1840            }
1841
1842            $image_width    = $x_offset + ($node_width * ($x_max-$x_min+2));
1843
1844            if( $this->isSmall() ) 
1845            {
1846                $image_width    = $max_width;
1847            }
1848            else if( $this->isBig() ) 
1849            {
1850                $image_width    = ($image_width < $max_width) ? $image_width : $max_width;
1851            }
1852            $image_height    = $y_offset + ($node_width * ($y_max-$y_min+2));
1853
1854            $this->width    = $image_width;
1855            $this->heigth    = $image_heigth;
1856
1857            $image        = imageCreateTrueColor( $image_width, $image_height );
1858            $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
1859
1860            imageFill( $image, 0, 0, $colorwhite );
1861
1862            if( $this->isSmall() )
1863            {
1864                // Draw a fancy little header text to explain what it is
1865                //
1866                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1867
1868                imageString( $image, $font, 2, 2, "Job Monarch: ".count($jobs)." jobs", $colorblue );
1869            }
1870
1871            if( $this->isBig() && ( isset( $SORT_XLABEL ) || isset( $SORT_YLABEL ) ) )
1872            {
1873                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1874
1875                if( isset( $SORT_XLABEL ) )
1876                {
1877                    // Print the {x} label: rack
1878                    //
1879                    imageString( $image, $font, $x_offset, $fontspaceing, $SORT_XLABEL, $colorblue );
1880                }
1881
1882                if( isset( $SORT_YLABEL ) )
1883                {
1884                    // Stupid php without imageStringDown function... we'll make one ourself
1885                    //
1886
1887                    // Print the {y} label: node
1888                    //
1889                    imageStringDown( $image, $font, $fontspaceing, $y_offset, $SORT_YLABEL, $colorblue );
1890                }
1891            }
1892
1893            $previous_n    = 0;
1894            $previous_m    = 0;
1895            $x_empty_count    = 0;
1896            $y_empty_count    = 0;
1897
1898            // Let's start assigning x,y coordinates now
1899            //
1900            for( $n = $x_min; $n <= $x_max; $n++ )
1901            {
1902                for( $m = $y_min; $m <= $y_max; $m++ )
1903                {
1904                    if( $x_min > 0 )
1905                    {
1906                        $x    = $x_offset + ( ($n-$x_min) * $node_width ) - ($x_empty_count * $node_width);
1907                    }
1908                    if( $y_min > 0 )
1909                    {
1910                        $y    = $y_offset + ( ($m-$y_min) * $node_width ) - ($y_empty_count * $node_width);
1911                    }
1912
1913                    // Don't show empty rows/columns if option enabled
1914                    //
1915                    if( !in_array( $n, $x_columns ) && !$SHOW_EMPTY_COLUMN )
1916                    {
1917                        // Skip to next iteration: we don't want a empty column
1918                        //
1919                        if( $n > $previous_n )
1920                        {
1921                            $previous_n = $n;
1922                            $x_empty_count++;
1923                        }
1924                        continue;
1925                    }
1926                    if( !in_array( $m, $y_rows ) && !$SHOW_EMPTY_ROW )
1927
1928                    {
1929                        // Skip to next iteration: we don't want a empty column
1930                        //
1931                        if( $m > $previous_m )
1932                        {
1933                            $previous_m = $m;
1934                            $y_empty_count++;
1935                        }
1936                        continue;
1937                    }
1938
1939                    if( $this->isBig() ) 
1940                    {
1941                        // Draw y(node) column number header
1942                        //
1943                        if(( $n == $x_min ) && ( isset($SORT_YLABEL) ) )
1944                        {
1945                            $mfontspacing    = 1;
1946
1947                            $ylabel_x    = $x - ( $fontwidth * strlen( $y_max ) ) - $mfontspacing;
1948                            $ylabel_y    = $y;
1949
1950                            imageString( $image, $font, $ylabel_x, $ylabel_y, strval( $m ), $colorblue );
1951
1952                            $xmin_hit[$n]    = true;
1953                        }
1954
1955                        // Draw x(rack) column number header
1956                        //
1957                        if(( $m == $y_min ) && ( isset($SORT_XLABEL) ) )
1958                        {
1959                            $mfontspacing    = 2;
1960                            $xlabel_y    = $y - ( $fontheight * strlen( $x_max ) );
1961                            $xlabel_x    = $x + $mfontspacing; 
1962
1963                            imageStringDown( $image, $font, $xlabel_x, $xlabel_y, strval( $n ), $colorblue );
1964                        }
1965                    }
1966
1967                    if( isset( $nodes[$cur_node] ) ) 
1968                    {
1969                        $host    = $nodes[$cur_node]->getHostname();
1970
1971                        if( $x_present && $y_present )
1972                        {
1973                            if( $x_first )
1974                            {
1975                                $nn = sscanf( $host, $skan_str, $rx, $ry );
1976                            }
1977                            else if( $y_first )
1978                            {
1979                                $nn = sscanf( $host, $skan_str, $ry, $rx );
1980                            }
1981                            if ( $nn < 2 )
1982                            {
1983                                //printf( "skipping node %s - y present & x present + <2 x,y matchs\n", $host);
1984                                continue;
1985                            }
1986                            if( intval( $rx ) > $n )
1987                            {
1988                                // If x(rack) is higher than current x, skip to next x(rack)
1989                                //
1990                                $m        = $y_max + 1;
1991
1992                                continue;
1993                            }
1994                            if( intval( $ry ) > $m )
1995                            {
1996                                // If y(node) is higher than current y, skip to next y(node)
1997                                //
1998                                continue;
1999                            }
2000                        }
2001                        else if( $x_present )
2002                        {
2003                            $nn = sscanf( $host, $skan_str, $rx );
2004                        }
2005                        else if( $y_present )
2006                        {
2007                            $nn = sscanf( $host, $skan_str, $ry );
2008                        }
2009
2010                        if( !in_array( $host, $filtered_nodes ) )
2011                        {
2012                            // This node has been filtered out: we only want to see certain nodes
2013                            //
2014                            $nodes[$cur_node]->setShowinfo( 0 );
2015                        }
2016
2017                        $nodes[$cur_node]->setCoords( $x, $y );
2018                        $nodes[$cur_node]->setImage( $image );
2019
2020                        if( $this->isSmall() )
2021                        {
2022                            $nodes[$cur_node]->drawSmall();
2023                        }
2024                        else if( $this->isBig() )
2025                        {
2026                            $nodes[$cur_node]->drawBig();
2027                        }
2028
2029                        $cur_node++;
2030                    }
2031                }
2032            }
2033
2034        }
2035        else
2036        {
2037            if( $this->isSmall() )
2038            {
2039                $image        = imageCreateTrueColor( $max_width, ($y_offset + (($node_rows*$node_width)+1) ) );
2040            }
2041            else if( $this->isBig() )
2042            {
2043                $image_width    = ($node_width * $nodes_nr) + 2;
2044                $image_width    = ($image_width < $max_width) ? $image_width : $max_width;
2045                $image        = imageCreateTrueColor( $image_width, ($y_offset + (($node_rows*$node_width)+1) ) );
2046            }
2047            $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
2048
2049            imageFill( $image, 0, 0, $colorwhite );
2050
2051            if( $this->isSmall() )
2052            {
2053                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
2054
2055                imageString( $image, $font, 2, 2, "Job Monarch: ".count( $jobs)." jobs", $colorblue );
2056            }
2057
2058            for( $n = 0; $n < $node_rows; $n++ )
2059            {
2060                for( $m = 0; $m < $nodes_per_row; $m++ )
2061                {
2062                    $x = ($m * $node_width);
2063                    $y = $y_offset + ($n * $node_width);
2064
2065                    $cur_node = ($n * $nodes_per_row) + ($m);
2066                    $host = isset( $nodes_hosts[$cur_node] ) ? $nodes_hosts[$cur_node] : '';
2067
2068                    if( isset( $nodes[$host] ) )
2069                    {
2070                        $nodes[$host]->setCoords( $x, $y );
2071                        $nodes[$host]->setImage( $image );
2072
2073                        if( !in_array( $host, $filtered_nodes ) )
2074                        {
2075                            $nodes[$host]->setShowinfo( 0 );
2076                        }
2077
2078                        if( $this->isSmall() )
2079                        {
2080                            $nodes[$host]->drawSmall();
2081                        }
2082                        else if( $this->isBig() )
2083                        {
2084                            $nodes[$host]->drawBig();
2085                        }
2086                    }
2087                }
2088            }
2089        }
2090   
2091        $this->nodes    = &$nodes;
2092
2093        if ($this->output)
2094        {
2095            header( 'Content-type: image/png' );
2096            imagePNG( $image );
2097            imageDestroy( $image );
2098        }
2099    }
2100
2101    function getImagemapArea()
2102    {
2103        $clusterimage_map    = "";
2104
2105        $nodes = &$this->getNodes();
2106
2107        foreach( $nodes as $node )
2108        {
2109            $node_map          = $node->getImagemapArea();
2110            $clusterimage_map .= $node_map;
2111        }
2112
2113        return $clusterimage_map;
2114    }
2115}
2116
2117class EmptyImage
2118{
2119    function draw()
2120    {
2121        $image        = imageCreateTrueColor( 1, 1 );
2122        $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
2123        imageFill( $image, 0, 0, $colorwhite );                         
2124
2125        header( 'Content-type: image/png' );
2126        imagePNG( $image );
2127        imageDestroy( $image );
2128    }
2129}
2130
2131class HostImage
2132{
2133    var $data_gather, $cluster, $host, $node, $image;
2134    var $headerstrlen;
2135
2136    function HostImage( $data_gather, $cluster, $host )
2137    {
2138        $this->data_gather     = $data_gather;
2139        $this->cluster        = $cluster;
2140        $this->host        = $host;
2141        $this->y_offset        = 0;
2142        $this->font        = 2;
2143        $this->fontspaceing    = 2;
2144        $this->headerstrlen    = array();
2145
2146        $this->fontheight    = ImageFontHeight( $this->font );
2147        $this->fontwidth    = ImageFontWidth( $this->font );
2148
2149        $dg            = &$this->data_gather;
2150        $this->node        = &$dg->getNode( $this->host );
2151        $n            = &$this->node;
2152        $this->njobs        = $n->getJobs();
2153    }
2154
2155    function drawJobs()
2156    {
2157        $dg                     = &$this->data_gather;
2158        $colorblack        = imageColorAllocate( $this->image, 0, 0, 0 );
2159
2160        for( $n = 0; $n < count( $this->njobs ); $n++ )
2161        {
2162            $jobid            = $this->njobs[$n];
2163            $jobinfo        = $dg->getJob( $jobid );
2164
2165            $xoffset        = 5;
2166            imageString( $this->image, $this->font, $xoffset, $this->y_offset, strval( $jobid ), $colorblack );
2167
2168            foreach( $this->headerstrlen as $headername => $headerlen )
2169            {
2170                if( $headername == 'nodes' )
2171                {
2172                    $attrval    = strval( count( $jobinfo['nodes'] ) );
2173                }
2174                else if( $headername == 'cpus' )
2175                {
2176                    if( !isset( $jobinfo['ppn'] ) )
2177                    {
2178                        $jobinfo['ppn'] = 1;
2179                    }
2180
2181                    $attrval    = strval( count( $jobinfo['nodes'] ) * intval( $jobinfo['ppn'] ) );
2182                }
2183                else if( $headername == 'runningtime' )
2184                {
2185                    $attrval    = makeTime( intval( $jobinfo['reported'] ) - intval( $jobinfo['start_timestamp'] ) );
2186                }
2187                else
2188                {
2189                    $attrval    = strval( $jobinfo[$headername] );
2190                }
2191
2192                imageString( $this->image, $this->font, $xoffset, $this->y_offset, $attrval, $colorblack );
2193       
2194                $xoffset    = $xoffset + ($this->fontwidth * ( $headerlen + 1 ) );
2195            }
2196           
2197            $this->newLineOffset();
2198        }
2199    }
2200
2201    function drawHeader()
2202    {
2203        $dg                     = &$this->data_gather;
2204
2205        for( $n = 0; $n < count( $this->njobs ); $n++ )
2206        {
2207            $jobid            = $this->njobs[$n];
2208            $jobinfo        = $dg->getJob( $jobid );
2209
2210            if( !isset( $this->headerstrlen['id'] ) )
2211            {
2212                $this->headerstrlen['id']    = strlen( strval( $jobid ) );
2213            }
2214            else if( strlen( strval( $jobid ) ) > $this->headerstrlen['id'] )
2215            {
2216                $this->headerstrlen['id']    = strlen( strval( $jobid ) );
2217            }
2218
2219            if( !isset( $this->headerstrlen['owner'] ) )
2220            {
2221                $this->headerstrlen['owner']    = strlen( strval( $jobinfo['owner'] ) );
2222            }
2223            else if( strlen( strval( $jobinfo['owner'] ) ) > $this->headerstrlen['owner'] )
2224            {
2225                $this->headerstrlen['owner']    = strlen( strval( $jobinfo['owner'] ) );
2226            }
2227
2228            if( !isset( $this->headerstrlen['queue'] ) )
2229            {
2230                $this->headerstrlen['queue']    = strlen( strval( $jobinfo['queue'] ) );
2231            }
2232            else if( strlen( strval( $jobinfo['queue'] ) ) > $this->headerstrlen['queue'] )
2233            {
2234                $this->headerstrlen['queue']    = strlen( strval( $jobinfo['queue'] ) );
2235            }
2236
2237            if( !isset( $jobinfo['ppn'] ) )
2238            {
2239                $jobinfo['ppn'] = 1;
2240            }
2241
2242            $cpus            = count( $jobinfo['nodes'] ) * intval( $jobinfo['ppn'] );
2243
2244            if( !isset( $this->headerstrlen['cpus'] ) )
2245            {
2246                $this->headerstrlen['cpus']    = strlen( strval( $cpus ) );
2247            }
2248            else if( strlen( strval( $cpus ) ) > $this->headerstrlen['cpus'] )
2249            {
2250                $this->headerstrlen['cpus']    = strlen( strval( $cpus ) );
2251            }
2252
2253            $nodes            = count( $jobinfo['nodes'] );
2254
2255            if( !isset( $this->headerstrlen['nodes'] ) )
2256            {
2257                $this->headerstrlen['nodes']    = strlen( strval( $nodes ) );
2258            }
2259            else if( strlen( strval( $nodes) ) > $this->headerstrlen['nodes'] )
2260            {
2261                $this->headerstrlen['nodes']    = strlen( strval( $nodes ) );
2262            }
2263
2264            $runningtime        = makeTime( intval( $jobinfo[reported] ) - intval( $jobinfo['start_timestamp'] ) );
2265
2266            if( !isset( $this->headerstrlen['runningtime'] ) )
2267            {
2268                $this->headerstrlen['runningtime']    = strlen( strval( $runningtime) );
2269            }
2270            else if( strlen( strval( $runningtime) ) > $this->headerstrlen['runningtime'] )
2271            {
2272                $this->headerstrlen['runningtime']    = strlen( strval( $runningtime) );
2273            }
2274
2275            if( !isset( $this->headerstrlen['name'] ) )
2276            {
2277                $this->headerstrlen['name']    = strlen( strval( $jobinfo['name'] ) );
2278            }
2279            else if( strlen( strval( $jobinfo['name'] ) ) > $this->headerstrlen['name'] )
2280            {
2281                $this->headerstrlen['name']    = strlen( strval( $jobinfo['name'] ) );
2282            }
2283        }
2284
2285        $xoffset    = 5;
2286
2287        foreach( $this->headerstrlen as $headername => $headerlen )
2288        {
2289            $colorgreen    = imageColorAllocate( $this->image, 0, 200, 0 );
2290
2291            if( $headerlen < strlen( $headername ) )
2292            {
2293                $this->headerstrlen[$headername]    = strlen( $headername );
2294            }
2295
2296            imageString( $this->image, $this->font, $xoffset, $this->y_offset, ucfirst( $headername ), $colorgreen );
2297
2298            $xoffset    = $xoffset + ($this->fontwidth * ( $this->headerstrlen[$headername] + 1 ) );
2299        }
2300        $this->newLineOffset();
2301    }
2302
2303    function newLineOffset()
2304    {
2305        $this->y_offset        = $this->y_offset + $this->fontheight + $this->fontspaceing;
2306    }
2307
2308    function draw()
2309    {
2310        $xlen        = 450;
2311        $ylen        = ( count( $this->njobs ) * ( $this->fontheight + $this->fontspaceing ) ) + (3 * $this->fontheight);
2312
2313        $this->image    = imageCreateTrueColor( $xlen, $ylen );
2314        $colorwhite    = imageColorAllocate( $this->image, 255, 255, 255 );
2315        imageFill( $this->image, 0, 0, $colorwhite );                         
2316
2317        $colorblue    = imageColorAllocate( $this->image, 0, 0, 255 );
2318
2319        imageString( $this->image, $this->font, 1, $this->y_offset, "Monarch Joblist - host: ".$this->host, $colorblue );
2320        $this->newLineOffset();
2321
2322        $this->drawHeader();
2323        $this->drawJobs();
2324
2325        header( 'Content-type: image/png' );
2326        imagePNG( $this->image );
2327        imageDestroy( $this->image );
2328    }
2329}
2330
2331function imageStringDown( &$image, $font, $x, $y, &$s, &$col )
2332{
2333    $fw    = imagefontwidth( $font);
2334    $fh    = imagefontheight( $font);
2335   
2336    $fontspacing = 0;
2337
2338    $fx    = $x;
2339    $fy    = $y;
2340
2341    for( $n=0; $n<strlen( $s ); $n++ )
2342    {
2343        $myc    = $s{$n};
2344
2345        imagestring( $image, $font, $fx, $fy, $myc, $col );
2346
2347        $fy    += ($fontspacing + $fh );
2348    }
2349}
2350
2351function array_rem( $val, &$arr )
2352{
2353    // Delete val from arr
2354    //
2355    $i    = array_search( $val, $arr );
2356
2357    if( $i == false ) return false;
2358
2359    $arr    = array_merge( array_slice( $arr, 0, $i ), array_slice( $arr, $i+1, count( $arr ) ) );
2360
2361    return true;
2362}
2363
2364function cmp( $a, $b ) 
2365{
2366    global $SORT_ORDER;
2367    global $skan_str;
2368    global $x_first, $y_first;
2369    global $x_present, $y_present;
2370
2371    $a_node        = $a;
2372    $b_node        = $b;
2373    $a        = $a_node->getHostname();
2374    $b        = $b_node->getHostname();
2375
2376    if( $a == $b ) return 0;
2377
2378    $a_x        = 0;
2379    $b_x        = 0;
2380    $a_y        = 0;
2381    $b_y        = 0;
2382
2383    if( $x_present && $y_present )
2384    {
2385        if( $x_first )
2386        {
2387            $n = sscanf( $a, $skan_str, $a_x, $a_y );
2388            $n = sscanf( $b, $skan_str, $b_x, $b_y );
2389        }
2390        else if( $y_first )
2391        {
2392            $n = sscanf( $a, $skan_str, $a_y, $a_x );
2393            $n = sscanf( $b, $skan_str, $b_y, $b_x );
2394        }
2395    } 
2396    else if( $x_present && !$y_present )
2397    {
2398        $n = sscanf( $a, $skan_str, $a_x );
2399        $n = sscanf( $b, $skan_str, $b_x );
2400    }
2401    else if( $y_present && !$x_present )
2402    {
2403        $n = sscanf( $a, $skan_str, $a_y );
2404        $n = sscanf( $b, $skan_str, $b_y );
2405    }
2406
2407    if ( $SORT_ORDER=="desc" )
2408    {
2409
2410        if( $x_present && $y_present )
2411        {
2412            // 1  = a < b
2413            // -1 = a > b
2414            //
2415            if ($a_x == $b_x)
2416            {
2417                if ($a_y < $b_y)
2418                {
2419                    return 1;
2420                }
2421                else if ($a_y > $b_y)
2422                {
2423                    return -1;
2424                }
2425            }
2426            else if ($a_x < $b_x)
2427            {
2428                return 1;
2429            }
2430            else if ($a_x > $b_x)
2431            {
2432                return -1;
2433            }
2434        } 
2435        else if( $x_present && !$y_present )
2436        {
2437            if ($a_x < $b_x)
2438            {
2439                return 1;
2440            }
2441            else if ($a_x > $b_x)
2442            {
2443                return -1;
2444            }
2445        }
2446        else if( $y_present && !$x_present )
2447        {
2448            if ($a_y < $b_y)
2449            {
2450                return 1;
2451            }
2452            else if ($a_y > $b_y)
2453            {
2454                return -1;
2455            }
2456        }
2457    }
2458    else if ( $SORT_ORDER == "asc" )
2459    {
2460
2461        if( $x_present && $y_present )
2462        {
2463            // 1  = a > b
2464            // -1 = a < b
2465            //
2466            if ($a_x == $b_x)
2467            {
2468                if ($a_y > $b_y)
2469                {
2470                    return 1;
2471                }
2472                else if ($a_y < $b_y)
2473                {
2474                    return -1;
2475                }
2476            }
2477            else if ($a_x > $b_x)
2478            {
2479                return 1;
2480            }
2481            else if ($a_x < $b_x)
2482            {
2483                return -1;
2484            }
2485        }
2486        else if( $x_present && !$y_present )
2487        {
2488            if ($a_x > $b_x)
2489            {
2490                return 1;
2491            }
2492            else if ($a_x < $b_x)
2493            {
2494                return -1;
2495            }
2496        }
2497        else if( $y_present && !$x_present )
2498        {
2499            if ($a_y > $b_y)
2500            {
2501                return 1;
2502            }
2503            else if ($a_y < $b_y)
2504            {
2505                return -1;
2506            }
2507        }
2508    }
2509}
2510function makeTime( $time )
2511{
2512        $days = intval( $time / 86400 );
2513        $time = ($days>0) ? $time % ($days * 86400) : $time;
2514
2515        $date_str = '';
2516        $day_str = '';
2517
2518        if( $days > 0 )
2519        {
2520            if( $days > 1 )
2521            {
2522                $day_str .= $days . ' days';
2523            }
2524            else
2525            {
2526                $day_str .= $days . ' day';
2527            }
2528        }
2529
2530        $hours = intval( $time / 3600 );
2531        $time = $hours ? $time % ($hours * 3600) : $time;
2532
2533        if( $hours > 0 )
2534        {
2535             $date_str .= $hours . ':';
2536             $date_unit = 'hours'; 
2537        }
2538
2539        $minutes = intval( $time / 60 );
2540        $seconds = $minutes ? $time % ($minutes * 60) : $time;
2541
2542        if( $minutes > 0 )
2543        {
2544            if( $minutes >= 10 )
2545            {
2546                $date_str .= $minutes . ':';
2547            }
2548            else
2549            {
2550                $date_str .= '0' . $minutes . ':';
2551            }
2552                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
2553        }
2554        else
2555        {
2556            if($hours > 0 )
2557            {
2558                $date_str .= '00:';
2559                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
2560            }
2561        }
2562
2563        $date_unit = (!isset($date_unit)) ? 'seconds' : $date_unit;
2564
2565        if( $seconds > 0 )
2566        {
2567            if( $seconds >= 10 )
2568            {
2569                $date_str .= $seconds . ' ' . $date_unit;
2570            }
2571            else
2572            {
2573                $date_str .= '0' . $seconds . ' ' . $date_unit;
2574            }
2575        }
2576        else if ( $hours > 0 or $minutes > 0 )
2577        {
2578            $date_str .= '00 ' . $date_unit;
2579        }
2580
2581        if( $days > 0)
2582        {
2583            if( $hours > 0 or $minutes > 0 or $seconds > 0 )
2584            {
2585                $date_str = $day_str . ' - ' . $date_str;
2586            }
2587            else
2588            {
2589                $date_str = $day_str;
2590            }
2591        }
2592        return $date_str;
2593}
2594?>
Note: See TracBrowser for help on using the repository browser.