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

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

libtoga.php:

  • calculate parsetime

templates/footer.tpl:

  • made parsetime optional

index.php:

  • don't show parsetime for archive: not applicable

overview.php:

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