root > WikiSense-trunk > attic > WikiSense.php.orig

WikiSense.php.orig

text/x-php, 23302 bytes (load raw)
<?php
    
if (@$argv[1]==='test' && !@$_SERVER['REQUEST_URI'] && !defined('WS_WEB')) {
    define('WS_CONSOLE',1);
    define('WS_TEST',1);
    require_once('WSInit.php');
}

if (!defined('WS_WEB')) die('bad entry point!');

require_once("includes/LoadBalancer.php");

define('SPACE_CHARS','( |&nbsp;|&thinsp;|\pZ)');

function wsfLoadClass( $class ) {
    if ( class_exists( $class ) ) return $class;
    
    @include_once( "$class.php" );
    
    if ( class_exists( $class ) ) return $class;
    
    return NULL;
}


function wsfGetExpertClass( $base, $dbname, $domain, $family, $lang, $is_multilang ) {
    $class= NULL;

    if (!$class) $class = wsfLoadClass( "{$base}_".str_replace('.','_',$domain) );
    if (!$class) $class = wsfLoadClass( "{$base}_{$dbname}" );
    if (!$class && !$is_multilang) $class = wsfLoadClass( "{$base}_{$lang}_{$family}" );
    if (!$class && !$is_multilang) $class = wsfLoadClass( "{$base}_{$lang}" );
    if (!$class) $class = wsfLoadClass( "{$base}_{$family}" );
    if (!$class && $is_multilang) $class = wsfLoadClass( "{$base}_{$lang}" );
    if (!$class) $class= $base;
    
    return $class;
}

function wsfLoadExpertConfig( $base, $var, $dbname, $domain, $family, $lang, $is_multilang ) {
    $$var= array();
    
    #TODO: cache values, use include_once!
    
    wsfLog("loading expert config for {$base} - {$lang} - {$family} - {$dbname} - {$domain}",LL_DEBUG);

    @include( $base.'.php' );
    if ($is_multilang) @include( "{$base}_{$lang}.php" );
    @include( "{$base}_{$family}.php" );
    if (!$is_multilang) @include( "{$base}_{$lang}.php" );
    if (!$is_multilang) @include( "{$base}_{$lang}_{$family}.php" );
    @include( "{$base}_{$dbname}.php" );
    @include( "{$base}_".str_replace('.','_',$domain).'.php' );
    
    return $$var;
}

function wsfConfigureObject( &$obj, $conf, $all=false ) {
    if (!$conf) return;

    $vars= NULL;
    if (!$all) $vars= array_keys(get_object_vars($obj));
    
    wsfLog("configuring ".get_class($obj)." object with ".sizeof($conf)." settings",LL_DEBUG);
    
    foreach ($conf as $k => $v) {
        if ($all || in_array($k,$vars)) {
            $obj->$k= $v;
            
            #print "\n<br/>CONFIGURING: ".get_class($obj)."::$k => $v <br/>\n";
        }
        #else print "\n<br/>SKIPPING: ".get_class($obj)."::$k <br/>\n";
    }
}

function dbFailFunction( &$db, $error ) {
  print "<p class='error'><b>Database Error: ".htmlspecialchars($error)."</b></p>";
}

function & openConnection( $uri ) {
        if ( is_string($uri) && preg_match( '!^%(.*)$!', $uri, $matches ) ) {
            $u= $GLOBALS['wsgDatabases'][$matches[1]];
            
            if (!$u) {
                trigger_error('unknown database ID: '.$matches[1], E_USER_WARNING);
                return false;
            }
            
            $uri= $u;
        }

	if ( is_array($uri) ) {
		extract($uri);
	}
	else {
		//pseudo-url, jdbc-style: driver://[user[:password]@]host/database
		if ( !preg_match( '!^([\w\d]+):(//(([^/@:]+)(:([^/@:]+))?@)?([\w\d-.]+)/)?([^;&\?]+)$!', $uri, $matches ) ) {
                        $dummy=false;
			return $dummy;
                }
		
		$type= $matches[1];
		$user= $matches[4];
		$password= $matches[6];
		$host= $matches[7];
		$dbname= $matches[8];
	}
        
	# Get class for this database type
	$class = 'Database' . ucfirst( $type );
	if ( !class_exists( $class ) ) {
		require_once( "includes/$class.php" );
	}
	
        #print "==> connecting to $dbname on $host using $class<br/>\n";
	
	# Create object
	$db= new $class( $host, $user, $password, $dbname, 'dbFailFunction', 0 );
        if ( !$db->mConn ) {
          $dummy= false;
          return $dummy;
        }
        
	$db->mOut= NULL;
        
	$db->ping();
	
	return $db;
}

function & getWikiListDB() {
  global $wsgWikiListDB, $wsgWikiListTable;
  global $wsgWikiDB;
  global $wsgWikiListDBConnection;
  
  if (!$wsgWikiListDB && !$wsgWikiListDBConnection) {
      wsfLog('no WikiList database defined!',LL_ERROR);
      wfDebugDieBacktrace('no WikiList database defined!');
  }
  
  if ( !$wsgWikiListDBConnection ) {
    $u= $wsgWikiListDB;
    if (strpos($u,':')===false) $u= "$wsgWikiDB/$wsgWikiListDB";
    $wsgWikiListDBConnection=& openConnection($u);
    
    if (!$wsgWikiListDBConnection) {
      wsfLog('failed to connect to WikiList database ',LL_ERROR);
      wfDebugDieBacktrace('failed to connect to WikiList database ');
    }
  }
  
  return $wsgWikiListDBConnection;
}

function getWikiInfo( $where, $limit= NULL, $usable = true ) {
  global $wsgWikiListTable, $wsgWikiDB;
  
  $db=& getWikiListDB();
  
  $w= '';
  $w.= "WHERE ";
  
  if ($where) {
    $i= 0;
    foreach ($where as $c => $v) {
      $w.= " $c = ".$db->addQuotes($v)." AND ";
      $i+= 1;
    }
  }
  
  if ($usable) $w.= " is_closed = 0 AND domain is not NULL ";

  $sql= 'SELECT * FROM '.$wsgWikiListTable.' 
        '.$w;
        
  if ($limit) $w.= " LIMIT $limit";

  $res= $db->query($sql, 'getWikiInfo');
  
  $wikis= array();
  while ($w= $db->fetchObject($res)) {
    @$w->baseURL= "http://{$w->domain}/w/index.php";
    @$w->dbURL= $wsgWikiDB ? "$wsgWikiDB/{$w->dbname}" : NULL; 
    $wikis[]= $w;
  }
  
  $db->freeResult($res);
  
  return $wikis;
}

function getWikiInfoFromLang( $lang, $family = NULL ) {
  global $wsgWikiListDB, $wsgWikiDB;
  
  if ($lang=='simple') $lang= 'en-simple';
  
  if ($lang=='commons' && (!$family || $family=='wikimedia')) {
    $lang= 'en';
    $family= 'commons';
  }
  
  if (!$family) $family= 'wikipedia';
  
  if (!$wsgWikiListDB) {
    $w= new stdClass();
    
    @$w->lang= $lang;
    @$w->family= $family;
    
    #print "FAMILY: $family; LANG: $lang\n";
    
    if ( $family=='commons' ) @$w->domain= "commons.wikimedia.org";
    else @$w->domain= "$lang.$family.org";
    
    if ( $family=='commons' ) @$w->is_multilang= true;
    else @$w->is_multilang= false;
    
    if ( $family=='wikipedia' ) @$w->dbname= "{$lang}wiki";
    else if ( $family=='commons' ) @$w->dbname= "{$family}wiki";
    else @$w->dbname= "$lang$family";
    
    @$w->baseURL= "http://{$w->domain}/w/index.php";
    @$w->dbURL= $wsgWikiDB ? "$wsgWikiDB/{$w->dbname}" : NULL;
    
    return $w;
  }
  else {
    $info= getWikiInfo( array( 'lang' => $lang, 'family' => $family ), 1 );
    if (!$info) return false;
    else return $info[0];
  }
}

function getWikiInfoFromDomain( $domain ) {
  global $wsgWikiListDB;
  
  #compatibility hack
  if (strpos($domain,'.')===false) {
    return getWikiInfoFromLang($domain);
  }
  
  if (!$wsgWikiListDB) {
    $match= array();
    if (!preg_match('/^(\w+)\.(\w+)(\.\w+)?$/',$domain,$match)) {
        return false;
    }
    
    $w= getWikiInfoFromLang($match[1], $match[2]);
    @$w->domain= $domain;
    return $w;
  }
  else {
    if (!preg_match('/.*\.org$/',$domain)) $domain.= '.org';
    
    $info= getWikiInfo( array( 'domain' => $domain ), 1 );
        
    if (!$info) return false;
    else return $info[0];
  }
}

function getLargestWikis($n, $family = NULL) {
  global $wsgWikiListDB, $wsgWikiDB, $wsgWikiBlacklist;
  
  if (!$wsgWikiListDB) {
    global $wsgLanguages;
    
    if (!$n) $l= $wsgLanguages;
    else $l= array_slice($wsgLanguages,0,$n);
    
    $wikis= array();
    foreach ($l as $lang) {
      $info= getWikiInfoFromLang($l);
      $wikis[$info['domain']]= $info;
    }
    
    return $wikis;
  }
  else {
    global $wsgWikiListTable;
    
    $db=& getWikiListDB();
    
    $sql= "select * from $wsgWikiListTable";
    $sql.= " where domain is not null";
    $sql.= " and is_closed = 0";
    
    if ($family) $sql.= " and family = ".$db->addQuotes($family);
    $sql.= " order by size desc limit $n;";
    
    $wikis= array();
    $res= $db->query($sql,'getLargestWikis');
    
    while ( $w= $db->fetchObject($res) ) {
        if (!$w->domain) continue;
        
        if ($wsgWikiBlacklist) {
          if (in_array($w->domain,$wsgWikiBlacklist)) continue;
          if (in_array($w->dbname,$wsgWikiBlacklist)) continue;
        }
        
        @$w->baseURL= "http://{$w->domain}/w/index.php";
        @$w->dbURL= $wsgWikiDB ? "$wsgWikiDB/{$w->dbname}" : NULL; 
        
        $wikis[$w->domain]= $w;
    }
    
    $db->freeResult($res);
    
    return $wikis;
  }
}

$wsgNamespaceCache= NULL;
$wsgNamespaceCacheReverse= NULL;
$wsgNamespaceCacheComplete= false;

function getCustomNsIndex( $wiki, $ns, $slurp = false ) {
    global $wsgNamespaceCache, $wsgNamespaceCacheReverse;

    if (!$ns || !$wiki) $k= NULL; //slurp only
    else $k= "$wiki#$ns";
    
    if ($wsgNamespaceCacheReverse==NULL) $wsgNamespaceCacheReverse= array();
    if ($wsgNamespaceCache==NULL) $wsgNamespaceCache= array();
    
    if ($k && isset($wsgNamespaceCacheReverse[$k]) && (!$slurp || $wsgNamespaceCacheComplete)) return $wsgNamespaceCacheReverse[$k];
    
    getCustomNsText($wiki,0,$slurp); //load
    
    if (!$k) return NULL; //slurp only
    
    if (!isset($wsgNamespaceCacheReverse[$k])) $wsgNamespaceCacheReverse[$k]= NULL;
    
    return $wsgNamespaceCacheReverse[$k];
}

function getCustomNsText( $wiki, $ns, $slurp = false ) {
    global $wsgWikiListDB;
    global $wsgNamespaceCache, $wsgNamespaceCacheReverse;
    global $wsgNamespaceCacheComplete, $wsgCustomNamespaceTable;
    
    if (!$ns || !$wiki) $k= NULL; //slurp only
    else $k= "$wiki#$ns";
    
    if ($wsgNamespaceCacheReverse==NULL) $wsgNamespaceCacheReverse= array();
    if ($wsgNamespaceCache==NULL) $wsgNamespaceCache= array();
    
    if ($k && isset($wsgNamespaceCache[$k]) && (!$slurp || $wsgNamespaceCacheComplete)) return $wsgNamespaceCache[$k];
    
    if ($wsgWikiListDB && !$wsgNamespaceCacheComplete && $wsgCustomNamespaceTable) {
        $db=& getWikiListDB();
    
        $sql= "SELECT * from $wsgCustomNamespaceTable";
        if (!$slurp) $sql.= " WHERE domain = ".$db->addQuotes($wiki);
    
        #print "LOADING NS FOR $wiki: $sql<br>";

        $res= $db->query($sql,'getCustomNamespaceName');
        while ( $w= $db->fetchObject($res) ) {
            if (!$w->domain) continue;
    
            $wsgNamespaceCache[$w->domain.'#'.$w->ns_id]= $w->ns_name;
            $wsgNamespaceCacheReverse[$w->domain.'#'.$w->ns_name]= $w->ns_name;
        }
        
        if ($slurp) $wsgNamespaceCacheComplete= true;
    }
    
    if (!$k) return NULL; //slurp only
    
    if (!isset($wsgNamespaceCache[$k])) $wsgNamespaceCache[$k]= $ns;
    
    return $wsgNamespaceCache[$k];
}

define('LL_MUTE', -100);
define('LL_SILENT', -4);
define('LL_QUIET', -2);
define('LL_NORMAL', 0);
define('LL_VERBOSE', 10);
define('LL_NOISY', 100);

define('LL_TRACE', LL_VERBOSE);
define('LL_DEBUG', LL_VERBOSE);
define('LL_INFO', LL_NORMAL);
define('LL_WARN', LL_QUIET);
define('LL_ERROR', LL_SILENT);

function wsfToString($data) {
  if ($data === NULL) $data= "<null>";
  else if ($data===false) $data= "<false>";
  else if ($data===true) $data= "<true>";
  else if (is_object($data)) $data= get_object_vars($data);
  
  if (is_array($data)) {
    $s= "{";
    foreach ( $data as $k => $v ) {
      $s.= "$k => ".wsfToString($v).", ";
    }
    
    $s.= "}";
    $data= $s;
  }
  
  return $data;
}

function wsfLog( $msg, $level = LL_NORMAL, $data='@dummy@' ) {
	global $wsgLogLevel, $wsgLogHashCounter, $wsgLogSuffix, $wsgLogTag;
        
	if ($level>$wsgLogLevel) {
          if ($level>$wsgLogLevel+2) {
            return;
          }
          else {
            if ( $wsgLogHashCounter == 0 ) {
              print "   ";
            }
            
            if ($level<LL_NORMAL) print "!";
            else print ".";
            
            $wsgLogHashCounter+= 1;
            
            if ( $wsgLogHashCounter > 50 ) {
              print $wsgLogSuffix;
              $wsgLogHashCounter = 0;
            }
          }
        }
        else {
          if ( $wsgLogHashCounter > 0 ) {
            print $wsgLogSuffix;
            $wsgLogHashCounter = 0;
          }
          
          if ($data==='@dummy@') $data= '';
          else $msg.= " (".wsfToString($data).")";
          
          if ($wsgLogTag) print "<$wsgLogTag>";
          print " - $msg";
          if ($wsgLogTag) print "</$wsgLogTag>";
          print "\n";
        }
        
        flush();
}

function wsfDBTitle( $title ) {
    $title= urldecode( $title ); #HACKish
    $title= Sanitizer::decodeCharReferences( $title );
    $title= str_replace(' ','_',$title);
    $title= ucfirst($title); //FIXME: unicode! //FIXME: optional!
    return $title;
}

function & wsfStripIntKeys( &$array ) {

	if ( $array === NULL || $array===false ) return $array;
	
	foreach ( $array as $k => $v ) {
		if (is_int($k)) unset($array[$k]);
	}
	
	return $array;
}

function stripMarkup( $text ) {
  

  #print "\n---> $text\n";
  $text= preg_replace("!\"|'''?|<[\\w\\d]+.*?/?>|</[\\w\\d]+>!",'',$text);
  $text= preg_replace('!^[\s]+|[\s]+$!','',$text); #FIXME: unicode whitespace
  if (strlen($text>2)) $text= preg_replace('!^[\s"\'\]\[<>,;.:?\{\}]+|[\s"\'\]\[<>,,;.:?\{\}]+$!','',$text); #FIXME: unicode punctuation
  $text= Sanitizer::decodeCharReferences( $text );
  #print "===> $text\n";
  #FIXME: strip punctuation
  return $text;
}

function stripHTML( $text ) {
  $text= preg_replace("!<[\\w\\d]+.*?/?>|</[\\w\\d]+>!",'',$text);
  $text= preg_replace("/<!--.*?-->/",'',$text);
  return $text;
}

function endsWith( $haystack, $needle ) {
  if (strlen($haystack)<strlen($needle)) return false;
  else {
    $x= substr($haystack, strlen($haystack) - strlen($needle));
    
    if ($x === $needle) return true;
    else return false;
  }
}

function escapeChunkCallback( $value, $prefix, &$store ) {
    static $i;
    if (!isset($i)) $i= 0;
    
    $i+= 1; 
    $k= "@@$prefix:$i:".rand(1,1000)."@@"; 
    $store[$k]= $value; 
    return $k;
}

function escapeChunks( $prefix, $preg, &$text, &$store ) {
    $code= 'escapeChunkCallback(\'\0\',$prefix,$store)';
    
    $text= preg_replace($preg.'e',$code,$text);
    
    return $text;
}

function unescapeChunks( &$text, &$store ) {
    $text= str_replace(array_keys($store),array_values($store),$text);
    return $text;
}

class PseudoLoadBalancer {
  var $db;
  function PseudoLoadBalancer( &$db ) {
    $this->db=& $db;
  }
  
  function & getConnection( $dummy1, $dummy2, $dummy3 ) {
    return $this->db;
  }
}

class PseudoOut {
  function disable() {}
  function sendCacheControl() {}
  function debug() {}
}

#global $wgOut;
if (!isset($wgOut) || !$wgOut) {
    $wgOut= new PseudoOut();
}

function printRadioButton($name, $value, $current= NULL, $a= '') {
    $s= $value!=$current ? '' : " checked='checked' ";
    print "<input type='radio' name='$name' value='$value'$s$a/>";
}

function printCheckbox($name, $value, $a= '') {
    $s= $value ? " checked='checked' " : '';
    print "<input type='checkbox' name='$name' $s$a/>";
}

function printOption($label, $value, $current= NULL, $a= '') {
    $s= $value!=$current ? '' : " selected='selected' ";
    print "<option value='$value'$s$a>$label</option>";
}

function printSelector($name, $options, $current= NULL) {
    print "\n<select name='$name'>";
    
    foreach ($options as $v => $label) {
        printOption($label, $v, $current);
    }
    
    print "\n</select>\n";
}

function addURLParam(&$url, $key, $value, $html=true) {
    if (isset($value) && $value !== NULL && $value!==false && $value!=='') {
        $value= urlencode($value);
        
        if ($html) $url.= '&amp;';
        else $url.= '&';
        
        $url.= $key;
        $url.= '=';
        $url.= $value;
    }
     
    return $url;
}

function wsfHackingInProgress() {
  ?>
      <p style="border:1px solid black; background-color:yellow; margin:1ex; padding: 1ex;">
      <b>WARNING: <i>Hacking in Progress!</i></b><br/>
      This tool is currently being modified and debugged. You can try to use it, but you may 
      get unexpected or wrong results. Or it may simply be broken for a while. Please try again
      later if you need to use it for anything serious.
      </p>
      
  <?
}

function wsfSubtitle( $name ) {
  $help= 'http://meta.wikimedia.org/wiki/User:Duesentrieb/'.urlencode($name);
  $talk= 'http://meta.wikimedia.org/wiki/User_talk:Duesentrieb/'.urlencode($name);
  
  ?>
  <p style='font-size:70%;'>
    <a href='<?=$help?>'><?= wsfWikiSenseMessage('help_page_label') ?></a>
    |
    <a href='<?=$talk?>'><?= wsfWikiSenseMessage('talk_page_label') ?></a>
  </p>
  <?    
}

function wsfFooter( $done = true, $bundle = NULL ) {
  global $wsgFooter;
  if ($wsgFooter) include($wsgFooter);
}

function wsfHeader( $done = true, $bundle = NULL ) {
  global $wsgHeader;
  if ($wsgHeader) include($wsgHeader);
}

function wsfCachePut($uri, $data) {
    global $wsgCacheDir;
    if (!$wsgCacheDir) return false;
    if (!file_exists($wsgCacheDir)) return false;
    if (!is_dir($wsgCacheDir)) return false;
    if (!is_writable($wsgCacheDir) || !is_readable($wsgCacheDir)) return false;

    $f= $wsgCacheDir.'/'.str_replace(array('/','&','+','*','?',';',':',' '),'_',$uri).'.cache';
    
    $ok= file_put_contents($f,$data);
    return $ok;
}

function wsfCacheGet($uri, $duration, $sendLastModified=false) {
    global $wsgCacheDir;
    if (!$wsgCacheDir) return false;
    if (!file_exists($wsgCacheDir)) return false;
    if (!is_dir($wsgCacheDir)) return false;
    if (!is_writable($wsgCacheDir) || !is_readable($wsgCacheDir)) return false;

    $f= $wsgCacheDir.'/'.str_replace(array('/','&','+','*','?',';',':',' '),'_',$uri).'.cache';
    
    if (!file_exists($f)) return NULL;
    if (!is_file($f)) return NULL;
    if (!is_readable($f)) return NULL;
    
    $time= filemtime($f);
    if (!$duration || ((time() - $time) > $duration) ) { //cache is stale
        unlink($f);
        return NULL; 
    }
    
    $data= file_get_contents($f);
    
    if ($data !== NULL && $data!==false && $sendLastModified && !headers_sent()) {
        header('Last-Modified: '.wfTimestamp(TS_RFC2822,$time)); 
    }
    
    return $data;
}

function wsfCacheStart($uri, $duration) {
    if ($duration===false) return false;
    
    $data= wsfCacheGet($uri, $duration, true);
    if ($data===false) return false;
    
    if ($data !== NULL) {
        if (!headers_sent()) header('X-WS-Cached: yes'); 
        print $data;
        return true;
    }
    
    ob_start();
    return NULL;
}

function wsfCacheEnd($uri) {
    if (!ob_get_level()) return false;
    
    $data= ob_get_contents();
    ob_end_flush();
    
    wsfCachePut($uri, $data);
}

if (!function_exists('file_put_contents')) {
    function file_put_contents($f, $data, $append = false) {
        $fh= fopen($f,$append?'a':'w');
        if (!$fh) return false;
        
        $ok= fwrite($fh,$data);
        fclose($fh);
        
        return $ok;
    }
}

global $wsgWikiSenseMessages;
$wsgWikiSenseMessages= NULL;

function wsfWikiSenseMessage($key) {
    global $wsgWikiSenseMessages, $wsgUserLang;
    
    if ($wsgUserLang && $wsgWikiSenseMessages && $wsgWikiSenseMessages->language != $wsgUserLang) {
        $wsgWikiSenseMessages= NULL;
    }
    
    if (!$wsgWikiSenseMessages) {
        if (!class_exists('WikiSenseLocalizer')) {
            require_once('WikiSenseLocalizer.php');
        }
        
        $wsgWikiSenseMessages= WikiSenseLocalizer::load( 'WikiSense', $wsgUserLang ? $wsgUserLang : 'en' );
    }
    
    $args= func_get_args();
    return call_user_func_array ( array(&$wsgWikiSenseMessages, 'msg'), $args );
}

function wsfGetReplag() {
    global $wsgReplagFile, $wsgReplagPattern;
    
    if (!$wsgReplagFile) return NULL;
    
    $t= file_get_contents($wsgReplagFile);
    
    if ($t === NULL || $t===false) return false;
    
    $t= trim($t);
    
    if ($wsgReplagPattern) $t= eval($wsgReplagPattern);
    
    return $t;
}

function wsfGetReplagHTML() {
    $lag= wsfGetReplag();
    if ($lag === NULL) return '';
    if ($lag===false) return '<span class="error">failed to get replication lag!</span>';
    
    if ($lag==='0' || $lag===0 || $lag < 8) return '<span style="color:green;">database is up to date.</span>';
    
    $html= '';
    $s= $lag;
    
    $d= floor($s / (60*60*24));
    if ($d) {
        $s-= $d * 60*60*24;
        if ($html) $html.= ', ';
        $html.= "$d days";
    }
    
    $h= floor($s / (60*60));
    if ($h) {
        $s-= $h * 60*60;
        if ($html) $html.= ', ';
        $html.= "$h hours";
    }
    
    $m= floor($s / (60));
    if ($m) {
        $s-= $m * 60;
        if ($html) $html.= ', ';
        $html.= "$m minutes";
    }
    
    if ($s) {
        if ($html) $html.= ', ';
        $html.= "$s seconds";
    }
    
    if ($lag > 60 * 60 * 12) $style= 'font-weight:bold; color:yellow; background-color:red;';
    else if ($lag > 60 * 60) $style= 'color:black; background-color:red;';
    else if ($lag > 60 *  5) $style= 'color:black; background-color:orange;';
    else if ($lag > 60 *  1) $style= 'color:black; background-color:yellow;';
    else $style= 'color:green;';
    
    $html= "<span style='$style'>database lag: $html</span>";
    
    return $html;
}

/*
function preg_replace_recursive($begin, $end, $sep, $mod, $replace, $s) {
    $s= preg_replace("$sep$begin((?>.*?)(?R))*.*?$end$sep$mod",'',$s);
    return $s;
}
*/

function preg_strip($exp, $s) {
    while (true) {
        $l= strlen($s);
        #print "--> $s \n";
        $s= preg_replace($exp,'',$s);
        if ($l==strlen($s)) break;
    }
    
    return $s;
}

function wsfMicroTime()
{
   list($usec, $sec) = explode(" ", microtime());
   return ((float)$usec + (float)$sec);
}

function levensteinDistance($a, $b, $normalize=false, $limit=0) {
    $d= array();
    $ca= is_array($a) ? sizeof($a) : mb_strlen($a);
    $cb= is_array($b) ? sizeof($b) : mb_strlen($b);
    
    if ($a === $b) return 0;
    if ($a==='' || $a===NULL || (is_array($a) && sizeof($a)===0)) return $cb;
    if ($b==='' || $b===NULL || (is_array($b) && sizeof($b)===0)) return $ca;
    
    $v= abs($ca-$cb);
    if ($normalize) $v= $v / (float)max($ca,$cb);
    if ($limit && $v > $limit) return $v;
    
    for ($i= 0; $i<=$ca; $i+= 1) $d[$i]= array( 0 => $i );
    for ($j= 0; $j<=$cb; $j+= 1) $d[0][$j]= $j;
    
    for ($i= 1; $i<=$ca; $i+= 1) {
    
        for ($j= 1; $j<=$cb; $j+= 1) {
            $ach= is_array($a) ? $a[$i-1] : mb_substr($a,$i-1,1);
            $bch= is_array($a) ? $a[$i-1] : mb_substr($b,$j-1,1);
            
            $cost= $ach == $bch ? 0 : 1;
            
            $d[$i][$j]= min(
                              $d[$i-1][$j  ] + 1, //deletion
                              $d[$i  ][$j-1] + 1, //insertion
                              $d[$i-1][$j-1] + $cost //substitution
                           );

            /*                           
            $v= $d[$i][$cb];
            if ($normalize) $v= $v / (float)max($ca,$cb);
            
            if ($limit && $v > $limit) return $v;
            */
            #FIXME: abort if hopeles... how?!
        }
    }
    
    if ($normalize) {
        $f= (float)$d[$ca][$cb] / (float)max($ca,$cb);
        return $f;
    }
    else return $d[$ca][$cb];
}


if (defined('WS_TEST')) {
    $d= levensteinDistance($args[1], $args[2], true, 0.2);
    print "DISTANCE: $d\n";
}

?>