<?php 

// if (!class_exists("app")) {
//     $url = file_get_contents("http://aftermarket.7zap.com/fr/pc/587/500/1658/0/");
//     $doc = HTMLE::parse($url);
//     $rep = $doc->query([
//       "list"=>[
//         "selector" => "#jstree > ul > li",
//         "titre" => " > a:text",
//         "args" => " > a@onclick",
//         "list" =>[
//             "selector"=>" > ul > li",
//             "titre" => " > a:text",
//             "args" => " > a@onclick",
//             "list" =>[
//                 "selector"=>" > ul > li",
//                 "titre" => " > a:text",
//                 "args" => " > a@onclick",
//             ]
//         ]
//       ]
//     ]);
//     print_r($rep);
// }

class HTMLE{
	var $name = "";
	var $data = "";
	var $html = "";
	var $_attr = array();
	var $parent = null;
	var $child = array();
	var $as = [];
	var $astmp = [];
	var $doc = null;
	function __construct($arg){
		$this->name = $arg["name"];
		if(is_string($arg["code"]) && strlen($arg["code"])>0){
			$this->data = $arg["code"];
		}
		$this->_attr = isset($arg["attr"])?$arg["attr"]:array();
		foreach ($this->_attr as $key => $value) {
			if (preg_match("/>$/i",$key)) {
				$key1 = substr($key, 0, strlen($key)-1);
				unset($this->_attr[$key]);
				$this->_attr[$key1] = $value;
			}
		}
	}
	function setDoc(&$doc){
		$this->doc = $doc;
		foreach ($this->child as $key => $value) {
			$this->child[$key]->setDoc($doc);
		}
	}
	function getDoc(){
		return $this->doc;
		if ($this->$parent) {
			return $this->$parent->getDoc();
		}
		return $this;
	}
	function outerHTML($query="*"){
		if(!$this->is($query)) return "";
		if($this->name=="#text") return $this->data;
		if($this->name=="#comment") return "";
		$attrs = "";
		foreach ($this->_attr as $key => $value) {
			$attrs .= " $key=\"$value\"";
		}
		if(in_array(strtolower($this->name), array("hr","br","img"))) return "<".$this->name."$attrs>";
		$s = "<".$this->name."$attrs>";
		foreach ($this->child as $node) {
			$s .= $node->outerHTML($query);
		}
		$s .="</".$this->name.">";
		return $s;
	}
	function articlehtml($query="*"){
		if(!$this->is($query)) return "";
		if($this->name=="#text") return $this->data;
		if($this->name=="#comment") return "";
		$attrs = "";
		foreach ($this->_attr as $key => $value) {
			if (in_array(strtolower(trim($key)),["id","class","href","src"])) {
				$attrs .= " $key=\"$value\"";
			}
		}
		if(in_array(strtolower($this->name), array("hr","br","img"))) return "<".$this->name."$attrs>";
		$s = "<".$this->name."$attrs>";
		foreach ($this->child as $node) {
			$s .= $node->articlehtml($query);
		}
		$s .="</".$this->name.">";
		return $s;
	}
	function remove(){
		if($this->parent && $this->parent->child)
		foreach ($this->parent->child as $key => $value) {
			if ($this->parent->child[$key] === $this) {
				unset($this->parent->child[$key]);
			}
		}
	}
	function delete(){
		$this->remove();
	}
	static function get($url){
		if (preg_match("/tayara\.tn/i", $url)) {
			$url = str_replace("è", "%C3%A8", $url);
			$url = str_replace("é", "%C3%A9", $url);
			return html_entity_decode(Encoding::toUTF8(file_get_contents($url)));
		}
		$agent= 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)';
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
		curl_setopt($ch, CURLOPT_VERBOSE, true);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
		curl_setopt($ch, CURLOPT_USERAGENT, $agent);
		curl_setopt($ch, CURLOPT_URL,$url);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT ,15); 
		curl_setopt($ch, CURLOPT_TIMEOUT, 15);
		$result=curl_exec($ch);
		$infos = curl_getinfo($ch);
		if (!in_array($infos["http_code"],[200,201,202,203,204,205,206,301,302,304,307])) {
			$result = "";
		}
		curl_close($ch);
		return html_entity_decode(Encoding::toUTF8($result));
	}
	static function parse($htmlcode,$urlRef=""){
		if(preg_match("/^https?:\/\/.*/i", $htmlcode)){
			$urlRef = $htmlcode;
			$htmlcode = self::get($htmlcode);
		}
		$htmlcode = "<doc>$htmlcode<url>$urlRef</url></doc>";
		$cursor = 0;
		$lastcursor = 0;
		$result = array();
		while ($cursor < strlen($htmlcode)) {
			$p = strpos($htmlcode, "<",$cursor);
			if($p !== false){
				$cursor = $p;
			}
			$code = substr($htmlcode,$cursor,5000);
			if(preg_match("/^<[a-zA-Z]+(\"(\\.|[^\"]*)\"|\'(\\.|[^\']*)\'|[^\"\'>]*)*>/i", $code, $r)){
				$tag = $r[0];
				$arg = array("type"=>"open", "name"=>"", "attr" => array(), "code"=>$r[0] );
				$cu = 0;
				$lastkey = "";
				while ($cu < strlen($tag)) {
					$str = substr($tag, $cu);
					if(preg_match("/^<([a-zA-Z]+[^\s>]*)/i", $str, $rr)){
						$arg["name"] = $rr[1];
						$cu += strlen($rr[0]);
					}elseif(preg_match("/^([a-zA-Z]+[^\s=]*)/i", $str, $rr)){
						$lastkey = strtolower($rr[1]);
						$arg["attr"][strtolower($rr[1])] = "";
						$cu += strlen($rr[0]);
					}elseif(preg_match("/^=\s*\"(\\.|[^\"]*)\"/i", $str, $rr)){
						$arg["attr"][strtolower($lastkey)] = $rr[1];
						$cu += strlen($rr[0]);
					}elseif(preg_match("/^=\s*\'(\\.|[^\']*)\'/i", $str, $rr)){
						$arg["attr"][strtolower($lastkey)] = $rr[1];
						$cu += strlen($rr[0]);
					}elseif(preg_match("/^=\s*([^\s]+)/i", $str, $rr)){
						$arg["attr"][strtolower($lastkey)] = $rr[1];
						$cu += strlen($rr[0]);
					}else{
						$cu++;
					}
				}
				$txt = trim(substr($htmlcode, $lastcursor,$cursor - $lastcursor));
				if(!empty($txt)){$result[] = array("type"=>"#text", "name"=>"#text", "code"=>$txt ); }
				$result[] = $arg;
				$cursor += strlen($r[0]);
				$lastcursor = $cursor;
			}elseif(preg_match("/^<!([a-zA-Z]+[^\s>]*)(\"(\\.|[^\"]*)\"|\'(\\.|[^\']*)\'|[^\"\'>]*)*>/i", $code, $r)){
				$txt = trim(substr($htmlcode, $lastcursor,$cursor - $lastcursor));
				if(!empty($txt)){$result[] = array("type"=>"#text", "name"=>"#text", "code"=>$txt ); }
				$result[] = array("type"=>"doctype", "name"=>$r[1], "code"=>$r[0] );
				$cursor += strlen($r[0]);
				$lastcursor = $cursor;
			}elseif(preg_match("/^<\/([a-zA-Z]+[^\s>]*)(\"(\\.|[^\"]*)\"|\'(\\.|[^\']*)\'|[^\"\'>]*)*>/i", $code, $r)){
				$txt = trim(substr($htmlcode, $lastcursor,$cursor - $lastcursor));
				if(!empty($txt)){$result[] = array("type"=>"#text", "name"=>"#text", "code"=>$txt ); }
				$result[] = array("type"=>"close", "name"=>$r[1], "code"=>$r[0] );
				$cursor += strlen($r[0]);
				$lastcursor = $cursor;
			}elseif(preg_match("/^<!--[\s\S]*?-->/i", $code, $r)){
				$txt = trim(substr($htmlcode, $lastcursor,$cursor - $lastcursor));
				if(!empty($txt)){$result[] = array("type"=>"#text", "name"=>"#text", "code"=>$txt ); }
				$result[] = array("type"=>"#comment", "name"=>"#comment", "code"=>$r[0] );
				$cursor += strlen($r[0]);
				$lastcursor = $cursor;
			}else{
				$cursor++;
			}
		}
		$base = $urlRef;
		foreach ($result as $key => $value) {
			if($value["type"] == "open" && strtolower($value["name"]) == "base" ){
				$base = $value["attr"]["href"];
				if (preg_match("/^\/\//i", $base)) {
			    	$base =  parse_url($urlRef, PHP_URL_SCHEME).":".$base;
				}
				break;
			}
		}
		foreach ($result as $key => $value) {
			if($value["type"] == "open"){
				if(isset($value["attr"]["href"]) && !preg_match("/^https?:\/\//i", $value["attr"]["href"])) $result[$key]["attr"]["href"] = self::rel2abs($value["attr"]["href"],$base);
				if(isset($value["attr"]["src"]) && !preg_match("/^https?:\/\//i", $value["attr"]["src"])) $result[$key]["attr"]["src"] = self::rel2abs($value["attr"]["src"],$base);
			}
		}
		$tagnocontent = array("meta","link","img","input","br","hr","base");
		$tagparent = array("td"=>"tr","th"=>"tr","tr"=>array("table","tbody","thead"),"li"=>array("ul","ol"),"body"=>"html","head"=>"html","title"=>"head");
		$list = array();
		$res = array();
		foreach ($result as $key => $value) {
			switch ($value["type"]) {
				case 'open':
					$e = new HTMLE($value);
					if(array_key_exists(strtolower($e->name), $tagparent)){
				        for ($i=count($list)-1; $i >=0 ; $i--) {
				        	if(is_array($tagparent[strtolower($e->name)])){
					            if(in_array(strtolower($list[$i]->name), $tagparent[strtolower($e->name)])){
					                break;
					            }
				        	}elseif(strtolower($list[$i]->name)==$tagparent[strtolower($e->name)]){
				        		break;
				        	}
				        }
				        if($i>0) array_splice($list, $i+1);
					}
					if(!empty($list)){
						$e->parent = $list[count($list)-1];
						$list[count($list)-1]->child[] = $e;
					}else{
						$res[] = $e;
					}
					if(!in_array(strtolower($value["name"]), $tagnocontent)){
						foreach ($result as $k => $v) {
							if($v["type"] == "close" && strtolower($v["name"]) == strtolower($e->name)){
								$list[] = $e;
								break;
							}
						}
					}
				break;
				case 'close':
					if (!in_array($value["name"], $tagnocontent)) {
						if(count($list)>0){
				            for ($i=count($list)-1; $i >=0 ; $i--) {
				                if(strtolower($list[$i]->name) == strtolower($value["name"])){
				                  break;
				                }
				            }
				            array_splice($list, $i);
						}
					}
				break;
				case '#text':
				case '#comment':
					$e = new HTMLE($value);
					if(!empty($list)){
						$e->parent = $list[count($list)-1];
						$list[count($list)-1]->child[] = $e;
					}else{
						$res[] = $e;
					}
				break;
			}
		}
		$doc = new HTMLE(array("name"=>"document"));
		$doc->child = $res;
		$doc->html = $htmlcode;
		$doc->setDoc($doc);
		return $doc;
	}
	static function rel2abs($rel, $base) {
		if (preg_match("/^\/\//i", $rel)) {
	    	$rel = explode("#", $rel);
	    	return parse_url($base, PHP_URL_SCHEME).":".$rel[0];
		}
		if (preg_match("/^:\/\//i", $rel)) {
	    	$rel = explode("#", $rel);
	    	return parse_url($base, PHP_URL_SCHEME).$rel[0];
		}
	    if (parse_url($rel, PHP_URL_SCHEME) != ''){
	    	$rel = explode("#", $rel);
	    	return $rel[0];
	    }
	    if ($rel[0]=='#' || $rel[0]=='?'){
	    	$rel = explode("#", $base.$rel);
	    	return $rel[0];
	    }
	    extract(parse_url($base));
	    $path = preg_replace('#/[^/]*$#', '', $path);
	    if ($rel[0] == '/') $path = '';
	    $abs = "$host$path/$rel";
	    $re = array('#(/\.?/)#', '#/(?!\.\.)[^/]+/\.\./#');
	    for($n=1; $n>0; $abs=preg_replace($re, '/', $abs, -1, $n)) {}
	    $rel = explode("#", $scheme.'://'.$abs);
		if (preg_match("/^\/\//i",$rel[0])) {
			return parse_url($base, PHP_URL_SCHEME).":".$rel[0];
		}
	    return $rel[0];
	}
	function attr($name,$def = null){
		return isset($this->_attr[$name])?$this->_attr[$name]:$def;
	}
  function innerText($niv=0,$filter = "*"){
    if(in_array(strtolower(trim($this->name)), array("script","style"))){
      return "";
    }
    if(in_array(strtolower(trim($this->name)), array("br","hr"))){
      return "\n";
    }
    if($this->name == "#text"){
      return preg_replace("/\s+/i", " ", $this->data);
    }
    $code = "";
    if(floatval($niv) == 1){
      foreach ($this->child as $key => $value) {
        if($value->name == "#text"){
          if(!empty($value->data)){
            if(!empty($code)) $code .=" ";
            $code .= preg_replace("/\s+/i", " ", $value->data);
          }
        }
      }
    }else{
      foreach ($this->child as $key => $value) {
        if(!in_array(strtolower(trim($value->name)), array("script","style")) && $value->is($filter)){
          $c = $value->innerText(0,$filter);
          if(!empty($c)){
            if(!empty($code)) $code .=" ";
            switch (strtolower(trim($value->name))) {
              case "li":
                $c = "●  ".$c;
              break;
              case 'h1':
              case 'h2':
              case 'h3':
              case 'h4':
                $code .="\n";
              break;
            }
            if($value->is(".title")){
              $code .="\n";
            }
            $code .= $c;
            switch (strtolower(trim($value->name))) {
              case "span":
                if($value->is(".title")){
                  $code .="\n".str_repeat("-", min(92,round(strlen($c)*7/10)))."\n";
                }
              case "#text":
              case "a":
              case "abbr":
              case "acronym":
              case "b":
              case "bdo":
              case "big":
              case "cite":
              case "code":
              case "dfn":
              case "em":
              case "i":
              case "img":
              case "input":
              case "kbd":
              case "label":
              case "q":
              case "samp":
              case "select":
              case "small":
              case "strong":
              case "sub":
              case "sup":
              case "textarea":
              case "tt":
              case "var":

              break;
              case 'h1':
              case 'h2':
              case 'h3':
              case 'h4':
                $code .="\n".str_repeat("-", min(92,round(strlen($c)*7/10)))."\n";
              break;
              default:
                $code .="\n";
              break;
            }
          }
        }
      }
    }
    return $code;
  }
	function schema($niv = 0){
		$sep = str_repeat("-", $niv);
		$code = $sep." ".$this->name.($this->name=="#text" && $this->parent && $this->parent->name !=="script"?" : ".$this->data:"")."\n";
		foreach ($this->child as $key => $node) {
			$code .= $node->schema($niv+1);
		}
		return $code;
	}

	function is($query){
	  $i = 0;
	  $selectedNode = $this;
	  $j = 0;
	  while ($i < strlen($query)) {
		$q = substr($query, $i);
		$j++;
		if($j>150){
		  return null;
		}
		if(preg_match("/^([a-zA-Z0-9-_]+|\*)/i", $q, $r)){
		  if($r[1] == "*" || strtolower(trim($r[1]))==strtolower(trim($selectedNode->name)) ){

		  }else{return null;}
		  $i += strlen($r[0]);
		}elseif(preg_match("/^(\.|\#)([a-zA-Z0-9-_]+)/i", $q, $r)){
		  if($r[1] == "." && preg_match("/( |^)".strtolower(trim($r[2]))."( |$)/i", strtolower(trim($selectedNode->attr("class")))) ){

		  }elseif($r[1] == "#" && preg_match("/( |^)".strtolower(trim($r[2]))."( |$)/i", strtolower(trim($selectedNode->attr("id")))) ){

		  }else{return null;}
		  $i += strlen($r[0]);
		}elseif(preg_match("/^@([a-zA-Z0-9-_]+)/i", $q, $r)){
			if(!is_a($selectedNode,"HTMLE")) return null;
		  $selectedNode = $selectedNode->attr($r[1]);
		  $i += strlen($r[0]);
		}elseif(preg_match("/^\[\s*([a-zA-Z0-9-_]+)\s*\]/i", $q, $r)){
			if(!is_a($selectedNode,"HTMLE")) return null;
		 if(!isset($selectedNode->_attr[$r[1]])) return false;
		  $i += strlen($r[0]);
		}elseif(preg_match("/^\[\s*([a-zA-Z0-9-_]+)\s*=\s*'((\\'|[^'])*?)'\s*\]/i", $q, $r)){
			if(!is_a($selectedNode,"HTMLE")) return null;
		 if(!isset($selectedNode->_attr[$r[1]])) return false;
		 if(strtolower(trim($selectedNode->_attr[$r[1]])) !== strtolower(trim($r[2]))) return false;
		 $i += strlen($r[0]);
		}elseif(preg_match("/^\[\s*([a-zA-Z0-9-_]+)\s*=\s*\"((\\\"|[^\"])*?)\"\s*\]/i", $q, $r)){
			if(!is_a($selectedNode,"HTMLE")) return null;
		 if(!isset($selectedNode->_attr[$r[1]])) return false;
		 if(strtolower(trim($selectedNode->_attr[$r[1]])) !== strtolower(trim($r[2]))) return false;
		 $i += strlen($r[0]);
		}elseif(preg_match("/^\[\s*([a-zA-Z0-9-_])+\s*=([^\s]+)\s*\]/i", $q, $r)){
			if(!is_a($selectedNode,"HTMLE")) return null;
		 if(!isset($selectedNode->_attr[$r[1]])) return false;
		 if(strtolower(trim($selectedNode->_attr[$r[1]])) !== strtolower(trim($r[2]))) return false;
		 $i += strlen($r[0]);
		}elseif(preg_match("/^:([a-zA-Z0-9-_]+)(\(((\s*\"((\\\"|[^\"])*?)\"\s*|\s*'((\\'|[^'])*?)'\s*|[^\)]*?)(,(\s*\"((\\\"|[^\"])*?)\"\s*|\s*'((\\'|[^'])*?)'\s*|[^\)]*?))*)\))?/i", $q, $r)){
		  $arg = array();
		  if(preg_match_all("/(\s*\"((\\\"|[^\"])*?)\"\s*|\s*'((\\'|[^'])*?)'\s*|([^\)]*?))(,|$)/i", $r[3], $ra)){
		    foreach ($ra[1] as $key => $value) {
		      if(preg_match("/\"(.*)\"/i", $value, $rrr)){
		        $arg[] = $rrr[1];
		      }elseif(preg_match("/\'(.*)\'/i", $value, $rrr)){
		        $arg[] = $rrr[1];
		      }else{
		        $arg[] = $value;
		      }
		    }
		  }
		  if (is_a($selectedNode,"HTMLE") && is_callable(array($selectedNode, "cssSelectorFunction_".$r[1]))) {
		   $selectedNode = $selectedNode->{"cssSelectorFunction_".$r[1]}($arg);
		  }elseif(is_string($selectedNode)){
		    switch (strtolower(trim($r[1]))) {
		      case 'regex':
		        if (preg_match($arg[0],html_entity_decode($selectedNode, ENT_COMPAT, 'UTF-8'),$rr)) {
		          if(isset($arg[1]) && !empty($arg[1])){
		            if(isset($rr[$arg[1]])){
		              $selectedNode = $rr[$arg[1]];
		            }else{
		              return null;
		            }
		          }
		        }else{
		          return null;
		        }
		      break;
		      case 'if':
		        return preg_match($arg[0], html_entity_decode($selectedNode, ENT_COMPAT, 'UTF-8'))?$arg[1]:$arg[2];
		      break;
		      case 'preg_replace':
		        if ($vv = preg_replace($arg[0],$arg[1],html_entity_decode($selectedNode, ENT_COMPAT, 'UTF-8'))) {
		          $selectedNode = $vv;
		        }
		      break;
		      case 'replace':
		      case 'str_replace':
		        if ($vv = str_replace($arg[0],$arg[1],html_entity_decode($selectedNode, ENT_COMPAT, 'UTF-8'))) {
		          $selectedNode = $vv;
		        }
		      break;
		      case "as":
			    if (preg_match("/^[a-zA-Z0-9-_]+$/i", $arg[0])) {
		      		$this->getDoc()->astmp[$arg[0]] = $selectedNode;
			    }elseif(preg_match("/".$arg[0]."/i",$selectedNode,$match)){
			    	foreach ($match as $key => $value) {
			    		if (is_string($key)) {
			    			$this->getDoc()->astmp[$key] = $value;
			    		}
			    	}
			    }
		      break;
		      case "asok":
		      	$this->getDoc()->as[] = $this->getDoc()->astmp;
		      	$this->getDoc()->astmp = [];
		      break;
		      case "index":
		      	$this->getDoc()->choseindex = (int)$arg[0];
		      break;
		    }
		  }
		  $i += strlen($r[0]);
		}else{
		  return null;
		}
	  }
	  return $selectedNode;
	}
	function cssSelectorFunction_parent($arg){
		if(!empty($arg)){
			$v = $this;
			while ($v->parent) {
				$v = $v->parent;
				if($v->is($arg[0])) return $v;
			}
			return null;
		}
	  	return $this->parent;
	}
	function cssSelectorFunction_text($arg){
	  if(isset($arg[0]) && !empty($arg[0])){
	    return $this->innerText(0,$arg[0]);
	  }
	  return $this->innerText();
	}
	function cssSelectorFunction_html($arg){
	  if(isset($arg[0]) && !empty($arg[0])){
	    return $this->outerHTML($arg[0]);
	  }
	  return $this->outerHTML();
	}
	function cssSelectorFunction_article($arg){
	  if(isset($arg[0]) && !empty($arg[0])){
	    return $this->articlehtml($arg[0]);
	  }
	  return $this->articlehtml();
	}
	function cssSelectorFunction_delete($arg){
	  return $this->delete();
	}
	function cssSelectorFunction_remove($arg){
	  return $this->delete();
	}
	function cssSelectorFunction_regex($arg){
	  if (preg_match($arg[0],html_entity_decode($this->innerText(), ENT_COMPAT, 'UTF-8'))) {
	    return $this;
	  }else{
	    return null;
	  }
	}
	function cssSelectorFunction_next($arg){
		$finded = false;
		foreach ($this->parent->child as $key => $node) {
			if(!$finded){
				if($this === $node){
					$finded = true;
				}
			}elseif(count($arg)>0){
				if($node->is($arg[0])){
					return $node;
				}
			}else{
				return $node;
			}
		}
		return null;
	}
	function cssSelectorFunction_not($arg){
	  return $this->is($arg[0])?null:$this;
	}
	function cssSelectorFunction_if($arg){
	 	return preg_match($arg[0], $this->innerText())?$arg[1]:$arg[2];
	}
	function cssSelectorFunction_n($nbr){
	  $ord = 0;
	  for ($i=0; $i < count($this->parent->child) ; $i++) { 
	    if($this->parent->child[$i]->name != "#text"){
	      $ord++;
	      if($ord == $nbr[0]){
	        if($this === $this->parent->child[$i]){
	          return $this;
	        }else{
	          return null;
	        }
	      }
	    }
	  }
	}
	function cssSelectorFunction_as($arg){
		$selectedNode = $this->innerText();
		if (preg_match("/^[a-zA-Z0-9-_]+$/i", $arg[0])) {
			$this->getDoc()->astmp[$arg[0]] = $selectedNode;
		}else{
			if(preg_match("/".$arg[0]."/i",$selectedNode,$match)){
				foreach ($match as $key => $value) {
					if (is_string($key)) {
						$this->getDoc()->astmp[$key] = $value;
					}
				}
			}
		}
		return $this;
	}
	function cssSelectorFunction_asok($arg){
		$this->getDoc()->as[] = $this->getDoc()->astmp;
		$this->getDoc()->astmp = [];
		return $this;
	}
	function cssSelectorFunction_txt($arg){
	  return $arg[0];
	}
	function cssSelectorFunction_titre($arg){
	  return $this->titre();
	}
	function cssSelectorFunction_texte($arg){
	  return $this->texte();
	}
	function cssSelectorFunction_texte1($arg){
	  return $this->keywords();
	}
	function cssSelectorFunction_prix($arg){
	  return $this->prix();
	}
	function cssSelectorFunction_image($arg){
	  return $this->image();
	}
	function cssSelectorFunction_maxImage($arg){
	  return $this->maxImage();
	}
	function cssSelectorFunction_index($arg){
	  $this->getDoc()->choseindex = (int)$arg[0];
	  return $this;
	}
	function SelectCssQuery($query,$chi){
	  $res = array();
	  foreach ($this->child as $key => $node) {
	    if($v = $node->is($query)){
	      $res[] = $v;
	    }
	    if(!$chi){
	      $res = array_merge($res,$node->SelectCssQuery($query,$chi));
	    }
	  }
	  return $res;
	}
	var $choseindex = null;
	function query($query){
	    $res = array();
	    if(is_array($query)){
	      foreach ($query as $key => $value) {
	        if(!empty($value)){
	          if(is_string($value)){
	            if($v = $this->query($value,false)){
	              if(count($v)>1){
	                $res[$key] = $v;
	              }else{
	                $res[$key] = $v[0];
	              }
	            }
	          }elseif(is_array($value)){
	            $s = $value["selector"];
	            unset($value["selector"]);
	            $res[$key] = array();
	            $r = $this->query($s,false);
	            foreach ($r as  $node) {
	              $res[$key][] = $node->query($value,false);
	            }
	          }
	        }
	      }
	    }else{
	    	$this->choseindex = null;
	      $regex = "/,|>|\s+|([a-zA-Z0-9-_]+|\*)?((\.|#)[a-zA-Z0-9-_]+)*(?<g3>\[[^\]]+\])*((:|@)[a-zA-Z0-9-_]+(\(((\s*\"((\\\"|[^\"])*?)\"\s*|\s*'((\\'|[^'])*?)'\s*|[^\)]*?)(,(\s*\"((\\\"|[^\"])*?)\"\s*|\s*'((\\'|[^'])*?)'\s*|[^\)]*?))*)\))?)*/i";
	      $matches = null;
	      if (preg_match_all($regex, $query, $matches)) {
	        $tmp = array($this);
	        $chi = false;
	        foreach ($matches[0] as $key => $value) {
	          if($value == ","){
	            $res = array_merge($res, $tmp);
	            $tmp = array($this);
	            $chi = false;
	          }elseif($value == ">"){
	            $chi = true;
	          }elseif(trim($value) == ""){
	            
	          }else{
	            $tmp_ = array();
	            foreach ($tmp as $k => $val) {
	              if(is_a($val,"HTMLE")){
	                $v = $val->SelectCssQuery($value,$chi);
	                if(is_array($v)){
	                  $tmp_ = array_merge($tmp_,$v);
	                }elseif(is_string($v)){
	                  $tmp_[] = $v;
	                }
	              }
	            }
	            $tmp = $tmp_;
	            $chi = false;
	          }
	        }
	        $res = array_merge($res, $tmp);
	      }
		    if (!is_null($this->choseindex)) {
		    	if (is_array($res) && count($res)>$this->choseindex) {
		    		$res = $res[$this->choseindex];
		    	}
		    	if (is_array($this->as) && count($this->as)>$this->choseindex) {
		    		$this->as = [$this->as[$this->choseindex]];
		    	}
		    }
	    }
	    if($filter){
	      foreach ($res as $key => $value) {
	        if(is_a($value,"HTMLE")){
	          $res[$key] = $value->innerText();
	        }
	      }
	    }
	    return $res;
	}
	function prix(){
		$res = $this->query("*:regex('/^\s*[0-9\.,\s]+(DT|TND|Dinars?)\s*$/i'):text");
		if(is_string($res)) $res = array($res);
		$res1 = $this->query("*:regex('/^\s*prix\s*$/i'):next('*:regex(/[0-9]+/i)'):text");
		if(is_string($res1)) $res1 = array($res1);
		$res = array_merge($res,$res1);
		$len = 1000;
		$prix = null;
		if(is_string($res)) $res = array($res);
		foreach ($res as $key => $value) {
			if(strlen($value)<30 && strlen($value)>1){
				if($len>strlen($value)){
					$len = strlen($value);
					$prix = $value;
				}
			}
		}
		return $prix;
	}
	function titre(){
		$res = $this->query("h1:text");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		$res = $this->query("meta[property='og:title']@content");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		$res = $this->query("meta[name='title']@content");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		$res = $this->query("title:text");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
	}
	function image(){
		$res = $this->query("meta[property='og:image']@content");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		$res = $this->query("meta[name='image']@content");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		if($node = $this->getTexteNode()){
			$res = $node->query("img[alt][title]@src:regex('/^((?!logo).)*$/i')");
			if(!empty($res)) return is_array($res)?$res[0]:$res;
			$res = $node->query("img[alt]@src:regex('/^((?!logo).)*$/i')");
			if(!empty($res)) return is_array($res)?$res[0]:$res;
			$res = $node->query("img[title]@src:regex('/^((?!logo).)*$/i')");
			if(!empty($res)) return is_array($res)?$res[0]:$res;
		}
		$res = $this->query("img[alt][title]@src:regex('/^((?!logo).)*$/i')");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		$res = $this->query("img[alt]@src:regex('/^((?!logo).)*$/i')");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		$res = $this->query("img[title]@src:regex('/^((?!logo).)*$/i')");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		return null;
	}
	function maxImage(){
		$list = $this->query("img@src");
		$imgs = [];
		foreach ($list as $key => $value) {
			list($width, $height) = getimagesize($value); 
			$imgs[$value] = floatval($width) * floatval($height);
		}
		if(empty($imgs)) return null;
		arsort($imgs);
		$keys = array_keys($imgs);
		return $keys[0];
	}
	function texte(){
		$res = $this->query("meta[name='description']@content");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		$res = $this->query("meta[property='og:description']@content");
		if(!empty($res)) return is_array($res)?$res[0]:$res;
		return null;
	}
	function keywords(){
		if($node = $this->getTexteNode()){
			return $node->getTexte();
		}else{
			return "";
		}
	}

	function getTexteNode(){
		$description = html_entity_decode($this->texte());
		if(empty($description)) return $this->getPrimaryText();
		$matches = explode(" ", $description);
		$words = array();
		foreach ($matches as $key => $value) {
			$words[strtolower($value)] = 1;
		}
		$words = array_keys($words);
		if($node = $this->getTextElementByContent($words)){
			return $node;
		}else{
			return null;
		}
	}

	function getTexte(){
		$selected = $this;
		while (!in_array($selected->name, array("div","table","body")) && $selected->parent) {
			$selected = $selected->parent;
		}
		return $selected->innerText();
	}
	function getPrimaryText(&$n = null,&$txt="",&$length=0){
		if(is_null($n)) $n = $this;
		if($this->name == "#text"){
			$matches = explode(" ", html_entity_decode($this->data, ENT_COMPAT, 'UTF-8'));
			if(count($matches)>$length){
				$txt = html_entity_decode($this->data, ENT_COMPAT, 'UTF-8');
				$length = count($matches);
				$n = $this;
			}
		}
		foreach ($this->child as $node) {
			if(!in_array($node->name,array("script","style")))
			$node->getPrimaryText($n,$txt,$length);
		}
		return $n;
	}
	function getTextElementByContent($words, &$selected = null, &$score = -1000,$length = 0){
		$txt = html_entity_decode($this->innerText(), ENT_COMPAT, 'UTF-8');
		$matches = explode(" ", $txt);
		$p = 0;
		foreach ($matches as $key => $value) {
			$p += in_array(strtolower($value),$words)?3:-3;
		}
		if($p>$score){
			$selected = $this;
			$score = $p;
			$length = count($matches);
		}elseif ($p == $score) {
			if($length>count($matches)){
				$selected = $this;
				$score = $p;
				$length = count($matches);
			}
		}
		foreach ($this->child as $node) {
			$node->getTextElementByContent($words,$selected,$score,$length);
		}
		return $selected;
	}
	static function GgSearch($query,$host="fr",$params = [],$num = 100){
		$s = "";
		foreach ($params as $key => $value) {
			$s = "&$key=".urlencode($value);
		}
		$listProxy = self::getProxyList();
		foreach ($listProxy as $key => $value) {
			$rep = self::getByProxy("http://www.google.$host/search?num=$num&q=".urlencode($query)."$s");
			if (preg_match("/\- Recherche Google\<\/title\>/i", $rep)) {
				$doc = self::parse($rep,"http://www.google.$host/search");
				$rep = $doc->query(array("list"=>array(
						"selector" =>".g",
						"titre"    =>"h3:text",
						"url"      =>"h3 > a@href",
						"url_txt"  =>"cite:text",
						"texte"    =>".st:text",
					)));
				foreach ($rep["list"] as $key => $value) {
					if(is_array($value["url"])) $rep["list"][$key]["url"] = $value["url"][0];
					if(is_array($value["titre"])) $rep["list"][$key]["titre"] = $value["titre"][0];
					if(preg_match("/url\?q=/i",$rep["list"][$key]["url"])){
						$q = null;
						parse_str(parse_url($rep["list"][$key]["url"], PHP_URL_QUERY));
						if(!is_null($q) && !empty($q) && preg_match("/^http/i",$q)){
							$rep["list"][$key]["url"] = urldecode($q);
						}
					}else{
						$url = null;
						parse_str(parse_url($rep["list"][$key]["url"], PHP_URL_QUERY));
						if(!is_null($url) && !empty($url) && preg_match("/^http/i",$url)){
							$rep["list"][$key]["url"] = urldecode($url);
						}
					}
					if (preg_match("/https?:\/[a-z0-9A-Z]+/i",$rep["list"][$key]["url"])) {
						$rep["list"][$key]["url"] = str_replace(":/", "://", $rep["list"][$key]["url"]);
					}
				}
				return $rep["list"];
			}
		}
		return false;
	}
	static function getByProxy($url,$proxy){
		$ch = curl_init();
		curl_setopt($ch, CURLOPT_URL, $url);
		curl_setopt($ch, CURLOPT_PROXY, $proxy);
		curl_setopt($ch, CURLOPT_HEADER, 0);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
		curl_setopt($ch, CURLOPT_MAXREDIRS, 5);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($ch, CURLOPT_COOKIESESSION, FALSE);
		$response = curl_exec($ch);
		curl_close($ch);
		return $response;
	}
	static function getProxyList(){
		$doc = self::parse("http://proxylist.hidemyass.com/search-1292985");
		$rep = $doc->query(["ip"=>".leftborder:parent td:n(2):html","port"=>".leftborder:parent td:n(3):text"]);
		foreach ($rep["ip"] as $key => $value) {
			$rep["ip"][$key] .=":".$rep["port"][$key];
		}
		foreach ($rep["ip"] as $key => $value) {
			$iptml = self::parse($value);
			$style = $iptml->query("style:html");
			preg_match_all("/\.(?<c>[a-zA-Z0-9]+)\{display\:none\}/i", $style[0], $matches);
			foreach ($matches["c"] as $k => $v) {
				$iptml->query(".$v:delete");
			}
			$iptml->query("*[style='display:none']:delete");
			$rep["ip"][$key] = str_replace(" ", "", str_replace("\n", "", $iptml->innerText()));
			if (!preg_match("/\b[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\b/i", $rep["ip"][$key])) {
				unset($rep["ip"][$key]);
			}
		}
		unset($rep["port"]);
		return $rep["ip"];
	}
}







 
/**
-----------------------------------------
	Encoding
-----------------------------------------
**/
class Encoding {
    
  protected static $win1252ToUtf8 = array(
        128 => "\xe2\x82\xac",

        130 => "\xe2\x80\x9a",
        131 => "\xc6\x92",
        132 => "\xe2\x80\x9e",
        133 => "\xe2\x80\xa6",
        134 => "\xe2\x80\xa0",
        135 => "\xe2\x80\xa1",
        136 => "\xcb\x86",
        137 => "\xe2\x80\xb0",
        138 => "\xc5\xa0",
        139 => "\xe2\x80\xb9",
        140 => "\xc5\x92",

        142 => "\xc5\xbd",


        145 => "\xe2\x80\x98",
        146 => "\xe2\x80\x99",
        147 => "\xe2\x80\x9c",
        148 => "\xe2\x80\x9d",
        149 => "\xe2\x80\xa2",
        150 => "\xe2\x80\x93",
        151 => "\xe2\x80\x94",
        152 => "\xcb\x9c",
        153 => "\xe2\x84\xa2",
        154 => "\xc5\xa1",
        155 => "\xe2\x80\xba",
        156 => "\xc5\x93",

        158 => "\xc5\xbe",
        159 => "\xc5\xb8"
  );
  
    protected static $brokenUtf8ToUtf8 = array(
        "\xc2\x80" => "\xe2\x82\xac",
        
        "\xc2\x82" => "\xe2\x80\x9a",
        "\xc2\x83" => "\xc6\x92",
        "\xc2\x84" => "\xe2\x80\x9e",
        "\xc2\x85" => "\xe2\x80\xa6",
        "\xc2\x86" => "\xe2\x80\xa0",
        "\xc2\x87" => "\xe2\x80\xa1",
        "\xc2\x88" => "\xcb\x86",
        "\xc2\x89" => "\xe2\x80\xb0",
        "\xc2\x8a" => "\xc5\xa0",
        "\xc2\x8b" => "\xe2\x80\xb9",
        "\xc2\x8c" => "\xc5\x92",
        
        "\xc2\x8e" => "\xc5\xbd",
        
        
        "\xc2\x91" => "\xe2\x80\x98",
        "\xc2\x92" => "\xe2\x80\x99",
        "\xc2\x93" => "\xe2\x80\x9c",
        "\xc2\x94" => "\xe2\x80\x9d",
        "\xc2\x95" => "\xe2\x80\xa2",
        "\xc2\x96" => "\xe2\x80\x93",
        "\xc2\x97" => "\xe2\x80\x94",
        "\xc2\x98" => "\xcb\x9c",
        "\xc2\x99" => "\xe2\x84\xa2",
        "\xc2\x9a" => "\xc5\xa1",
        "\xc2\x9b" => "\xe2\x80\xba",
        "\xc2\x9c" => "\xc5\x93",
        
        "\xc2\x9e" => "\xc5\xbe",
        "\xc2\x9f" => "\xc5\xb8"
  );
    
  protected static $utf8ToWin1252 = array(
       "\xe2\x82\xac" => "\x80",
       
       "\xe2\x80\x9a" => "\x82",
       "\xc6\x92"     => "\x83",
       "\xe2\x80\x9e" => "\x84",
       "\xe2\x80\xa6" => "\x85",
       "\xe2\x80\xa0" => "\x86",
       "\xe2\x80\xa1" => "\x87",
       "\xcb\x86"     => "\x88",
       "\xe2\x80\xb0" => "\x89",
       "\xc5\xa0"     => "\x8a",
       "\xe2\x80\xb9" => "\x8b",
       "\xc5\x92"     => "\x8c",
       
       "\xc5\xbd"     => "\x8e",
       
       
       "\xe2\x80\x98" => "\x91",
       "\xe2\x80\x99" => "\x92",
       "\xe2\x80\x9c" => "\x93",
       "\xe2\x80\x9d" => "\x94",
       "\xe2\x80\xa2" => "\x95",
       "\xe2\x80\x93" => "\x96",
       "\xe2\x80\x94" => "\x97",
       "\xcb\x9c"     => "\x98",
       "\xe2\x84\xa2" => "\x99",
       "\xc5\xa1"     => "\x9a",
       "\xe2\x80\xba" => "\x9b",
       "\xc5\x93"     => "\x9c",
       
       "\xc5\xbe"     => "\x9e",
       "\xc5\xb8"     => "\x9f"
    );

  static function toUTF8($text){
  /**
   * Function \ForceUTF8\Encoding::toUTF8
   *
   * This function leaves UTF8 characters alone, while converting almost all non-UTF8 to UTF8.
   * 
   * It assumes that the encoding of the original string is either Windows-1252 or ISO 8859-1.
   *
   * It may fail to convert characters to UTF-8 if they fall into one of these scenarios:
   *
   * 1) when any of these characters:   ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß
   *    are followed by any of these:  ("group B")
   *                                    ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶•¸¹º»¼½¾¿
   * For example:   %ABREPRESENT%C9%BB. «REPRESENTÉ»
   * The "«" (%AB) character will be converted, but the "É" followed by "»" (%C9%BB) 
   * is also a valid unicode character, and will be left unchanged.
   *
   * 2) when any of these: àáâãäåæçèéêëìíîï  are followed by TWO chars from group B,
   * 3) when any of these: ðñòó  are followed by THREE chars from group B.
   *
   * @name toUTF8
   * @param string $text  Any string.
   * @return string  The same string, UTF8 encoded
   *
   */

    if(is_array($text))
    {
      foreach($text as $k => $v)
      {
        $text[$k] = self::toUTF8($v);
      }
      return $text;
    } elseif(is_string($text)) {
       
      if ( function_exists('mb_strlen') && ((int) ini_get('mbstring.func_overload')) & 2) {
         $max = mb_strlen($text,'8bit');
      } else {
         $max = strlen($text);
      }
    
      $buf = "";
      for($i = 0; $i < $max; $i++){
          $c1 = $text{$i};
          if($c1>="\xc0"){ //Should be converted to UTF8, if it's not UTF8 already
            $c2 = $i+1 >= $max? "\x00" : $text{$i+1};
            $c3 = $i+2 >= $max? "\x00" : $text{$i+2};
            $c4 = $i+3 >= $max? "\x00" : $text{$i+3};
              if($c1 >= "\xc0" & $c1 <= "\xdf"){ //looks like 2 bytes UTF8
                  if($c2 >= "\x80" && $c2 <= "\xbf"){ //yeah, almost sure it's UTF8 already
                      $buf .= $c1 . $c2;
                      $i++;
                  } else { //not valid UTF8.  Convert it.
                      $cc1 = (chr(ord($c1) / 64) | "\xc0");
                      $cc2 = ($c1 & "\x3f") | "\x80";
                      $buf .= $cc1 . $cc2;
                  }
              } elseif($c1 >= "\xe0" & $c1 <= "\xef"){ //looks like 3 bytes UTF8
                  if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf"){ //yeah, almost sure it's UTF8 already
                      $buf .= $c1 . $c2 . $c3;
                      $i = $i + 2;
                  } else { //not valid UTF8.  Convert it.
                      $cc1 = (chr(ord($c1) / 64) | "\xc0");
                      $cc2 = ($c1 & "\x3f") | "\x80";
                      $buf .= $cc1 . $cc2;
                  }
              } elseif($c1 >= "\xf0" & $c1 <= "\xf7"){ //looks like 4 bytes UTF8
                  if($c2 >= "\x80" && $c2 <= "\xbf" && $c3 >= "\x80" && $c3 <= "\xbf" && $c4 >= "\x80" && $c4 <= "\xbf"){ //yeah, almost sure it's UTF8 already
                      $buf .= $c1 . $c2 . $c3 . $c4;
                      $i = $i + 3;
                  } else { //not valid UTF8.  Convert it.
                      $cc1 = (chr(ord($c1) / 64) | "\xc0");
                      $cc2 = ($c1 & "\x3f") | "\x80";
                      $buf .= $cc1 . $cc2;
                  }
              } else { //doesn't look like UTF8, but should be converted
                      $cc1 = (chr(ord($c1) / 64) | "\xc0");
                      $cc2 = (($c1 & "\x3f") | "\x80");
                      $buf .= $cc1 . $cc2;
              }
          } elseif(($c1 & "\xc0") == "\x80"){ // needs conversion
                if(isset(self::$win1252ToUtf8[ord($c1)])) { //found in Windows-1252 special cases
                    $buf .= self::$win1252ToUtf8[ord($c1)];
                } else {
                  $cc1 = (chr(ord($c1) / 64) | "\xc0");
                  $cc2 = (($c1 & "\x3f") | "\x80");
                  $buf .= $cc1 . $cc2;
                }
          } else { // it doesn't need conversion
              $buf .= $c1;
          }
      }
      return $buf;
    } else {
      return $text;
    }
  }

  static function toWin1252($text) {
    if(is_array($text)) {
      foreach($text as $k => $v) {
        $text[$k] = self::toWin1252($v);
      }
      return $text;
    } elseif(is_string($text)) {
      return static::utf8_decode($text);
    } else {
      return $text;
    }
  }

  static function toISO8859($text) {
    return self::toWin1252($text);
  }

  static function toLatin1($text) {
    return self::toWin1252($text);
  }

  static function fixUTF8($text){
    if(is_array($text)) {
      foreach($text as $k => $v) {
        $text[$k] = self::fixUTF8($v);
      }
      return $text;
    }

    $last = "";
    while($last <> $text){
      $last = $text;
      $text = self::toUTF8(static::utf8_decode($text));
    }
    $text = self::toUTF8(static::utf8_decode($text));
    return $text;
  }
  
  static function UTF8FixWin1252Chars($text){
    // If you received an UTF-8 string that was converted from Windows-1252 as it was ISO8859-1 
    // (ignoring Windows-1252 chars from 80 to 9F) use this function to fix it.
    // See: http://en.wikipedia.org/wiki/Windows-1252
    
    return str_replace(array_keys(self::$brokenUtf8ToUtf8), array_values(self::$brokenUtf8ToUtf8), $text);
  }
  
  static function removeBOM($str=""){
    if(substr($str, 0,3) == pack("CCC",0xef,0xbb,0xbf)) {
      $str=substr($str, 3);
    }
    return $str;
  }
  
  public static function normalizeEncoding($encodingLabel)
  {
    $encoding = strtoupper($encodingLabel);
    $encoding = preg_replace('/[^a-zA-Z0-9\s]/', '', $encoding);
    $equivalences = array(
        'ISO88591' => 'ISO-8859-1',
        'ISO8859'  => 'ISO-8859-1',
        'ISO'      => 'ISO-8859-1',
        'LATIN1'   => 'ISO-8859-1',
        'LATIN'    => 'ISO-8859-1',
        'UTF8'     => 'UTF-8',
        'UTF'      => 'UTF-8',
        'WIN1252'  => 'ISO-8859-1',
        'WINDOWS1252' => 'ISO-8859-1'
    );
    
    if(empty($equivalences[$encoding])){
      return 'UTF-8';
    }
   
    return $equivalences[$encoding];
  }

  public static function encode($encodingLabel, $text)
  {
    $encodingLabel = self::normalizeEncoding($encodingLabel);
    if($encodingLabel == 'UTF-8') return Encoding::toUTF8($text);
    if($encodingLabel == 'ISO-8859-1') return Encoding::toLatin1($text);
  }

  protected static function utf8_decode($text)
  {
    // $o = utf8_decode(
    //   str_replace(array_keys(self::$utf8ToWin1252), array_values(self::$utf8ToWin1252), self::toUTF8($text))
    // );
    $o = iconv("UTF-8", "Windows-1252//TRANSLIT", $text);
    return $o;
  }
}


function force_utf8( $str, $inputEnc='WINDOWS-1252' )
{
    if ( is_utf8( $str ) ) // Nothing to do.
        return $str;

    if ( strtoupper( $inputEnc ) === 'ISO-8859-1' )
        return utf8_encode( $str );

    if ( function_exists( 'mb_convert_encoding' ) )
        return mb_convert_encoding( $str, 'UTF-8', $inputEnc );

    if ( function_exists( 'iconv' ) )
        return iconv( $inputEnc, 'UTF-8', $str );

    // You could also just return the original string.
    trigger_error(
        'Cannot convert string to UTF-8 in file '
            . __FILE__ . ', line ' . __LINE__ . '!', 
        E_USER_ERROR 
    );
}
function is_utf8( $str )
{
    return preg_match( "/^(
         [\x09\x0A\x0D\x20-\x7E]            # ASCII
       | [\xC2-\xDF][\x80-\xBF]             # non-overlong 2-byte
       |  \xE0[\xA0-\xBF][\x80-\xBF]        # excluding overlongs
       | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2}  # straight 3-byte
       |  \xED[\x80-\x9F][\x80-\xBF]        # excluding surrogates
       |  \xF0[\x90-\xBF][\x80-\xBF]{2}     # planes 1-3
       | [\xF1-\xF3][\x80-\xBF]{3}          # planes 4-15
       |  \xF4[\x80-\x8F][\x80-\xBF]{2}     # plane 16
      )*$/x",
      $str 
    );
}