gosa-core-2.7.4/0000755000175000017500000000000011752422554012406 5ustar cajuscajusgosa-core-2.7.4/include/0000755000175000017500000000000011752422553014030 5ustar cajuscajusgosa-core-2.7.4/include/class_listingSortIterator.inc0000644000175000017500000000541311327523573021750 0ustar cajuscajusdata= array_reverse($data, true); } else { $this->data= $data; } } function rewind() { return reset($this->data); } function current() { return current($this->data); } function key() { return key($this->data); } function next() { return next($this->data); } function valid() { return key($this->data) !== null; } } ?> gosa-core-2.7.4/include/functions_debug.inc0000644000175000017500000003036010763021251017672 0ustar cajuscajus ** Filename......: debuglib.php(s) ** Last changed..: 16. July 2003 ** License.......: Free to use. Postcardware ;) ** ************************************************* ** ** Functions in this library: ** ** print_a( array array [,int mode] ) ** prints arrays in a readable, understandable form. ** if mode is defined the function returns the output instead of ** printing it to the browser ** ** ** show_vars([int mode]) ** use this function on the bottom of your script to see all ** superglobals and global variables in your script in a nice ** formated way ** ** show_vars() without parameter shows $_GET, $_POST, $_SESSION, ** $_FILES and all global variables you've defined in your script ** ** show_vars(1) shows $_SERVER and $_ENV in addition ** ** ** ** print_result( result_handle ) ** prints a mysql_result set returned by mysql_query() as a table ** this function is work in progress! use at your own risk ** ** ** ** ** Happy debugging and feel free to email me your comments. ** ** ** ** History: (starting with version 0.5.3 at 2003-02-24) ** ** - added tooltips to the td's showing the type of keys and values (thanks Itomic) ** 2003-07-16 ** - pre() function now trims trailing tabs ************************************************/ # This file must be the first include on your page. /* used for tracking of generation-time */ { $MICROTIME_START = microtime(); @$GLOBALS_initial_count = count($GLOBALS); } /************************************************ ** print_a class and helper function ** prints out an array in a more readable way ** than print_r() ** ** based on the print_a() function from ** Stephan Pirson (Saibot) ************************************************/ class Print_a_class { # this can be changed to FALSE if you don't like the fancy string formatting var $look_for_leading_tabs = TRUE; var $output; var $iterations; var $key_bg_color = '1E32C8'; var $value_bg_color = 'DDDDEE'; var $fontsize = '8pt'; var $keyalign = 'center'; var $fontfamily = 'Verdana'; var $export_flag; var $show_object_vars; var $export_dumper_path = 'http://tools.www.mdc.xmc.de/print_a_dumper/print_a_dumper.php'; # i'm still working on the dumper! don't use it now # put the next line into the print_a_dumper.php file (optional) # print htmlspecialchars( stripslashes ( $_POST['array'] ) ); var $export_hash; function Print_a_class() { $this->export_hash = uniqid(''); } # recursive function! function print_a($array, $iteration = FALSE, $key_bg_color = FALSE) { $key_bg_color or $key_bg_color = $this->key_bg_color; # if print_a() was called with a fourth parameter (1 or 2) # and you click on the table a window opens with only the output of print_a() in it # 1 = serialized array # 2 = normal print_a() display /* put the following code on the page defined with $export_dumper_path; --->%---- snip --->%---- if($_GET['mode'] == 1) { print htmlspecialchars( stripslashes ( $_POST['array'] ) ); } elseif($_GET['mode'] == 2) { print_a(unserialize( stripslashes($_POST['array'])) ); } ---%<---- snip ---%<---- */ if( !$iteration && isset($this->export_flag) ) { $this->output .= '
'; } # lighten up the background color for the key td's =) if( $iteration ) { for($i=0; $i<6; $i+=2) { $c = substr( $key_bg_color, $i, 2 ); $c = hexdec( $c ); ( $c += 15 ) > 255 and $c = 255; isset($tmp_key_bg_color) or $tmp_key_bg_color = ''; $tmp_key_bg_color .= sprintf( "%02X", $c ); } $key_bg_color = $tmp_key_bg_color; } # build a single table ... may be nested $this->output .= 'export_flag ? 'onClick="document.getElementById(\'pa_form_'.$this->export_hash.'\').submit();" )' : '' ).'>'; foreach( $array as $key => $value ) { $value_style = 'color:black;'; $key_style = 'color:white;'; $type = gettype( $value ); # print $type.'
'; # change the color and format of the value switch( $type ) { case 'array': break; case 'object': $key_style = 'color:#FF9B2F;'; break; case 'integer': $value_style = 'color:green;'; break; case 'double': $value_style = 'color:red;'; break; case 'bool': $value_style = 'color:blue;'; break; case 'resource': $value_style = 'color:darkblue;'; break; case 'string': if( $this->look_for_leading_tabs && preg_match('/^\t/m', $value) ) { $search = array('/\t/', "/\n/"); $replace = array('   ','
'); $value = preg_replace( $search, $replace, htmlspecialchars( $value ) ); $value_style = 'color:black;border:1px gray dotted;'; } else { $value_style = 'color:black;'; $value = nl2br( htmlspecialchars( $value ) ); } break; } $this->output .= ''; $this->output .= ''; $this->output .= ''; $this->output .= ''; } $this->output .= '
'; $this->output .= $key; $this->output .= ''; # value output if($type == 'array') { if(count($value)){ $this->print_a( $value, TRUE, $key_bg_color ); }else{ $this->output .= '
Array (empty)
'; } } elseif($type == 'object') { if( $this->show_object_vars ) { $this->print_a( get_object_vars( $value ), TRUE, $key_bg_color ); } else { $this->output .= '
OBJECT - '.get_class($value).'
'; } } else { $this->output .= '
'.$value.'
'; } $this->output .= '
'; } } # helper function.. calls print_a() inside the print_a_class function print_a( $array, $return_mode = FALSE, $show_object_vars = FALSE, $export_flag = FALSE ) { $e= error_reporting (0); if( is_array( $array ) or is_object( $array ) ) { $pa = new Print_a_class; $show_object_vars and $pa->show_object_vars = TRUE; $export_flag and $pa->export_flag = $export_flag; $pa->print_a( $array ); # $output = $pa->output; unset($pa); $output = &$pa->output; } else { $output = 'print_a( '.gettype( $array ).' )'; } error_reporting ($e); if($return_mode) { return $output; } else { print $output; return TRUE; } } // shows mysql-result as a table.. # not ready yet :( function print_result($RESULT) { if(!$RESULT) return; $fieldcount = mysql_num_fields($RESULT); for($i=0; $i<$fieldcount; $i++) { $tables[mysql_field_table($RESULT, $i)]++; } print ' '; print ''; print ''; foreach($tables as $tableName => $tableCount) { $col == '0054A6' ? $col = '003471' : $col = '0054A6'; print ''; } print ''; print ''; for($i=0;$i < mysql_num_fields($RESULT);$i++) { $FIELD = mysql_field_name($RESULT, $i); $col == '0054A6' ? $col = '003471' : $col = '0054A6'; print ''; } print ''; mysql_data_seek($RESULT, 0); while($DB_ROW = mysql_fetch_array($RESULT, MYSQL_NUM)) { $pointer++; if($toggle) { $col1 = "E6E6E6"; $col2 = "DADADA"; } else { $col1 = "E1F0FF"; $col2 = "DAE8F7"; } $toggle = !$toggle; print ''; foreach($DB_ROW as $value) { $col == $col1 ? $col = $col2 : $col = $col1; print ''; } print ''; } print '
'.$tableName.'
'.$FIELD.'
'.nl2br($value).'
'; mysql_data_seek($RESULT, 0); } function _script_globals() { global $GLOBALS_initial_count; $varcount = 0; foreach($GLOBALS as $GLOBALS_current_key => $GLOBALS_current_value) { if(++$varcount > $GLOBALS_initial_count) { /* die wollen wir nicht! */ if ($GLOBALS_current_key != 'HTTP_SESSION_VARS' && $GLOBALS_current_key != '_SESSION') { $script_GLOBALS[$GLOBALS_current_key] = $GLOBALS_current_value; } } } unset($script_GLOBALS['GLOBALS_initial_count']); return $script_GLOBALS; } function show_runtime() { $MICROTIME_END = microtime(); $MICROTIME_START = explode(' ', $GLOBALS['MICROTIME_START']); $MICROTIME_END = explode(' ', $MICROTIME_END); $GENERATIONSEC = $MICROTIME_END[1] - $MICROTIME_START[1]; $GENERATIONMSEC = $MICROTIME_END[0] - $MICROTIME_START[0]; $GENERATIONTIME = substr($GENERATIONSEC + $GENERATIONMSEC, 0, 8); return '(runtime: '.$GENERATIONTIME.' sec)'; } ###################### # function shows all superglobals and script defined global variables # show_vars() without the first parameter shows all superglobals except $_ENV and $_SERVER # show_vars(1) shows all # show_vars(,1) shows object properties in addition # function show_vars($show_all_vars = FALSE, $show_object_vars = FALSE) { if(isset($GLOBALS['no_vars'])) return; $script_globals = _script_globals(); print ' '; print '
DEBUG '.show_runtime().' '; $vars_arr['script_globals'] = array('global script variables', '#7ACCC8'); $vars_arr['_GET'] = array('$_GET', '#7DA7D9'); $vars_arr['_POST'] = array('$_POST', '#F49AC1'); $vars_arr['_FILES'] = array('$_POST FILES', '#82CA9C'); $vars_arr['_SESSION'] = array('$_SESSION', '#FCDB26'); $vars_arr['_COOKIE'] = array('$_COOKIE', '#A67C52'); if($show_all_vars) { $vars_arr['_SERVER'] = array('SERVER', '#A186BE'); $vars_arr['_ENV'] = array('ENV', '#7ACCC8'); } foreach($vars_arr as $vars_name => $vars_data) { if($vars_name != 'script_globals') global $$vars_name; if($$vars_name) { print '
'.$vars_data[0].'
'; print_a($$vars_name, FALSE, $show_object_vars, FALSE ); print '
'; } } print '
'; } ###################### # function prints sql strings # function pre($sql_string, $simple_mode = FALSE) { if(!$simple_mode) { # erste leere Zeile im SQL löschen $sql_string = preg_replace('/\^s+/m','', $sql_string); # letze leere Zeile im SQL löschen $sql_string = preg_replace('/\s+$/m','', $sql_string); # kleinste Anzahl von führenden TABS zählen preg_match_all('/^\t+/m', $sql_string, $matches); $minTabCount = strlen(min($matches[0])); # und entfernen $sql_string = preg_replace('/^\t{'.$minTabCount.'}/m', '', $sql_string); } print '
'.$sql_string.'
'; } ?> gosa-core-2.7.4/include/class_socketClient.inc0000644000175000017500000001212711365250364020341 0ustar cajuscajushost= $host; $this->port= $port; $this->timeout= $timeout; $this->reset_error(); /* Connect if needed */ if($connect){ $this->open(); } } public function setEncryptionKey($key) { if(!function_exists("mcrypt_get_iv_size")){ $this->set_error(msgPool::missingext("mcrypt")); $this->ckey = ""; $this->b_encrypt = FALSE; } if ($this->connected()){ $this->ckey = substr(md5($key), 0, $this->ks); $this->b_encrypt = TRUE; } return($this->b_encrypt); } private function encrypt($data) { if($this->b_encrypt){ mcrypt_generic_init($this->td, $this->ckey, $this->iv); $data = base64_encode(mcrypt_generic($this->td, $data)); } return($data); } private function decrypt($data) { /* decrypt data */ if($this->b_encrypt && strlen($data)){ $data = base64_decode($data); mcrypt_generic_init($this->td, $this->ckey, $this->iv); $data = mdecrypt_generic($this->td, $data); } return($data); } public function connected() { return ($this->handle == TRUE); } public function open() { $this->reset_error(); $this->handle = @fsockopen($this->host, $this->port, $this->errno, $this->errstr, $this->timeout); if(!$this->handle){ $this->handle = NULL; $this->set_error(sprintf(_("Socket connection to %s:%s failed: %s"), bold($this->host), bold($this->port), $this->errstr)); }else{ $this->b_data_send = TRUE; /* Open the cipher */ $this->td = mcrypt_module_open('rijndael-128', '', 'cbc', ''); /* Create the IV and determine the keysize length */ $this->iv = substr(md5('GONICUS GmbH'),0, mcrypt_enc_get_iv_size($this->td)); $this->ks = mcrypt_enc_get_key_size($this->td); } } public function set_error($str) { $this->is_error =TRUE; $this->error=$str; } public function reset_error() { $this->is_error =FALSE; $this->error = ""; } public function is_error() { return($this->is_error); } public function get_error() { return $this->error; } public function write($data){ if($this->handle){ $data = $this->encrypt($data); fputs($this->handle, $data."\n"); $this->b_data_send = TRUE; }else{ $this->b_data_send = FALSE; } return $this->b_data_send; } public function read() { // Output the request results $this->reset_error(); $str = ""; $data = "test"; socket_set_timeout($this->handle,$this->timeout); stream_set_blocking($this->handle,0); $start = microtime(TRUE); /* Read while * nothing was read yet * the timelimit reached * there is not data left on the socket. */ while(TRUE){ usleep(10000); $data = fread($this->handle, 1024000); if($data && strlen($data)>0) { $str .= $data; } else { if(strlen($str) != 0){ /* We got but is still missing, keep on reading */ if(preg_match("/<\/xml>/",$this->decrypt($str))){ break; } } } if((microtime(TRUE) - $start) > $this->timeout ){ $this->set_error(sprintf(_("Socket timeout of %s seconds reached!"), bold($this->timeout))); break; } } $this->bytes_read = strlen($str); $this->b_data_send = FALSE; $str = $this->decrypt($str); return($str); } public function bytes_read() { return $this->bytes_read; } public function close() { if($this->handle){ fclose($this->handle); } /* Terminate decryption handle and close module */ @mcrypt_generic_deinit($this->td); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_pathNavigator.inc0000644000175000017500000000534111365473437020531 0ustar cajuscajusplHeadline)){ $str= _($class->plHeadline); } // Shown title of sub dialogs (They have no plHeadline set.) if($class instanceOf plugin && !isset($class->plHeadline)){ if(!empty($class->pathTitle)){ $str = _($class->pathTitle); } } // In case of tabs add the 'dn' of the entry if($class instanceOf tabs){ // Convert dn to cn if(isset($class->dn)){ if(!session::is_set("pathNavigator::registerPlugin:{$class->dn}")){ global $config; $ldap = $config->get_ldap_link(); if(!empty($class->dn)){ $namingAttr = preg_replace("/^([^=]*)=.*$/","\\1",$class->dn); $ldap->cat($class->dn, array($namingAttr)); if($ldap->count()){ $attrs = $ldap->fetch(); $str = $attrs[$namingAttr][0]; } session::set("pathNavigator::registerPlugin:{$class->dn}", $str); } } $str = session::get("pathNavigator::registerPlugin:{$class->dn}"); if(empty($title)){ $title = $class->dn; } } } // Simple string given if(is_string($class)){ $str = $class; } if(!empty($str)){ $cur = session::get('pathNavigator::position'); $entry = array('TITLE' => $title, 'NAME' => $str); $cur[] = $entry; session::set('pathNavigator::position', $cur); } } static function getCurrentPath() { // Ensure that we've a position value initialized. if(!session::is_set('pathNavigator::position')) { session::set('pathNavigator::position',array()); } // Get position and validate its value $list = session::get('pathNavigator::position'); if(!is_array($list)){ $list = array(); } // Build up title and path string. $path = ""; $sTitle = ""; foreach($list as $entry){ $title = (!empty($entry['TITLE']))? 'title="'.htmlentities(LDAP::fix($entry['TITLE']),ENT_COMPAT,'UTF-8').'"': ''; $path.= "\n
  • {$entry['NAME']}
  • "; $sTitle .= " - ".$entry['NAME']; } // If no path is given then show a simple 'Welcome to GOsa' string. if(empty($path)){ $path = "
  • "._("Welcome to GOsa")."
  • "; } $smarty = get_smarty(); $smarty->assign('title', 'GOsa '.$sTitle); return($path); } static function clear() { session::set('pathNavigator::position', array()); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_remoteObject.inc0000644000175000017500000002262011613731145020330 0ustar cajuscajusrpcHandle = $rpcHandle; $this->properties = $properties; $this->methods = $methods; $this->type = $type; $this->ref_id = $ref_id; $this->object_id = $object_id; $this->values = $values; $this->cache = $values; } /*!\brief Returns the object type. * @return String The type of the object. E.g. 'user'. */ function getType() { return($this->type); } /*!\brief Returns a list of available property names. * @return Array A list of property names. */ function getProperties() { return($this->properties); } /*!\brief Returns the objects reference ID. * @return String the server side object id. */ function getReferenceId() { return($this->ref_id); } /*!\brief Clears all object modification when in not in * 'directStorage' mode. */ function clearCache() { $this->__clearCache(); } /*!\brief Catch all method for undefined function calls. * This method detects setter, getter and methods calls * and forwards them to the right object method. * @param String The name of the function to call. * @param Array A list of parameters. * @return Mixed E.g. The answer from the server. */ function __call($name, $args) { // Check if such an attribute is registered if(preg_match("/^get/", $name)){ $varName = ucfirst(preg_replace("/^get/","", $name)); $varName2 = lcfirst($varName); if(in_array_strict($varName, $this->properties)){ $force = isset($args[0]) && $args[0]; return($this->__getProperty($varName, $force)); }elseif(in_array_strict($varName2, $this->properties)){ $force = isset($args[0]) && $args[0]; return($this->__getProperty($varName2, $force)); } }elseif(preg_match("/^set/", $name)){ $varName = ucfirst(preg_replace("/^set/","", $name)); $varName2 = lcfirst($varName); if(in_array_strict($varName, $this->properties)){ return($this->__setProperty($varName, $args[0])); }elseif(in_array_strict($varName2, $this->properties)){ return($this->__setProperty($varName2, $args[0])); } } // Forward to the call to the backend. if(in_array_strict($name, $this->methods)){ $this->lastError = ""; $this->success = TRUE; $fArgs = array(); $fArgs[] = $this->ref_id; $fArgs[] = $name; $fArgs = array_merge($fArgs, $args); $res = call_user_func_array(array($this->rpcHandle,"dispatchObjectMethod"), $fArgs); if(!$this->rpcHandle->success()){ $this->success = FALSE; $this->lastError = $this->rpcHandle->get_error(); trigger_error($this->lastError); } return($res); } // Show an error, we do not know what to to with this.. trigger_error("Unknown method '{$name}' called for {$this->object_id}!"); } function success() { return($this->success); } function getError() { return($this->lastError); } /*!\brief A catch all method for setter calls. * * @param String The name of the property to set. * @param String The value to use. * @return */ function __set($varName, $value) { // Set property value if(in_array_strict($varName, $this->properties)){ return($this->__setProperty($varName, $value)); } // Set class member value if(isset($this->$varName)){ $this->$varName = $value; return(TRUE); } trigger_error("No attribute '{$varName}' defined!"); return(FALSE); } /*!\brief A catch all method for getter calls. * @param String The name of the requested property. * @return Mixed. */ function __get($varName) { if(in_array_strict($varName, $this->properties)){ return($this->__getProperty($varName)); } // Set class member value if(isset($this->$varName)){ return($this->$varName); } trigger_error("No attribute '{$varName}' defined!"); return(NULL); } /*!\brief Internal method used to set properties. * @param String The name of property to set. * @param Mixed The new value for the property. * @return Boolean true on success else false. */ function __setProperty($name, $value, $forceSave = FALSE) { if($this->directStorage || $forceSave){ $this->rpcHandle->setObjectProperty($this->ref_id, $name,$value); if($this->rpcHandle->success()){ $this->__addPropValueToCache($name, $value); return(TRUE); }else{ return(FALSE); } }else{ $this->__addPropValueToCache($name, $value); return(TRUE); } } /*!\brief Internal method used to get property values. * @param String The name of the property. * @return Mixed. */ function __getProperty($name, $force = FALSE) { if(!$force && $this->__propIsCached($name)){ return($this->__getPropFromCache($name)); } $res = $this->rpcHandle->getObjectProperty($this->ref_id, $name); if(!$this->rpcHandle->success()){ return(NULL); }else{ $this->__addPropValueToCache($name, $res); $this->values[$name] = $res; return($res); } } /*!\brief Closes the object on the server side. * @return The closing status. */ function close() { $res = $this->rpcHandle->closeObject($this->ref_id); if($this->success){ $this->ref_id = ""; } return($this->rpcHandle->success()); } /*!\brief Internal method used to add property values to the cache. * @param String The name of the propterty to add. * @param String The value of the property to add. */ function __addPropValueToCache($name, $value) { $this->cache[$name] = $value; } /*!\brief Internal method used to fetch property values from the cache. * @param String The name of the property to fetch. * @return Mixed. */ function __getPropFromCache($name) { return($this->cache[$name]); } /*!\brief Internal method to check whether a property value is cached or not. * @param String The name of the property. * @return Boolean True on success else false */ function __propIsCached($name) { return(isset($this->cache[$name])); } /*!\brief Clears the internal property cache. */ function __clearCache() { $this->cache = array(); } /* \brief See commit(); */ function save() { return($this->commit()); } /*! \brief Saves property modifications back to the server. * This is only necessary in directStorage mode. * @param Boolean If set to true all attributes will be saved, even not modified. */ function commit($saveUntouchedPropertiesToo = FALSE) { foreach($this->properties as $prop){ if(!$this->__propIsCached($prop)) continue; if($saveUntouchedPropertiesToo || $this->values[$prop] != $this->__getPropFromCache($prop)){ $this->__setProperty($prop, $this->__getPropFromCache($prop), TRUE); } } } /*!\brief Internal method which removes a property from the cache. * @param String The name of the property. * @return */ function __removePropFromCache($name) { if($this->__propIsCached($name)){ unset($this->cache[$name]); } } } ?> gosa-core-2.7.4/include/exporter/0000755000175000017500000000000011752422553015700 5ustar cajuscajusgosa-core-2.7.4/include/exporter/class_PDF.inc0000644000175000017500000000074311244761735020201 0ustar cajuscajusheadline= $headline; } function Header() { $this->SetFont('Helvetica','B',10); $this->Cell(0, 0, $this->headline, 0, 0, 'L'); $this->Ln(5); } function Footer() { $this->SetY(-15); $this->SetFont('Helvetica','I',8); $this->Cell(0,10, _("Page")." ".$this->PageNo().'/{nb}',0,0,'C'); } } ?> gosa-core-2.7.4/include/exporter/class_pdfExporter.inc0000644000175000017500000000735111613731145022064 0ustar cajuscajus $dummy) { $columns[]= $index; } } // Create new PDF $this->result=new PDF('L', 'mm', 'A4'); $this->result->AliasNbPages(); $this->result->SetFont('Helvetica', '', 10); $this->result->setHeadline(utf8_decode($headline)); $this->result->AddPage(); // Analyze for width $width= $this->calcWidth($header, $entries, $columns); // Render head $this->result->SetFont('','B'); $this->result->SetTextColor(0); $this->result->SetDrawColor(0,0,0); $this->result->SetLineWidth(.3); // Height calculator $height= 0; $fill= false; foreach ($entries as $row) { // Render header if ($height == 0) { // Generate header $this->result->SetFillColor(230,230,230); $this->result->SetFont('','B'); foreach ($columns as $order => $index) { if (isset($header[$index])){ $this->result->Cell($width[$order], 7, utf8_decode($header[$index]), 1, 0, 'C', 1); } else { $this->result->Cell($width[$order], 7, '', 1, 0, 'C', 1); } } $this->result->Ln(); $height= 7; // Set entry collors $this->result->SetFillColor(240,240,240); $this->result->SetFont(''); } foreach ($columns as $order => $index) { if (isset($row["_sort$index"])){ $this->result->Cell($width[$order], 6, utf8_decode($row["_sort$index"]), 'LR', 0, 'L', $fill); } else { $this->result->Cell($width[$order], 6, '', 'LR', 0, 'L', $fill); } } $this->result->Ln(); // Increase height to eventually create new page $height+= 8; if ($height > 220) { $height= 0; $this->result->Cell(array_sum($width), 0, '', 'T'); $this->result->AddPage(); $fill= false; } else { $fill= !$fill; } } $this->result->Cell(array_sum($width), 0, '', 'T'); } function calcWidth($header, $entries, $columns) { $width= array(); // Locate longest value for each column foreach ($columns as $order => $index) { $max= 0; if (isset($header[$index])){ $len= $this->result->GetStringWidth($header[$index]); if ($len > $max) { $max= $len; } } foreach ($entries as $row) { if (isset($row["_sort$index"])){ $len= $this->result->GetStringWidth($row["_sort$index"]); if ($len > $max) { $max= $len; } } } $width[]= $max; } // Scale to page width $printWidth= 280; $scale= $printWidth / array_sum($width); foreach ($width as $index => $w) { $width[$index]= (int)($width[$index] * $scale); } return $width; } function query() { return $this->result->Output("", "S"); } static function getInfo() { // Check if class defined $classes= get_declared_classes(); if(in_array_strict('FPDF', $classes)) { return array("exportPDF" => array( "label" => _("PDF"), "image" => "images/lists/pdf.png", "class"=> "pdfExporter", "mime" => "application/pdf", "filename" => "export.pdf" )); } else { return null; } } } ?> gosa-core-2.7.4/include/exporter/class_csvExporter.inc0000644000175000017500000000227411662665632022120 0ustar cajuscajus $dummy) { $columns[]= $index; } } // Generate header $this->result= "#"; foreach ($columns as $index) { if (isset($header[$index])){ $this->result.= trim($header[$index]).";"; } else { $this->result.= ";"; } } $this->result= preg_replace('/;$/', '', $this->result)."\n"; // Append entries foreach ($entries as $row) { foreach ($columns as $index) { if (isset($row["_sort$index"])){ $this->result.= trim(utf8_encode(html_entity_decode($row["_sort$index"]))).";"; } else { $this->result.= ";"; } } $this->result= preg_replace('/;$/', '', $this->result)."\n"; } } function query() { return $this->result; } static function getInfo() { return array("exportCVS" => array( "label" => _("CSV"), "image" => "images/lists/csv.png", "class"=> "csvExporter", "mime" => "text/x-csv", "filename" => "export.csv" )); } } ?> gosa-core-2.7.4/include/utils/0000755000175000017500000000000011752422553015170 5ustar cajuscajusgosa-core-2.7.4/include/utils/class_msgPool.inc0000644000175000017500000003732711472705006020500 0ustar cajuscajus
    $name")); }else{ return (sprintf(_("This %s object will be deleted: %s"), bold($type), "

    $name")); } } if (count($name) == 1){ if($type == ""){ return (_("This object will be deleted:")."
    ".msgPool::buildList($name)); }else{ return (sprintf(_("This %s object will be deleted:"), bold($type)). "
    ".msgPool::buildList($name)); } } if($type == ""){ return (sprintf(_("These objects will be deleted: %s"), "

    ".msgPool::buildList($name))); }else{ return (sprintf(_("These %s objects will be deleted: %s"), bold($type), "
    ".msgPool::buildList($name))); } } public static function permDelete($name= "") { if ($name == "") { return (_("You have no permission to delete this object!")); } if (!is_array($name)){ return (_("You have no permission to delete the object:")."

    $name"); } if (count($name) == 1){ return (_("You have no permission to delete the object:")."
    ".msgPool::buildList($name)); } return (_("You have no permission to delete these objects:")."
    ".msgPool::buildList($name)); } public static function permCreate($name= "") { if ($name == "") { return (_("You have no permission to create this object!")); } if (!is_array($name)){ return (_("You have no permission to create the object:")."

    $name"); } if (count($name) == 1){ return (_("You have no permission to create the object:")."
    ".msgPool::buildList($name)); } return (_("You have no permission to create these objects:")."
    ".msgPool::buildList($name)); } public static function permModify($name= "") { if ($name == "") { return (_("You have no permission to modify this object!")); } if (!is_array($name)){ return (_("You have no permission to modify the object:")."

    $name"); } if (count($name) == 1){ return (_("You have no permission to modify the object:")."
    ".msgPool::buildList($name)); } return (_("You have no permission to modify these objects:")."
    ".msgPool::buildList($name)); } public static function permView($name= "") { if ($name == "") { return (_("You have no permission to view this object!")); } if (!is_array($name)){ return (_("You have no permission to view the object:")."

    $name"); } if (count($name) == 1){ return (_("You have no permission to view the object:")."
    ".msgPool::buildList($name)); } return (_("You have no permission to view these objects:")."
    ".msgPool::buildList($name)); } public static function permMove($name= "") { if ($name == "") { return (_("You have no permission to move this object!")); } if (!is_array($name)){ return (_("You have no permission to move the object:")."

    $name"); } if (count($name) == 1){ return (_("You have no permission to move the object:")."
    ".msgPool::buildList($name)); } return (_("You have no permission to move these objects:")."
    ".msgPool::buildList($name)); } public static function dbconnect($name, $error= "", $dbinfo= "") { if ($error != ""){ $error= "

    "._("Error").": ".bold($error); } if ($dbinfo != ""){ $error.= "

    "._("Connection information").": ".bold($dbinfo); } return (sprintf(_("Cannot connect to %s database!"), bold($name)).$error); } public static function dbselect($name, $error= "", $dbinfo= "") { if ($error != ""){ $error= "

    "._("Error").": ".bold($error); } if ($dbinfo != ""){ $error.= "

    "._("Connection information").": ".bold($dbinfo); } return (sprintf(_("Cannot select %s database!"), bold($name)).$error); } public static function noserver($name) { return (sprintf(_("No %s server defined!"), bold($name))); } public static function dbquery($name, $error= "", $dbinfo= "") { if ($error != ""){ $error= "

    "._("Error").": ".bold($error); } if ($dbinfo != ""){ $error.= "

    "._("Connection information").": ".bold($dbinfo); } return (sprintf(_("Cannot query %s database!"), bold($name)).$error); } public static function reserved($name) { return (sprintf(_("The field %s contains a reserved keyword!"), bold($name))); } public static function cmdnotfound($type, $plugin) { return (sprintf(_("Command specified as %s hook for plugin %s does not exist!"), bold($type), bold($plugin))); } public static function cmdinvalid($type, $command = "",$plugin="") { if(empty($command)){ return (sprintf(_("%s command is invalid!"), bold($type))); }elseif($command != "" && $plugin != ""){ return (sprintf(_("%s command (%s) for plugin %s is invalid!"), bold($type), bold($command) ,bold($plugin))); }elseif($plugin != "" && $command =""){ return (sprintf(_("%s command for plugin %s is invalid!"), bold($type), bold($plugin))); }else{ return (sprintf(_("%s command (%s) is invalid!"), bold($type), bold($command))); } } public static function cmdexecfailed($type, $command = "",$plugin="") { if(empty($command)){ return (sprintf(_("Cannot execute %s command!"), bold($type))); }elseif($command != "" && $plugin != ""){ return (sprintf(_("Cannot execute %s command (%s) for plugin %s!"), bold($type), bold($command), bold($plugin))); }elseif($plugin != "" && $command =""){ return (sprintf(_("Cannot execute %s command for plugin %s!"), bold($type), bold($plugin))); }else{ return (sprintf(_("Cannot execute %s command (%s)!"), bold($type), bold($command))); } } public static function toobig($name, $min= "") { if ($min == ""){ return (sprintf(_("Value for %s is too large!"), bold($name))); } else { return (sprintf(_("%s must be smaller than %s!"), bold($name), bold($min))); } } public static function toosmall($name, $min= "") { if ($min == ""){ return (sprintf(_("Value for %s is too small!"), bold($name))); } else { return (sprintf(_("%s must be %s or above!"), bold($name), bold($min))); } } public static function depends($name1, $name2) { return (sprintf(_("%s depends on %s - please provide both values!"), bold($name1), bold($name2))); } public static function duplicated($name) { return (sprintf(_("There is already an entry with this %s attribute in the system!"), bold($name))); } public static function required($name) { return (sprintf(_("The required field %s is empty!"), bold($name))); } public static function invalid($name, $data= "", $regex= "", $example= "") { /* Stylize example */ if ($example != ""){ $example= "

    "._("Example").": ".bold($example); } /* If validChars are posted, take data and paint all invalid characters... */ if ($regex) { $result= ""; $mismatch= ""; mb_internal_encoding('UTF-8'); for($i=0; $i<=mb_strlen($data);$i++){ $currentChar= mb_substr($data, $i,1); if (preg_match("$regex", $currentChar)){ $result.= $currentChar; } else { $result.= "".($currentChar).""; $mismatch.= $currentChar; } } return sprintf(_("The Field %s contains invalid characters"), bold($name)).". ". (strlen($mismatch)==1?sprintf(_("%s is not allowed:"), bold($mismatch)):sprintf(_("%s are not allowed!"), bold($mismatch))). "

    \"$result\"$example"; } else { return sprintf(_("The Field %s contains invalid characters!"), bold($name))."!$example"; } } public static function missingext($name) { return sprintf(_("Missing %s PHP extension!"), bold($name)); } public static function cancelButton() { return sprintf(_("Cancel")); } public static function okButton() { return sprintf(_("OK")); } public static function applyButton() { return sprintf(_("Apply")); } public static function saveButton() { return sprintf(_("Save")); } public static function addButton($what= "") { return $what == "" ? sprintf(_("Add")): sprintf(_("Add %s"), $what); } public static function delButton($what= "") { return $what == "" ? sprintf(_("Delete")): sprintf(_("Delete %s"), $what); } public static function setButton($what= "") { return $what == "" ? sprintf(_("Set")): sprintf(_("Set %s"), $what); } public static function editButton($what= "") { return $what == "" ? sprintf(_("Edit...")): sprintf(_("Edit %s..."), $what); } public static function backButton($what= "") { return _("Back"); } public static function buildList($data) { $objects= ""; return($objects); } public static function noValidExtension($name) { return sprintf(_("This account has no valid %s extensions!"), bold($name)); } public static function featuresEnabled($name, $depends= "") { if ($depends == ""){ return sprintf(_("This account has %s settings enabled. You can disable them by clicking below."), bold($name)); } else { if (count($depends) == 1){ return sprintf(_("This account has %s settings enabled. To disable them, you'll need to remove the %s settings first!"), bold($name), bold($depends)); } else { $deps= ""; foreach ($depends as $dep){ $deps.= "$dep / "; } $deps= preg_replace("/ \/ $/", "", $deps); return sprintf(_("This account has %s settings enabled. To disable them, you'll need to remove the %s settings first!"), bold($name), bold($deps)); } } } public static function featuresDisabled($name, $depends= "") { if ($depends == ""){ return sprintf(_("This account has %s settings disabled. You can enable them by clicking below."), bold($name)); } else { if (count($depends) == 1){ return sprintf(_("This account has %s settings disabled. To enable them, you'll need to add the %s settings first!"), bold($name), bold($depends)); } else { $deps= ""; foreach ($depends as $dep){ $deps.= "$dep / "; } $deps= preg_replace("/ \/ $/", "", $deps); return sprintf(_("This account has %s settings disabled. To enable them, you'll need to add the %s settings first!"), bold($name), bold($deps)); } } } public static function addFeaturesButton($name) { return sprintf(_("Add %s settings"), $name); } public static function removeFeaturesButton($name) { return sprintf(_("Remove %s settings"), $name); } public static function clickEditToChange() { return _("Click the 'Edit' button below to change informations in this dialog"); } public static function months() { return array(_("January"), _("February"), _("March"), _("April"), _("May"), _("June"), _("July"), _("August"), _("September"), _("October"), _("November"), _("December")); } public static function weekdays() { return array( _("Sunday"), _("Monday"), _("Tuesday"), _("Wednesday"), _("Thursday"), _("Friday"), _("Saturday")); } public static function mysqlerror($error, $plugin= "") { /* Assign headline depending on type */ $headline= _("MySQL operation failed!"); return $headline."

    "._("Error").": ".bold($error); } public static function ldaperror($error, $dn= "", $type= 0, $plugin= "") { /* Assign headline depending on type */ $typemap= array(1 => _("read operation"), _("add operation"), _("modify operation"), _("delete operation"), _("search operation"), _("authentication")); if (isset($typemap[$type])){ $headline= sprintf(_("LDAP %s failed!"), bold($typemap[$type])); } else { $headline= _("LDAP operation failed!"); } /* Fill DN information */ $dn_info=""; if ($dn != ""){ $dn_info= "

    "._("Object").": ".bold(LDAP::fix($dn)); } return $headline.$dn_info."

    "._("Error").": ".bold($error); } public static function incorrectUpload($reason= "") { if ($reason == ""){ return _("Upload failed!"); } return sprintf(_("Upload failed: %s"), "

    ".bold($reason)); } public static function siError($error= "") { if ($error == ""){ return _("Communication failure with the infrastructure service!"); } return sprintf(_("Communication failure with the infrastructure service: %s"), "

    ".$error); } public static function rpcError($error= "") { if ($error == ""){ return _("Communication failure with the GOsa-NG service!"); } return sprintf(_("Communication failure with the GOsa-NG service: %s"), "

    ".$error); } public static function stillInUse($type, $objects= array()) { if (!is_array($objects)){ return sprintf(_("This %s is still in use by this object: %s"), bold($type), "

    ".$objects); } if (count($objects) == 1){ return sprintf(_("This %s is still in use by this object: %s"), bold($type), "
    ".msgPool::buildList($objects)); } if (count($objects) == 0){ return sprintf(_("This %s is still in use."), bold($type)); } return sprintf(_("This %s is still in use by these objects: %s"), bold($type), "
    ".msgPool::buildList($objects)); } public static function fileDoesNotExist($file) { return sprintf(_("File %s does not exist!"), bold($file)); } public static function cannotReadFile($file) { return sprintf(_("Cannot open file %s for reading!"), bold($file)); } public static function cannotWriteFile($file) { return sprintf(_("Cannot open file %s for writing!"), bold($file)); } public static function invalidConfigurationAttribute($attr) { return sprintf(_("The value for %s is currently unconfigured or invalid, please check your configuration file!"), bold($attr)); } public static function cannotDeleteFile($file) { return sprintf(_("Cannot delete file %s!"), bold($file)); } public static function cannotCreateFolder($path) { return sprintf(_("Cannot create folder %s!"), bold($path)); } public static function cannotDeleteFolder($path) { return sprintf(_("Cannot delete folder %s!"), bold($path)); } public static function checkingFor($what) { return sprintf(_("Checking for %s support"), bold($what)); } public static function installPhpModule($what) { return sprintf(_("Install and activate the %s PHP module."), bold($what)); } public static function class_not_found($plugin) { return (sprintf(_("Cannot initialize class %s! Maybe there is a plugin missing in your gosa setup?"), bold($plugin))); } public static function check_base() { return _("The supplied base is not valid and has been reset to its previous value!"); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/utils/excel/0000755000175000017500000000000011752422553016270 5ustar cajuscajusgosa-core-2.7.4/include/utils/excel/class.writeexcel_worksheet.inc.php0000644000175000017500000027015511327532760025135 0ustar cajuscajuswriteexcel_biffwriter(); $rowmax = 65536; // 16384 in Excel 5 $colmax = 256; $strmax = 255; $this->_name = $name; $this->_index = $index; $this->_activesheet = $activesheet; $this->_firstsheet = $firstsheet; $this->_url_format = $url_format; $this->_parser = $parser; $this->_tempdir = $tempdir; $this->_ext_sheets = array(); $this->_using_tmpfile = 1; $this->_filehandle = false; $this->_fileclosed = 0; $this->_offset = 0; $this->_xls_rowmax = $rowmax; $this->_xls_colmax = $colmax; $this->_xls_strmax = $strmax; $this->_dim_rowmin = $rowmax +1; $this->_dim_rowmax = 0; $this->_dim_colmin = $colmax +1; $this->_dim_colmax = 0; $this->_colinfo = array(); $this->_selection = array(0, 0); $this->_panes = array(); $this->_active_pane = 3; $this->_frozen = 0; $this->_selected = 0; $this->_paper_size = 0x0; $this->_orientation = 0x1; $this->_header = ''; $this->_footer = ''; $this->_hcenter = 0; $this->_vcenter = 0; $this->_margin_head = 0.50; $this->_margin_foot = 0.50; $this->_margin_left = 0.75; $this->_margin_right = 0.75; $this->_margin_top = 1.00; $this->_margin_bottom = 1.00; $this->_title_rowmin = false; $this->_title_rowmax = false; $this->_title_colmin = false; $this->_title_colmax = false; $this->_print_rowmin = false; $this->_print_rowmax = false; $this->_print_colmin = false; $this->_print_colmax = false; $this->_print_gridlines = 1; $this->_screen_gridlines = 1; $this->_print_headers = 0; $this->_fit_page = 0; $this->_fit_width = 0; $this->_fit_height = 0; $this->_hbreaks = array(); $this->_vbreaks = array(); $this->_protect = 0; $this->_password = false; $this->_col_sizes = array(); $this->_row_sizes = array(); $this->_col_formats = array(); $this->_row_formats = array(); $this->_zoom = 100; $this->_print_scale = 100; $this->_initialize(); } ############################################################################### # # _initialize() # # Open a tmp file to store the majority of the Worksheet data. If this fails, # for example due to write permissions, store the data in memory. This can be # slow for large files. # function _initialize() { # Open tmp file for storing Worksheet data. $fh=fopen(tempnam($this->_tempdir, "php_writeexcel"), "w+b"); if ($fh) { # Store filehandle $this->_filehandle = $fh; } else { # If tempfile() failed store data in memory $this->_using_tmpfile = 0; if ($this->_index == 0) { $dir = $this->_tempdir; //todo warn "Unable to create temp files in $dir. Refer to set_tempdir()". // " in the Spreadsheet::WriteExcel documentation.\n" ; } } } /* * Add data to the beginning of the workbook (note the reverse order) * and to the end of the workbook. */ function _close($sheetnames) { /////////////////////////////// // Prepend in reverse order!! // $this->_store_dimensions(); // Prepend the sheet dimensions $this->_store_password(); // Prepend the sheet password $this->_store_protect(); // Prepend the sheet protection $this->_store_setup(); // Prepend the page setup $this->_store_margin_bottom(); // Prepend the bottom margin $this->_store_margin_top(); // Prepend the top margin $this->_store_margin_right(); // Prepend the right margin $this->_store_margin_left(); // Prepend the left margin $this->_store_vcenter(); // Prepend the page vertical // centering $this->_store_hcenter(); // Prepend the page horizontal // centering $this->_store_footer(); // Prepend the page footer $this->_store_header(); // Prepend the page header $this->_store_vbreak(); // Prepend the vertical page breaks $this->_store_hbreak(); // Prepend the horizontal // page breaks $this->_store_wsbool(); // Prepend WSBOOL $this->_store_gridset(); // Prepend GRIDSET $this->_store_print_gridlines(); // Prepend PRINTGRIDLINES $this->_store_print_headers(); // Prepend PRINTHEADERS // Prepend EXTERNSHEET references $num_sheets = sizeof($sheetnames); for ($i = $num_sheets; $i > 0; $i--) { $sheetname = $sheetnames[$i-1]; $this->_store_externsheet($sheetname); } $this->_store_externcount($num_sheets); // Prepend the EXTERNCOUNT // of external references. // Prepend the COLINFO records if they exist if (sizeof($this->_colinfo)>0){ while (sizeof($this->_colinfo)>0) { $arrayref = array_pop ($this->_colinfo); $this->_store_colinfo($arrayref); } $this->_store_defcol(); } $this->_store_bof(0x0010); // Prepend the BOF record // // End of prepend. Read upwards from here. //////////////////////////////////////////// // Append $this->_store_window2(); $this->_store_zoom(); if (sizeof($this->_panes)>0) { $this->_store_panes($this->_panes); } $this->_store_selection($this->_selection); $this->_store_eof(); } /* * Retrieve the worksheet name. */ function get_name() { return $this->_name; } ############################################################################### # # get_data(). # # Retrieves data from memory in one chunk, or from disk in $buffer # sized chunks. # function get_data() { $buffer = 4096; # Return data stored in memory if ($this->_data!==false) { $tmp = $this->_data; $this->_data=false; $fh = $this->_filehandle; if ($this->_using_tmpfile) { fseek($fh, 0, SEEK_SET); } if ($this->_debug) { print "*** worksheet::get_data() called (1):"; for ($c=0;$c_using_tmpfile) { if ($tmp=fread($this->_filehandle, $buffer)) { if ($this->_debug) { print "*** worksheet::get_data() called (2):"; for ($c=0;$c_selected = 1; } /* * Set this worksheet as the active worksheet, i.e. the worksheet * that is displayed when the workbook is opened. Also set it as * selected. */ function activate() { $this->_selected = 1; $this->_activesheet = $this->_index; } /* * Set this worksheet as the first visible sheet. This is necessary * when there are a large number of worksheets and the activated * worksheet is not visible on the screen. */ function set_first_sheet() { $this->_firstsheet = $this->_index; } /* * Set the worksheet protection flag to prevent accidental modification * and to hide formulas if the locked and hidden format properties have * been set. */ function protect($password) { $this->_protect = 1; $this->_password = $this->_encode_password($password); } ############################################################################### # # set_column($firstcol, $lastcol, $width, $format, $hidden) # # Set the width of a single column or a range of column. # See also: _store_colinfo # function set_column() { $_=func_get_args(); $cell = $_[0]; # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $cell)) { $_ = $this->_substitute_cellref($_); } array_push($this->_colinfo, $_); # Store the col sizes for use when calculating image vertices taking # hidden columns into account. Also store the column formats. # if (sizeof($_)<3) { # Ensure at least $firstcol, $lastcol and $width return; } $width = $_[4] ? 0 : $_[2]; # Set width to zero if column is hidden $format = $_[3]; list($firstcol, $lastcol) = $_; for ($col=$firstcol;$col<=$lastcol;$col++) { $this->_col_sizes[$col] = $width; if ($format) { $this->_col_formats[$col] = $format; } } } ############################################################################### # # set_selection() # # Set which cell or cells are selected in a worksheet: see also the # function _store_selection # function set_selection() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } $this->_selection = $_; } ############################################################################### # # freeze_panes() # # Set panes and mark them as frozen. See also _store_panes(). # function freeze_panes() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } $this->_frozen = 1; $this->_panes = $_; } ############################################################################### # # thaw_panes() # # Set panes and mark them as unfrozen. See also _store_panes(). # function thaw_panes() { $_=func_get_args(); $this->_frozen = 0; $this->_panes = $_; } /* * Set the page orientation as portrait. */ function set_portrait() { $this->_orientation = 1; } /* * Set the page orientation as landscape. */ function set_landscape() { $this->_orientation = 0; } /* * Set the paper type. Ex. 1 = US Letter, 9 = A4 */ function set_paper($type) { $this->_paper_size = $type; } /* * Set the page header caption and optional margin. */ function set_header($string, $margin) { if (strlen($string) >= 255) { trigger_error("Header string must be less than 255 characters", E_USER_WARNING); return; } $this->_header = $string; $this->_margin_head = $margin; } /* * Set the page footer caption and optional margin. */ function set_footer($string, $margin) { if (strlen($string) >= 255) { trigger_error("Footer string must be less than 255 characters", E_USER_WARNING); return; } $this->_footer = $string; $this->_margin_foot = $margin; } /* * Center the page horizontally. */ function center_horizontally($hcenter=1) { $this->_hcenter = $hcenter; } /* * Center the page horizontally. */ function center_vertically($vcenter=1) { $this->_vcenter = $vcenter; } /* * Set all the page margins to the same value in inches. */ function set_margins($margin) { $this->set_margin_left($margin); $this->set_margin_right($margin); $this->set_margin_top($margin); $this->set_margin_bottom($margin); } /* * Set the left and right margins to the same value in inches. */ function set_margins_LR($margin) { $this->set_margin_left($margin); $this->set_margin_right($margin); } /* * Set the top and bottom margins to the same value in inches. */ function set_margins_TB($margin) { $this->set_margin_top($margin); $this->set_margin_bottom($margin); } /* * Set the left margin in inches. */ function set_margin_left($margin=0.75) { $this->_margin_left = $margin; } /* * Set the right margin in inches. */ function set_margin_right($margin=0.75) { $this->_margin_right = $margin; } /* * Set the top margin in inches. */ function set_margin_top($margin=1.00) { $this->_margin_top = $margin; } /* * Set the bottom margin in inches. */ function set_margin_bottom($margin=1.00) { $this->_margin_bottom = $margin; } ############################################################################### # # repeat_rows($first_row, $last_row) # # Set the rows to repeat at the top of each printed page. See also the # _store_name_xxxx() methods in Workbook.pm. # function repeat_rows() { $_=func_get_args(); $this->_title_rowmin = $_[0]; $this->_title_rowmax = isset($_[1]) ? $_[1] : $_[0]; # Second row is optional } ############################################################################### # # repeat_columns($first_col, $last_col) # # Set the columns to repeat at the left hand side of each printed page. # See also the _store_names() methods in Workbook.pm. # function repeat_columns() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } $this->_title_colmin = $_[0]; $this->_title_colmax = isset($_[1]) ? $_[1] : $_[0]; # Second col is optional } ############################################################################### # # print_area($first_row, $first_col, $last_row, $last_col) # # Set the area of each worksheet that will be printed. See also the # _store_names() methods in Workbook.pm. # function print_area() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } if (sizeof($_) != 4) { # Require 4 parameters return; } $this->_print_rowmin = $_[0]; $this->_print_colmin = $_[1]; $this->_print_rowmax = $_[2]; $this->_print_colmax = $_[3]; } /* * Set the option to hide gridlines on the screen and the printed page. * There are two ways of doing this in the Excel BIFF format: The first * is by setting the DspGrid field of the WINDOW2 record, this turns off * the screen and subsequently the print gridline. The second method is * to via the PRINTGRIDLINES and GRIDSET records, this turns off the * printed gridlines only. The first method is probably sufficient for * most cases. The second method is supported for backwards compatibility. */ function hide_gridlines($option=1) { if ($option == 0) { $this->_print_gridlines = 1; # 1 = display, 0 = hide $this->_screen_gridlines = 1; } elseif ($option == 1) { $this->_print_gridlines = 0; $this->_screen_gridlines = 1; } else { $this->_print_gridlines = 0; $this->_screen_gridlines = 0; } } /* * Set the option to print the row and column headers on the printed page. * See also the _store_print_headers() method below. */ function print_row_col_headers($headers=1) { $this->_print_headers = $headers; } /* * Store the vertical and horizontal number of pages that will define * the maximum area printed. See also _store_setup() and _store_wsbool() * below. */ function fit_to_pages($width, $height) { $this->_fit_page = 1; $this->_fit_width = $width; $this->_fit_height = $height; } /* * Store the horizontal page breaks on a worksheet. */ function set_h_pagebreaks($breaks) { $this->_hbreaks=array_merge($this->_hbreaks, $breaks); } /* * Store the vertical page breaks on a worksheet. */ function set_v_pagebreaks($breaks) { $this->_vbreaks=array_merge($this->_vbreaks, $breaks); } /* * Set the worksheet zoom factor. */ function set_zoom($scale=100) { // Confine the scale to Excel's range if ($scale < 10 || $scale > 400) { trigger_error("Zoom factor $scale outside range: ". "10 <= zoom <= 400", E_USER_WARNING); $scale = 100; } $this->_zoom = $scale; } /* * Set the scale factor for the printed page. */ function set_print_scale($scale=100) { // Confine the scale to Excel's range if ($scale < 10 || $scale > 400) { trigger_error("Print scale $scale outside range: ". "10 <= zoom <= 400", E_USER_WARNING); $scale = 100; } // Turn off "fit to page" option $this->_fit_page = 0; $this->_print_scale = $scale; } ############################################################################### # # write($row, $col, $token, $format) # # Parse $token call appropriate write method. $row and $column are zero # indexed. $format is optional. # # Returns: return value of called subroutine # function write() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } $token = $_[2]; # Match an array ref. if (is_array($token)) { return call_user_func_array(array($this, 'write_row'), $_); } # Match number if (preg_match('/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/', $token)) { return call_user_func_array(array($this, 'write_number'), $_); } # Match http, https or ftp URL elseif (preg_match('|^[fh]tt?ps?://|', $token)) { return call_user_func_array(array($this, 'write_url'), $_); } # Match mailto: elseif (preg_match('/^mailto:/', $token)) { return call_user_func_array(array($this, 'write_url'), $_); } # Match internal or external sheet link elseif (preg_match('[^(?:in|ex)ternal:]', $token)) { return call_user_func_array(array($this, 'write_url'), $_); } # Match formula elseif (preg_match('/^=/', $token)) { return call_user_func_array(array($this, 'write_formula'), $_); } # Match blank elseif ($token == '') { array_splice($_, 2, 1); # remove the empty string from the parameter list return call_user_func_array(array($this, 'write_blank'), $_); } # Default: match string else { return call_user_func_array(array($this, 'write_string'), $_); } } ############################################################################### # # write_row($row, $col, $array_ref, $format) # # Write a row of data starting from ($row, $col). Call write_col() if any of # the elements of the array ref are in turn array refs. This allows the writing # of 1D or 2D arrays of data in one go. # # Returns: the first encountered error value or zero for no errors # function write_row() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } # Catch non array refs passed by user. if (!is_array($_[2])) { trigger_error("Not an array ref in call to write_row()!", E_USER_ERROR); } list($row, $col, $tokens)=array_splice($_, 0, 3); $options = $_[0]; $error = 0; foreach ($tokens as $token) { # Check for nested arrays if (is_array($token)) { $ret = $this->write_col($row, $col, $token, $options); } else { $ret = $this->write ($row, $col, $token, $options); } # Return only the first error encountered, if any. $error = $error || $ret; $col++; } return $error; } ############################################################################### # # _XF() # # Returns an index to the XF record in the workbook. # TODO # # Note: this is a function, not a method. # function _XF($row=false, $col=false, $format=false) { if ($format) { return $format->get_xf_index(); } elseif (isset($this->_row_formats[$row])) { return $this->_row_formats[$row]->get_xf_index(); } elseif (isset($this->_col_formats[$col])) { return $this->_col_formats[$col]->get_xf_index(); } else { return 0x0F; } } ############################################################################### # # write_col($row, $col, $array_ref, $format) # # Write a column of data starting from ($row, $col). Call write_row() if any of # the elements of the array ref are in turn array refs. This allows the writing # of 1D or 2D arrays of data in one go. # # Returns: the first encountered error value or zero for no errors # function write_col() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } # Catch non array refs passed by user. if (!is_array($_[2])) { trigger_error("Not an array ref in call to write_row()!", E_USER_ERROR); } $row = array_shift($_); $col = array_shift($_); $tokens = array_shift($_); $options = $_; $error = 0; foreach ($tokens as $token) { # write() will deal with any nested arrays $ret = $this->write($row, $col, $token, $options); # Return only the first error encountered, if any. $error = $error || $ret; $row++; } return $error; } ############################################################################### ############################################################################### # # Internal methods # ############################################################################### # # _append(), overloaded. # # Store Worksheet data in memory using the base class _append() or to a # temporary file, the default. # function _append($data) { if (func_num_args()>1) { trigger_error("writeexcel_worksheet::_append() ". "called with more than one argument", E_USER_ERROR); } if ($this->_using_tmpfile) { if ($this->_debug) { print "worksheet::_append() called:"; for ($c=0;$c $this->_limit) { $data = $this->_add_continue($data); } fputs($this->_filehandle, $data); $this->_datasize += strlen($data); } else { parent::_append($data); } } ############################################################################### # # _substitute_cellref() # # Substitute an Excel cell reference in A1 notation for zero based row and # column values in an argument list. # # Ex: ("A4", "Hello") is converted to (3, 0, "Hello"). # // Exactly one array must be passed! function _substitute_cellref($_) { $cell = strtoupper(array_shift($_)); # Convert a column range: 'A:A' or 'B:G' if (preg_match('/([A-I]?[A-Z]):([A-I]?[A-Z])/', $cell, $reg)) { list($dummy, $col1) = $this->_cell_to_rowcol($reg[1] .'1'); # Add a dummy row list($dummy, $col2) = $this->_cell_to_rowcol($reg[2] .'1'); # Add a dummy row return array_merge(array($col1, $col2), $_); } # Convert a cell range: 'A1:B7' if (preg_match('/\$?([A-I]?[A-Z]\$?\d+):\$?([A-I]?[A-Z]\$?\d+)/', $cell, $reg)) { list($row1, $col1) = $this->_cell_to_rowcol($reg[1]); list($row2, $col2) = $this->_cell_to_rowcol($reg[2]); return array_merge(array($row1, $col1, $row2, $col2), $_); } # Convert a cell reference: 'A1' or 'AD2000' if (preg_match('/\$?([A-I]?[A-Z]\$?\d+)/', $cell, $reg)) { list($row1, $col1) = $this->_cell_to_rowcol($reg[1]); return array_merge(array($row1, $col1), $_); } trigger_error("Unknown cell reference $cell", E_USER_ERROR); } ############################################################################### # # _cell_to_rowcol($cell_ref) # # Convert an Excel cell reference in A1 notation to a zero based row and column # reference; converts C1 to (0, 2). # # Returns: row, column # # TODO use functions in Utility.pm # function _cell_to_rowcol($cell) { preg_match('/\$?([A-I]?[A-Z])\$?(\d+)/', $cell, $reg); $col = $reg[1]; $row = $reg[2]; # Convert base26 column string to number # All your Base are belong to us. $chars = preg_split('//', $col, -1, PREG_SPLIT_NO_EMPTY); $expn = 0; $col = 0; while (sizeof($chars)) { $char = array_pop($chars); # LS char first $col += (ord($char) -ord('A') +1) * pow(26, $expn); $expn++; } # Convert 1-index to zero-index $row--; $col--; return array($row, $col); } /* * This is an internal method that is used to filter elements of the * array of pagebreaks used in the _store_hbreak() and _store_vbreak() * methods. It: * 1. Removes duplicate entries from the list. * 2. Sorts the list. * 3. Removes 0 from the list if present. */ function _sort_pagebreaks($breaks) { // Hash slice to remove duplicates foreach ($breaks as $break) { $hash["$break"]=1; } // Numerical sort $breaks=array_keys($hash); sort($breaks, SORT_NUMERIC); // Remove zero if ($breaks[0] == 0) { array_shift($breaks); } // 1000 vertical pagebreaks appears to be an internal Excel 5 limit. // It is slightly higher in Excel 97/200, approx. 1026 if (sizeof($breaks) > 1000) { array_splice($breaks, 1000); } return $breaks; } /* * Based on the algorithm provided by Daniel Rentz of OpenOffice. */ function _encode_password($plaintext) { $chars=preg_split('//', $plaintext, -1, PREG_SPLIT_NO_EMPTY); $count=sizeof($chars); for ($c=0;$c> 15; $char = $low_15 | $high_15; } $password = 0x0000; foreach ($chars as $char) { $password ^= $char; } $password ^= $count; $password ^= 0xCE4B; return $password; } ############################################################################### ############################################################################### # # BIFF RECORDS # ############################################################################### # # write_number($row, $col, $num, $format) # # Write a double to the specified row and column (zero indexed). # An integer can be written as a double. Excel will display an # integer. $format is optional. # # Returns 0 : normal termination # -1 : insufficient number of arguments # -2 : row or column out of range # function write_number() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } # Check the number of args if (sizeof($_) < 3) { return -1; } $record = 0x0203; # Record identifier $length = 0x000E; # Number of bytes to follow $row = $_[0]; # Zero indexed row $col = $_[1]; # Zero indexed column $num = $_[2]; //!!! $xf = $this->_XF($row, $col, $_[3]); # The cell format # Check that row and col are valid and store max and min values if ($row >= $this->_xls_rowmax) { return -2; } if ($col >= $this->_xls_colmax) { return -2; } if ($row < $this->_dim_rowmin) { $this->_dim_rowmin = $row; } if ($row > $this->_dim_rowmax) { $this->_dim_rowmax = $row; } if ($col < $this->_dim_colmin) { $this->_dim_colmin = $col; } if ($col > $this->_dim_colmax) { $this->_dim_colmax = $col; } $header = pack("vv", $record, $length); $data = pack("vvv", $row, $col, $xf); $xl_double = pack("d", $num); if ($this->_byte_order) { //TODO $xl_double = strrev($xl_double); } $this->_append($header . $data . $xl_double); return 0; } ############################################################################### # # write_string ($row, $col, $string, $format) # # Write a string to the specified row and column (zero indexed). # NOTE: there is an Excel 5 defined limit of 255 characters. # $format is optional. # Returns 0 : normal termination # -1 : insufficient number of arguments # -2 : row or column out of range # -3 : long string truncated to 255 chars # function write_string() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } # Check the number of args if (sizeof($_) < 3) { return -1; } $record = 0x0204; # Record identifier $length = 0x0008 + strlen($_[2]); # Bytes to follow $row = $_[0]; # Zero indexed row $col = $_[1]; # Zero indexed column $strlen = strlen($_[2]); $str = $_[2]; $xf = $this->_XF($row, $col, $_[3]); # The cell format $str_error = 0; # Check that row and col are valid and store max and min values if ($row >= $this->_xls_rowmax) { return -2; } if ($col >= $this->_xls_colmax) { return -2; } if ($row < $this->_dim_rowmin) { $this->_dim_rowmin = $row; } if ($row > $this->_dim_rowmax) { $this->_dim_rowmax = $row; } if ($col < $this->_dim_colmin) { $this->_dim_colmin = $col; } if ($col > $this->_dim_colmax) { $this->_dim_colmax = $col; } if ($strlen > $this->_xls_strmax) { # LABEL must be < 255 chars $str = substr($str, 0, $this->_xls_strmax); $length = 0x0008 + $this->_xls_strmax; $strlen = $this->_xls_strmax; $str_error = -3; } $header = pack("vv", $record, $length); $data = pack("vvvv", $row, $col, $xf, $strlen); $this->_append($header . $data . $str); return $str_error; } ############################################################################### # # write_blank($row, $col, $format) # # Write a blank cell to the specified row and column (zero indexed). # A blank cell is used to specify formatting without adding a string # or a number. # # A blank cell without a format serves no purpose. Therefore, we don't write # a BLANK record unless a format is specified. This is mainly an optimisation # for the write_row() and write_col() methods. # # Returns 0 : normal termination (including no format) # -1 : insufficient number of arguments # -2 : row or column out of range # function write_blank() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } # Check the number of args if (sizeof($_) < 2) { return -1; } # Don't write a blank cell unless it has a format if (!isset($_[2])) { return 0; } $record = 0x0201; # Record identifier $length = 0x0006; # Number of bytes to follow $row = $_[0]; # Zero indexed row $col = $_[1]; # Zero indexed column $xf = $this->_XF($row, $col, $_[2]); # The cell format # Check that row and col are valid and store max and min values if ($row >= $this->_xls_rowmax) { return -2; } if ($col >= $this->_xls_colmax) { return -2; } if ($row < $this->_dim_rowmin) { $this->_dim_rowmin = $row; } if ($row > $this->_dim_rowmax) { $this->_dim_rowmax = $row; } if ($col < $this->_dim_colmin) { $this->_dim_colmin = $col; } if ($col > $this->_dim_colmax) { $this->_dim_colmax = $col; } $header = pack("vv", $record, $length); $data = pack("vvv", $row, $col, $xf); $this->_append($header . $data); return 0; } ############################################################################### # # write_formula($row, $col, $formula, $format) # # Write a formula to the specified row and column (zero indexed). # The textual representation of the formula is passed to the parser in # Formula.pm which returns a packed binary string. # # $format is optional. # # Returns 0 : normal termination # -1 : insufficient number of arguments # -2 : row or column out of range # function write_formula() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } # Check the number of args if (sizeof($_) < 3) { return -1; } $record = 0x0006; # Record identifier $length=0; # Bytes to follow $row = $_[0]; # Zero indexed row $col = $_[1]; # Zero indexed column $formula = $_[2]; # The formula text string # Excel normally stores the last calculated value of the formula in $num. # Clearly we are not in a position to calculate this a priori. Instead # we set $num to zero and set the option flags in $grbit to ensure # automatic calculation of the formula when the file is opened. # $xf = $this->_XF($row, $col, $_[3]); # The cell format $num = 0x00; # Current value of formula $grbit = 0x03; # Option flags $chn = 0x0000; # Must be zero # Check that row and col are valid and store max and min values if ($row >= $this->_xls_rowmax) { return -2; } if ($col >= $this->_xls_colmax) { return -2; } if ($row < $this->_dim_rowmin) { $this->_dim_rowmin = $row; } if ($row > $this->_dim_rowmax) { $this->_dim_rowmax = $row; } if ($col < $this->_dim_colmin) { $this->_dim_colmin = $col; } if ($col > $this->_dim_colmax) { $this->_dim_colmax = $col; } # Strip the = sign at the beginning of the formula string $formula = preg_replace('/^=/', "", $formula); # Parse the formula using the parser in Formula.pm $parser = $this->_parser; $formula = $parser->parse_formula($formula); $formlen = strlen($formula); # Length of the binary string $length = 0x16 + $formlen; # Length of the record data $header = pack("vv", $record, $length); $data = pack("vvvdvVv", $row, $col, $xf, $num, $grbit, $chn, $formlen); $this->_append($header . $data . $formula); return 0; } ############################################################################### # # write_url($row, $col, $url, $string, $format) # # Write a hyperlink. This is comprised of two elements: the visible label and # the invisible link. The visible label is the same as the link unless an # alternative string is specified. The label is written using the # write_string() method. Therefore the 255 characters string limit applies. # $string and $format are optional and their order is interchangeable. # # The hyperlink can be to a http, ftp, mail, internal sheet, or external # directory url. # # Returns 0 : normal termination # -1 : insufficient number of arguments # -2 : row or column out of range # -3 : long string truncated to 255 chars # function write_url() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } # Check the number of args if (sizeof($_) < 3) { return -1; } # Add start row and col to arg list return call_user_func_array(array($this, 'write_url_range'), array_merge(array($_[0], $_[1]), $_)); } ############################################################################### # # write_url_range($row1, $col1, $row2, $col2, $url, $string, $format) # # This is the more general form of write_url(). It allows a hyperlink to be # written to a range of cells. This function also decides the type of hyperlink # to be written. These are either, Web (http, ftp, mailto), Internal # (Sheet1!A1) or external ('c:\temp\foo.xls#Sheet1!A1'). # # See also write_url() above for a general description and return values. # function write_url_range() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } # Check the number of args if (sizeof($_) < 5) { return -1; } # Reverse the order of $string and $format if necessary. //TODO ($_[5], $_[6]) = ($_[6], $_[5]) if (ref $_[5]); $url = $_[4]; # Check for internal/external sheet links or default to web link if (preg_match('[^internal:]', $url)) { return call_user_func_array(array($this, '_write_url_internal'), $_); } if (preg_match('[^external:]', $url)) { return call_user_func_array(array($this, '_write_url_external'), $_); } return call_user_func_array(array($this, '_write_url_web'), $_); } ############################################################################### # # _write_url_web($row1, $col1, $row2, $col2, $url, $string, $format) # # Used to write http, ftp and mailto hyperlinks. # The link type ($options) is 0x03 is the same as absolute dir ref without # sheet. However it is differentiated by the $unknown2 data stream. # # See also write_url() above for a general description and return values. # function _write_url_web() { $_=func_get_args(); $record = 0x01B8; # Record identifier $length = 0x00000; # Bytes to follow $row1 = $_[0]; # Start row $col1 = $_[1]; # Start column $row2 = $_[2]; # End row $col2 = $_[3]; # End column $url = $_[4]; # URL string if (isset($_[5])) { $str = $_[5]; # Alternative label } $xf = $_[6] ? $_[6] : $this->_url_format; # The cell format # Write the visible label using the write_string() method. if(!isset($str)) { $str = $url; } $str_error = $this->write_string($row1, $col1, $str, $xf); if ($str_error == -2) { return $str_error; } # Pack the undocumented parts of the hyperlink stream $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000"); $unknown2 = pack("H*", "E0C9EA79F9BACE118C8200AA004BA90B"); # Pack the option flags $options = pack("V", 0x03); # Convert URL to a null terminated wchar string $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY)); $url = $url . "\0\0\0"; # Pack the length of the URL $url_len = pack("V", strlen($url)); # Calculate the data length $length = 0x34 + strlen($url); # Pack the header data $header = pack("vv", $record, $length); $data = pack("vvvv", $row1, $row2, $col1, $col2); # Write the packed data $this->_append($header. $data. $unknown1. $options. $unknown2. $url_len. $url); return $str_error; } ############################################################################### # # _write_url_internal($row1, $col1, $row2, $col2, $url, $string, $format) # # Used to write internal reference hyperlinks such as "Sheet1!A1". # # See also write_url() above for a general description and return values. # function _write_url_internal() { $_=func_get_args(); $record = 0x01B8; # Record identifier $length = 0x00000; # Bytes to follow $row1 = $_[0]; # Start row $col1 = $_[1]; # Start column $row2 = $_[2]; # End row $col2 = $_[3]; # End column $url = $_[4]; # URL string if (isset($_[5])) { $str = $_[5]; # Alternative label } $xf = $_[6] ? $_[6] : $this->_url_format; # The cell format # Strip URL type $url = preg_replace('s[^internal:]', '', $url); # Write the visible label if (!isset($str)) { $str = $url; } $str_error = $this->write_string($row1, $col1, $str, $xf); if ($str_error == -2) { return $str_error; } # Pack the undocumented parts of the hyperlink stream $unknown1 = pack("H*", "D0C9EA79F9BACE118C8200AA004BA90B02000000"); # Pack the option flags $options = pack("V", 0x08); # Convert the URL type and to a null terminated wchar string $url = join("\0", preg_split("''", $url, -1, PREG_SPLIT_NO_EMPTY)); $url = $url . "\0\0\0"; # Pack the length of the URL as chars (not wchars) $url_len = pack("V", int(strlen($url)/2)); # Calculate the data length $length = 0x24 + strlen($url); # Pack the header data $header = pack("vv", $record, $length); $data = pack("vvvv", $row1, $row2, $col1, $col2); # Write the packed data $this->_append($header. $data. $unknown1. $options. $url_len. $url); return $str_error; } ############################################################################### # # _write_url_external($row1, $col1, $row2, $col2, $url, $string, $format) # # Write links to external directory names such as 'c:\foo.xls', # c:\foo.xls#Sheet1!A1', '../../foo.xls'. and '../../foo.xls#Sheet1!A1'. # # Note: Excel writes some relative links with the $dir_long string. We ignore # these cases for the sake of simpler code. # # See also write_url() above for a general description and return values. # function _write_url_external() { $_=func_get_args(); # Network drives are different. We will handle them separately # MS/Novell network drives and shares start with \\ if (preg_match('[^external:\\\\]', $_[4])) { return call_user_func_array(array($this, '_write_url_external_net'), $_); } $record = 0x01B8; # Record identifier $length = 0x00000; # Bytes to follow $row1 = $_[0]; # Start row $col1 = $_[1]; # Start column $row2 = $_[2]; # End row $col2 = $_[3]; # End column $url = $_[4]; # URL string if (isset($_[5])) { $str = $_[5]; # Alternative label } $xf = $_[6] ? $_[6] : $this->_url_format; # The cell format # Strip URL type and change Unix dir separator to Dos style (if needed) # $url = preg_replace('[^external:]', '', $url); $url = preg_replace('[/]', "\\", $url); # Write the visible label if (!isset($str)) { $str = preg_replace('[\#]', ' - ', $url); } $str_error = $this->write_string($row1, $col1, $str, $xf); if ($str_error == -2) { return $str_error; } # Determine if the link is relative or absolute: # relative if link contains no dir separator, "somefile.xls" # relative if link starts with up-dir, "..\..\somefile.xls" # otherwise, absolute # $absolute = 0x02; # Bit mask if (!preg_match('[\\]', $url)) { $absolute = 0x00; } if (preg_match('[^\.\.\\]', $url)) { $absolute = 0x00; } # Determine if the link contains a sheet reference and change some of the # parameters accordingly. # Split the dir name and sheet name (if it exists) # list($dir_long, $sheet) = preg_split('/\#/', $url); $link_type = 0x01 | $absolute; //!!! if (isset($sheet)) { $link_type |= 0x08; $sheet_len = pack("V", length($sheet) + 0x01); $sheet = join("\0", str_split($sheet)); $sheet .= "\0\0\0"; } else { $sheet_len = ''; $sheet = ''; } # Pack the link type $link_type = pack("V", $link_type); # Calculate the up-level dir count e.g.. (..\..\..\ == 3) /* TODO $up_count = 0; $up_count++ while $dir_long =~ s[^\.\.\\][]; $up_count = pack("v", $up_count); */ # Store the short dos dir name (null terminated) $dir_short = $dir_long . "\0"; # Store the long dir name as a wchar string (non-null terminated) $dir_long = join("\0", preg_split('', $dir_long, -1, PREG_SPLIT_NO_EMPTY)); $dir_long = $dir_long . "\0"; # Pack the lengths of the dir strings $dir_short_len = pack("V", strlen($dir_short) ); $dir_long_len = pack("V", strlen($dir_long) ); $stream_len = pack("V", strlen($dir_long) + 0x06); # Pack the undocumented parts of the hyperlink stream $unknown1 =pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000' ); $unknown2 =pack("H*",'0303000000000000C000000000000046' ); $unknown3 =pack("H*",'FFFFADDE000000000000000000000000000000000000000'); $unknown4 =pack("v", 0x03 ); # Pack the main data stream $data = pack("vvvv", $row1, $row2, $col1, $col2) . $unknown1 . $link_type . $unknown2 . $up_count . $dir_short_len. $dir_short . $unknown3 . $stream_len . $dir_long_len . $unknown4 . $dir_long . $sheet_len . $sheet ; # Pack the header data $length = strlen($data); $header = pack("vv", $record, $length); # Write the packed data $this->_append($header . $data); return $str_error; } ############################################################################### # # write_url_xxx($row1, $col1, $row2, $col2, $url, $string, $format) # # Write links to external MS/Novell network drives and shares such as # '//NETWORK/share/foo.xls' and '//NETWORK/share/foo.xls#Sheet1!A1'. # # See also write_url() above for a general description and return values. # function _write_url_external_net() { $_=func_get_args(); $record = 0x01B8; # Record identifier $length = 0x00000; # Bytes to follow $row1 = $_[0]; # Start row $col1 = $_[1]; # Start column $row2 = $_[2]; # End row $col2 = $_[3]; # End column $url = $_[4]; # URL string if(isset($_[5])) { $str = $_[5]; # Alternative label } $xf = $_[6] ? $_[6] : $this->_url_format; # The cell format # Strip URL type and change Unix dir separator to Dos style (if needed) # $url = preg_replace('[^external:]', "", $url); $url = preg_replace('[/]', "\\"); # Write the visible label if (!isset($str)) { $str = preg_replace('[\#]', " - ", $url); } $str_error = $this->write_string($row1, $col1, $str, $xf); if ($str_error == -2) { return $str_error; } # Determine if the link contains a sheet reference and change some of the # parameters accordingly. # Split the dir name and sheet name (if it exists) # list($dir_long , $sheet) = preg_split('\#', $url); $link_type = 0x0103; # Always absolute //!!! if (isset($sheet)) { $link_type |= 0x08; $sheet_len = pack("V", strlen($sheet) + 0x01); $sheet = join("\0", preg_split("''", $sheet, -1, PREG_SPLIT_NO_EMPTY)); $sheet .= "\0\0\0"; } else { $sheet_len = ''; $sheet = ''; } # Pack the link type $link_type = pack("V", $link_type); # Make the string null terminated $dir_long = $dir_long . "\0"; # Pack the lengths of the dir string $dir_long_len = pack("V", strlen($dir_long)); # Store the long dir name as a wchar string (non-null terminated) $dir_long = join("\0", preg_split("''", $dir_long, -1, PREG_SPLIT_NO_EMPTY)); $dir_long = $dir_long . "\0"; # Pack the undocumented part of the hyperlink stream $unknown1 = pack("H*",'D0C9EA79F9BACE118C8200AA004BA90B02000000'); # Pack the main data stream $data = pack("vvvv", $row1, $row2, $col1, $col2) . $unknown1 . $link_type . $dir_long_len . $dir_long . $sheet_len . $sheet ; # Pack the header data $length = strlen($data); $header = pack("vv", $record, $length); # Write the packed data $this->_append($header . $data); return $str_error; } ############################################################################### # # set_row($row, $height, $XF) # # This method is used to set the height and XF format for a row. # Writes the BIFF record ROW. # function set_row() { $_=func_get_args(); $record = 0x0208; # Record identifier $length = 0x0010; # Number of bytes to follow $rw = $_[0]; # Row Number $colMic = 0x0000; # First defined column $colMac = 0x0000; # Last defined column //$miyRw; # Row height $irwMac = 0x0000; # Used by Excel to optimise loading $reserved = 0x0000; # Reserved $grbit = 0x01C0; # Option flags. (monkey) see $1 do //$ixfe; # XF index if (isset($_[2])) { $format = $_[2]; # Format object } # Check for a format object if (isset($_[2])) { $ixfe = $format->get_xf_index(); } else { $ixfe = 0x0F; } # Use set_row($row, undef, $XF) to set XF without setting height if (isset($_[1])) { $miyRw = $_[1] *20; } else { $miyRw = 0xff; } $header = pack("vv", $record, $length); $data = pack("vvvvvvvv", $rw, $colMic, $colMac, $miyRw, $irwMac,$reserved, $grbit, $ixfe); $this->_append($header . $data); # Store the row sizes for use when calculating image vertices. # Also store the column formats. # # Ensure at least $row and $height if (sizeof($_) < 2) { return; } $this->_row_sizes[$_[0]] = $_[1]; if (isset($_[2])) { $this->_row_formats[$_[0]] = $_[2]; } } /* * Writes Excel DIMENSIONS to define the area in which there is data. */ function _store_dimensions() { $record = 0x0000; // Record identifier $length = 0x000A; // Number of bytes to follow $row_min = $this->_dim_rowmin; // First row $row_max = $this->_dim_rowmax; // Last row plus 1 $col_min = $this->_dim_colmin; // First column $col_max = $this->_dim_colmax; // Last column plus 1 $reserved = 0x0000; // Reserved by Excel $header = pack("vv", $record, $length); $data = pack("vvvvv", $row_min, $row_max, $col_min, $col_max, $reserved); $this->_prepend($header . $data); } /* * Write BIFF record Window2. */ function _store_window2() { $record = 0x023E; // Record identifier $length = 0x000A; // Number of bytes to follow $grbit = 0x00B6; // Option flags $rwTop = 0x0000; // Top row visible in window $colLeft = 0x0000; // Leftmost column visible in window $rgbHdr = 0x00000000; // Row/column heading and gridline // color // The options flags that comprise $grbit $fDspFmla = 0; // 0 - bit $fDspGrid = $this->_screen_gridlines; // 1 $fDspRwCol = 1; // 2 $fFrozen = $this->_frozen; // 3 $fDspZeros = 1; // 4 $fDefaultHdr = 1; // 5 $fArabic = 0; // 6 $fDspGuts = 1; // 7 $fFrozenNoSplit = 0; // 0 - bit $fSelected = $this->_selected; // 1 $fPaged = 1; // 2 $grbit = $fDspFmla; $grbit |= $fDspGrid << 1; $grbit |= $fDspRwCol << 2; $grbit |= $fFrozen << 3; $grbit |= $fDspZeros << 4; $grbit |= $fDefaultHdr << 5; $grbit |= $fArabic << 6; $grbit |= $fDspGuts << 7; $grbit |= $fFrozenNoSplit << 8; $grbit |= $fSelected << 9; $grbit |= $fPaged << 10; $header = pack("vv", $record, $length); $data = pack("vvvV", $grbit, $rwTop, $colLeft, $rgbHdr); $this->_append($header . $data); } /* * Write BIFF record DEFCOLWIDTH if COLINFO records are in use. */ function _store_defcol() { $record = 0x0055; // Record identifier $length = 0x0002; // Number of bytes to follow $colwidth = 0x0008; // Default column width $header = pack("vv", $record, $length); $data = pack("v", $colwidth); $this->_prepend($header . $data); } ############################################################################### # # _store_colinfo($firstcol, $lastcol, $width, $format, $hidden) # # Write BIFF record COLINFO to define column widths # # Note: The SDK says the record length is 0x0B but Excel writes a 0x0C # length record. # function _store_colinfo($_) { $record = 0x007D; # Record identifier $length = 0x000B; # Number of bytes to follow $colFirst = $_[0] ? $_[0] : 0; # First formatted column $colLast = $_[1] ? $_[1] : 0; # Last formatted column $coldx = $_[2] ? $_[2] : 8.43; # Col width, 8.43 is Excel default $coldx += 0.72; # Fudge. Excel subtracts 0.72 !? $coldx *= 256; # Convert to units of 1/256 of a char //$ixfe; # XF index $grbit = $_[4] || 0; # Option flags $reserved = 0x00; # Reserved $format = $_[3]; # Format object # Check for a format object if (isset($_[3])) { $ixfe = $format->get_xf_index(); } else { $ixfe = 0x0F; } $header = pack("vv", $record, $length); $data = pack("vvvvvC", $colFirst, $colLast, $coldx, $ixfe, $grbit, $reserved); $this->_prepend($header . $data); } ############################################################################### # # _store_selection($first_row, $first_col, $last_row, $last_col) # # Write BIFF record SELECTION. # function _store_selection($_) { $record = 0x001D; # Record identifier $length = 0x000F; # Number of bytes to follow $pnn = $this->_active_pane; # Pane position $rwAct = $_[0]; # Active row $colAct = $_[1]; # Active column $irefAct = 0; # Active cell ref $cref = 1; # Number of refs $rwFirst = $_[0]; # First row in reference $colFirst = $_[1]; # First col in reference $rwLast = $_[2] ? $_[2] : $rwFirst; # Last row in reference $colLast = $_[3] ? $_[3] : $colFirst; # Last col in reference # Swap last row/col for first row/col as necessary if ($rwFirst > $rwLast) { list($rwFirst, $rwLast) = array($rwLast, $rwFirst); } if ($colFirst > $colLast) { list($colFirst, $colLast) = array($colLast, $colFirst); } $header = pack("vv", $record, $length); $data = pack("CvvvvvvCC", $pnn, $rwAct, $colAct, $irefAct, $cref, $rwFirst, $rwLast, $colFirst, $colLast); $this->_append($header . $data); } /* * Write BIFF record EXTERNCOUNT to indicate the number of external * sheet references in a worksheet. * * Excel only stores references to external sheets that are used in * formulas. For simplicity we store references to all the sheets in * the workbook regardless of whether they are used or not. This reduces * the overall complexity and eliminates the need for a two way dialogue * between the formula parser the worksheet objects. */ function _store_externcount($cxals) { // $cxals Number of external references $record = 0x0016; // Record identifier $length = 0x0002; // Number of bytes to follow $header = pack("vv", $record, $length); $data = pack("v", $cxals); $this->_prepend($header . $data); } /* * Writes the Excel BIFF EXTERNSHEET record. These references are used * by formulas. A formula references a sheet name via an index. Since we * store a reference to all of the external worksheets the EXTERNSHEET * index is the same as the worksheet index. */ function _store_externsheet($sheetname) { $record = 0x0017; # Record identifier // $length Number of bytes to follow // $cch Length of sheet name // $rgch Filename encoding // References to the current sheet are encoded differently to // references to external sheets. if ($this->_name == $sheetname) { $sheetname = ''; $length = 0x02; // The following 2 bytes $cch = 1; // The following byte $rgch = 0x02; // Self reference } else { $length = 0x02 + strlen($sheetname); $cch = strlen($sheetname); $rgch = 0x03; // Reference to a sheet in the current // workbook } $header = pack("vv", $record, $length); $data = pack("CC", $cch, $rgch); $this->_prepend($header . $data . $sheetname); } ############################################################################### # # _store_panes() # # # Writes the Excel BIFF PANE record. # The panes can either be frozen or thawed (unfrozen). # Frozen panes are specified in terms of a integer number of rows and columns. # Thawed panes are specified in terms of Excel's units for rows and columns. # function _store_panes() { $_=func_get_args(); $record = 0x0041; # Record identifier $length = 0x000A; # Number of bytes to follow $y = $_[0] || 0; # Vertical split position $x = $_[1] || 0; # Horizontal split position if (isset($_[2])) { $rwTop = $_[2]; # Top row visible } if (isset($_[3])) { $colLeft = $_[3]; # Leftmost column visible } if (isset($_[4])) { $pnnAct = $_[4]; # Active pane } # Code specific to frozen or thawed panes. if ($this->_frozen) { # Set default values for $rwTop and $colLeft if (!isset($rwTop)) { $rwTop = $y; } if (!isset($colLeft)) { $colLeft = $x; } } else { # Set default values for $rwTop and $colLeft if (!isset($rwTop)) { $rwTop = 0; } if (!isset($colLeft)) { $colLeft = 0; } # Convert Excel's row and column units to the internal units. # The default row height is 12.75 # The default column width is 8.43 # The following slope and intersection values were interpolated. # $y = 20*$y + 255; $x = 113.879*$x + 390; } # Determine which pane should be active. There is also the undocumented # option to override this should it be necessary: may be removed later. # if (!isset($pnnAct)) { # Bottom right if ($x != 0 && $y != 0) { $pnnAct = 0; } # Top right if ($x != 0 && $y == 0) { $pnnAct = 1; } # Bottom left if ($x == 0 && $y != 0) { $pnnAct = 2; } # Top left if ($x == 0 && $y == 0) { $pnnAct = 3; } } $this->_active_pane = $pnnAct; # Used in _store_selection $header = pack("vv", $record, $length); $data = pack("vvvvv", $x, $y, $rwTop, $colLeft, $pnnAct); $this->_append($header . $data); } /* * Store the page setup SETUP BIFF record. */ function _store_setup() { $record = 0x00A1; // Record identifier $length = 0x0022; // Number of bytes to follow $iPaperSize = $this->_paper_size; // Paper size $iScale = $this->_print_scale; // Print scaling factor $iPageStart = 0x01; // Starting page number $iFitWidth = $this->_fit_width; // Fit to number of pages wide $iFitHeight = $this->_fit_height; // Fit to number of pages high $grbit = 0x00; // Option flags $iRes = 0x0258; // Print resolution $iVRes = 0x0258; // Vertical print resolution $numHdr = $this->_margin_head; // Header Margin $numFtr = $this->_margin_foot; // Footer Margin $iCopies = 0x01; // Number of copies $fLeftToRight = 0x0; // Print over then down $fLandscape = $this->_orientation; // Page orientation $fNoPls = 0x0; // Setup not read from printer $fNoColor = 0x0; // Print black and white $fDraft = 0x0; // Print draft quality $fNotes = 0x0; // Print notes $fNoOrient = 0x0; // Orientation not set $fUsePage = 0x0; // Use custom starting page $grbit = $fLeftToRight; $grbit |= $fLandscape << 1; $grbit |= $fNoPls << 2; $grbit |= $fNoColor << 3; $grbit |= $fDraft << 4; $grbit |= $fNotes << 5; $grbit |= $fNoOrient << 6; $grbit |= $fUsePage << 7; $numHdr = pack("d", $numHdr); $numFtr = pack("d", $numFtr); if ($this->_byte_order) { $numHdr = strrev($numHdr); $numFtr = strrev($numFtr); } $header = pack("vv", $record, $length); $data1 = pack("vvvvvvvv", $iPaperSize, $iScale, $iPageStart, $iFitWidth, $iFitHeight, $grbit, $iRes, $iVRes); $data2 = $numHdr . $numFtr; $data3 = pack("v", $iCopies); $this->_prepend($header . $data1 . $data2 . $data3); } /* * Store the header caption BIFF record. */ function _store_header() { $record = 0x0014; // Record identifier $str = $this->_header; // header string $cch = strlen($str); // Length of header string $length = 1 + $cch; // Bytes to follow $header = pack("vv", $record, $length); $data = pack("C", $cch); $this->_append($header . $data . $str); } /* * Store the footer caption BIFF record. */ function _store_footer() { $record = 0x0015; // Record identifier $str = $this->_footer; // Footer string $cch = strlen($str); // Length of footer string $length = 1 + $cch; // Bytes to follow $header = pack("vv", $record, $length); $data = pack("C", $cch); $this->_append($header . $data . $str); } /* * Store the horizontal centering HCENTER BIFF record. */ function _store_hcenter() { $record = 0x0083; // Record identifier $length = 0x0002; // Bytes to follow $fHCenter = $this->_hcenter; // Horizontal centering $header = pack("vv", $record, $length); $data = pack("v", $fHCenter); $this->_append($header . $data); } /* * Store the vertical centering VCENTER BIFF record. */ function _store_vcenter() { $record = 0x0084; // Record identifier $length = 0x0002; // Bytes to follow $fVCenter = $this->_vcenter; // Horizontal centering $header = pack("vv", $record, $length); $data = pack("v", $fVCenter); $this->_append($header . $data); } /* * Store the LEFTMARGIN BIFF record. */ function _store_margin_left() { $record = 0x0026; // Record identifier $length = 0x0008; // Bytes to follow $margin = $this->_margin_left; // Margin in inches $header = pack("vv", $record, $length); $data = pack("d", $margin); if ($this->_byte_order) { $data = strrev($data); } $this->_append($header . $data); } /* * Store the RIGHTMARGIN BIFF record. */ function _store_margin_right() { $record = 0x0027; // Record identifier $length = 0x0008; // Bytes to follow $margin = $this->_margin_right; // Margin in inches $header = pack("vv", $record, $length); $data = pack("d", $margin); if ($this->_byte_order) { $data = strrev($data); } $this->_append($header . $data); } /* * Store the TOPMARGIN BIFF record. */ function _store_margin_top() { $record = 0x0028; // Record identifier $length = 0x0008; // Bytes to follow $margin = $this->_margin_top; // Margin in inches $header = pack("vv", $record, $length); $data = pack("d", $margin); if ($this->_byte_order) { $data = strrev($data); } $this->_append($header . $data); } /* * Store the BOTTOMMARGIN BIFF record. */ function _store_margin_bottom() { $record = 0x0029; // Record identifier $length = 0x0008; // Bytes to follow $margin = $this->_margin_bottom; // Margin in inches $header = pack("vv", $record, $length); $data = pack("d", $margin); if ($this->_byte_order) { $data = strrev($data); } $this->_append($header . $data); } ############################################################################### # # merge_cells($first_row, $first_col, $last_row, $last_col) # # This is an Excel97/2000 method. It is required to perform more complicated # merging than the normal align merge in Format.pm # function merge_cells() { $_=func_get_args(); // Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } $record = 0x00E5; # Record identifier $length = 0x000A; # Bytes to follow $cref = 1; # Number of refs $rwFirst = $_[0]; # First row in reference $colFirst = $_[1]; # First col in reference $rwLast = $_[2] || $rwFirst; # Last row in reference $colLast = $_[3] || $colFirst; # Last col in reference // Swap last row/col for first row/col as necessary if ($rwFirst > $rwLast) { list($rwFirst, $rwLast) = array($rwLast, $rwFirst); } if ($colFirst > $colLast) { list($colFirst, $colLast) = array($colLast, $colFirst); } $header = pack("vv", $record, $length); $data = pack("vvvvv", $cref, $rwFirst, $rwLast, $colFirst, $colLast); $this->_append($header . $data); } /* * Write the PRINTHEADERS BIFF record. */ function _store_print_headers() { $record = 0x002a; // Record identifier $length = 0x0002; // Bytes to follow $fPrintRwCol = $this->_print_headers; // Boolean flag $header = pack("vv", $record, $length); $data = pack("v", $fPrintRwCol); $this->_prepend($header . $data); } /* * Write the PRINTGRIDLINES BIFF record. Must be used in conjunction * with the GRIDSET record. */ function _store_print_gridlines() { $record = 0x002b; // Record identifier $length = 0x0002; // Bytes to follow $fPrintGrid = $this->_print_gridlines; // Boolean flag $header = pack("vv", $record, $length); $data = pack("v", $fPrintGrid); $this->_prepend($header . $data); } /* * Write the GRIDSET BIFF record. Must be used in conjunction with the * PRINTGRIDLINES record. */ function _store_gridset() { $record = 0x0082; // Record identifier $length = 0x0002; // Bytes to follow $fGridSet = !$this->_print_gridlines; // Boolean flag $header = pack("vv", $record, $length); $data = pack("v", $fGridSet); $this->_prepend($header . $data); } /* * Write the WSBOOL BIFF record, mainly for fit-to-page. Used in * conjunction with the SETUP record. */ function _store_wsbool() { $record = 0x0081; # Record identifier $length = 0x0002; # Bytes to follow // $grbit Option flags // The only option that is of interest is the flag for fit to page. // So we set all the options in one go. if ($this->_fit_page) { $grbit = 0x05c1; } else { $grbit = 0x04c1; } $header = pack("vv", $record, $length); $data = pack("v", $grbit); $this->_prepend($header . $data); } /* * Write the HORIZONTALPAGEBREAKS BIFF record. */ function _store_hbreak() { // Return if the user hasn't specified pagebreaks if(sizeof($this->_hbreaks)==0) { return; } # Sort and filter array of page breaks $breaks = $this->_sort_pagebreaks($this->_hbreaks); $record = 0x001b; // Record identifier $cbrk = sizeof($breaks); // Number of page breaks $length = ($cbrk + 1) * 2; // Bytes to follow $header = pack("vv", $record, $length); $data = pack("v", $cbrk); // Append each page break foreach ($breaks as $break) { $data .= pack("v", $break); } $this->_prepend($header . $data); } /* * Write the VERTICALPAGEBREAKS BIFF record. */ function _store_vbreak() { // Return if the user hasn't specified pagebreaks if(sizeof($this->_vbreaks)==0) { return; } // Sort and filter array of page breaks $breaks = $this->_sort_pagebreaks($this->_vbreaks); $record = 0x001a; // Record identifier $cbrk = sizeof($breaks); // Number of page breaks $length = ($cbrk + 1) * 2; // Bytes to follow $header = pack("vv", $record, $length); $data = pack("v", $cbrk); // Append each page break foreach ($breaks as $break) { $data .= pack("v", $break); } $this->_prepend($header . $data); } /* * Set the Biff PROTECT record to indicate that the worksheet is * protected. */ function _store_protect() { // Exit unless sheet protection has been specified if (!$this->_protect) { return; } $record = 0x0012; // Record identifier $length = 0x0002; // Bytes to follow $fLock = $this->_protect; // Worksheet is protected $header = pack("vv", $record, $length); $data = pack("v", $fLock); $this->_prepend($header . $data); } /* * Write the worksheet PASSWORD record. */ function _store_password() { // Exit unless sheet protection and password have been specified if (!$this->_protect || !$this->_password) { return; } $record = 0x0013; // Record identifier $length = 0x0002; // Bytes to follow $wPassword = $this->_password; // Encoded password $header = pack("vv", $record, $length); $data = pack("v", $wPassword); $this->_prepend($header . $data); } ############################################################################### # # insert_bitmap($row, $col, $filename, $x, $y, $scale_x, $scale_y) # # Insert a 24bit bitmap image in a worksheet. The main record required is # IMDATA but it must be proceeded by a OBJ record to define its position. # function insert_bitmap() { $_=func_get_args(); # Check for a cell reference in A1 notation and substitute row and column if (preg_match('/^\D/', $_[0])) { $_ = $this->_substitute_cellref($_); } $row = $_[0]; $col = $_[1]; $bitmap = $_[2]; $x = $_[3] ? $_[3] : 0; $y = $_[4] ? $_[4] : 0; $scale_x = $_[5] ? $_[5] : 1; $scale_y = $_[6] ? $_[6] : 1; list($width, $height, $size, $data) = $this->_process_bitmap($bitmap); # Scale the frame of the image. $width *= $scale_x; $height *= $scale_y; # Calculate the vertices of the image and write the OBJ record $this->_position_image($col, $row, $x, $y, $width, $height); # Write the IMDATA record to store the bitmap data $record = 0x007f; $length = 8 + $size; $cf = 0x09; $env = 0x01; $lcb = $size; $header = pack("vvvvV", $record, $length, $cf, $env, $lcb); $this->_append($header . $data); } /* * Calculate the vertices that define the position of the image as * required by the OBJ record. * * +------------+------------+ * | A | B | * +-----+------------+------------+ * | |(x1,y1) | | * | 1 |(A1)._______|______ | * | | | | | * | | | | | * +-----+----| BITMAP |-----+ * | | | | | * | 2 | |______________. | * | | | (B2)| * | | | (x2,y2)| * +---- +------------+------------+ * * Example of a bitmap that covers some of the area from cell A1 to * cell B2. * * Based on the width and height of the bitmap we need to calculate 8 *vars: * $col_start, $row_start, $col_end, $row_end, $x1, $y1, $x2, $y2. * The width and height of the cells are also variable and have to be * taken into account. * The values of $col_start and $row_start are passed in from the calling * function. The values of $col_end and $row_end are calculated by * subtracting the width and height of the bitmap from the width and * height of the underlying cells. * The vertices are expressed as a percentage of the underlying cell * width as follows (rhs values are in pixels): * * x1 = X / W *1024 * y1 = Y / H *256 * x2 = (X-1) / W *1024 * y2 = (Y-1) / H *256 * * Where: X is distance from the left side of the underlying cell * Y is distance from the top of the underlying cell * W is the width of the cell * H is the height of the cell * * Note: the SDK incorrectly states that the height should be expressed * as a percentage of 1024. */ function _position_image($col_start, $row_start, $x1, $y1, $width, $height) { // $col_start Col containing upper left corner of object // $x1 Distance to left side of object // $row_start Row containing top left corner of object // $y1 Distance to top of object // $col_end Col containing lower right corner of object // $x2 Distance to right side of object // $row_end Row containing bottom right corner of object // $y2 Distance to bottom of object // $width Width of image frame // $height Height of image frame // Initialise end cell to the same as the start cell $col_end = $col_start; $row_end = $row_start; // Zero the specified offset if greater than the cell dimensions if ($x1 >= $this->_size_col($col_start)) { $x1 = 0; } if ($y1 >= $this->_size_row($row_start)) { $y1 = 0; } $width = $width + $x1 -1; $height = $height + $y1 -1; // Subtract the underlying cell widths to find the end cell of the // image while ($width >= $this->_size_col($col_end)) { $width -= $this->_size_col($col_end); $col_end++; } // Subtract the underlying cell heights to find the end cell of the // image while ($height >= $this->_size_row($row_end)) { $height -= $this->_size_row($row_end); $row_end++; } // Bitmap isn't allowed to start or finish in a hidden cell, i.e. a // cell with zero height or width. if ($this->_size_col($col_start) == 0) { return; } if ($this->_size_col($col_end) == 0) { return; } if ($this->_size_row($row_start) == 0) { return; } if ($this->_size_row($row_end) == 0) { return; } // Convert the pixel values to the percentage value expected by Excel $x1 = $x1 / $this->_size_col($col_start) * 1024; $y1 = $y1 / $this->_size_row($row_start) * 256; $x2 = $width / $this->_size_col($col_end) * 1024; $y2 = $height / $this->_size_row($row_end) * 256; $this->_store_obj_picture($col_start, $x1, $row_start, $y1, $col_end, $x2, $row_end, $y2); } /* * Convert the width of a cell from user's units to pixels. By * interpolation the relationship is: y = 7x +5. If the width * hasn't been set by the user we use the default value. If the * col is hidden we use a value of zero. */ function _size_col($col) { // Look up the cell value to see if it has been changed if (isset($this->_col_sizes[$col])) { if ($this->_col_sizes[$col] == 0) { return 0; } else { return floor(7 * $this->_col_sizes[$col] + 5); } } else { return 64; } } /* * Convert the height of a cell from user's units to pixels. By * interpolation # the relationship is: y = 4/3x. If the height * hasn't been set by the user we use the default value. If the * row is hidden we use a value of zero. (Not possible to hide row * yet). */ function _size_row($row) { // Look up the cell value to see if it has been changed if (isset($this->_row_sizes[$row])) { if ($this->_row_sizes[$row] == 0) { return 0; } else { return floor(4/3 * $this->_row_sizes[$row]); } } else { return 17; } } /* * Store the OBJ record that precedes an IMDATA record. This could * be generalized to support other Excel objects. */ function _store_obj_picture($col_start, $x1, $row_start, $y1, $col_end, $x2, $row_end, $y2) { $record = 0x005d; // Record identifier $length = 0x003c; // Bytes to follow $cObj = 0x0001; // Count of objects in file (set to 1) $OT = 0x0008; // Object type. 8 = Picture $id = 0x0001; // Object ID $grbit = 0x0614; // Option flags $colL = $col_start; // Col containing upper left corner of // object $dxL = $x1; // Distance from left side of cell $rwT = $row_start; // Row containing top left corner of // object $dyT = $y1; // Distance from top of cell $colR = $col_end; // Col containing lower right corner of // object $dxR = $x2; // Distance from right of cell $rwB = $row_end; // Row containing bottom right corner of // object $dyB = $y2; // Distance from bottom of cell $cbMacro = 0x0000; // Length of FMLA structure $Reserved1 = 0x0000; // Reserved $Reserved2 = 0x0000; // Reserved $icvBack = 0x09; // Background colour $icvFore = 0x09; // Foreground colour $fls = 0x00; // Fill pattern $fAuto = 0x00; // Automatic fill $icv = 0x08; // Line colour $lns = 0xff; // Line style $lnw = 0x01; // Line weight $fAutoB = 0x00; // Automatic border $frs = 0x0000; // Frame style $cf = 0x0009; // Image format, 9 = bitmap $Reserved3 = 0x0000; // Reserved $cbPictFmla = 0x0000; // Length of FMLA structure $Reserved4 = 0x0000; // Reserved $grbit2 = 0x0001; // Option flags $Reserved5 = 0x0000; // Reserved $header = pack("vv", $record, $length); $data = pack("V", $cObj); $data .= pack("v", $OT); $data .= pack("v", $id); $data .= pack("v", $grbit); $data .= pack("v", $colL); $data .= pack("v", $dxL); $data .= pack("v", $rwT); $data .= pack("v", $dyT); $data .= pack("v", $colR); $data .= pack("v", $dxR); $data .= pack("v", $rwB); $data .= pack("v", $dyB); $data .= pack("v", $cbMacro); $data .= pack("V", $Reserved1); $data .= pack("v", $Reserved2); $data .= pack("C", $icvBack); $data .= pack("C", $icvFore); $data .= pack("C", $fls); $data .= pack("C", $fAuto); $data .= pack("C", $icv); $data .= pack("C", $lns); $data .= pack("C", $lnw); $data .= pack("C", $fAutoB); $data .= pack("v", $frs); $data .= pack("V", $cf); $data .= pack("v", $Reserved3); $data .= pack("v", $cbPictFmla); $data .= pack("v", $Reserved4); $data .= pack("v", $grbit2); $data .= pack("V", $Reserved5); $this->_append($header . $data); } /* * Convert a 24 bit bitmap into the modified internal format used by * Windows. This is described in BITMAPCOREHEADER and BITMAPCOREINFO * structures in the MSDN library. */ function _process_bitmap($bitmap) { // Open file and binmode the data in case the platform needs it. $bmp=fopen($bitmap, "rb"); if (!$bmp) { trigger_error("Could not open file '$bitmap'.", E_USER_ERROR); } $data=fread($bmp, filesize($bitmap)); // Check that the file is big enough to be a bitmap. if (strlen($data) <= 0x36) { trigger_error("$bitmap doesn't contain enough data.", E_USER_ERROR); } // The first 2 bytes are used to identify the bitmap. if (substr($data, 0, 2) != "BM") { trigger_error("$bitmap doesn't appear to to be a ". "valid bitmap image.", E_USER_ERROR); } // Remove bitmap data: ID. $data = substr($data, 2); // Read and remove the bitmap size. This is more reliable than reading // the data size at offset 0x22. $array = unpack("Vsize", $data); $data = substr($data, 4); $size = $array["size"]; $size -= 0x36; # Subtract size of bitmap header. $size += 0x0C; # Add size of BIFF header. // Remove bitmap data: reserved, offset, header length. $data = substr($data, 12); // Read and remove the bitmap width and height. Verify the sizes. $array = unpack("Vwidth/Vheight", $data); $data = substr($data, 8); $width = $array["width"]; $height = $array["height"]; if ($width > 0xFFFF) { trigger_error("$bitmap: largest image width supported is 64k.", E_USER_ERROR); } if ($height > 0xFFFF) { trigger_error("$bitmap: largest image height supported is 64k.", E_USER_ERROR); } // Read and remove the bitmap planes and bpp data. Verify them. $array = unpack("vplanes/vbitcount", $data); $data = substr($data, 4); $planes = $array["planes"]; $bitcount = $array["bitcount"]; if ($bitcount != 24) { trigger_error("$bitmap isn't a 24bit true color bitmap.", E_USER_ERROR); } if ($planes != 1) { trigger_error("$bitmap: only 1 plane supported in bitmap image.", E_USER_ERROR); } // Read and remove the bitmap compression. Verify compression. $array = unpack("Vcompression", $data); $data = substr($data, 4); $compression = $array["compression"]; if ($compression != 0) { trigger_error("$bitmap: compression not supported in bitmap image.", E_USER_ERROR); } // Remove bitmap data: data size, hres, vres, colours, imp. colours. $data = substr($data, 20); // Add the BITMAPCOREHEADER data $header = pack("Vvvvv", 0x000c, $width, $height, 0x01, 0x18); $data = $header . $data; return array($width, $height, $size, $data); } /* * Store the window zoom factor. This should be a reduced fraction but for * simplicity we will store all fractions with a numerator of 100. */ function _store_zoom() { // If scale is 100% we don't need to write a record if ($this->_zoom == 100) { return; } $record = 0x00A0; // Record identifier $length = 0x0004; // Bytes to follow $header = pack("vv", $record, $length); $data = pack("vv", $this->_zoom, 100); $this->_append($header . $data); } } ?> gosa-core-2.7.4/include/utils/excel/class.writeexcel_formula.inc.php0000644000175000017500000015556311327534170024571 0ustar cajuscajus"); // @const SPREADSHEET_EXCEL_WRITER_GT token identifier for character ">" define('SPREADSHEET_EXCEL_WRITER_LT',"<"); // @const SPREADSHEET_EXCEL_WRITER_LT token identifier for character "<" define('SPREADSHEET_EXCEL_WRITER_LE',"<="); // @const SPREADSHEET_EXCEL_WRITER_LE token identifier for character "<=" define('SPREADSHEET_EXCEL_WRITER_GE',">="); // @const SPREADSHEET_EXCEL_WRITER_GE token identifier for character ">=" define('SPREADSHEET_EXCEL_WRITER_EQ',"="); // @const SPREADSHEET_EXCEL_WRITER_EQ token identifier for character "=" define('SPREADSHEET_EXCEL_WRITER_NE',"<>"); // @const SPREADSHEET_EXCEL_WRITER_NE token identifier for character "<>" class writeexcel_formula { ############################################################################### # # Class data. # var $parser; var $ptg; var $_functions; var $_current_char; var $_current_token; var $_lookahead; var $_debug; var $_byte_order; var $_volatile; var $_workbook; var $_ext_sheets; var $_formula; ############################################################################### # # new() # # Constructor # function writeexcel_formula($byte_order) { $this->parser = false; $this->ptg = array(); $this->_functions = array(); $this->_debug = 0; $this->_byte_order = $byte_order; $this->_volatile = 0; $this->_workbook = ""; $this->_ext_sheets = array(); $this->_current_token = ''; $this->_lookahead = ''; $this->_current_char = 0; $this->_formula = ''; } ############################################################################### # # _init_parser() # # There is a small overhead involved in generating the parser. Therefore, the # initialisation is delayed until a formula is required. TODO: use a pre- # compiled header. # function _init_parser() { $this->_initializeHashes(); if ($this->_debug) { print "Init_parser.\n\n"; } } ############################################################################### # # parse_formula() # # This is the only public method. It takes a textual description of a formula # and returns a RPN encoded byte string. # function parse_formula() { $_=func_get_args(); # Initialise the parser if this is the first call if ($this->parser===false) { $this->_init_parser(); } $formula = array_shift($_); //$str; //$tokens; if ($this->_debug) { print "$formula\n"; } # Build the parse tree for the formula $this->_formula = $formula; $this->_current_char = 0; $this->_lookahead = $this->_formula{1}; $this->_advance($formula); $parsetree = $this->_condition(); $str = $this->toReversePolish($parsetree); return $str; } function set_ext_sheet($key, $value) { $this->_ext_sheets->$key = $value; } function isError($data) { return (bool)(is_object($data) && (get_class($data) == 'pear_error' || is_subclass_of($data, 'pear_error'))); } /** * Class for parsing Excel formulas * * @author Xavier Noguer * @category FileFormats * @package Spreadsheet_Excel_Writer */ /** * Initialize the ptg and function hashes. * * @access private */ function _initializeHashes() { // The Excel ptg indices $this->ptg = array( 'ptgExp' => 0x01, 'ptgTbl' => 0x02, 'ptgAdd' => 0x03, 'ptgSub' => 0x04, 'ptgMul' => 0x05, 'ptgDiv' => 0x06, 'ptgPower' => 0x07, 'ptgConcat' => 0x08, 'ptgLT' => 0x09, 'ptgLE' => 0x0A, 'ptgEQ' => 0x0B, 'ptgGE' => 0x0C, 'ptgGT' => 0x0D, 'ptgNE' => 0x0E, 'ptgIsect' => 0x0F, 'ptgUnion' => 0x10, 'ptgRange' => 0x11, 'ptgUplus' => 0x12, 'ptgUminus' => 0x13, 'ptgPercent' => 0x14, 'ptgParen' => 0x15, 'ptgMissArg' => 0x16, 'ptgStr' => 0x17, 'ptgAttr' => 0x19, 'ptgSheet' => 0x1A, 'ptgEndSheet' => 0x1B, 'ptgErr' => 0x1C, 'ptgBool' => 0x1D, 'ptgInt' => 0x1E, 'ptgNum' => 0x1F, 'ptgArray' => 0x20, 'ptgFunc' => 0x21, 'ptgFuncVar' => 0x22, 'ptgName' => 0x23, 'ptgRef' => 0x24, 'ptgArea' => 0x25, 'ptgMemArea' => 0x26, 'ptgMemErr' => 0x27, 'ptgMemNoMem' => 0x28, 'ptgMemFunc' => 0x29, 'ptgRefErr' => 0x2A, 'ptgAreaErr' => 0x2B, 'ptgRefN' => 0x2C, 'ptgAreaN' => 0x2D, 'ptgMemAreaN' => 0x2E, 'ptgMemNoMemN' => 0x2F, 'ptgNameX' => 0x39, 'ptgRef3d' => 0x3A, 'ptgArea3d' => 0x3B, 'ptgRefErr3d' => 0x3C, 'ptgAreaErr3d' => 0x3D, 'ptgArrayV' => 0x40, 'ptgFuncV' => 0x41, 'ptgFuncVarV' => 0x42, 'ptgNameV' => 0x43, 'ptgRefV' => 0x44, 'ptgAreaV' => 0x45, 'ptgMemAreaV' => 0x46, 'ptgMemErrV' => 0x47, 'ptgMemNoMemV' => 0x48, 'ptgMemFuncV' => 0x49, 'ptgRefErrV' => 0x4A, 'ptgAreaErrV' => 0x4B, 'ptgRefNV' => 0x4C, 'ptgAreaNV' => 0x4D, 'ptgMemAreaNV' => 0x4E, 'ptgMemNoMemN' => 0x4F, 'ptgFuncCEV' => 0x58, 'ptgNameXV' => 0x59, 'ptgRef3dV' => 0x5A, 'ptgArea3dV' => 0x5B, 'ptgRefErr3dV' => 0x5C, 'ptgAreaErr3d' => 0x5D, 'ptgArrayA' => 0x60, 'ptgFuncA' => 0x61, 'ptgFuncVarA' => 0x62, 'ptgNameA' => 0x63, 'ptgRefA' => 0x64, 'ptgAreaA' => 0x65, 'ptgMemAreaA' => 0x66, 'ptgMemErrA' => 0x67, 'ptgMemNoMemA' => 0x68, 'ptgMemFuncA' => 0x69, 'ptgRefErrA' => 0x6A, 'ptgAreaErrA' => 0x6B, 'ptgRefNA' => 0x6C, 'ptgAreaNA' => 0x6D, 'ptgMemAreaNA' => 0x6E, 'ptgMemNoMemN' => 0x6F, 'ptgFuncCEA' => 0x78, 'ptgNameXA' => 0x79, 'ptgRef3dA' => 0x7A, 'ptgArea3dA' => 0x7B, 'ptgRefErr3dA' => 0x7C, 'ptgAreaErr3d' => 0x7D ); // Thanks to Michael Meeks and Gnumeric for the initial arg values. // // The following hash was generated by "function_locale.pl" in the distro. // Refer to function_locale.pl for non-English function names. // // The array elements are as follow: // ptg: The Excel function ptg code. // args: The number of arguments that the function takes: // >=0 is a fixed number of arguments. // -1 is a variable number of arguments. // class: The reference, value or array class of the function args. // vol: The function is volatile. // $this->_functions = array( // function ptg args class vol 'COUNT' => array( 0, -1, 0, 0 ), 'IF' => array( 1, -1, 1, 0 ), 'ISNA' => array( 2, 1, 1, 0 ), 'ISERROR' => array( 3, 1, 1, 0 ), 'SUM' => array( 4, -1, 0, 0 ), 'AVERAGE' => array( 5, -1, 0, 0 ), 'MIN' => array( 6, -1, 0, 0 ), 'MAX' => array( 7, -1, 0, 0 ), 'ROW' => array( 8, -1, 0, 0 ), 'COLUMN' => array( 9, -1, 0, 0 ), 'NA' => array( 10, 0, 0, 0 ), 'NPV' => array( 11, -1, 1, 0 ), 'STDEV' => array( 12, -1, 0, 0 ), 'DOLLAR' => array( 13, -1, 1, 0 ), 'FIXED' => array( 14, -1, 1, 0 ), 'SIN' => array( 15, 1, 1, 0 ), 'COS' => array( 16, 1, 1, 0 ), 'TAN' => array( 17, 1, 1, 0 ), 'ATAN' => array( 18, 1, 1, 0 ), 'PI' => array( 19, 0, 1, 0 ), 'SQRT' => array( 20, 1, 1, 0 ), 'EXP' => array( 21, 1, 1, 0 ), 'LN' => array( 22, 1, 1, 0 ), 'LOG10' => array( 23, 1, 1, 0 ), 'ABS' => array( 24, 1, 1, 0 ), 'INT' => array( 25, 1, 1, 0 ), 'SIGN' => array( 26, 1, 1, 0 ), 'ROUND' => array( 27, 2, 1, 0 ), 'LOOKUP' => array( 28, -1, 0, 0 ), 'INDEX' => array( 29, -1, 0, 1 ), 'REPT' => array( 30, 2, 1, 0 ), 'MID' => array( 31, 3, 1, 0 ), 'LEN' => array( 32, 1, 1, 0 ), 'VALUE' => array( 33, 1, 1, 0 ), 'TRUE' => array( 34, 0, 1, 0 ), 'FALSE' => array( 35, 0, 1, 0 ), 'AND' => array( 36, -1, 0, 0 ), 'OR' => array( 37, -1, 0, 0 ), 'NOT' => array( 38, 1, 1, 0 ), 'MOD' => array( 39, 2, 1, 0 ), 'DCOUNT' => array( 40, 3, 0, 0 ), 'DSUM' => array( 41, 3, 0, 0 ), 'DAVERAGE' => array( 42, 3, 0, 0 ), 'DMIN' => array( 43, 3, 0, 0 ), 'DMAX' => array( 44, 3, 0, 0 ), 'DSTDEV' => array( 45, 3, 0, 0 ), 'VAR' => array( 46, -1, 0, 0 ), 'DVAR' => array( 47, 3, 0, 0 ), 'TEXT' => array( 48, 2, 1, 0 ), 'LINEST' => array( 49, -1, 0, 0 ), 'TREND' => array( 50, -1, 0, 0 ), 'LOGEST' => array( 51, -1, 0, 0 ), 'GROWTH' => array( 52, -1, 0, 0 ), 'PV' => array( 56, -1, 1, 0 ), 'FV' => array( 57, -1, 1, 0 ), 'NPER' => array( 58, -1, 1, 0 ), 'PMT' => array( 59, -1, 1, 0 ), 'RATE' => array( 60, -1, 1, 0 ), 'MIRR' => array( 61, 3, 0, 0 ), 'IRR' => array( 62, -1, 0, 0 ), 'RAND' => array( 63, 0, 1, 1 ), 'MATCH' => array( 64, -1, 0, 0 ), 'DATE' => array( 65, 3, 1, 0 ), 'TIME' => array( 66, 3, 1, 0 ), 'DAY' => array( 67, 1, 1, 0 ), 'MONTH' => array( 68, 1, 1, 0 ), 'YEAR' => array( 69, 1, 1, 0 ), 'WEEKDAY' => array( 70, -1, 1, 0 ), 'HOUR' => array( 71, 1, 1, 0 ), 'MINUTE' => array( 72, 1, 1, 0 ), 'SECOND' => array( 73, 1, 1, 0 ), 'NOW' => array( 74, 0, 1, 1 ), 'AREAS' => array( 75, 1, 0, 1 ), 'ROWS' => array( 76, 1, 0, 1 ), 'COLUMNS' => array( 77, 1, 0, 1 ), 'OFFSET' => array( 78, -1, 0, 1 ), 'SEARCH' => array( 82, -1, 1, 0 ), 'TRANSPOSE' => array( 83, 1, 1, 0 ), 'TYPE' => array( 86, 1, 1, 0 ), 'ATAN2' => array( 97, 2, 1, 0 ), 'ASIN' => array( 98, 1, 1, 0 ), 'ACOS' => array( 99, 1, 1, 0 ), 'CHOOSE' => array( 100, -1, 1, 0 ), 'HLOOKUP' => array( 101, -1, 0, 0 ), 'VLOOKUP' => array( 102, -1, 0, 0 ), 'ISREF' => array( 105, 1, 0, 0 ), 'LOG' => array( 109, -1, 1, 0 ), 'CHAR' => array( 111, 1, 1, 0 ), 'LOWER' => array( 112, 1, 1, 0 ), 'UPPER' => array( 113, 1, 1, 0 ), 'PROPER' => array( 114, 1, 1, 0 ), 'LEFT' => array( 115, -1, 1, 0 ), 'RIGHT' => array( 116, -1, 1, 0 ), 'EXACT' => array( 117, 2, 1, 0 ), 'TRIM' => array( 118, 1, 1, 0 ), 'REPLACE' => array( 119, 4, 1, 0 ), 'SUBSTITUTE' => array( 120, -1, 1, 0 ), 'CODE' => array( 121, 1, 1, 0 ), 'FIND' => array( 124, -1, 1, 0 ), 'CELL' => array( 125, -1, 0, 1 ), 'ISERR' => array( 126, 1, 1, 0 ), 'ISTEXT' => array( 127, 1, 1, 0 ), 'ISNUMBER' => array( 128, 1, 1, 0 ), 'ISBLANK' => array( 129, 1, 1, 0 ), 'T' => array( 130, 1, 0, 0 ), 'N' => array( 131, 1, 0, 0 ), 'DATEVALUE' => array( 140, 1, 1, 0 ), 'TIMEVALUE' => array( 141, 1, 1, 0 ), 'SLN' => array( 142, 3, 1, 0 ), 'SYD' => array( 143, 4, 1, 0 ), 'DDB' => array( 144, -1, 1, 0 ), 'INDIRECT' => array( 148, -1, 1, 1 ), 'CALL' => array( 150, -1, 1, 0 ), 'CLEAN' => array( 162, 1, 1, 0 ), 'MDETERM' => array( 163, 1, 2, 0 ), 'MINVERSE' => array( 164, 1, 2, 0 ), 'MMULT' => array( 165, 2, 2, 0 ), 'IPMT' => array( 167, -1, 1, 0 ), 'PPMT' => array( 168, -1, 1, 0 ), 'COUNTA' => array( 169, -1, 0, 0 ), 'PRODUCT' => array( 183, -1, 0, 0 ), 'FACT' => array( 184, 1, 1, 0 ), 'DPRODUCT' => array( 189, 3, 0, 0 ), 'ISNONTEXT' => array( 190, 1, 1, 0 ), 'STDEVP' => array( 193, -1, 0, 0 ), 'VARP' => array( 194, -1, 0, 0 ), 'DSTDEVP' => array( 195, 3, 0, 0 ), 'DVARP' => array( 196, 3, 0, 0 ), 'TRUNC' => array( 197, -1, 1, 0 ), 'ISLOGICAL' => array( 198, 1, 1, 0 ), 'DCOUNTA' => array( 199, 3, 0, 0 ), 'ROUNDUP' => array( 212, 2, 1, 0 ), 'ROUNDDOWN' => array( 213, 2, 1, 0 ), 'RANK' => array( 216, -1, 0, 0 ), 'ADDRESS' => array( 219, -1, 1, 0 ), 'DAYS360' => array( 220, -1, 1, 0 ), 'TODAY' => array( 221, 0, 1, 1 ), 'VDB' => array( 222, -1, 1, 0 ), 'MEDIAN' => array( 227, -1, 0, 0 ), 'SUMPRODUCT' => array( 228, -1, 2, 0 ), 'SINH' => array( 229, 1, 1, 0 ), 'COSH' => array( 230, 1, 1, 0 ), 'TANH' => array( 231, 1, 1, 0 ), 'ASINH' => array( 232, 1, 1, 0 ), 'ACOSH' => array( 233, 1, 1, 0 ), 'ATANH' => array( 234, 1, 1, 0 ), 'DGET' => array( 235, 3, 0, 0 ), 'INFO' => array( 244, 1, 1, 1 ), 'DB' => array( 247, -1, 1, 0 ), 'FREQUENCY' => array( 252, 2, 0, 0 ), 'ERROR.TYPE' => array( 261, 1, 1, 0 ), 'REGISTER.ID' => array( 267, -1, 1, 0 ), 'AVEDEV' => array( 269, -1, 0, 0 ), 'BETADIST' => array( 270, -1, 1, 0 ), 'GAMMALN' => array( 271, 1, 1, 0 ), 'BETAINV' => array( 272, -1, 1, 0 ), 'BINOMDIST' => array( 273, 4, 1, 0 ), 'CHIDIST' => array( 274, 2, 1, 0 ), 'CHIINV' => array( 275, 2, 1, 0 ), 'COMBIN' => array( 276, 2, 1, 0 ), 'CONFIDENCE' => array( 277, 3, 1, 0 ), 'CRITBINOM' => array( 278, 3, 1, 0 ), 'EVEN' => array( 279, 1, 1, 0 ), 'EXPONDIST' => array( 280, 3, 1, 0 ), 'FDIST' => array( 281, 3, 1, 0 ), 'FINV' => array( 282, 3, 1, 0 ), 'FISHER' => array( 283, 1, 1, 0 ), 'FISHERINV' => array( 284, 1, 1, 0 ), 'FLOOR' => array( 285, 2, 1, 0 ), 'GAMMADIST' => array( 286, 4, 1, 0 ), 'GAMMAINV' => array( 287, 3, 1, 0 ), 'CEILING' => array( 288, 2, 1, 0 ), 'HYPGEOMDIST' => array( 289, 4, 1, 0 ), 'LOGNORMDIST' => array( 290, 3, 1, 0 ), 'LOGINV' => array( 291, 3, 1, 0 ), 'NEGBINOMDIST' => array( 292, 3, 1, 0 ), 'NORMDIST' => array( 293, 4, 1, 0 ), 'NORMSDIST' => array( 294, 1, 1, 0 ), 'NORMINV' => array( 295, 3, 1, 0 ), 'NORMSINV' => array( 296, 1, 1, 0 ), 'STANDARDIZE' => array( 297, 3, 1, 0 ), 'ODD' => array( 298, 1, 1, 0 ), 'PERMUT' => array( 299, 2, 1, 0 ), 'POISSON' => array( 300, 3, 1, 0 ), 'TDIST' => array( 301, 3, 1, 0 ), 'WEIBULL' => array( 302, 4, 1, 0 ), 'SUMXMY2' => array( 303, 2, 2, 0 ), 'SUMX2MY2' => array( 304, 2, 2, 0 ), 'SUMX2PY2' => array( 305, 2, 2, 0 ), 'CHITEST' => array( 306, 2, 2, 0 ), 'CORREL' => array( 307, 2, 2, 0 ), 'COVAR' => array( 308, 2, 2, 0 ), 'FORECAST' => array( 309, 3, 2, 0 ), 'FTEST' => array( 310, 2, 2, 0 ), 'INTERCEPT' => array( 311, 2, 2, 0 ), 'PEARSON' => array( 312, 2, 2, 0 ), 'RSQ' => array( 313, 2, 2, 0 ), 'STEYX' => array( 314, 2, 2, 0 ), 'SLOPE' => array( 315, 2, 2, 0 ), 'TTEST' => array( 316, 4, 2, 0 ), 'PROB' => array( 317, -1, 2, 0 ), 'DEVSQ' => array( 318, -1, 0, 0 ), 'GEOMEAN' => array( 319, -1, 0, 0 ), 'HARMEAN' => array( 320, -1, 0, 0 ), 'SUMSQ' => array( 321, -1, 0, 0 ), 'KURT' => array( 322, -1, 0, 0 ), 'SKEW' => array( 323, -1, 0, 0 ), 'ZTEST' => array( 324, -1, 0, 0 ), 'LARGE' => array( 325, 2, 0, 0 ), 'SMALL' => array( 326, 2, 0, 0 ), 'QUARTILE' => array( 327, 2, 0, 0 ), 'PERCENTILE' => array( 328, 2, 0, 0 ), 'PERCENTRANK' => array( 329, -1, 0, 0 ), 'MODE' => array( 330, -1, 2, 0 ), 'TRIMMEAN' => array( 331, 2, 0, 0 ), 'TINV' => array( 332, 2, 1, 0 ), 'CONCATENATE' => array( 336, -1, 1, 0 ), 'POWER' => array( 337, 2, 1, 0 ), 'RADIANS' => array( 342, 1, 1, 0 ), 'DEGREES' => array( 343, 1, 1, 0 ), 'SUBTOTAL' => array( 344, -1, 0, 0 ), 'SUMIF' => array( 345, -1, 0, 0 ), 'COUNTIF' => array( 346, 2, 0, 0 ), 'COUNTBLANK' => array( 347, 1, 0, 0 ), 'ROMAN' => array( 354, -1, 1, 0 ) ); } /** * Convert a token to the proper ptg value. * * @access private * @param mixed $token The token to convert. * @return mixed the converted token on success. PEAR_Error if the token * is not recognized */ function _convert($token) { if (preg_match("/^\"[^\"]{0,255}\"$/", $token)) { return $this->_convertString($token); } elseif (is_numeric($token)) { return $this->_convertNumber($token); } // match references like A1 or $A$1 elseif (preg_match('/^\$?([A-Ia-i]?[A-Za-z])\$?(\d+)$/',$token)) { return $this->_convertRef2d($token); } // match external references like Sheet1:Sheet2!A1 elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\![A-Ia-i]?[A-Za-z](\d+)$/",$token)) { return $this->_convertRef3d($token); } // match ranges like A1:B2 elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\:(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) { return $this->_convertRange2d($token); } // match ranges like A1..B2 elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/",$token)) { return $this->_convertRange2d($token); } // match external ranges like Sheet1:Sheet2!A1:B2 elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/",$token)) { return $this->_convertRange3d($token); } // match external ranges like 'Sheet1:Sheet2'!A1:B2 elseif (preg_match("/^'[A-Za-z0-9_ ]+(\:[A-Za-z0-9_ ]+)?'\!([A-Ia-i]?[A-Za-z])?(\d+)\:([A-Ia-i]?[A-Za-z])?(\d+)$/",$token)) { return $this->_convertRange3d($token); } elseif (isset($this->ptg[$token])) // operators (including parentheses) { return pack("C", $this->ptg[$token]); } // commented so argument number can be processed correctly. See toReversePolish(). /*elseif (preg_match("/[A-Z0-9\xc0-\xdc\.]+/",$token)) { return($this->_convertFunction($token,$this->_func_args)); }*/ // if it's an argument, ignore the token (the argument remains) elseif ($token == 'arg') { return ''; } // TODO: use real error codes trigger_error("Unknown token $token", E_USER_ERROR); } /** * Convert a number token to ptgInt or ptgNum * * @access private * @param mixed $num an integer or double for conversion to its ptg value */ function _convertNumber($num) { // Integer in the range 0..2**16-1 if ((preg_match("/^\d+$/",$num)) and ($num <= 65535)) { return(pack("Cv", $this->ptg['ptgInt'], $num)); } else { // A float if ($this->_byte_order) { // if it's Big Endian $num = strrev($num); } return pack("Cd", $this->ptg['ptgNum'], $num); } } /** * Convert a string token to ptgStr * * @access private * @param string $string A string for conversion to its ptg value */ function _convertString($string) { // chop away beggining and ending quotes $string = substr($string, 1, strlen($string) - 2); return pack("CC", $this->ptg['ptgStr'], strlen($string)).$string; } /** * Convert a function to a ptgFunc or ptgFuncVarV depending on the number of * args that it takes. * * @access private * @param string $token The name of the function for convertion to ptg value. * @param integer $num_args The number of arguments the function receives. * @return string The packed ptg for the function */ function _convertFunction($token, $num_args) { $args = $this->_functions[$token][1]; $volatile = $this->_functions[$token][3]; // Fixed number of args eg. TIME($i,$j,$k). if ($args >= 0) { return pack("Cv", $this->ptg['ptgFuncV'], $this->_functions[$token][0]); } // Variable number of args eg. SUM($i,$j,$k, ..). if ($args == -1) { return pack("CCv", $this->ptg['ptgFuncVarV'], $num_args, $this->_functions[$token][0]); } } /** * Convert an Excel range such as A1:D4 to a ptgRefV. * * @access private * @param string $range An Excel range in the A1:A2 or A1..A2 format. */ function _convertRange2d($range) { $class = 2; // as far as I know, this is magick. // Split the range into 2 cell refs if (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\:([A-Ia-i]?[A-Za-z])(\d+)$/",$range)) { list($cell1, $cell2) = explode(':', $range); } elseif (preg_match("/^([A-Ia-i]?[A-Za-z])(\d+)\.\.([A-Ia-i]?[A-Za-z])(\d+)$/",$range)) { list($cell1, $cell2) = explode('..', $range); } else { // TODO: use real error codes trigger_error("Unknown range separator", E_USER_ERROR); } // Convert the cell references $cell_array1 = $this->_cellToPackedRowcol($cell1); if ($this->isError($cell_array1)) { return $cell_array1; } list($row1, $col1) = $cell_array1; $cell_array2 = $this->_cellToPackedRowcol($cell2); if ($this->isError($cell_array2)) { return $cell_array2; } list($row2, $col2) = $cell_array2; // The ptg value depends on the class of the ptg. if ($class == 0) { $ptgArea = pack("C", $this->ptg['ptgArea']); } elseif ($class == 1) { $ptgArea = pack("C", $this->ptg['ptgAreaV']); } elseif ($class == 2) { $ptgArea = pack("C", $this->ptg['ptgAreaA']); } else { // TODO: use real error codes trigger_error("Unknown class $class", E_USER_ERROR); } return $ptgArea . $row1 . $row2 . $col1. $col2; } /** * Convert an Excel 3d range such as "Sheet1!A1:D4" or "Sheet1:Sheet2!A1:D4" to * a ptgArea3dV. * * @access private * @param string $token An Excel range in the Sheet1!A1:A2 format. */ function _convertRange3d($token) { $class = 2; // as far as I know, this is magick. // Split the ref at the ! symbol list($ext_ref, $range) = explode('!', $token); // Convert the external reference part $ext_ref = $this->_packExtRef($ext_ref); if ($this->isError($ext_ref)) { return $ext_ref; } // Split the range into 2 cell refs list($cell1, $cell2) = explode(':', $range); // Convert the cell references if (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?(\d+)$/", $cell1)) { $cell_array1 = $this->_cellToPackedRowcol($cell1); if ($this->isError($cell_array1)) { return $cell_array1; } list($row1, $col1) = $cell_array1; $cell_array2 = $this->_cellToPackedRowcol($cell2); if ($this->isError($cell_array2)) { return $cell_array2; } list($row2, $col2) = $cell_array2; } else { // It's a columns range (like 26:27) $cells_array = $this->_rangeToPackedRange($cell1.':'.$cell2); if ($this->isError($cells_array)) { return $cells_array; } list($row1, $col1, $row2, $col2) = $cells_array; } // The ptg value depends on the class of the ptg. if ($class == 0) { $ptgArea = pack("C", $this->ptg['ptgArea3d']); } elseif ($class == 1) { $ptgArea = pack("C", $this->ptg['ptgArea3dV']); } elseif ($class == 2) { $ptgArea = pack("C", $this->ptg['ptgArea3dA']); } else { trigger_error("Unknown class $class", E_USER_ERROR); } return $ptgArea . $ext_ref . $row1 . $row2 . $col1. $col2; } /** * Convert an Excel reference such as A1, $B2, C$3 or $D$4 to a ptgRefV. * * @access private * @param string $cell An Excel cell reference * @return string The cell in packed() format with the corresponding ptg */ function _convertRef2d($cell) { $class = 2; // as far as I know, this is magick. // Convert the cell reference $cell_array = $this->_cellToPackedRowcol($cell); if ($this->isError($cell_array)) { return $cell_array; } list($row, $col) = $cell_array; // The ptg value depends on the class of the ptg. if ($class == 0) { $ptgRef = pack("C", $this->ptg['ptgRef']); } elseif ($class == 1) { $ptgRef = pack("C", $this->ptg['ptgRefV']); } elseif ($class == 2) { $ptgRef = pack("C", $this->ptg['ptgRefA']); } else { // TODO: use real error codes trigger_error("Unknown class $class",E_USER_ERROR); } return $ptgRef.$row.$col; } /** * Convert an Excel 3d reference such as "Sheet1!A1" or "Sheet1:Sheet2!A1" to a * ptgRef3dV. * * @access private * @param string $cell An Excel cell reference * @return string The cell in packed() format with the corresponding ptg */ function _convertRef3d($cell) { $class = 2; // as far as I know, this is magick. // Split the ref at the ! symbol list($ext_ref, $cell) = explode('!', $cell); // Convert the external reference part $ext_ref = $this->_packExtRef($ext_ref); if ($this->isError($ext_ref)) { return $ext_ref; } // Convert the cell reference part list($row, $col) = $this->_cellToPackedRowcol($cell); // The ptg value depends on the class of the ptg. if ($class == 0) { $ptgRef = pack("C", $this->ptg['ptgRef3d']); } elseif ($class == 1) { $ptgRef = pack("C", $this->ptg['ptgRef3dV']); } elseif ($class == 2) { $ptgRef = pack("C", $this->ptg['ptgRef3dA']); } else { trigger_error("Unknown class $class", E_USER_ERROR); } return $ptgRef . $ext_ref. $row . $col; } /** * Convert the sheet name part of an external reference, for example "Sheet1" or * "Sheet1:Sheet2", to a packed structure. * * @access private * @param string $ext_ref The name of the external reference * @return string The reference index in packed() format */ function _packExtRef($ext_ref) { $ext_ref = preg_replace("/^'/", '', $ext_ref); // Remove leading ' if any. $ext_ref = preg_replace("/'$/", '', $ext_ref); // Remove trailing ' if any. // Check if there is a sheet range eg., Sheet1:Sheet2. if (preg_match("/:/", $ext_ref)) { list($sheet_name1, $sheet_name2) = explode(':', $ext_ref); $sheet1 = $this->_getSheetIndex($sheet_name1); if ($sheet1 == -1) { trigger_error("Unknown sheet name $sheet_name1 in formula",E_USER_ERROR); } $sheet2 = $this->_getSheetIndex($sheet_name2); if ($sheet2 == -1) { trigger_error("Unknown sheet name $sheet_name2 in formula",E_USER_ERROR); } // Reverse max and min sheet numbers if necessary if ($sheet1 > $sheet2) { list($sheet1, $sheet2) = array($sheet2, $sheet1); } } else { // Single sheet name only. $sheet1 = $this->_getSheetIndex($ext_ref); if ($sheet1 == -1) { trigger_error("Unknown sheet name $ext_ref in formula",E_USER_ERROR); } $sheet2 = $sheet1; } // References are stored relative to 0xFFFF. $offset = -1 - $sheet1; return pack('vdvv', $offset, 0x00, $sheet1, $sheet2); } /** * Look up the index that corresponds to an external sheet name. The hash of * sheet names is updated by the addworksheet() method of the * Spreadsheet_Excel_Writer_Workbook class. * * @access private * @return integer */ function _getSheetIndex($sheet_name) { if (!isset($this->_ext_sheets[$sheet_name])) { return -1; } else { return $this->_ext_sheets[$sheet_name]; } } /** * This method is used to update the array of sheet names. It is * called by the addWorksheet() method of the Spreadsheet_Excel_Writer_Workbook class. * * @access private * @param string $name The name of the worksheet being added * @param integer $index The index of the worksheet being added */ function setExtSheet($name, $index) { $this->_ext_sheets[$name] = $index; } /** * pack() row and column into the required 3 byte format. * * @access private * @param string $cell The Excel cell reference to be packed * @return array Array containing the row and column in packed() format */ function _cellToPackedRowcol($cell) { $cell = strtoupper($cell); list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell); if ($col >= 256) { trigger_error("Column in: $cell greater than 255", E_USER_ERROR); } if ($row >= 16384) { trigger_error("Row in: $cell greater than 16384 ", E_USER_ERROR); } // Set the high bits to indicate if row or col are relative. $row |= $col_rel << 14; $row |= $row_rel << 15; $row = pack('v', $row); $col = pack('C', $col); return array($row, $col); } /** * pack() row range into the required 3 byte format. * Just using maximun col/rows, which is probably not the correct solution * * @access private * @param string $range The Excel range to be packed * @return array Array containing (row1,col1,row2,col2) in packed() format */ function _rangeToPackedRange($range) { preg_match('/(\$)?(\d+)\:(\$)?(\d+)/', $range, $match); // return absolute rows if there is a $ in the ref $row1_rel = empty($match[1]) ? 1 : 0; $row1 = $match[2]; $row2_rel = empty($match[3]) ? 1 : 0; $row2 = $match[4]; // Convert 1-index to zero-index $row1--; $row2--; // Trick poor inocent Excel $col1 = 0; $col2 = 16383; // maximum possible value for Excel 5 (change this!!!) //list($row, $col, $row_rel, $col_rel) = $this->_cellToRowcol($cell); if (($row1 >= 16384) or ($row2 >= 16384)) { trigger_error("Row in: $range greater than 16384 ",E_USER_ERROR); } // Set the high bits to indicate if rows are relative. $row1 |= $row1_rel << 14; $row2 |= $row2_rel << 15; $row1 = pack('v', $row1); $row2 = pack('v', $row2); $col1 = pack('C', $col1); $col2 = pack('C', $col2); return array($row1, $col1, $row2, $col2); } /** * Convert an Excel cell reference such as A1 or $B2 or C$3 or $D$4 to a zero * indexed row and column number. Also returns two (0,1) values to indicate * whether the row or column are relative references. * * @access private * @param string $cell The Excel cell reference in A1 format. * @return array */ function _cellToRowcol($cell) { preg_match('/(\$)?([A-I]?[A-Z])(\$)?(\d+)/',$cell,$match); // return absolute column if there is a $ in the ref $col_rel = empty($match[1]) ? 1 : 0; $col_ref = $match[2]; $row_rel = empty($match[3]) ? 1 : 0; $row = $match[4]; // Convert base26 column string to a number. $expn = strlen($col_ref) - 1; $col = 0; for ($i=0; $i < strlen($col_ref); $i++) { $col += (ord($col_ref{$i}) - ord('A') + 1) * pow(26, $expn); $expn--; } // Convert 1-index to zero-index $row--; $col--; return array($row, $col, $row_rel, $col_rel); } /** * Advance to the next valid token. * * @access private */ function _advance() { $i = $this->_current_char; // eat up white spaces if ($i < strlen($this->_formula)) { while ($this->_formula{$i} == " ") { $i++; } if ($i < strlen($this->_formula) - 1) { $this->_lookahead = $this->_formula{$i+1}; } $token = ""; } while ($i < strlen($this->_formula)) { $token .= $this->_formula{$i}; if ($i < strlen($this->_formula) - 1) { $this->_lookahead = $this->_formula{$i+1}; } else { $this->_lookahead = ''; } if ($this->_match($token) != '') { //if ($i < strlen($this->_formula) - 1) { // $this->_lookahead = $this->_formula{$i+1}; //} $this->_current_char = $i + 1; $this->_current_token = $token; return 1; } if ($i < strlen($this->_formula) - 2) { $this->_lookahead = $this->_formula{$i+2}; } else { // if we run out of characters _lookahead becomes empty $this->_lookahead = ''; } $i++; } //die("Lexical error ".$this->_current_char); } /** * Checks if it's a valid token. * * @access private * @param mixed $token The token to check. * @return mixed The checked token or false on failure */ function _match($token) { switch($token) { case SPREADSHEET_EXCEL_WRITER_ADD: return($token); break; case SPREADSHEET_EXCEL_WRITER_SUB: return($token); break; case SPREADSHEET_EXCEL_WRITER_MUL: return($token); break; case SPREADSHEET_EXCEL_WRITER_DIV: return($token); break; case SPREADSHEET_EXCEL_WRITER_OPEN: return($token); break; case SPREADSHEET_EXCEL_WRITER_CLOSE: return($token); break; case SPREADSHEET_EXCEL_WRITER_SCOLON: return($token); break; case SPREADSHEET_EXCEL_WRITER_COMA: return($token); break; case SPREADSHEET_EXCEL_WRITER_GT: if ($this->_lookahead == '=') { // it's a GE token break; } return($token); break; case SPREADSHEET_EXCEL_WRITER_LT: // it's a LE or a NE token if (($this->_lookahead == '=') or ($this->_lookahead == '>')) { break; } return($token); break; case SPREADSHEET_EXCEL_WRITER_GE: return($token); break; case SPREADSHEET_EXCEL_WRITER_LE: return($token); break; case SPREADSHEET_EXCEL_WRITER_EQ: return($token); break; case SPREADSHEET_EXCEL_WRITER_NE: return($token); break; default: // if it's a reference if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$token) and !preg_match("/[0-9]/",$this->_lookahead) and ($this->_lookahead != ':') and ($this->_lookahead != '.') and ($this->_lookahead != '!')) { return $token; } // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\![A-Ia-i]?[A-Za-z][0-9]+$/",$token) and !preg_match("/[0-9]/",$this->_lookahead) and ($this->_lookahead != ':') and ($this->_lookahead != '.')) { return $token; } // if it's a range (A1:A2) elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and !preg_match("/[0-9]/",$this->_lookahead)) { return $token; } // if it's a range (A1..A2) elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$token) and !preg_match("/[0-9]/",$this->_lookahead)) { return $token; } // If it's an external range like Sheet1:Sheet2!A1:B2 elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/",$token) and !preg_match("/[0-9]/",$this->_lookahead)) { return $token; } // If it's an external range like 'Sheet1:Sheet2'!A1:B2 elseif (preg_match("/^'[A-Za-z0-9_ ]+(\:[A-Za-z0-9_ ]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/",$token) and !preg_match("/[0-9]/",$this->_lookahead)) { return $token; } // If it's a number (check that it's not a sheet name or range) elseif (is_numeric($token) and (!is_numeric($token.$this->_lookahead) or ($this->_lookahead == '')) and ($this->_lookahead != '!') and ($this->_lookahead != ':')) { return $token; } // If it's a string (of maximum 255 characters) elseif (preg_match("/^\"[^\"]{0,255}\"$/",$token)) { return $token; } // if it's a function call elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$token) and ($this->_lookahead == "(")) { return $token; } return ''; } } /** * The parsing method. It parses a formula. * * @access public * @param string $formula The formula to parse, without the initial equal sign (=). */ function parse($formula) { $this->_current_char = 0; $this->_formula = $formula; $this->_lookahead = $formula{1}; $this->_advance(); $this->_parse_tree = $this->_condition(); if ($this->isError($this->_parse_tree)) { return $this->_parse_tree; } } /** * It parses a condition. It assumes the following rule: * Cond -> Expr [(">" | "<") Expr] * * @access private * @return mixed The parsed ptg'd tree */ function _condition() { $result = $this->_expression(); if ($this->isError($result)) { return $result; } if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LT) { $this->_advance(); $result2 = $this->_expression(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgLT', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GT) { $this->_advance(); $result2 = $this->_expression(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgGT', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_LE) { $this->_advance(); $result2 = $this->_expression(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgLE', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_GE) { $this->_advance(); $result2 = $this->_expression(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgGE', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_EQ) { $this->_advance(); $result2 = $this->_expression(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgEQ', $result, $result2); } elseif ($this->_current_token == SPREADSHEET_EXCEL_WRITER_NE) { $this->_advance(); $result2 = $this->_expression(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgNE', $result, $result2); } return $result; } /** * It parses a expression. It assumes the following rule: * Expr -> Term [("+" | "-") Term] * * @access private * @return mixed The parsed ptg'd tree */ function _expression() { // If it's a string return a string node if (preg_match("/^\"[^\"]{0,255}\"$/", $this->_current_token)) { $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } $result = $this->_term(); if ($this->isError($result)) { return $result; } while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) or ($this->_current_token == SPREADSHEET_EXCEL_WRITER_SUB)) { if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_ADD) { $this->_advance(); $result2 = $this->_term(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgAdd', $result, $result2); } else { $this->_advance(); $result2 = $this->_term(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgSub', $result, $result2); } } return $result; } /** * This function just introduces a ptgParen element in the tree, so that Excel * doesn't get confused when working with a parenthesized formula afterwards. * * @access private * @see _fact() * @return mixed The parsed ptg'd tree */ function _parenthesizedExpression() { $result = $this->_createTree('ptgParen', $this->_expression(), ''); return $result; } /** * It parses a term. It assumes the following rule: * Term -> Fact [("*" | "/") Fact] * * @access private * @return mixed The parsed ptg'd tree */ function _term() { $result = $this->_fact(); if ($this->isError($result)) { return $result; } while (($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) or ($this->_current_token == SPREADSHEET_EXCEL_WRITER_DIV)) { if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_MUL) { $this->_advance(); $result2 = $this->_fact(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgMul', $result, $result2); } else { $this->_advance(); $result2 = $this->_fact(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('ptgDiv', $result, $result2); } } return $result; } /** * It parses a factor. It assumes the following rule: * Fact -> ( Expr ) * | CellRef * | CellRange * | Number * | Function * * @access private * @return mixed The parsed ptg'd tree */ function _fact() { if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_OPEN) { $this->_advance(); // eat the "(" $result = $this->_parenthesizedExpression(); if ($this->_current_token != SPREADSHEET_EXCEL_WRITER_CLOSE) { trigger_error("')' token expected.",E_USER_ERROR); } $this->_advance(); // eat the ")" return $result; } if (preg_match('/^\$?[A-Ia-i]?[A-Za-z]\$?[0-9]+$/',$this->_current_token)) { // if it's a reference $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\![A-Ia-i]?[A-Za-z][0-9]+$/",$this->_current_token)) { // If it's an external reference (Sheet1!A1 or Sheet1:Sheet2!A1) $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } elseif (preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+:(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token) or preg_match("/^(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+\.\.(\$)?[A-Ia-i]?[A-Za-z](\$)?[0-9]+$/",$this->_current_token)) { // if it's a range $result = $this->_current_token; $this->_advance(); return $result; } elseif (preg_match("/^[A-Za-z0-9_]+(\:[A-Za-z0-9_]+)?\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/",$this->_current_token)) { // If it's an external range (Sheet1!A1:B2) $result = $this->_current_token; $this->_advance(); return $result; } elseif (preg_match("/^'[A-Za-z0-9_ ]+(\:[A-Za-z0-9_ ]+)?'\!([A-Ia-i]?[A-Za-z])?[0-9]+:([A-Ia-i]?[A-Za-z])?[0-9]+$/",$this->_current_token)) { // If it's an external range ('Sheet1'!A1:B2) $result = $this->_current_token; $this->_advance(); return $result; } elseif (is_numeric($this->_current_token)) { $result = $this->_createTree($this->_current_token, '', ''); $this->_advance(); return $result; } elseif (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/i",$this->_current_token)) { // if it's a function call $result = $this->_func(); return $result; } trigger_error("Sintactic error: ".$this->_current_token.", lookahead: ". $this->_lookahead.", current char: ".$this->_current_char, E_USER_ERROR); } /** * It parses a function call. It assumes the following rule: * Func -> ( Expr [,Expr]* ) * * @access private */ function _func() { $num_args = 0; // number of arguments received $function = $this->_current_token; $this->_advance(); $this->_advance(); // eat the "(" while ($this->_current_token != ')') { if ($num_args > 0) { if ($this->_current_token == SPREADSHEET_EXCEL_WRITER_COMA || $this->_current_token == SPREADSHEET_EXCEL_WRITER_SCOLON) { $this->_advance(); // eat the "," } else { trigger_error("Sintactic error: coma expected in ". "function $function, {$num_args}º arg", E_USER_ERROR); } $result2 = $this->_condition(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('arg', $result, $result2); } else { // first argument $result2 = $this->_condition(); if ($this->isError($result2)) { return $result2; } $result = $this->_createTree('arg', '', $result2); } $num_args++; } $args = $this->_functions[$function][1]; // If fixed number of args eg. TIME($i,$j,$k). Check that the number of args is valid. if (($args >= 0) and ($args != $num_args)) { trigger_error("Incorrect number of arguments in function $function() ",E_USER_ERROR); } $result = $this->_createTree($function, $result, $num_args); $this->_advance(); // eat the ")" return $result; } /** * Creates a tree. In fact an array which may have one or two arrays (sub-trees) * as elements. * * @access private * @param mixed $value The value of this node. * @param mixed $left The left array (sub-tree) or a final node. * @param mixed $right The right array (sub-tree) or a final node. */ function _createTree($value, $left, $right) { return(array('value' => $value, 'left' => $left, 'right' => $right)); } /** * Builds a string containing the tree in reverse polish notation (What you * would use in a HP calculator stack). * The following tree: * * + * / \ * 2 3 * * produces: "23+" * * The following tree: * * + * / \ * 3 * * / \ * 6 A1 * * produces: "36A1*+" * * In fact all operands, functions, references, etc... are written as ptg's * * @access public * @param array $tree The optional tree to convert. * @return string The tree in reverse polish notation */ function toReversePolish($tree = array()) { $polish = ""; // the string we are going to return if (empty($tree)) { // If it's the first call use _parse_tree $tree = $this->_parse_tree; } if (is_array($tree['left'])) { $converted_tree = $this->toReversePolish($tree['left']); if ($this->isError($converted_tree)) { return $converted_tree; } $polish .= $converted_tree; } elseif ($tree['left'] != '') { // It's a final node $converted_tree = $this->_convert($tree['left']); if ($this->isError($converted_tree)) { return $converted_tree; } $polish .= $converted_tree; } if (is_array($tree['right'])) { $converted_tree = $this->toReversePolish($tree['right']); if ($this->isError($converted_tree)) { return $converted_tree; } $polish .= $converted_tree; } elseif ($tree['right'] != '') { // It's a final node $converted_tree = $this->_convert($tree['right']); if ($this->isError($converted_tree)) { return $converted_tree; } $polish .= $converted_tree; } // if it's a function convert it here (so we can set it's arguments) if (preg_match("/^[A-Z0-9\xc0-\xdc\.]+$/",$tree['value']) and !preg_match('/^([A-Ia-i]?[A-Za-z])(\d+)$/',$tree['value']) and !preg_match("/^[A-Ia-i]?[A-Za-z](\d+)\.\.[A-Ia-i]?[A-Za-z](\d+)$/",$tree['value']) and !is_numeric($tree['value']) and !isset($this->ptg[$tree['value']])) { // left subtree for a function is always an array. if ($tree['left'] != '') { $left_tree = $this->toReversePolish($tree['left']); } else { $left_tree = ''; } if ($this->isError($left_tree)) { return $left_tree; } // add it's left subtree and return. return $left_tree.$this->_convertFunction($tree['value'], $tree['right']); } else { $converted_tree = $this->_convert($tree['value']); if ($this->isError($converted_tree)) { return $converted_tree; } } $polish .= $converted_tree; return $polish; } } ?> gosa-core-2.7.4/include/utils/excel/functions.writeexcel_utility.inc.php0000644000175000017500000001677010330363250025516 0ustar cajuscajus 0) { $chr1 = chr(ord('A') + $int - 1); } $chr2 = chr(ord('A') + $frac); // Zero index to 1-index $row++; return $col_abs.$chr1.$chr2.$row_abs.$row; } /* * Converts an Excel cell reference string in A1 notation * to numeric $row/$col notation. * * Returns: array($row, $col, $row_absolute, $col_absolute) * * The $row_absolute and $col_absolute parameters aren't documented because * they are mainly used internally and aren't very useful to the user. */ function xl_cell_to_rowcol($cell) { preg_match('/(\$?)([A-I]?[A-Z])(\$?)(\d+)/', $cell, $reg); $col_abs = ($reg[1] == "") ? 0 : 1; $col = $reg[2]; $row_abs = ($reg[3] == "") ? 0 : 1; $row = $reg[4]; // Convert base26 column string to number // All your Base are belong to us. $chars = preg_split('//', $col, -1, PREG_SPLIT_NO_EMPTY); $expn = 0; $col = 0; while (sizeof($chars)>0) { $char = array_pop($chars); // Least significant character first $col += (ord($char) - ord('A') + 1) * pow(26, $expn); $expn++; } // Convert 1-index to zero-index $row--; $col--; return array($row, $col, $row_abs, $col_abs); } /* * Increments the row number of an Excel cell reference string * in A1 notation. * For example C4 to C5 * * Returns: a cell reference string in A1 notation. */ function xl_inc_row($cell) { list($row, $col, $row_abs, $col_abs) = xl_cell_to_rowcol($cell); return xl_rowcol_to_cell(++$row, $col, $row_abs, $col_abs); } /* * Decrements the row number of an Excel cell reference string * in A1 notation. * For example C4 to C3 * * Returns: a cell reference string in A1 notation. */ function xl_dec_row($cell) { list($row, $col, $row_abs, $col_abs) = xl_cell_to_rowcol($cell); return xl_rowcol_to_cell(--$row, $col, $row_abs, $col_abs); } /* * Increments the column number of an Excel cell reference string * in A1 notation. * For example C3 to D3 * * Returns: a cell reference string in A1 notation. */ function xl_inc_col($cell) { list($row, $col, $row_abs, $col_abs) = xl_cell_to_rowcol($cell); return xl_rowcol_to_cell($row, ++$col, $row_abs, $col_abs); } /* * Decrements the column number of an Excel cell reference string * in A1 notation. * For example C3 to B3 * * Returns: a cell reference string in A1 notation. */ function xl_dec_col($cell) { list($row, $col, $row_abs, $col_abs) = xl_cell_to_rowcol($cell); return xl_rowcol_to_cell($row, --$col, $row_abs, $col_abs); } function xl_date_list($year, $month=1, $day=1, $hour=0, $minute=0, $second=0) { $monthdays=array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31); // Leap years since 1900 (year is dividable by 4) $leapyears=floor(($year-1900)/4); // Non-leap years since 1900 (year is dividable by 100) $nonleapyears=floor(($year-1900)/100); // Non-non-leap years since 1900 (year is dividable by 400) // (Yes, it MUST be "1600", not "1900") $nonnonleapyears=floor(($year-1600)/400); // Don't count the leap day of the specified year if it didn't // happen yet (i.e. before 1 March) // // Please note that $leapyears becomes -1 for dates before 1 March 1900; // this is not logical, but later we will add a day for Excel's // phantasie leap day in 1900 without checking if the date is actually // after 28 February 1900; so these two logic errors "neutralize" // each other if ($year%4==0 && $month<3) { $leapyears--; } $days=365*($year-1900)+$leapyears-$nonleapyears+$nonnonleapyears; for ($c=1;$c<$month;$c++) { $days+=$monthdays[$c-1]; } // Excel actually wants the days since 31 December 1899, not since // 1 January 1900; this will also add this extra day $days+=$day; // Excel treats 1900 erroneously as a leap year, so we must // add one day // // Please note that we DON'T have to check if the date is after // 28 February 1900, because for such dates $leapyears is -1 // (see above) $days++; return (float)($days+($hour*3600+$minute*60+$second)/86400); } function xl_parse_time($time) { if (preg_match('/(\d{1,2}):(\d\d):?((?:\d\d)(?:\.\d+)?)?(?:\s+)?(am|pm)?/i', $time, $reg)) { $hours = $reg[1]; $minutes = $reg[2]; $seconds = $reg[3] || 0; $meridian = strtolower($reg[4]) || ''; // Normalise midnight and midday if ($hours == 12 && $meridian != '') { $hours = 0; } // Add 12 hours to the pm times. Note: 12.00 pm has been set to 0.00. if ($meridian == 'pm') { $hours += 12; } // Calculate the time as a fraction of 24 hours in seconds return (float)(($hours*3600+$minutes*60+$seconds)/86400); } else { return false; // Not a valid time string } } /* * Automagically converts almost any date/time string to an Excel date. * This function will always only be as good as strtotime() is. */ function xl_parse_date($date) { $unixtime=strtotime($date); $year=date("Y", $unixtime); $month=date("m", $unixtime); $day=date("d", $unixtime); $hour=date("H", $unixtime); $minute=date("i", $unixtime); $second=date("s", $unixtime); // Convert to Excel date return xl_date_list($year, $month, $day, $hour, $minute, $second); } /* * Dummy function to be "compatible" to Spreadsheet::WriteExcel */ function xl_parse_date_init() { // Erm... do nothing... // strtotime() doesn't require anything to be initialized // (do not ask me how to set the timezone...) } /* * xl_decode_date_EU() and xl_decode_date_US() are mapped * to xl_parse_date(); there seems to be no PHP function that * differentiates between EU and US dates; I've never seen * somebody using dd/mm/yyyy anyway, it always should be one of: * - yyyy-mm-dd (international) * - dd.mm.yyyy (european) * - mm/dd/yyyy (english/US/british?) */ function xl_decode_date_EU($date) { return xl_parse_date($date); } function xl_decode_date_US($date) { return xl_parse_date($date); } function xl_date_1904($exceldate) { if ($exceldate < 1462) { // date is before 1904 $exceldate = 0; } else { $exceldate -= 1462; } return $exceldate; } ?> gosa-core-2.7.4/include/utils/excel/class.writeexcel_olewriter.inc.php0000644000175000017500000002552010767572700025135 0ustar cajuscajus_OLEfilename = $filename; $this->_filehandle = false; $this->_fileclosed = 0; $this->_internal_fh = 0; $this->_biff_only = 0; $this->_size_allowed = 0; $this->_biffsize = 0; $this->_booksize = 0; $this->_big_blocks = 0; $this->_list_blocks = 0; $this->_root_start = 0; $this->_block_count = 4; $this->_initialize(); } /* * Check for a valid filename and store the filehandle. */ function _initialize() { $OLEfile = $this->_OLEfilename; /* Check for a filename. Workbook.pm will catch this first. */ if ($OLEfile == '') { trigger_error("Filename required", E_USER_ERROR); } /* * If the filename is a resource it is assumed that it is a valid * filehandle, if not we create a filehandle. */ if (is_resource($OLEfile)) { $fh = $OLEfile; } else { // Create a new file, open for writing $fh = fopen($OLEfile, "wb"); // The workbook class also checks this but something may have // happened since then. if (!$fh) { trigger_error("Cannot open $OLEfile! It may be in use or ". "protected.", E_USER_ERROR); } $this->_internal_fh = 1; } // Store filehandle $this->_filehandle = $fh; } /* * Set the size of the data to be written to the OLE stream * * $big_blocks = (109 depot block x (128 -1 marker word) * - (1 x end words)) = 13842 * $maxsize = $big_blocks * 512 bytes = 7087104 */ function set_size($size) { $maxsize = 7087104; if ($size > $maxsize) { trigger_error("Maximum file size, $maxsize, exceeded. To create ". "files bigger than this limit please use the ". "workbookbig class.", E_USER_ERROR); return ($this->_size_allowed = 0); } $this->_biffsize = $size; // Set the min file size to 4k to avoid having to use small blocks if ($size > 4096) { $this->_booksize = $size; } else { $this->_booksize = 4096; } return ($this->_size_allowed = 1); } /* * Calculate various sizes needed for the OLE stream */ function _calculate_sizes() { $datasize = $this->_booksize; if ($datasize % 512 == 0) { $this->_big_blocks = $datasize/512; } else { $this->_big_blocks = floor($datasize/512)+1; } // There are 127 list blocks and 1 marker blocks for each big block // depot + 1 end of chain block $this->_list_blocks = floor(($this->_big_blocks)/127)+1; $this->_root_start = $this->_big_blocks; //print $this->_biffsize. "\n"; //print $this->_big_blocks. "\n"; //print $this->_list_blocks. "\n"; } /* * Write root entry, big block list and close the filehandle. * This method must be called so that the file contents are * actually written. */ function close() { if (!$this->_size_allowed) { return; } if (!$this->_biff_only) { $this->_write_padding(); $this->_write_property_storage(); $this->_write_big_block_depot(); } // Close the filehandle if it was created internally. if ($this->_internal_fh) { fclose($this->_filehandle); } /* ABR */ if ($this->_OLEtmpfilename != '') { $fh = fopen($this->_OLEtmpfilename, "rb"); if ($fh == false) { trigger_error("Cannot read temporary file!", E_USER_ERROR); } fpassthru($fh); fclose($fh); unlink($this->_OLEtmpfilename); }; $this->_fileclosed = 1; } /* * Write BIFF data to OLE file. */ function write($data) { fputs($this->_filehandle, $data); } /* * Write OLE header block. */ function write_header() { if ($this->_biff_only) { return; } $this->_calculate_sizes(); $root_start = $this->_root_start; $num_lists = $this->_list_blocks; $id = pack("C8", 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1); $unknown1 = pack("VVVV", 0x00, 0x00, 0x00, 0x00); $unknown2 = pack("vv", 0x3E, 0x03); $unknown3 = pack("v", -2); $unknown4 = pack("v", 0x09); $unknown5 = pack("VVV", 0x06, 0x00, 0x00); $num_bbd_blocks = pack("V", $num_lists); $root_startblock = pack("V", $root_start); $unknown6 = pack("VV", 0x00, 0x1000); $sbd_startblock = pack("V", -2); $unknown7 = pack("VVV", 0x00, -2 ,0x00); $unused = pack("V", -1); fputs($this->_filehandle, $id); fputs($this->_filehandle, $unknown1); fputs($this->_filehandle, $unknown2); fputs($this->_filehandle, $unknown3); fputs($this->_filehandle, $unknown4); fputs($this->_filehandle, $unknown5); fputs($this->_filehandle, $num_bbd_blocks); fputs($this->_filehandle, $root_startblock); fputs($this->_filehandle, $unknown6); fputs($this->_filehandle, $sbd_startblock); fputs($this->_filehandle, $unknown7); for ($c=1;$c<=$num_lists;$c++) { $root_start++; fputs($this->_filehandle, pack("V", $root_start)); } for ($c=$num_lists;$c<=108;$c++) { fputs($this->_filehandle, $unused); } } /* * Write big block depot. */ function _write_big_block_depot() { $num_blocks = $this->_big_blocks; $num_lists = $this->_list_blocks; $total_blocks = $num_lists * 128; $used_blocks = $num_blocks + $num_lists + 2; $marker = pack("V", -3); $end_of_chain = pack("V", -2); $unused = pack("V", -1); for ($i=1;$i<=($num_blocks-1);$i++) { fputs($this->_filehandle, pack("V", $i)); } fputs($this->_filehandle, $end_of_chain); fputs($this->_filehandle, $end_of_chain); for ($c=1;$c<=$num_lists;$c++) { fputs($this->_filehandle, $marker); } for ($c=$used_blocks;$c<=$total_blocks;$c++) { fputs($this->_filehandle, $unused); } } /* * Write property storage. TODO: add summary sheets */ function _write_property_storage() { $rootsize = -2; $booksize = $this->_booksize; // name type dir start size $this->_write_pps('Root Entry', 0x05, 1, -2, 0x00); $this->_write_pps('Book', 0x02, -1, 0x00, $booksize); $this->_write_pps('', 0x00, -1, 0x00, 0x0000); $this->_write_pps('', 0x00, -1, 0x00, 0x0000); } /* * Write property sheet in property storage */ function _write_pps($name, $type, $dir, $start, $size) { $names = array(); $length = 0; if ($name != '') { $name = $name . "\0"; // Simulate a Unicode string $chars=preg_split("''", $name, -1, PREG_SPLIT_NO_EMPTY); foreach ($chars as $char) { array_push($names, ord($char)); } $length = strlen($name) * 2; } $rawname = call_user_func_array('pack', array_merge(array("v*"), $names)); $zero = pack("C", 0); $pps_sizeofname = pack("v", $length); //0x40 $pps_type = pack("v", $type); //0x42 $pps_prev = pack("V", -1); //0x44 $pps_next = pack("V", -1); //0x48 $pps_dir = pack("V", $dir); //0x4c $unknown1 = pack("V", 0); $pps_ts1s = pack("V", 0); //0x64 $pps_ts1d = pack("V", 0); //0x68 $pps_ts2s = pack("V", 0); //0x6c $pps_ts2d = pack("V", 0); //0x70 $pps_sb = pack("V", $start); //0x74 $pps_size = pack("V", $size); //0x78 fputs($this->_filehandle, $rawname); fputs($this->_filehandle, str_repeat($zero, (64-$length))); fputs($this->_filehandle, $pps_sizeofname); fputs($this->_filehandle, $pps_type); fputs($this->_filehandle, $pps_prev); fputs($this->_filehandle, $pps_next); fputs($this->_filehandle, $pps_dir); fputs($this->_filehandle, str_repeat($unknown1, 5)); fputs($this->_filehandle, $pps_ts1s); fputs($this->_filehandle, $pps_ts1d); fputs($this->_filehandle, $pps_ts2d); fputs($this->_filehandle, $pps_ts2d); fputs($this->_filehandle, $pps_sb); fputs($this->_filehandle, $pps_size); fputs($this->_filehandle, $unknown1); } /* * Pad the end of the file */ function _write_padding() { $biffsize = $this->_biffsize; if ($biffsize < 4096) { $min_size = 4096; } else { $min_size = 512; } if ($biffsize % $min_size != 0) { $padding = $min_size - ($biffsize % $min_size); fputs($this->_filehandle, str_repeat("\0", $padding)); } } } ?> gosa-core-2.7.4/include/utils/excel/class.writeexcel_biffwriter.inc.php0000644000175000017500000001400110330363250025234 0ustar cajuscajusbyte_order = ''; $this->BIFF_version = 0x0500; $this->_byte_order = ''; $this->_data = false; $this->_datasize = 0; $this->_limit = 2080; $this->_set_byte_order(); } /* * Determine the byte order and store it as class data to avoid * recalculating it for each call to new(). */ function _set_byte_order() { $this->byteorder=0; // Check if "pack" gives the required IEEE 64bit float $teststr = pack("d", 1.2345); $number = pack("C8", 0x8D, 0x97, 0x6E, 0x12, 0x83, 0xC0, 0xF3, 0x3F); if ($number == $teststr) { $this->byte_order = 0; // Little Endian } elseif ($number == strrev($teststr)) { $this->byte_order = 1; // Big Endian } else { // Give up trigger_error("Required floating point format not supported ". "on this platform. See the portability section ". "of the documentation.", E_USER_ERROR); } $this->_byte_order = $this->byte_order; } /* * General storage function */ function _prepend($data) { if (func_num_args()>1) { trigger_error("writeexcel_biffwriter::_prepend() ". "called with more than one argument", E_USER_ERROR); } if ($this->_debug) { print "*** writeexcel_biffwriter::_prepend() called:"; for ($c=0;$c $this->_limit) { $data = $this->_add_continue($data); } $this->_data = $data . $this->_data; $this->_datasize += strlen($data); } /* * General storage function */ function _append($data) { if (func_num_args()>1) { trigger_error("writeexcel_biffwriter::_append() ". "called with more than one argument", E_USER_ERROR); } if ($this->_debug) { print "*** writeexcel_biffwriter::_append() called:"; for ($c=0;$c $this->_limit) { $data = $this->_add_continue($data); } $this->_data = $this->_data . $data; $this->_datasize += strlen($data); } /* * Writes Excel BOF record to indicate the beginning of a stream or * sub-stream in the BIFF file. * * $type = 0x0005, Workbook * $type = 0x0010, Worksheet */ function _store_bof($type) { $record = 0x0809; // Record identifier $length = 0x0008; // Number of bytes to follow $version = $this->BIFF_version; // According to the SDK $build and $year should be set to zero. // However, this throws a warning in Excel 5. So, use these // magic numbers. $build = 0x096C; $year = 0x07C9; $header = pack("vv", $record, $length); $data = pack("vvvv", $version, $type, $build, $year); $this->_prepend($header . $data); } /* * Writes Excel EOF record to indicate the end of a BIFF stream. */ function _store_eof() { $record = 0x000A; // Record identifier $length = 0x0000; // Number of bytes to follow $header = pack("vv", $record, $length); $this->_append($header); } /* * Excel limits the size of BIFF records. In Excel 5 the limit is 2084 * bytes. In Excel 97 the limit is 8228 bytes. Records that are longer * than these limits must be split up into CONTINUE blocks. * * This function take a long BIFF record and inserts CONTINUE records as * necessary. */ function _add_continue($data) { $limit = $this->_limit; $record = 0x003C; // Record identifier // The first 2080/8224 bytes remain intact. However, we have to change // the length field of the record. $tmp = substr($data, 0, $limit); $data = substr($data, $limit); $tmp = substr($tmp, 0, 2) . pack ("v", $limit-4) . substr($tmp, 4); // Strip out chunks of 2080/8224 bytes +4 for the header. while (strlen($data) > $limit) { $header = pack("vv", $record, $limit); $tmp .= $header; $tmp .= substr($data, 0, $limit); $data = substr($data, $limit); } // Mop up the last of the data $header = pack("vv", $record, strlen($data)); $tmp .= $header; $tmp .= $data; return $tmp; } } ?> gosa-core-2.7.4/include/utils/excel/class.writeexcel_format.inc.php0000644000175000017500000004651711327532760024415 0ustar cajuscajus_xf_index = (sizeof($_)>0) ? array_shift($_) : 0; $this->_font_index = 0; $this->_font = 'Arial'; $this->_size = 10; $this->_bold = 0x0190; $this->_italic = 0; $this->_color = 0x7FFF; $this->_underline = 0; $this->_font_strikeout = 0; $this->_font_outline = 0; $this->_font_shadow = 0; $this->_font_script = 0; $this->_font_family = 0; $this->_font_charset = 0; $this->_num_format = 0; $this->_hidden = 0; $this->_locked = 1; $this->_text_h_align = 0; $this->_text_wrap = 0; $this->_text_v_align = 2; $this->_text_justlast = 0; $this->_rotation = 0; $this->_fg_color = 0x40; $this->_bg_color = 0x41; $this->_pattern = 0; $this->_bottom = 0; $this->_top = 0; $this->_left = 0; $this->_right = 0; $this->_bottom_color = 0x40; $this->_top_color = 0x40; $this->_left_color = 0x40; $this->_right_color = 0x40; // Set properties passed to writeexcel_workbook::addformat() if (sizeof($_)>0) { call_user_func_array(array($this, 'set_properties'), $_); } } /* * Copy the attributes of another writeexcel_format object. */ function copy($other) { $xf = $this->_xf_index; // Backup XF index /* A better way to copy member vars, ... won't cause fatal errors in PHP5. The only thing i can understand is : For what is this function used, it is never used by any object, as I can see in the source code. ... */ foreach(get_object_vars($other) as $var => $val){ $this->$var = $val; } // $this = $other; // Copy properties $this->_xf_index = $xf; // Restore XF index } /* * Generate an Excel BIFF XF record. */ function get_xf() { $_=func_get_args(); // $record Record identifier // $length Number of bytes to follow // $ifnt Index to FONT record // $ifmt Index to FORMAT record // $style Style and other options // $align Alignment // $icv fg and bg pattern colors // $fill Fill and border line style // $border1 Border line style and color // $border2 Border color // Set the type of the XF record and some of the attributes. if ($_[0] == "style") { $style = 0xFFF5; } else { $style = $this->_locked; $style |= $this->_hidden << 1; } // Flags to indicate if attributes have been set. $atr_num = ($this->_num_format != 0) ? 1 : 0; $atr_fnt = ($this->_font_index != 0) ? 1 : 0; $atr_alc = $this->_text_wrap ? 1 : 0; $atr_bdr = ($this->_bottom || $this->_top || $this->_left || $this->_right) ? 1 : 0; $atr_pat = ($this->_fg_color != 0x41 || $this->_bg_color != 0x41 || $this->_pattern != 0x00) ? 1 : 0; $atr_prot = 0; // Reset the default colors for the non-font properties if ($this->_fg_color == 0x7FFF) $this->_fg_color = 0x40; if ($this->_bg_color == 0x7FFF) $this->_bg_color = 0x41; if ($this->_bottom_color == 0x7FFF) $this->_bottom_color = 0x41; if ($this->_top_color == 0x7FFF) $this->_top_color = 0x41; if ($this->_left_color == 0x7FFF) $this->_left_color = 0x41; if ($this->_right_color == 0x7FFF) $this->_right_color = 0x41; // Zero the default border colour if the border has not been set. if ($this->_bottom == 0) { $this->_bottom_color = 0; } if ($this->_top == 0) { $this->_top_color = 0; } if ($this->_right == 0) { $this->_right_color = 0; } if ($this->_left == 0) { $this->_left_color = 0; } // The following 2 logical statements take care of special cases in // relation to cell colors and patterns: // 1. For a solid fill (_pattern == 1) Excel reverses the role of // foreground and background colors // 2. If the user specifies a foreground or background color // without a pattern they probably wanted a solid fill, so we // fill in the defaults. if ($this->_pattern <= 0x01 && $this->_bg_color != 0x41 && $this->_fg_color == 0x40 ) { $this->_fg_color = $this->_bg_color; $this->_bg_color = 0x40; $this->_pattern = 1; } if ($this->_pattern <= 0x01 && $this->_bg_color == 0x41 && $this->_fg_color != 0x40 ) { $this->_bg_color = 0x40; $this->_pattern = 1; } $record = 0x00E0; $length = 0x0010; $ifnt = $this->_font_index; $ifmt = $this->_num_format; $align = $this->_text_h_align; $align |= $this->_text_wrap << 3; $align |= $this->_text_v_align << 4; $align |= $this->_text_justlast << 7; $align |= $this->_rotation << 8; $align |= $atr_num << 10; $align |= $atr_fnt << 11; $align |= $atr_alc << 12; $align |= $atr_bdr << 13; $align |= $atr_pat << 14; $align |= $atr_prot << 15; $icv = $this->_fg_color; $icv |= $this->_bg_color << 7; $fill = $this->_pattern; $fill |= $this->_bottom << 6; $fill |= $this->_bottom_color << 9; $border1 = $this->_top; $border1 |= $this->_left << 3; $border1 |= $this->_right << 6; $border1 |= $this->_top_color << 9; $border2 = $this->_left_color; $border2 |= $this->_right_color << 7; $header = pack("vv", $record, $length); $data = pack("vvvvvvvv", $ifnt, $ifmt, $style, $align, $icv, $fill, $border1, $border2); return($header . $data); } /* * Generate an Excel BIFF FONT record. */ function get_font() { // $record Record identifier // $length Record length // $dyHeight Height of font (1/20 of a point) // $grbit Font attributes // $icv Index to color palette // $bls Bold style // $sss Superscript/subscript // $uls Underline // $bFamily Font family // $bCharSet Character set // $reserved Reserved // $cch Length of font name // $rgch Font name $dyHeight = $this->_size * 20; $icv = $this->_color; $bls = $this->_bold; $sss = $this->_font_script; $uls = $this->_underline; $bFamily = $this->_font_family; $bCharSet = $this->_font_charset; $rgch = $this->_font; $cch = strlen($rgch); $record = 0x31; $length = 0x0F + $cch; $reserved = 0x00; $grbit = 0x00; if ($this->_italic) { $grbit |= 0x02; } if ($this->_font_strikeout) { $grbit |= 0x08; } if ($this->_font_outline) { $grbit |= 0x10; } if ($this->_font_shadow) { $grbit |= 0x20; } $header = pack("vv", $record, $length); $data = pack("vvvvvCCCCC", $dyHeight, $grbit, $icv, $bls, $sss, $uls, $bFamily, $bCharSet, $reserved, $cch); return($header . $data . $this->_font); } /* * Returns a unique hash key for a font. * Used by writeexcel_workbook::_store_all_fonts() */ function get_font_key() { # The following elements are arranged to increase the probability of # generating a unique key. Elements that hold a large range of numbers # eg. _color are placed between two binary elements such as _italic # $key = $this->_font.$this->_size. $this->_font_script.$this->_underline. $this->_font_strikeout.$this->_bold.$this->_font_outline. $this->_font_family.$this->_font_charset. $this->_font_shadow.$this->_color.$this->_italic; $key = preg_replace('/ /', '_', $key); # Convert the key to a single word return $key; } /* * Returns the used by Worksheet->_XF() */ function get_xf_index() { return $this->_xf_index; } /* * Used in conjunction with the set_xxx_color methods to convert a color * string into a number. Color range is 0..63 but we will restrict it * to 8..63 to comply with Gnumeric. Colors 0..7 are repeated in 8..15. */ function _get_color($color=false) { $colors = array( 'aqua' => 0x0F, 'cyan' => 0x0F, 'black' => 0x08, 'blue' => 0x0C, 'brown' => 0x10, 'magenta' => 0x0E, 'fuchsia' => 0x0E, 'gray' => 0x17, 'grey' => 0x17, 'green' => 0x11, 'lime' => 0x0B, 'navy' => 0x12, 'orange' => 0x35, 'purple' => 0x14, 'red' => 0x0A, 'silver' => 0x16, 'white' => 0x09, 'yellow' => 0x0D ); // Return the default color, 0x7FFF, if undef, if ($color===false) { return 0x7FFF; } // or the color string converted to an integer, if (isset($colors[strtolower($color)])) { return $colors[strtolower($color)]; } // or the default color if string is unrecognised, if (preg_match('/\D/', $color)) { return 0x7FFF; } // or an index < 8 mapped into the correct range, if ($color<8) { return $color + 8; } // or the default color if arg is outside range, if ($color>63) { return 0x7FFF; } // or an integer in the valid range return $color; } /* * Set cell alignment. */ function set_align($location) { // Ignore numbers if (preg_match('/\d/', $location)) { return; } $location = strtolower($location); switch ($location) { case 'left': $this->set_text_h_align(1); break; case 'centre': case 'center': $this->set_text_h_align(2); break; case 'right': $this->set_text_h_align(3); break; case 'fill': $this->set_text_h_align(4); break; case 'justify': $this->set_text_h_align(5); break; case 'merge': $this->set_text_h_align(6); break; case 'equal_space': $this->set_text_h_align(7); break; case 'top': $this->set_text_v_align(0); break; case 'vcentre': case 'vcenter': $this->set_text_v_align(1); break; break; case 'bottom': $this->set_text_v_align(2); break; case 'vjustify': $this->set_text_v_align(3); break; case 'vequal_space': $this->set_text_v_align(4); break; } } /* * Set vertical cell alignment. This is required by the set_properties() * method to differentiate between the vertical and horizontal properties. */ function set_valign($location) { $this->set_align($location); } /* * This is an alias for the unintuitive set_align('merge') */ function set_merge() { $this->set_text_h_align(6); } /* * Bold has a range 0x64..0x3E8. * 0x190 is normal. 0x2BC is bold. */ function set_bold($weight=1) { if ($weight == 1) { // Bold text $weight = 0x2BC; } if ($weight == 0) { // Normal text $weight = 0x190; } if ($weight < 0x064) { // Lower bound $weight = 0x190; } if ($weight > 0x3E8) { // Upper bound $weight = 0x190; } $this->_bold = $weight; } /* * Set all cell borders (bottom, top, left, right) to the same style */ function set_border($style) { $this->set_bottom($style); $this->set_top($style); $this->set_left($style); $this->set_right($style); } /* * Set all cell borders (bottom, top, left, right) to the same color */ function set_border_color($color) { $this->set_bottom_color($color); $this->set_top_color($color); $this->set_left_color($color); $this->set_right_color($color); } /* * Convert hashes of properties to method calls. */ function set_properties() { $_=func_get_args(); $properties=array(); foreach($_ as $props) { if (is_array($props)) { $properties=array_merge($properties, $props); } else { $properties[]=$props; } } foreach ($properties as $key=>$value) { // Strip leading "-" from Tk style properties eg. -color => 'red'. $key = preg_replace('/^-/', '', $key); /* Make sure method names are alphanumeric characters only, in case tainted data is passed to the eval(). */ if (preg_match('/\W/', $key)) { trigger_error("Unknown property: $key.", E_USER_ERROR); } /* Evaling all $values as a strings gets around the problem of some numerical format strings being evaluated as numbers, for example "00000" for a zip code. */ if (is_int($key)) { eval("\$this->set_$value();"); } else { eval("\$this->set_$key('$value');"); } } } function set_font($font) { $this->_font=$font; } function set_size($size) { $this->_size=$size; } function set_italic($italic=1) { $this->_italic=$italic; } function set_color($color) { $this->_color=$this->_get_color($color); } function set_underline($underline=1) { $this->_underline=$underline; } function set_font_strikeout($font_strikeout=1) { $this->_font_strikeout=$font_strikeout; } function set_font_outline($font_outline=1) { $this->_font_outline=$font_outline; } function set_font_shadow($font_shadow=1) { $this->_font_shadow=$font_shadow; } function set_font_script($font_script=1) { $this->_font_script=$font_script; } /* Undocumented */ function set_font_family($font_family=1) { $this->_font_family=$font_family; } /* Undocumented */ function set_font_charset($font_charset=1) { $this->_font_charset=$font_charset; } function set_num_format($num_format=1) { $this->_num_format=$num_format; } function set_hidden($hidden=1) { $this->_hidden=$hidden; } function set_locked($locked=1) { $this->_locked=$locked; } function set_text_h_align($align) { $this->_text_h_align=$align; } function set_text_wrap($wrap=1) { $this->_text_wrap=$wrap; } function set_text_v_align($align) { $this->_text_v_align=$align; } function set_text_justlast($text_justlast=1) { $this->_text_justlast=$text_justlast; } function set_rotation($rotation=1) { $this->_rotation=$rotation; } function set_fg_color($color) { $this->_fg_color=$this->_get_color($color); } function set_bg_color($color) { $this->_bg_color=$this->_get_color($color); } function set_pattern($pattern=1) { $this->_pattern=$pattern; } function set_bottom($bottom=1) { $this->_bottom=$bottom; } function set_top($top=1) { $this->_top=$top; } function set_left($left=1) { $this->_left=$left; } function set_right($right=1) { $this->_right=$right; } function set_bottom_color($color) { $this->_bottom_color=$this->_get_color($color); } function set_top_color($color) { $this->_top_color=$this->_get_color($color); } function set_left_color($color) { $this->_left_color=$this->_get_color($color); } function set_right_color($color) { $this->_right_color=$this->_get_color($color); } } ?> gosa-core-2.7.4/include/utils/excel/class.writeexcel_workbook.inc.php0000644000175000017500000011166011010522516024735 0ustar cajuscajuswriteexcel_biffwriter(); $tmp_format = new writeexcel_format(); $byte_order = $this->_byte_order; $parser = new writeexcel_formula($byte_order); $this->_filename = $filename; $this->_parser = $parser; //? $this->_tempdir = undef; $this->_1904 = 0; $this->_activesheet = 0; $this->_firstsheet = 0; $this->_selected = 0; $this->_xf_index = 16; # 15 style XF's and 1 cell XF. $this->_fileclosed = 0; $this->_biffsize = 0; $this->_sheetname = "Sheet"; $this->_tmp_format = $tmp_format; $this->_url_format = false; $this->_worksheets = array(); $this->_sheetnames = array(); $this->_formats = array(); $this->_palette = array(); # Add the default format for hyperlinks $this->_url_format = $this->addformat(array('color' => 'blue', 'underline' => 1)); # Check for a filename if ($this->_filename == '') { //todo: print error return; } # Try to open the named file and see if it throws any errors. # If the filename is a reference it is assumed that it is a valid # filehandle and ignore # //todo # Set colour palette. $this->set_palette_xl97(); } ############################################################################### # # close() # # Calls finalization methods and explicitly close the OLEwriter file # handle. # function close() { # Prevent close() from being called twice. if ($this->_fileclosed) { return; } $this->_store_workbook(); $this->_fileclosed = 1; } //PHPport: method DESTROY deleted ############################################################################### # # sheets() # # An accessor for the _worksheets[] array # # Returns: a list of the worksheet objects in a workbook # function sheets() { return $this->_worksheets; } //PHPport: method worksheets deleted: # This method is now deprecated. Use the sheets() method instead. ############################################################################### # # addworksheet($name) # # Add a new worksheet to the Excel workbook. # TODO: Add accessor for $self->{_sheetname} for international Excel versions. # # Returns: reference to a worksheet object # function addworksheet($name="") { # Check that sheetname is <= 31 chars (Excel limit). if (strlen($name) > 31) { trigger_error("Sheetname $name must be <= 31 chars", E_USER_ERROR); } $index = sizeof($this->_worksheets); $sheetname = $this->_sheetname; if ($name == "") { $name = $sheetname . ($index+1); } # Check that the worksheet name doesn't already exist: a fatal Excel error. foreach ($this->_worksheets as $tmp) { if ($name == $tmp->get_name()) { trigger_error("Worksheet '$name' already exists", E_USER_ERROR); } } $worksheet = new writeexcel_worksheet($name, $index, $this->_activesheet, $this->_firstsheet, $this->_url_format, $this->_parser, $this->_tempdir); $this->_worksheets[$index] = $worksheet; # Store ref for iterator $this->_sheetnames[$index] = $name; # Store EXTERNSHEET names $this->_parser->set_ext_sheet($name, $index); # Store names in Formula.pm return $worksheet; } ############################################################################### # # addformat(%properties) # # Add a new format to the Excel workbook. This adds an XF record and # a FONT record. Also, pass any properties to the Format::new(). # function addformat($para=false) { if($para===false) { $format = new writeexcel_format($this->_xf_index); } else { $format = new writeexcel_format($this->_xf_index, $para); } $this->_xf_index += 1; # Store format reference $this->_formats[]=$format; return $format; } ############################################################################### # # set_1904() # # Set the date system: 0 = 1900 (the default), 1 = 1904 # function set_1904($_1904) { $this->_1904 = $_1904; } ############################################################################### # # get_1904() # # Return the date system: 0 = 1900, 1 = 1904 # function get_1904() { return $this->_1904; } ############################################################################### # # set_custom_color() # # Change the RGB components of the elements in the colour palette. # function set_custom_color($index, $red, $green, $blue) { // todo /* # Match a HTML #xxyyzz style parameter if (defined $_[1] and $_[1] =~ /^#(\w\w)(\w\w)(\w\w)/ ) { @_ = ($_[0], hex $1, hex $2, hex $3); } */ $aref = $this->_palette; # Check that the colour index is the right range if ($index < 8 or $index > 64) { //todo carp "Color index $index outside range: 8 <= index <= 64"; return; } # Check that the colour components are in the right range if ( ($red < 0 || $red > 255) || ($green < 0 || $green > 255) || ($blue < 0 || $blue > 255) ) { //todo carp "Color component outside range: 0 <= color <= 255"; return; } $index -=8; # Adjust colour index (wingless dragonfly) # Set the RGB value $aref[$index] = array($red, $green, $blue, 0); return $index +8; } ############################################################################### # # set_palette_xl97() # # Sets the colour palette to the Excel 97+ default. # function set_palette_xl97() { $this->_palette = array( array(0x00, 0x00, 0x00, 0x00), # 8 array(0xff, 0xff, 0xff, 0x00), # 9 array(0xff, 0x00, 0x00, 0x00), # 10 array(0x00, 0xff, 0x00, 0x00), # 11 array(0x00, 0x00, 0xff, 0x00), # 12 array(0xff, 0xff, 0x00, 0x00), # 13 array(0xff, 0x00, 0xff, 0x00), # 14 array(0x00, 0xff, 0xff, 0x00), # 15 array(0x80, 0x00, 0x00, 0x00), # 16 array(0x00, 0x80, 0x00, 0x00), # 17 array(0x00, 0x00, 0x80, 0x00), # 18 array(0x80, 0x80, 0x00, 0x00), # 19 array(0x80, 0x00, 0x80, 0x00), # 20 array(0x00, 0x80, 0x80, 0x00), # 21 array(0xc0, 0xc0, 0xc0, 0x00), # 22 array(0x80, 0x80, 0x80, 0x00), # 23 array(0x99, 0x99, 0xff, 0x00), # 24 array(0x99, 0x33, 0x66, 0x00), # 25 array(0xff, 0xff, 0xcc, 0x00), # 26 array(0xcc, 0xff, 0xff, 0x00), # 27 array(0x66, 0x00, 0x66, 0x00), # 28 array(0xff, 0x80, 0x80, 0x00), # 29 array(0x00, 0x66, 0xcc, 0x00), # 30 array(0xcc, 0xcc, 0xff, 0x00), # 31 array(0x00, 0x00, 0x80, 0x00), # 32 array(0xff, 0x00, 0xff, 0x00), # 33 array(0xff, 0xff, 0x00, 0x00), # 34 array(0x00, 0xff, 0xff, 0x00), # 35 array(0x80, 0x00, 0x80, 0x00), # 36 array(0x80, 0x00, 0x00, 0x00), # 37 array(0x00, 0x80, 0x80, 0x00), # 38 array(0x00, 0x00, 0xff, 0x00), # 39 array(0x00, 0xcc, 0xff, 0x00), # 40 array(0xcc, 0xff, 0xff, 0x00), # 41 array(0xcc, 0xff, 0xcc, 0x00), # 42 array(0xff, 0xff, 0x99, 0x00), # 43 array(0x99, 0xcc, 0xff, 0x00), # 44 array(0xff, 0x99, 0xcc, 0x00), # 45 array(0xcc, 0x99, 0xff, 0x00), # 46 array(0xff, 0xcc, 0x99, 0x00), # 47 array(0x33, 0x66, 0xff, 0x00), # 48 array(0x33, 0xcc, 0xcc, 0x00), # 49 array(0x99, 0xcc, 0x00, 0x00), # 50 array(0xff, 0xcc, 0x00, 0x00), # 51 array(0xff, 0x99, 0x00, 0x00), # 52 array(0xff, 0x66, 0x00, 0x00), # 53 array(0x66, 0x66, 0x99, 0x00), # 54 array(0x96, 0x96, 0x96, 0x00), # 55 array(0x00, 0x33, 0x66, 0x00), # 56 array(0x33, 0x99, 0x66, 0x00), # 57 array(0x00, 0x33, 0x00, 0x00), # 58 array(0x33, 0x33, 0x00, 0x00), # 59 array(0x99, 0x33, 0x00, 0x00), # 60 array(0x99, 0x33, 0x66, 0x00), # 61 array(0x33, 0x33, 0x99, 0x00), # 62 array(0x33, 0x33, 0x33, 0x00), # 63 ); return 0; } ############################################################################### # # set_palette_xl5() # # Sets the colour palette to the Excel 5 default. # function set_palette_xl5() { $this->_palette = array( array(0x00, 0x00, 0x00, 0x00), # 8 array(0xff, 0xff, 0xff, 0x00), # 9 array(0xff, 0x00, 0x00, 0x00), # 10 array(0x00, 0xff, 0x00, 0x00), # 11 array(0x00, 0x00, 0xff, 0x00), # 12 array(0xff, 0xff, 0x00, 0x00), # 13 array(0xff, 0x00, 0xff, 0x00), # 14 array(0x00, 0xff, 0xff, 0x00), # 15 array(0x80, 0x00, 0x00, 0x00), # 16 array(0x00, 0x80, 0x00, 0x00), # 17 array(0x00, 0x00, 0x80, 0x00), # 18 array(0x80, 0x80, 0x00, 0x00), # 19 array(0x80, 0x00, 0x80, 0x00), # 20 array(0x00, 0x80, 0x80, 0x00), # 21 array(0xc0, 0xc0, 0xc0, 0x00), # 22 array(0x80, 0x80, 0x80, 0x00), # 23 array(0x80, 0x80, 0xff, 0x00), # 24 array(0x80, 0x20, 0x60, 0x00), # 25 array(0xff, 0xff, 0xc0, 0x00), # 26 array(0xa0, 0xe0, 0xe0, 0x00), # 27 array(0x60, 0x00, 0x80, 0x00), # 28 array(0xff, 0x80, 0x80, 0x00), # 29 array(0x00, 0x80, 0xc0, 0x00), # 30 array(0xc0, 0xc0, 0xff, 0x00), # 31 array(0x00, 0x00, 0x80, 0x00), # 32 array(0xff, 0x00, 0xff, 0x00), # 33 array(0xff, 0xff, 0x00, 0x00), # 34 array(0x00, 0xff, 0xff, 0x00), # 35 array(0x80, 0x00, 0x80, 0x00), # 36 array(0x80, 0x00, 0x00, 0x00), # 37 array(0x00, 0x80, 0x80, 0x00), # 38 array(0x00, 0x00, 0xff, 0x00), # 39 array(0x00, 0xcf, 0xff, 0x00), # 40 array(0x69, 0xff, 0xff, 0x00), # 41 array(0xe0, 0xff, 0xe0, 0x00), # 42 array(0xff, 0xff, 0x80, 0x00), # 43 array(0xa6, 0xca, 0xf0, 0x00), # 44 array(0xdd, 0x9c, 0xb3, 0x00), # 45 array(0xb3, 0x8f, 0xee, 0x00), # 46 array(0xe3, 0xe3, 0xe3, 0x00), # 47 array(0x2a, 0x6f, 0xf9, 0x00), # 48 array(0x3f, 0xb8, 0xcd, 0x00), # 49 array(0x48, 0x84, 0x36, 0x00), # 50 array(0x95, 0x8c, 0x41, 0x00), # 51 array(0x8e, 0x5e, 0x42, 0x00), # 52 array(0xa0, 0x62, 0x7a, 0x00), # 53 array(0x62, 0x4f, 0xac, 0x00), # 54 array(0x96, 0x96, 0x96, 0x00), # 55 array(0x1d, 0x2f, 0xbe, 0x00), # 56 array(0x28, 0x66, 0x76, 0x00), # 57 array(0x00, 0x45, 0x00, 0x00), # 58 array(0x45, 0x3e, 0x01, 0x00), # 59 array(0x6a, 0x28, 0x13, 0x00), # 60 array(0x85, 0x39, 0x6a, 0x00), # 61 array(0x4a, 0x32, 0x85, 0x00), # 62 array(0x42, 0x42, 0x42, 0x00), # 63 ); return 0; } ############################################################################### # # set_tempdir() # # Change the default temp directory used by _initialize() in Worksheet.pm. # function set_tempdir($tempdir) { //todo /* croak "$_[0] is not a valid directory" unless -d $_[0]; croak "set_tempdir must be called before addworksheet" if $self->sheets(); */ $this->_tempdir = $tempdir; } ############################################################################### # # _store_workbook() # # Assemble worksheets into a workbook and send the BIFF data to an OLE # storage. # function _store_workbook() { # Ensure that at least one worksheet has been selected. if ($this->_activesheet == 0) { $this->_worksheets[0]->_selected = 1; } # Calculate the number of selected worksheet tabs and call the finalization # methods for each worksheet for ($c=0;$c_worksheets);$c++) { $sheet=$this->_worksheets[$c]; if ($sheet->_selected) { $this->_selected++; } $sheet->_close($this->_sheetnames); } # Add Workbook globals $this->_store_bof(0x0005); $this->_store_externs(); # For print area and repeat rows $this->_store_names(); # For print area and repeat rows $this->_store_window1(); $this->_store_1904(); $this->_store_all_fonts(); $this->_store_all_num_formats(); $this->_store_all_xfs(); $this->_store_all_styles(); $this->_store_palette(); $this->_calc_sheet_offsets(); # Add BOUNDSHEET records for ($c=0;$c_worksheets);$c++) { $sheet=$this->_worksheets[$c]; $this->_store_boundsheet($sheet->_name, $sheet->_offset); } # End Workbook globals $this->_store_eof(); # Store the workbook in an OLE container $this->_store_OLE_file(); } ############################################################################### # # _store_OLE_file() # # Store the workbook in an OLE container if the total size of the workbook data # is less than ~ 7MB. # function _store_OLE_file() { ## ABR if ($this->_tmpfilename != '') { $OLE = new writeexcel_olewriter(CACHE_DIR.'/tmp/'.$this->_tmpfilename); $OLE->_OLEtmpfilename = CACHE_DIR.$this->_tmpfilename; } else { $OLE = new writeexcel_olewriter($this->_filename); $OLE->_OLEtmpfilename = ''; }; ## END ABR # Write Worksheet data if data <~ 7MB if ($OLE->set_size($this->_biffsize)) { $OLE->write_header(); $OLE->write($this->_data); for ($c=0;$c_worksheets);$c++) { $sheet=$this->_worksheets[$c]; while ($tmp = $sheet->get_data()) { $OLE->write($tmp); } } } $OLE->close(); } ############################################################################### # # _calc_sheet_offsets() # # Calculate offsets for Worksheet BOF records. # function _calc_sheet_offsets() { $BOF = 11; $EOF = 4; $offset = $this->_datasize; foreach ($this->_worksheets as $sheet) { $offset += $BOF + strlen($sheet->_name); } $offset += $EOF; for ($c=0;$c_worksheets);$c++) { $sheet=$this->_worksheets[$c]; $sheet->_offset = $offset; $offset += $sheet->_datasize; } $this->_biffsize = $offset; } ############################################################################### # # _store_all_fonts() # # Store the Excel FONT records. # function _store_all_fonts() { # _tmp_format is added by new(). We use this to write the default XF's $format = $this->_tmp_format; $font = $format->get_font(); # Note: Fonts are 0-indexed. According to the SDK there is no index 4, # so the following fonts are 0, 1, 2, 3, 5 # for ($c=0;$c<5;$c++) { $this->_append($font); } # Iterate through the XF objects and write a FONT record if it isn't the # same as the default FONT and if it hasn't already been used. # $index = 6; # The first user defined FONT $key = $format->get_font_key(); # The default font from _tmp_format $fonts[$key] = 0; # Index of the default font for ($c=0;$c_formats);$c++) { $format=$this->_formats[$c]; $key = $format->get_font_key(); if (isset($fonts[$key])) { # FONT has already been used $format->_font_index = $fonts[$key]; } else { # Add a new FONT record $fonts[$key] = $index; $format->_font_index = $index; $index++; $font = $format->get_font(); $this->_append($font); } } } ############################################################################### # # _store_all_num_formats() # # Store user defined numerical formats i.e. FORMAT records # function _store_all_num_formats() { # Leaning num_format syndrome $num_formats_list=array(); $index = 164; # Iterate through the XF objects and write a FORMAT record if it isn't a # built-in format type and if the FORMAT string hasn't already been used. # for ($c=0;$c_formats);$c++) { $format=$this->_formats[$c]; $num_format = $format->_num_format; # Check if $num_format is an index to a built-in format. # Also check for a string of zeros, which is a valid format string # but would evaluate to zero. # if (!preg_match('/^0+\d/', $num_format)) { if (preg_match('/^\d+$/', $num_format)) { # built-in continue; } } if (isset($num_formats[$num_format])) { # FORMAT has already been used $format->_num_format = $num_formats[$num_format]; } else { # Add a new FORMAT $num_formats[$num_format] = $index; $format->_num_format = $index; array_push($num_formats_list, $num_format); $index++; } } # Write the new FORMAT records starting from 0xA4 $index = 164; foreach ($num_formats_list as $num_format) { $this->_store_num_format($num_format, $index); $index++; } } ############################################################################### # # _store_all_xfs() # # Write all XF records. # function _store_all_xfs() { # _tmp_format is added by new(). We use this to write the default XF's # The default font index is 0 # $format = $this->_tmp_format; $xf; for ($c=0;$c<15;$c++) { $xf = $format->get_xf('style'); # Style XF $this->_append($xf); } $xf = $format->get_xf('cell'); # Cell XF $this->_append($xf); # User defined XFs foreach ($this->_formats as $format) { $xf = $format->get_xf('cell'); $this->_append($xf); } } ############################################################################### # # _store_all_styles() # # Write all STYLE records. # function _store_all_styles() { $this->_store_style(); } ############################################################################### # # _store_externs() # # Write the EXTERNCOUNT and EXTERNSHEET records. These are used as indexes for # the NAME records. # function _store_externs() { # Create EXTERNCOUNT with number of worksheets $this->_store_externcount(sizeof($this->_worksheets)); # Create EXTERNSHEET for each worksheet foreach ($this->_sheetnames as $sheetname) { $this->_store_externsheet($sheetname); } } ############################################################################### # # _store_names() # # Write the NAME record to define the print area and the repeat rows and cols. # function _store_names() { # Create the print area NAME records foreach ($this->_worksheets as $worksheet) { # Write a Name record if the print area has been defined if ($worksheet->_print_rowmin!==false) { $this->_store_name_short( $worksheet->_index, 0x06, # NAME type $worksheet->_print_rowmin, $worksheet->_print_rowmax, $worksheet->_print_colmin, $worksheet->_print_colmax ); } } # Create the print title NAME records foreach ($this->_worksheets as $worksheet) { $rowmin = $worksheet->_title_rowmin; $rowmax = $worksheet->_title_rowmax; $colmin = $worksheet->_title_colmin; $colmax = $worksheet->_title_colmax; # Determine if row + col, row, col or nothing has been defined # and write the appropriate record # if ($rowmin!==false && $colmin!==false) { # Row and column titles have been defined. # Row title has been defined. $this->_store_name_long( $worksheet->_index, 0x07, # NAME type $rowmin, $rowmax, $colmin, $colmax ); } elseif ($rowmin!==false) { # Row title has been defined. $this->_store_name_short( $worksheet->_index, 0x07, # NAME type $rowmin, $rowmax, 0x00, 0xff ); } elseif ($colmin!==false) { # Column title has been defined. $this->_store_name_short( $worksheet->_index, 0x07, # NAME type 0x0000, 0x3fff, $colmin, $colmax ); } else { # Print title hasn't been defined. } } } ############################################################################### ############################################################################### # # BIFF RECORDS # ############################################################################### # # _store_window1() # # Write Excel BIFF WINDOW1 record. # function _store_window1() { $record = 0x003D; # Record identifier $length = 0x0012; # Number of bytes to follow $xWn = 0x0000; # Horizontal position of window $yWn = 0x0000; # Vertical position of window $dxWn = 0x25BC; # Width of window $dyWn = 0x1572; # Height of window $grbit = 0x0038; # Option flags $ctabsel = $this->_selected; # Number of workbook tabs selected $wTabRatio = 0x0258; # Tab to scrollbar ratio $itabFirst = $this->_firstsheet; # 1st displayed worksheet $itabCur = $this->_activesheet; # Active worksheet $header = pack("vv", $record, $length); $data = pack("vvvvvvvvv", $xWn, $yWn, $dxWn, $dyWn, $grbit, $itabCur, $itabFirst, $ctabsel, $wTabRatio); $this->_append($header . $data); } ############################################################################### # # _store_boundsheet() # # Writes Excel BIFF BOUNDSHEET record. # function _store_boundsheet($sheetname, $offset) { $record = 0x0085; # Record identifier $length = 0x07 + strlen($sheetname); # Number of bytes to follow //$sheetname = $_[0]; # Worksheet name //$offset = $_[1]; # Location of worksheet BOF $grbit = 0x0000; # Sheet identifier $cch = strlen($sheetname); # Length of sheet name $header = pack("vv", $record, $length); $data = pack("VvC", $offset, $grbit, $cch); $this->_append($header . $data . $sheetname); } ############################################################################### # # _store_style() # # Write Excel BIFF STYLE records. # function _store_style() { $record = 0x0293; # Record identifier $length = 0x0004; # Bytes to follow $ixfe = 0x8000; # Index to style XF $BuiltIn = 0x00; # Built-in style $iLevel = 0xff; # Outline style level $header = pack("vv", $record, $length); $data = pack("vCC", $ixfe, $BuiltIn, $iLevel); $this->_append($header . $data); } ############################################################################### # # _store_num_format() # # Writes Excel FORMAT record for non "built-in" numerical formats. # function _store_num_format($num_format, $index) { $record = 0x041E; # Record identifier $length = 0x03 + strlen($num_format); # Number of bytes to follow $format = $num_format; # Custom format string $ifmt = $index; # Format index code $cch = strlen($format); # Length of format string $header = pack("vv", $record, $length); $data = pack("vC", $ifmt, $cch); $this->_append($header . $data . $format); } ############################################################################### # # _store_1904() # # Write Excel 1904 record to indicate the date system in use. # function _store_1904() { $record = 0x0022; # Record identifier $length = 0x0002; # Bytes to follow $f1904 = $this->_1904; # Flag for 1904 date system $header = pack("vv", $record, $length); $data = pack("v", $f1904); $this->_append($header . $data); } ############################################################################### # # _store_externcount($count) # # Write BIFF record EXTERNCOUNT to indicate the number of external sheet # references in the workbook. # # Excel only stores references to external sheets that are used in NAME. # The workbook NAME record is required to define the print area and the repeat # rows and columns. # # A similar method is used in Worksheet.pm for a slightly different purpose. # function _store_externcount($par0) { $record = 0x0016; # Record identifier $length = 0x0002; # Number of bytes to follow $cxals = $par0; # Number of external references $header = pack("vv", $record, $length); $data = pack("v", $cxals); $this->_append($header . $data); } ############################################################################### # # _store_externsheet($sheetname) # # # Writes the Excel BIFF EXTERNSHEET record. These references are used by # formulas. NAME record is required to define the print area and the repeat # rows and columns. # # A similar method is used in Worksheet.pm for a slightly different purpose. # function _store_externsheet($par0) { $record = 0x0017; # Record identifier $length = 0x02 + strlen($par0); # Number of bytes to follow $sheetname = $par0; # Worksheet name $cch = strlen($sheetname); # Length of sheet name $rgch = 0x03; # Filename encoding $header = pack("vv", $record, $length); $data = pack("CC", $cch, $rgch); $this->_append($header . $data . $sheetname); } ############################################################################### # # _store_name_short() # # # Store the NAME record in the short format that is used for storing the print # area, repeat rows only and repeat columns only. # function _store_name_short($par0, $par1, $par2, $par3, $par4, $par5) { $record = 0x0018; # Record identifier $length = 0x0024; # Number of bytes to follow $index = $par0; # Sheet index $type = $par1; $grbit = 0x0020; # Option flags $chKey = 0x00; # Keyboard shortcut $cch = 0x01; # Length of text name $cce = 0x0015; # Length of text definition $ixals = $index +1; # Sheet index $itab = $ixals; # Equal to ixals $cchCustMenu = 0x00; # Length of cust menu text $cchDescription = 0x00; # Length of description text $cchHelptopic = 0x00; # Length of help topic text $cchStatustext = 0x00; # Length of status bar text $rgch = $type; # Built-in name type $unknown03 = 0x3b; $unknown04 = 0xffff-$index; $unknown05 = 0x0000; $unknown06 = 0x0000; $unknown07 = 0x1087; $unknown08 = 0x8005; $rowmin = $par2; # Start row $rowmax = $par3; # End row $colmin = $par4; # Start column $colmax = $par5; # end column $header = pack("vv", $record, $length); $data = pack("v", $grbit); $data .= pack("C", $chKey); $data .= pack("C", $cch); $data .= pack("v", $cce); $data .= pack("v", $ixals); $data .= pack("v", $itab); $data .= pack("C", $cchCustMenu); $data .= pack("C", $cchDescription); $data .= pack("C", $cchHelptopic); $data .= pack("C", $cchStatustext); $data .= pack("C", $rgch); $data .= pack("C", $unknown03); $data .= pack("v", $unknown04); $data .= pack("v", $unknown05); $data .= pack("v", $unknown06); $data .= pack("v", $unknown07); $data .= pack("v", $unknown08); $data .= pack("v", $index); $data .= pack("v", $index); $data .= pack("v", $rowmin); $data .= pack("v", $rowmax); $data .= pack("C", $colmin); $data .= pack("C", $colmax); $this->_append($header . $data); } ############################################################################### # # _store_name_long() # # # Store the NAME record in the long format that is used for storing the repeat # rows and columns when both are specified. This share a lot of code with # _store_name_short() but we use a separate method to keep the code clean. # Code abstraction for reuse can be carried too far, and I should know. ;-) # function _store_name_long($par0, $par1, $par2, $par3, $par4, $par5) { $record = 0x0018; # Record identifier $length = 0x003d; # Number of bytes to follow $index = $par0; # Sheet index $type = $par1; $grbit = 0x0020; # Option flags $chKey = 0x00; # Keyboard shortcut $cch = 0x01; # Length of text name $cce = 0x002e; # Length of text definition $ixals = $index +1; # Sheet index $itab = $ixals; # Equal to ixals $cchCustMenu = 0x00; # Length of cust menu text $cchDescription = 0x00; # Length of description text $cchHelptopic = 0x00; # Length of help topic text $cchStatustext = 0x00; # Length of status bar text $rgch = $type; # Built-in name type $unknown01 = 0x29; $unknown02 = 0x002b; $unknown03 = 0x3b; $unknown04 = 0xffff-$index; $unknown05 = 0x0000; $unknown06 = 0x0000; $unknown07 = 0x1087; $unknown08 = 0x8008; $rowmin = $par2; # Start row $rowmax = $par3; # End row $colmin = $par4; # Start column $colmax = $par5; # end column $header = pack("vv", $record, $length); $data = pack("v", $grbit); $data .= pack("C", $chKey); $data .= pack("C", $cch); $data .= pack("v", $cce); $data .= pack("v", $ixals); $data .= pack("v", $itab); $data .= pack("C", $cchCustMenu); $data .= pack("C", $cchDescription); $data .= pack("C", $cchHelptopic); $data .= pack("C", $cchStatustext); $data .= pack("C", $rgch); $data .= pack("C", $unknown01); $data .= pack("v", $unknown02); # Column definition $data .= pack("C", $unknown03); $data .= pack("v", $unknown04); $data .= pack("v", $unknown05); $data .= pack("v", $unknown06); $data .= pack("v", $unknown07); $data .= pack("v", $unknown08); $data .= pack("v", $index); $data .= pack("v", $index); $data .= pack("v", 0x0000); $data .= pack("v", 0x3fff); $data .= pack("C", $colmin); $data .= pack("C", $colmax); # Row definition $data .= pack("C", $unknown03); $data .= pack("v", $unknown04); $data .= pack("v", $unknown05); $data .= pack("v", $unknown06); $data .= pack("v", $unknown07); $data .= pack("v", $unknown08); $data .= pack("v", $index); $data .= pack("v", $index); $data .= pack("v", $rowmin); $data .= pack("v", $rowmax); $data .= pack("C", 0x00); $data .= pack("C", 0xff); # End of data $data .= pack("C", 0x10); $this->_append($header . $data); } ############################################################################### # # _store_palette() # # Stores the PALETTE biff record. # function _store_palette() { $aref = $this->_palette; $record = 0x0092; # Record identifier $length = 2 + 4 * sizeof($aref); # Number of bytes to follow $ccv = sizeof($aref); # Number of RGB values to follow //$data; # The RGB data # Pack the RGB data foreach($aref as $dat) { $data .= call_user_func_array('pack', array_merge(array("CCCC"), $dat)); } $header = pack("vvv", $record, $length, $ccv); $this->_append($header . $data); } } ?> gosa-core-2.7.4/include/utils/class_timezone.inc0000644000175000017500000000473611370241175020707 0ustar cajuscajus "unconfigured", "value" => 0); /* Use current timestamp if $stamp is not set */ if($stamp === NULL){ $stamp = time(); } /* Is there a timezone configured in the gosa configuration (gosa.conf) */ if ($config->get_cfg_value("core","timezone") != ""){ /* Get zonename */ $tz = $config->get_cfg_value("core","timezone"); if(!@date_default_timezone_set($tz)){ msg_dialog::display(_("Configuration error"), sprintf(_("The configured timezone %s is not valid!"), bold($tz)), ERROR_DIALOG); } $tz_delta = date("Z", $stamp); $tz_delta = $tz_delta / 3600 ; return(array("name" => $tz, "value" => $tz_delta)); } return($zone); } /* Return zone informations */ static public function _get_tz_zones() { $timezone_identifiers = DateTimeZone::listIdentifiers(); $timezones = array(); $zones = DateTimeZone::listAbbreviations(); foreach($zones as $group){ foreach($group as $zone) { $timezones[$zone['timezone_id']] = $zone['offset']; if($zone['dst']){ $dst_timezones[$zone['timezone_id']] = 1; } } } return(array("TIMEZONES" => @$timezones, "DST_ZONES" => @$dst_timezones)); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/utils/class_xml.inc0000644000175000017500000001713111613731145017647 0ustar cajuscajusload($file); if (!$xml->schemaValidate($schema)) { $errors = libxml_get_errors(); foreach ($errors as $error) { $estr= ""; switch ($error->level) { case LIBXML_ERR_WARNING: $estr= _("Warning")." ".$error->code.":"; break; case LIBXML_ERR_ERROR: $estr= _("Error")." ".$error->code.":"; break; case LIBXML_ERR_FATAL: $estr= _("Fatal error")." ".$error->code.":"; break; } if ($error->file) { $str= sprintf("%s %s in %s", $estr, trim($error->message), $error->file); } else { $str= sprintf("%s %s in %s on line %s", $estr, trim($error->message), $error->file, $error->line); } msg_dialog::display(_("XML error"), $str, ERROR_DIALOG); } libxml_clear_errors(); } } static function xml2array($contents, $get_attributes=1, $priority = 'tag') { if(!$contents) return array(); if(!function_exists('xml_parser_create')) { //print "'xml_parser_create()' function not found!"; return array(); } //Get the XML parser of PHP - PHP must have this module for the parser to work $parser = xml_parser_create(''); xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); # http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0); xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1); xml_parse_into_struct($parser, trim($contents), $xml_values); xml_parser_free($parser); if(!$xml_values) return;//Hmm... //Initializations $xml_array = array(); $parents = array(); $opened_tags = array(); $arr = array(); $current = &$xml_array; //Refference //Go through the tags. $repeated_tag_index = array();//Multiple tags with same name will be turned into an array foreach($xml_values as $data) { unset($attributes,$value);//Remove existing values, or there will be trouble //This command will extract these variables into the foreach scope // tag(string), type(string), level(int), attributes(array). extract($data);//We could use the array by itself, but this cooler. $result = array(); $attributes_data = array(); if(isset($value)) { if($priority == 'tag') $result = $value; else $result['value'] = $value; //Put the value in a assoc array if we are in the 'Attribute' mode } //Set the attributes too. if(isset($attributes) and $get_attributes) { foreach($attributes as $attr => $val) { if($priority == 'tag') $attributes_data[$attr] = $val; else $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr' } } //See tag status and do the needed. if($type == "open") {//The starting of the tag '' $parent[$level-1] = &$current; if(!is_array($current) or (!in_array_strict($tag, array_keys($current)))) { //Insert New tag $current[$tag] = $result; if($attributes_data) $current[$tag. '_attr'] = $attributes_data; $repeated_tag_index[$tag.'_'.$level] = 1; $current = &$current[$tag]; } else { //There was another element with the same tag name if(isset($current[$tag][0])) {//If there is a 0th element it is already an array $current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result; $repeated_tag_index[$tag.'_'.$level]++; } else {//This section will make the value an array if multiple tags with the same name appear together $current[$tag] = array($current[$tag],$result);//This will combine the existing item and the new item together to make an array $repeated_tag_index[$tag.'_'.$level] = 2; if(isset($current[$tag.'_attr'])) { //The attribute of the last(0th) tag must be moved as well $current[$tag]['0_attr'] = $current[$tag.'_attr']; unset($current[$tag.'_attr']); } } $last_item_index = $repeated_tag_index[$tag.'_'.$level]-1; $current = &$current[$tag][$last_item_index]; } } elseif($type == "complete") { //Tags that ends in 1 line '' //See if the key is already taken. if(!isset($current[$tag])) { //New Key $current[$tag] = $result; $repeated_tag_index[$tag.'_'.$level] = 1; if($priority == 'tag' and $attributes_data) $current[$tag. '_attr'] = $attributes_data; } else { //If taken, put all things inside a list(array) if(isset($current[$tag][0]) and is_array($current[$tag])) {//If it is already an array... // ...push the new element into that array. $current[$tag][$repeated_tag_index[$tag.'_'.$level]] = $result; if($priority == 'tag' and $get_attributes and $attributes_data) { $current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data; } $repeated_tag_index[$tag.'_'.$level]++; } else { //If it is not an array... $current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value $repeated_tag_index[$tag.'_'.$level] = 1; if($priority == 'tag' and $get_attributes) { if(isset($current[$tag.'_attr'])) { //The attribute of the last(0th) tag must be moved as well $current[$tag]['0_attr'] = $current[$tag.'_attr']; unset($current[$tag.'_attr']); } if($attributes_data) { $current[$tag][$repeated_tag_index[$tag.'_'.$level] . '_attr'] = $attributes_data; } } $repeated_tag_index[$tag.'_'.$level]++; //0 and 1 index is already taken } } } elseif($type == 'close') { //End of tag '' $current = &$parent[$level-1]; } } return($xml_array); } } gosa-core-2.7.4/include/utils/class_tests.inc0000644000175000017500000002556011725072237020222 0ustar cajuscajus= 255){ $reason = 1; return(FALSE); } # Check hostname length if(strlen(preg_replace("/\..*$/", "", $str)) > 63){ $reason = 2; return(FALSE); } # Split host and domain part $tmp = preg_split("/\./", $str, 2); $host = $tmp[0]; $domain = count($tmp) == 1 ? NULL : $tmp[1]; if(!preg_match("/^{$regex}*$/i", $host)){ $reason = 3; return(FALSE); } if ($domain) { $regex = "[a-z0-9\.\-_]"; if(!preg_match("/^{$regex}*$/i", $domain)){ $reason = 4; return(FALSE); } } return(TRUE); } /*! \brief Test if the given string is an URL */ public static function is_url($url) { if ($url == ""){ return (TRUE); } return preg_match ("/^(http|https):\/\/((?:[a-zA-Z0-9_-]+\.?)+):?(\d*)/", $url); } /*! \brief Test if the given string is a DN */ public static function is_dn($dn) { if ($dn == ""){ return (TRUE); } return preg_match ("/^[a-z0-9 _-]+$/i", $dn); } /*! \brief Test if the given string is an uid */ public static function is_uid($uid) { if ($uid == ""){ return (TRUE); } /* STRICT adds spaces and case insenstivity to the uid check. This is dangerous and should not be used. */ if (strict_uid_mode()){ return preg_match ("/^[a-z0-9_-]+$/", $uid); } else { return preg_match ("/^[a-z0-9 _.-]+$/i", $uid); } } /*! \brief Test if the given string is an IP */ public static function is_ip($ip) { if(function_exists('filter_var')) { return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4); } else { return preg_match("/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/", $ip); } } public static function is_ipv6($ip) { if(function_exists('filter_var')) { return filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6); } else { $ipv4 = '(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)'; $g = '([0-9a-f]{1,4})'; //IPv6 group return preg_match("/^$g:$g:$g:$g:$g:$g:$g:$g$/", $ip) || preg_match("/^$g:$g:$g:$g:$g:$g:$ipv4$/", $ip); } } /*! \brief Test if the given string is a mac address */ public static function is_mac($mac) { return preg_match("/^[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]:[a-f0-9][a-f0-9]$/i", $mac); } /*! \brief Checks if the given ip address dosen't match "is_ip" because there is also a sub net mask given */ public static function is_ip_with_subnetmask($ip) { /* Generate list of valid submasks */ $res = array(); for($e = 0 ; $e <= 32; $e++){ $res[$e] = $e; } $i[0] =255; $i[1] =255; $i[2] =255; $i[3] =255; for($a= 3 ; $a >= 0 ; $a --){ $c = 1; while($i[$a] > 0 ){ $str = $i[0].".".$i[1].".".$i[2].".".$i[3]; $res[$str] = $str; $i[$a] -=$c; $c = 2*$c; } } $res["0.0.0.0"] = "0.0.0.0"; if(preg_match("/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.". "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.". "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.". "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/", $ip)){ $mask = preg_replace("/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.". "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.". "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.". "(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/","",$ip); $mask = preg_replace("/^\//","",$mask); if((in_array_strict("$mask",$res)) && preg_match("/^[0-9\.]/",$mask)){ return(TRUE); } } return(FALSE); } /*! \brief Simple is domain check * * This checks if the given string looks like "string(...).string" */ public static function is_domain($str) { return(preg_match("/^(([a-z0-9\-]{2,63})\.)*[a-z]{2,63}$/i",$str)); } /*! \brief Check if the given argument is an id */ public static function is_id($id) { if ($id == ""){ return (FALSE); } return preg_match ("/^[0-9]+$/", $id); } /*! \brief Check if the given argument is a path */ public static function is_path($path) { if ($path == ""){ return (TRUE); } if (!preg_match('/^[a-z0-9%\/_.+-]+$/i', $path)){ return (FALSE); } return preg_match ("/\/.+$/", $path); } /*! \brief Check if the given argument is an email */ public static function is_email($address, $template= FALSE) { if ($address == ""){ return (TRUE); } if ($template){ return preg_match ("/^[._a-z0-9{\[\]}%\+-]+@[_a-{}\[\]%z0-9-]+(\.[a-z0-9-]+)(\.[a-z0-9-]+)*$/i", $address); } else { return preg_match ("/^[._a-z0-9\+-]+@[_a-z0-9-]+(\.[a-z0-9i-]+)(\.[a-z0-9-]+)*$/i", $address); } } /* \brief Check if the given department name is valid */ public static function is_department_name_reserved($name,$base) { $reservedName = array("systems","apps","incomming","internal","accounts","fax","addressbook", preg_replace("/ou=(.*),/","\\1",get_people_ou()), preg_replace("/ou=(.*),/","\\1",get_groups_ou())); $follwedNames['/ou=fai,ou=configs,ou=systems,/'] = array("fai","hooks","templates","scripts","disk","packages","variables","profiles"); /* Check if name is one of the reserved names */ if(in_array_ics($name,$reservedName)) { return(true); } /* Check all follow combinations if name is in array && parent base == array_key, return false*/ foreach($follwedNames as $key => $names){ if((in_array_ics($name,$names)) && (preg_match($key,$base))){ return(true); } } return(false); } /* \brief Check if $ip1 and $ip2 represents a valid IP range * \return TRUE in case of a valid range, FALSE in case of an error. */ public static function is_ip_range($ip1,$ip2) { if(!tests::is_ip($ip1) || !tests::is_ip($ip2)){ return(FALSE); }else{ $ar1 = explode(".",$ip1); $var1 = $ar1[0] * (16777216) + $ar1[1] * (65536) + $ar1[2] * (256) + $ar1[3]; $ar2 = explode(".",$ip2); $var2 = $ar2[0] * (16777216) + $ar2[1] * (65536) + $ar2[2] * (256) + $ar2[3]; return($var1 < $var2); } } /* \brief Check if the specified IP address $address is inside the given network */ public static function is_in_network($network, $netmask, $address) { $nw= explode('.', $network); $nm= explode('.', $netmask); $ad= explode('.', $address); /* Generate inverted netmask */ for ($i= 0; $i<4; $i++){ $ni[$i]= 255-$nm[$i]; $la[$i]= $nw[$i] | $ni[$i]; } /* Transform to integer */ $first= $nw[0] * (16777216) + $nw[1] * (65536) + $nw[2] * (256) + $nw[3]; $curr= $ad[0] * (16777216) + $ad[1] * (65536) + $ad[2] * (256) + $ad[3]; $last= $la[0] * (16777216) + $la[1] * (65536) + $la[2] * (256) + $la[3]; return ($first < $curr&& $last > $curr); } /* Check if entry value is a valid date */ public static function is_date($date) { global $lang; if ($date == ""){ return (TRUE); } #TODO: use $lang to check date format if (!preg_match("/^([0-9]{1,2})\.([0-9]{1,2})\.([0-9]{4})$/", $date, $matches)) { return false; } return checkdate($matches[2],$matches[1],$matches[3]); } /* * Compares two dates * @param $dataA as String in german dateformat * @param $dataB as String in german dateformat * @return float or false on error * * * <0 => a a=b * >0 => a>b */ public static function compareDate($dateA, $dateB){ /* * TODO: * use $lang to check date format */ $tstampA = strtotime($dateA); if($tstampA === false){ trigger_error("Given date can not be converted to timestamp(".$dataA.") in function tests::compareDate."); return false; } $tstampB = strtotime($dateB); if($tstampB === false){ trigger_error("Given date can not be converted to timestamp(".$dataB.") in function tests::compareDate."); return false; } return $tstampA-$tstampB; } /* \brief Check if the specified IP address $address is inside the given network */ public static function is_in_ip_range($from, $to, $address) { $from = explode('.', $from); $to = explode('.', $to); $ad = explode('.', $address); /* Transform to integer */ $from= $from[0] * (16777216) + $from[1] * (65536) + $from[2] * (256) + $from[3]; $to= $to[0] * (16777216) + $to[1] * (65536) + $to[2] * (256) + $to[3]; $ad= $ad[0] * (16777216) + $ad[1] * (65536) + $ad[2] * (256) + $ad[3]; return ($ad >= $from && $ad <= $to); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_SnapshotHandler.inc0000644000175000017500000004317411435726775021031 0ustar cajuscajusconfig = &$config; $config = $this->config; if($config->get_cfg_value("core","enableSnapshots") == "true"){ /* Check if the snapshot_base is defined */ if ($config->get_cfg_value("core","snapshotBase") == ""){ /* Send message if not done already */ if(!session::is_set("snapshotFailMessageSend")){ session::set("snapshotFailMessageSend",TRUE); msg_dialog::display(_("Configuration error"), sprintf(_("The snapshot functionality is enabled but the required variable %s is not set!"), bold("snapshotBase")), ERROR_DIALOG); } return; } /* Check if the snapshot_base is defined */ if (!is_callable("gzcompress")){ /* Send message if not done already */ if(!session::is_set("snapshotFailMessageSend")){ session::set("snapshotFailMessageSend",TRUE); msg_dialog::display(_("Configuration error"), sprintf(_("The snapshot functionality is enabled but the required PHP compression module is missing: %s!"), bold("php5-zip / php5-gzip")), ERROR_DIALOG); } return; } /* check if there are special server configurations for snapshots */ if ($config->get_cfg_value("core","snapshotURI") != ""){ /* check if all required vars are available to create a new ldap connection */ $missing = ""; foreach(array("snapshotURI","snapshotAdminDn","snapshotAdminPassword","snapshotBase") as $var){ if($config->get_cfg_value("core",$var) == ""){ $missing .= $var." "; /* Send message if not done already */ if(!session::is_set("snapshotFailMessageSend")){ session::set("snapshotFailMessageSend",TRUE); msg_dialog::display(_("Configuration error"), sprintf(_("The snapshot functionality is enabled but the required variable %s is not set!"), bold($missing)), ERROR_DIALOG); } return; } } } $this->isEnabled= true; return; } } function enabled() { return $this->isEnabled; } function setSnapshotBases($bases) { $this->snapshotBases= $bases; } function getSnapshotBases() { return $this->snapshotBases; } function get_snapshot_link() { $snapshotLdap= null; /* check if there are special server configurations for snapshots */ if($this->config->get_cfg_value("core","snapshotURI") != ""){ $server= $this->config->get_cfg_value("core","snapshotURI"); $user= $this->config->get_cfg_value("core","snapshotAdminDn"); $password= $this->config->get_credentials($this->config->get_cfg_value("core","snapshotAdminPassword")); $snapshotLdap= new ldapMultiplexer(new LDAP($user,$password, $server)); } /* Prepare bases */ $this->snapshotLdapBase= $this->config->get_cfg_value("core","snapshotBase"); $snapshotLdap->cd($this->snapshotLdapBase); if (!$snapshotLdap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($snapshotLdap->get_error(), $this->snapshotLdapBase, "", get_class())); } return $snapshotLdap; } function getDeletedSnapshots($objectBase, $raw= false) { // Skip if not enabled if(!$this->enabled()){ return(array()); } // Load user info $ui= get_userinfo(); /* Create an additional ldap object which points to our ldap snapshot server */ $ldap= $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); $snapshotLdap= $this->get_snapshot_link(); if (!$snapshotLdap) { $snapshotLdap= $ldap; } // Initialize base $base= preg_replace("/".preg_quote($this->config->current['BASE'], '/')."$/", "", $objectBase).$this->snapshotLdapBase; /* Fetch all objects and check if they do not exist anymore */ $objects= array(); $snapshotLdap->cd($base); $snapshotLdap->ls("(objectClass=gosaSnapshotObject)", $base, array("gosaSnapshotType", "gosaSnapshotTimestamp", "gosaSnapshotDN", "description")); while($entry = $snapshotLdap->fetch()){ $chk = str_replace($base,"",$entry['dn']); if(preg_match("/,ou=/",$chk)) continue; if(!isset($entry['description'][0])){ $entry['description'][0] = ""; } $objects[] = $entry; } /* Check if entry still exists */ foreach($objects as $key => $entry){ $ldap->cat($entry['gosaSnapshotDN'][0]); if($ldap->count()){ unset($objects[$key]); } } /* Format result as requested */ if($raw) { return($objects); }else{ $tmp = array(); foreach($objects as $key => $entry){ $tmp[base64_encode($entry['dn'])] = $entry['description'][0]; } } return($tmp); } function hasSnapshots($dn) { return (count($this->getSnapshots($dn)) > 0); } function getSnapshots($dn, $raw= false) { // Empty if disabled if(!$this->enabled()){ return(array()); } /* Create an additional ldap object which points to our ldap snapshot server */ $ldap= $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); // Load snapshot LDAP connection $snapshotLdap= $this->get_snapshot_link(); if (!$snapshotLdap) { $snapshotLdap= $ldap; } $objectBase= preg_replace("/^[^,]*./","",$dn); // Initialize base $base= preg_replace("/".preg_quote($this->config->current['BASE'], '/')."$/", "", $objectBase).$this->snapshotLdapBase; /* Fetch all objects with gosaSnapshotDN=$dn */ $snapshotLdap->cd($base); $snapshotLdap->ls("(&(objectClass=gosaSnapshotObject)(gosaSnapshotDN=".$dn."))",$base, array("gosaSnapshotType","gosaSnapshotTimestamp","gosaSnapshotDN","description")); /* Put results into a list and add description if missing */ $objects= array(); while($entry = $snapshotLdap->fetch()){ if(!isset($entry['description'][0])){ $entry['description'][0] = ""; } $objects[] = $entry; } /* Return the raw array, or format the result */ if($raw){ return($objects); }else{ $tmp = array(); foreach($objects as $entry){ $tmp[base64_encode($entry['dn'])] = $entry['description'][0]; } } return($tmp); } /* Create a snapshot of the current object */ function create_snapshot($dn, $description= array()) { /* Check if snapshot functionality is enabled */ if(!$this->snapshotEnabled()){ return; } /* Get configuration from gosa.conf */ $config = $this->config; /* Create lokal ldap connection */ $ldap= $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); /* check if there are special server configurations for snapshots */ if($config->get_cfg_value("core","snapshotURI") == ""){ /* Source and destination server are both the same, just copy source to dest obj */ $ldap_to = $ldap; $snapldapbase = $this->config->current['BASE']; }else{ $server = $config->get_cfg_value("core","snapshotURI"); $user = $config->get_cfg_value("core","snapshotAdminDn"); $password = $this->config->get_credentials($config->get_cfg_value("core","snapshotAdminPassword")); $snapldapbase = $config->get_cfg_value("core","snapshotBase"); $ldap_to = new ldapMultiplexer(new LDAP($user,$password, $server)); $ldap_to -> cd($snapldapbase); if (!$ldap_to->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap_to->get_error(), $snapldapbase, "", get_class())); } } /* check if the dn exists */ if ($ldap->dn_exists($dn)){ /* Extract seconds & mysecs, they are used as entry index */ list($usec, $sec)= explode(" ", microtime()); /* Collect some infos */ $base = $this->config->current['BASE']; $snap_base = $config->get_cfg_value("core","snapshotBase"); $base_of_object = preg_replace ('/^[^,]+,/i', '', $dn); $new_base = preg_replace("/".preg_quote($base, '/')."$/","",$base_of_object).$snap_base; /* Create object */ $data = $ldap->generateLdif(LDAP::fix($dn), "(&(!(objectClass=gosaDepartment))(!(objectClass=FAIclass)))",'base'); $newName = str_replace(".", "", $sec."-".$usec); $target= array(); $target['objectClass'] = array("top", "gosaSnapshotObject"); $target['gosaSnapshotData'] = gzcompress($data, 6); $target['gosaSnapshotType'] = "snapshot"; $target['gosaSnapshotDN'] = $dn; $target['description'] = $description; $target['gosaSnapshotTimestamp'] = $newName; /* Insert the new snapshot But we have to check first, if the given gosaSnapshotTimestamp is already used, in this case we should increment this value till there is an unused value. */ $new_dn = "gosaSnapshotTimestamp=".$newName.",".$new_base; $ldap_to->cat($new_dn); while($ldap_to->count()){ $ldap_to->cat($new_dn); $newName = str_replace(".", "", $sec."-".($usec++)); $new_dn = "gosaSnapshotTimestamp=".$newName.",".$new_base; $target['gosaSnapshotTimestamp'] = $newName; } /* Inset this new snapshot */ $ldap_to->cd($snapldapbase); $ldap_to->create_missing_trees($snapldapbase); $ldap_to->create_missing_trees($new_base); $ldap_to->cd($new_dn); $ldap_to->add($target); if (!$ldap_to->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap_to->get_error(), $new_dn, LDAP_ADD, get_class())); } if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $new_base, "", get_class())); } } } function remove_snapshot($dn) { $ui = get_userinfo(); $ldap = $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); $ldap->rmdir_recursive($dn); if(!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn)); } } /* returns true if snapshots are enabled, and false if it is disalbed There will also be some errors psoted, if the configuration failed */ function snapshotEnabled() { return $this->config->snapshotEnabled(); } /* Return available snapshots for the given base */ function Available_SnapsShots($dn,$raw = false) { if(!$this->snapshotEnabled()) return(array()); /* Create an additional ldap object which points to our ldap snapshot server */ $ldap= $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); $cfg= &$this->config->current; /* check if there are special server configurations for snapshots */ if($this->config->get_cfg_value("core","snapshotURI") == ""){ $ldap_to = $ldap; }else{ $server = $this->config->get_cfg_value("core","snapshotURI"); $user = $this->config->get_cfg_value("core","snapshotAdminDn"); $password = $this->config->get_credentials($this->config->get_cfg_value("core","snapshotAdminPassword")); $snapldapbase = $this->config->get_cfg_value("core","snapshotBase"); $ldap_to = new ldapMultiplexer(new LDAP($user,$password, $server)); $ldap_to -> cd($snapldapbase); if (!$ldap_to->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap_to->get_error(), $snapldapbase, "", get_class())); } } /* Prepare bases and some other infos */ $base = $this->config->current['BASE']; $snap_base = $this->config->get_cfg_value("core","snapshotBase"); $base_of_object = preg_replace ('/^[^,]+,/i', '', $dn); $new_base = preg_replace("/".preg_quote($base, '/')."$/","",$base_of_object).$snap_base; $tmp = array(); /* Fetch all objects with gosaSnapshotDN=$dn */ $ldap_to->cd($new_base); $ldap_to->ls("(&(objectClass=gosaSnapshotObject)(gosaSnapshotDN=".$dn."))",$new_base, array("gosaSnapshotType","gosaSnapshotTimestamp","gosaSnapshotDN","description")); /* Put results into a list and add description if missing */ while($entry = $ldap_to->fetch()){ if(!isset($entry['description'][0])){ $entry['description'][0] = ""; } $tmp[] = $entry; } /* Return the raw array, or format the result */ if($raw){ return($tmp); }else{ $tmp2 = array(); foreach($tmp as $entry){ $tmp2[base64_encode($entry['dn'])] = $entry['description'][0]; } } return($tmp2); } function getAllDeletedSnapshots($base_of_object,$raw = false) { if(!$this->snapshotEnabled()) return(array()); /* Create an additional ldap object which points to our ldap snapshot server */ $ldap= $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); $cfg= &$this->config->current; /* check if there are special server configurations for snapshots */ if($this->config->get_cfg_value("core","snapshotURI") == ""){ $ldap_to = $ldap; }else{ $server = $this->config->get_cfg_value("core","snapshotURI"); $user = $this->config->get_cfg_value("core","snapshotAdminDn"); $password = $this->config->get_credentials($this->config->get_cfg_value("core","snapshotAdminPassword")); $snapldapbase = $this->config->get_cfg_value("core","snapshotBase"); $ldap_to = new ldapMultiplexer(new LDAP($user,$password, $server)); $ldap_to -> cd($snapldapbase); if (!$ldap_to->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap_to->get_error(), $snapldapbase, "", get_class())); } } /* Prepare bases */ $base = $this->config->current['BASE']; $snap_base = $this->config->get_cfg_value("core","snapshotBase"); $new_base = preg_replace("/".preg_quote($base, '/')."$/","",$base_of_object).$snap_base; /* Fetch all objects and check if they do not exist anymore */ $ui = get_userinfo(); $tmp = array(); $ldap_to->cd($new_base); $ldap_to->ls("(objectClass=gosaSnapshotObject)",$new_base,array("gosaSnapshotType","gosaSnapshotTimestamp","gosaSnapshotDN","description")); while($entry = $ldap_to->fetch()){ $chk = str_replace($new_base,"",$entry['dn']); if(preg_match("/,ou=/",$chk)) continue; if(!isset($entry['description'][0])){ $entry['description'][0] = ""; } $tmp[] = $entry; } /* Check if entry still exists */ foreach($tmp as $key => $entry){ $ldap->cat($entry['gosaSnapshotDN'][0]); if($ldap->count()){ unset($tmp[$key]); } } /* Format result as requested */ if($raw) { return($tmp); }else{ $tmp2 = array(); foreach($tmp as $key => $entry){ $tmp2[base64_encode($entry['dn'])] = $entry['description'][0]; } } return($tmp2); } /* Restore selected snapshot */ function restore_snapshot($dn) { if(!$this->snapshotEnabled()) return(array()); $ldap= $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); $cfg= &$this->config->current; /* check if there are special server configurations for snapshots */ if($this->config->get_cfg_value("core","snapshotURI") == ""){ $ldap_to = $ldap; }else{ $server = $this->config->get_cfg_value("core","snapshotURI"); $user = $this->config->get_cfg_value("core","snapshotAdminDn"); $password = $this->config->get_credentials($this->config->get_cfg_value("core","snapshotAdminPassword")); $snapldapbase = $this->config->get_cfg_value("core","snapshotBase"); $ldap_to = new ldapMultiplexer(new LDAP($user,$password, $server)); $ldap_to -> cd($snapldapbase); if (!$ldap_to->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap_to->get_error(), $snapldapbase, "", get_class())); } } /* Get the snapshot */ $ldap_to->cat($dn); $restoreObject = $ldap_to->fetch(); /* Prepare import string */ $data = gzuncompress($ldap_to->get_attribute($dn,'gosaSnapshotData')); /* Import the given data */ $err = ""; $ldap->import_complete_ldif($data,$err,false,false); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, "", get_class())); } } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/functions.inc0000644000175000017500000035566311734031247016551 0ustar cajuscajus "ae", "ö" => "oe", "ü" => "ue", "Ä" => "Ae", "Ö" => "Oe", "Ü" => "Ue", "ß" => "ss", "á" => "a", "é" => "e", "í" => "i", "ó" => "o", "ú" => "u", "Ã" => "A", "É" => "E", "Ã" => "I", "Ó" => "O", "Ú" => "U", "ñ" => "ny", "Ñ" => "Ny" ); /*! \brief Cyrillic (russian) fonetic transliteration (converts russian letters to ASCII and backward according to GOST 7.79-2000 ) * \param string 'str' Source string in russian codepage * \return string Translitered string value. */ function cyrillic2ascii($str) { $ru = array('а', 'б', 'в', 'г', 'д', 'е', 'Ñ‘', 'ж', 'з', 'и', 'й', 'к', 'л', 'м', 'н', 'о', 'п', 'Ñ€', 'Ñ', 'Ñ‚', 'у', 'Ñ„', 'Ñ…', 'ц', 'ч', 'ш', 'щ', 'ÑŠ', 'Ñ‹', 'ÑŒ', 'Ñ', 'ÑŽ', 'Ñ', 'Ð', 'Б', 'Ð’', 'Г', 'Д', 'Е', 'Ð', 'Ж', 'З', 'И', 'Й', 'К', 'Л', 'М', 'H', 'О', 'П', 'Р', 'С', 'Т', 'У', 'Ф', 'Ð¥', 'Ц', 'Ч', 'Ш', 'Щ', 'Ъ', 'Ы', 'Ь', 'Э', 'Ю', 'Я', 'Ò‘', 'Ñ”', 'Ñ—', 'Ò', 'Є', 'Ї' ); $en = array('a', 'b', 'v', 'g', 'd', 'e', 'jo','zh','z', 'i', 'jj','k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'f', 'kh','c', 'ch','sh','shh','"', 'y', '\'','eh','ju','ja', 'A', 'B', 'V', 'G', 'D', 'E', 'Jo','Je','Z', 'I', 'Jj','K', 'L', 'M', 'N', 'O', 'P', 'R', 'S', 'T', 'U', 'F', 'Kh','C', 'CH','SH','Shh','"', 'Y', '\'','Eh','Ju','Ja', 'g', 'ye','yi','G', 'Ye','Yi' ); return str_replace($ru, $en, $str); } /*! \brief Does autoloading for classes used in GOsa. * * Takes the list generated by 'update-gosa' and loads the * file containing the requested class. * * \param string 'class_name' The currently requested class */ function __gosa_autoload($class_name) { global $class_mapping, $BASE_DIR; if ($class_mapping === NULL){ echo sprintf(_("Fatal error: no class locations defined - please run %s to fix this"), bold("update-gosa")); exit; } if (isset($class_mapping["$class_name"])){ require_once($BASE_DIR."/".$class_mapping["$class_name"]); } else { echo sprintf(_("Fatal error: cannot instantiate class %s - try running %s to fix this"), bold($class_name), bold("update-gosa")); exit; } } spl_autoload_register('__gosa_autoload'); /*! \brief Checks if a class is available. * \param string 'name' The subject of the test * \return boolean True if class is available, else false. */ function class_available($name) { global $class_mapping, $config; $disabled = array(); if($config instanceOf config && $config->configRegistry instanceOf configRegistry){ $disabled = $config->configRegistry->getDisabledPlugins(); } return(isset($class_mapping[$name]) && !isset($disabled[$name])); } /*! \brief Check if plugin is available * * Checks if a given plugin is available and readable. * * \param string 'plugin' the subject of the check * \return boolean True if plugin is available, else FALSE. */ function plugin_available($plugin) { global $class_mapping, $BASE_DIR; if (!isset($class_mapping[$plugin])){ return false; } else { return is_readable($BASE_DIR."/".$class_mapping[$plugin]); } } /*! \brief Create seed with microseconds * * Example: * \code * srand(make_seed()); * $random = rand(); * \endcode * * \return float a floating point number which can be used to feed srand() with it * */ function make_seed() { list($usec, $sec) = explode(' ', microtime()); return (float) $sec + ((float) $usec * 100000); } /*! \brief DEBUG level action * * print a DEBUG level if specified debug level of the level matches the * the configured debug level. * * \param int 'level' The log level of the message (should use the constants, * defined in functions.in (DEBUG_TRACE, DEBUG_LDAP, etc.) * \param int 'line' Define the line of the logged action (using __LINE__ is common) * \param string 'function' Define the function where the logged action happened in * (using __FUNCTION__ is common) * \param string 'file' Define the file where the logged action happend in * (using __FILE__ is common) * \param mixed 'data' The data to log. Can be a message or an array, which is printed * with print_a * \param string 'info' Optional: Additional information * * */ function DEBUG($level, $line, $function, $file, $data, $info="") { global $config; $debugLevel = 0; if($config instanceOf config){ $debugLevel = $config->get_cfg_value('core', 'debugLevel'); } if ($debugLevel & $level){ $output= "DEBUG[$level] "; if ($function != ""){ $output.= "($file:$function():$line) - $info: "; } else { $output.= "($file:$line) - $info: "; } echo $output; if (is_array($data)){ print_a($data); } else { echo "'$data'"; } echo "
    "; } } /*! \brief Determine which language to show to the user * * Determines which language should be used to present gosa content * to the user. It does so by looking at several possibilites and returning * the first setting that can be found. * * -# Language configured by the user * -# Global configured language * -# Language as returned by al2gt (as configured in the browser) * * \return string gettext locale string */ function get_browser_language() { /* Try to use users primary language */ global $config; $ui= get_userinfo(); if (isset($ui) && $ui !== NULL){ if ($ui->language != ""){ return ($ui->language.".UTF-8"); } } /* Check for global language settings in gosa.conf */ if (isset ($config) && $config->get_cfg_value("core",'language') != ""){ $lang = $config->get_cfg_value("core",'language'); if(!preg_match("/utf/i",$lang)){ $lang .= ".UTF-8"; } return($lang); } /* Load supported languages */ $gosa_languages= get_languages(); /* Move supported languages to flat list */ $langs = array_map(function($lang){return $lang.'.UTF-8';}, array_keys($gosa_languages)); /* Return gettext based string */ return (al2gt($langs, 'text/html')); } /*! \brief Rewrite ui object to another dn * * Usually used when a user is renamed. In this case the dn * in the user object must be updated in order to point * to the correct DN. * * \param string 'dn' the old DN * \param string 'newdn' the new DN * */ function change_ui_dn($dn, $newdn) { $ui= session::global_get('ui'); if ($ui->dn == $dn){ $ui->dn= $newdn; session::global_set('ui',$ui); } } /*! \brief Return themed path for specified base file * * Depending on its parameters, this function returns the full * path of a template file. First match wins while searching * in this order: * * - load theme depending file * - load global theme depending file * - load default theme file * - load global default theme file * * \param string 'filename' The base file name * \param boolean 'plugin' Flag to take the plugin directory as search base * \param string 'path' User specified path to take as search base * \return string Full path to the template file */ function get_template_path($filename= '', $plugin= FALSE, $path= "") { global $config, $BASE_DIR; /* Set theme */ if (isset ($config)){ $theme= $config->get_cfg_value("core","theme"); } else { $theme= "default"; } /* Return path for empty filename */ if ($filename == ''){ return ("themes/$theme/"); } /* Return plugin dir or root directory? */ if ($plugin){ if ($path == ""){ $nf= preg_replace("!^".$BASE_DIR."/!", "", preg_replace('/^\.\.\//', '', session::global_get('plugin_dir'))); } else { $nf= preg_replace("!^".$BASE_DIR."/!", "", $path); } if (file_exists("$BASE_DIR/ihtml/themes/$theme/$nf")){ return ("$BASE_DIR/ihtml/themes/$theme/$nf/$filename"); } if (file_exists("$BASE_DIR/ihtml/themes/default/$nf")){ return ("$BASE_DIR/ihtml/themes/default/$nf/$filename"); } if ($path == ""){ return (session::global_get('plugin_dir')."/$filename"); } else { return ($path."/$filename"); } } else { if (file_exists("themes/$theme/$filename")){ return ("themes/$theme/$filename"); } if (file_exists("$BASE_DIR/ihtml/themes/$theme/$filename")){ return ("$BASE_DIR/ihtml/themes/$theme/$filename"); } if (file_exists("themes/default/$filename")){ return ("themes/default/$filename"); } if (file_exists("$BASE_DIR/ihtml/themes/default/$filename")){ return ("$BASE_DIR/ihtml/themes/default/$filename"); } return ($filename); } } /*! \brief Remove multiple entries from an array * * Removes every element that is in $needles from the * array given as $haystack * * \param array 'needles' array of the entries to remove * \param array 'haystack' original array to remove the entries from */ function array_remove_entries($needles, $haystack) { return (array_merge(array_diff($haystack, $needles))); } /*! \brief Remove multiple entries from an array (case-insensitive) * * Same as array_remove_entries(), but case-insensitive. */ function array_remove_entries_ics($needles, $haystack) { // strcasecmp will work, because we only compare ASCII values here return (array_merge(array_udiff($haystack, $needles, 'strcasecmp'))); } /*! Merge to array but remove duplicate entries * * Merges two arrays and removes duplicate entries. Triggers * an error if first or second parametre is not an array. * * \param array 'ar1' first array * \param array 'ar2' second array- * \return array */ function gosa_array_merge($ar1,$ar2) { if(!is_array($ar1) || !is_array($ar2)){ trigger_error("Specified parameter(s) are not valid arrays."); }else{ return(array_values(array_unique(array_merge($ar1,$ar2)))); } } /*! \brief Generate a system log info * * Creates a syslog message, containing user information. * * \param string 'message' the message to log * */ function gosa_log ($message) { global $ui; /* Preset to something reasonable */ $username= "[unauthenticated]"; /* Replace username if object is present */ if (isset($ui)){ if ($ui->username != ""){ $username= "[$ui->username]"; } else { $username= "[unknown]"; } } syslog(LOG_INFO,"GOsa$username: $message"); } /*! \brief Initialize a LDAP connection * * Initializes a LDAP connection. * * \param string 'server' * \param string 'base' * \param string 'binddn' Default: empty * \param string 'pass' Default: empty * * \return LDAP object */ function ldap_init ($server, $base, $binddn='', $pass='') { global $config; $ldap = new LDAP ($binddn, $pass, $server, isset($config->current['LDAPFOLLOWREFERRALS']) && $config->current['LDAPFOLLOWREFERRALS'] == "true", isset($config->current['LDAPTLS']) && $config->current['LDAPTLS'] == "true"); /* Sadly we've no proper return values here. Use the error message instead. */ if (!$ldap->success()){ msg_dialog::display(_("Fatal error"), sprintf(_("Error while connecting to LDAP: %s"), $ldap->get_error()), FATAL_ERROR_DIALOG); exit(); } /* Preset connection base to $base and return to caller */ $ldap->cd ($base); return $ldap; } /* \brief Process htaccess authentication */ function process_htaccess ($username, $kerberos= FALSE) { global $config; /* Search for $username and optional @REALM in all configured LDAP trees */ foreach($config->data["LOCATIONS"] as $name => $data){ $config->set_current($name); $mode= "kerberos"; if ($config->get_cfg_value("core","useSaslForKerberos") == "true"){ $mode= "sasl"; } /* Look for entry or realm */ $ldap= $config->get_ldap_link(); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), "", LDAP_AUTH)."

    ".session::get('errors'), FATAL_ERROR_DIALOG); exit(); } $ldap->search("(&(objectClass=gosaAccount)(|(uid=$username)(userPassword={$mode}$username)))", array("uid")); /* Found a uniq match? Return it... */ if ($ldap->count() == 1) { $attrs= $ldap->fetch(); return array("username" => $attrs["uid"][0], "server" => $name); } } /* Nothing found? Return emtpy array */ return array("username" => "", "server" => ""); } /*! \brief Verify user login against htaccess * * Checks if the specified username is available in apache, maps the user * to an LDAP user. The password has been checked by apache already. * * \param string 'username' * \return * - TRUE on SUCCESS, NULL or FALSE on error */ function ldap_login_user_htaccess ($username) { global $config; /* Look for entry or realm */ $ldap= $config->get_ldap_link(); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), "", LDAP_AUTH)."

    ".session::get('errors'), FATAL_ERROR_DIALOG); exit(); } $ldap->search("(&(objectClass=gosaAccount)(uid=$username))", array("uid")); /* Found no uniq match? Strange, because we did above... */ if ($ldap->count() != 1) { msg_dialog::display(_("LDAP error"), _("User ID is not unique!"), FATAL_ERROR_DIALOG); return (NULL); } $attrs= $ldap->fetch(); /* got user dn, fill acl's */ $ui= new userinfo($config, $ldap->getDN()); $ui->username= $attrs['uid'][0]; /* Bail out if we have login restrictions set, for security reasons the message is the same than failed user/pw */ if (!$ui->loginAllowed()){ new log("security","login","",array(),"Login restriction for user \"$username\", login not permitted"); return (NULL); } /* No password check needed - the webserver did it for us */ $ldap->disconnect(); /* Username is set, load subtreeACL's now */ $ui->loadACL(); /* TODO: check java script for htaccess authentication */ session::global_set('js', true); return ($ui); } /*! \brief Verify user login against LDAP directory * * Checks if the specified username is in the LDAP and verifies if the * password is correct by binding to the LDAP with the given credentials. * * \param string 'username' * \param string 'password' * \return * - TRUE on SUCCESS, NULL or FALSE on error */ function ldap_login_user ($username, $password) { global $config; /* look through the entire ldap */ $ldap = $config->get_ldap_link(); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), "", LDAP_AUTH)."

    ".session::get('errors'), FATAL_ERROR_DIALOG); exit(); } $ldap->cd($config->current['BASE']); $allowed_attributes = array("uid","mail"); $verify_attr = array(); if($config->get_cfg_value("core","loginAttribute") != ""){ $tmp = explode(",", $config->get_cfg_value("core","loginAttribute")); foreach($tmp as $attr){ if(in_array_strict($attr,$allowed_attributes)){ $verify_attr[] = $attr; } } } if(count($verify_attr) == 0){ $verify_attr = array("uid"); } $tmp= $verify_attr; $tmp[] = "uid"; $filter = ""; foreach($verify_attr as $attr) { $filter.= "(".$attr."=".$username.")"; } $filter = "(&(|".$filter.")(objectClass=gosaAccount))"; $ldap->search($filter,$tmp); /* get results, only a count of 1 is valid */ switch ($ldap->count()){ /* user not found */ case 0: return (NULL); /* valid uniq user */ case 1: break; /* found more than one matching id */ default: msg_dialog::display(_("Internal error"), _("User ID is not unique!"), FATAL_ERROR_DIALOG); return (NULL); } /* LDAP schema is not case sensitive. Perform additional check. */ $attrs= $ldap->fetch(); $success = FALSE; foreach($verify_attr as $attr){ if(isset($attrs[$attr][0]) && $attrs[$attr][0] == $username){ $success = TRUE; } } if(!$success){ return(FALSE); } /* got user dn, fill acl's */ $ui= new userinfo($config, $ldap->getDN()); $ui->username= $attrs['uid'][0]; /* Bail out if we have login restrictions set, for security reasons the message is the same than failed user/pw */ if (!$ui->loginAllowed()){ new log("security","login","",array(),"Login restriction for user \"$username\", login not permitted"); return (NULL); } /* password check, bind as user with supplied password */ $ldap->disconnect(); $ldap= new LDAP($ui->dn, $password, $config->current['SERVER'], isset($config->current['LDAPFOLLOWREFERRALS']) && $config->current['LDAPFOLLOWREFERRALS'] == "true", isset($config->current['LDAPTLS']) && $config->current['LDAPTLS'] == "true"); if (!$ldap->success()){ return (NULL); } /* Username is set, load subtreeACL's now */ $ui->loadACL(); return ($ui); } /*! \brief Checks the posixAccount status by comparing the shadow attributes. * * @param Object The GOsa configuration object. * @param String The 'dn' of the user to test the account status for. * @param String The 'uid' of the user we're going to test. * @return Const * POSIX_ACCOUNT_EXPIRED - If the account is expired. * POSIX_WARN_ABOUT_EXPIRATION - If the account is going to expire. * POSIX_FORCE_PASSWORD_CHANGE - The password has to be changed. * POSIX_DISALLOW_PASSWORD_CHANGE - The password cannot be changed right now. * * * * shadowLastChange * | * |---- shadowMin ---> | <-- shadowMax -- * | | | * |------- shadowWarning -> | * |-- shadowInactive --> DEACTIVATED * | * EXPIRED * */ function ldap_expired_account($config, $userdn, $uid) { // Skip this for the admin account, we do not want to lock him out. if($uid == 'admin') return(0); $ldap= $config->get_ldap_link(); $ldap->cd($config->current['BASE']); $ldap->cat($userdn); $attrs= $ldap->fetch(); $current= floor(date("U") /60 /60 /24); // Fetch required attributes foreach(array('shadowExpire','shadowLastChange','shadowMax','shadowMin', 'shadowInactive','shadowWarning','sambaKickoffTime') as $attr){ $$attr = (isset($attrs[$attr][0]))? $attrs[$attr][0] : null; } // Check if the account has reached its kick off limitations. // --------------------------------------------------------- // Once the accout reaches the kick off limit it has expired. if($sambaKickoffTime !== null){ if(time() >= $sambaKickoffTime){ return(POSIX_ACCOUNT_EXPIRED); } } // Check if the account has expired. // --------------------------------- // An account is locked/expired once its expiration date has reached (shadowExpire). // If the optional attribute (shadowInactive) is set, we've to postpone // the account expiration by the amount of days specified in (shadowInactive). if($shadowExpire != null && $shadowExpire <= $current){ // The account seems to be expired, but we've to check 'shadowInactive' additionally. // ShadowInactive specifies an amount of days we've to reprieve the user. // It some kind of x days' grace. if($shadowInactive == null || $current > $shadowExpire + $shadowInactive){ // Finally we've detect that the account is deactivated. return(POSIX_ACCOUNT_EXPIRED); } } // The users password is going to expire. // -------------------------------------- // We've to warn the user in the case of an expiring account. // An account is going to expire when it reaches its expiration date (shadowExpire). // The user has to be warned, if the days left till expiration, match the // configured warning period (shadowWarning) // --> shadowWarning: Warn x days before account expiration. if($shadowExpire != null && $shadowWarning != null){ // Check if the account is still active and not already expired. if($shadowExpire >= $current){ // Check if we've to warn the user by comparing the remaining // number of days till expiration with the configured amount // of days in shadowWarning. if(($shadowExpire - $current) <= $shadowWarning){ return(POSIX_WARN_ABOUT_EXPIRATION); } } } // -- I guess this is the correct detection, isn't it? if($shadowLastChange != null && $shadowWarning != null && $shadowMax != null){ $daysRemaining = ($shadowLastChange + $shadowMax) - $current ; if($daysRemaining > 0 && $daysRemaining <= $shadowWarning){ return(POSIX_WARN_ABOUT_EXPIRATION); } } // Check if we've to force the user to change his password. // -------------------------------------------------------- // A password change is enforced when the password is older than // the configured amount of days (shadowMax). // The age of the current password (shadowLastChange) plus the maximum // amount amount of days (shadowMax) has to be smaller than the // current timestamp. if($shadowLastChange != null && $shadowMax != null){ // Check if we've an outdated password. if($current >= ($shadowLastChange + $shadowMax)){ return(POSIX_FORCE_PASSWORD_CHANGE); } } // Check if we've to freeze the users password. // -------------------------------------------- // Once a user has changed his password, he cannot change it again // for a given amount of days (shadowMin). // We should not allow to change the password within GOsa too. if($shadowLastChange != null && $shadowMin != null){ // Check if we've an outdated password. if(($shadowLastChange + $shadowMin) >= $current){ return(POSIX_DISALLOW_PASSWORD_CHANGE); } } return(0); } /*! \brief Add a lock for object(s) * * Adds a lock by the specified user for one ore multiple objects. * If the lock for that object already exists, an error is triggered. * * \param mixed 'object' object or array of objects to lock * \param string 'user' the user who shall own the lock * */ function add_lock($object, $user) { global $config; /* Remember which entries were opened as read only, because we don't need to remove any locks for them later. */ if(!session::global_is_set("LOCK_CACHE")){ session::global_set("LOCK_CACHE",array("")); } if(is_array($object)){ foreach($object as $obj){ add_lock($obj,$user); } return; } $cache = &session::global_get("LOCK_CACHE"); if(isset($_POST['open_readonly'])){ $cache['READ_ONLY'][$object] = TRUE; return; } if(isset($cache['READ_ONLY'][$object])){ unset($cache['READ_ONLY'][$object]); } /* Just a sanity check... */ if ($object == "" || $user == ""){ msg_dialog::display(_("Internal error"), _("Error while locking entry!"), ERROR_DIALOG); return; } /* Check for existing entries in lock area */ $ldap= $config->get_ldap_link(); $ldap->cd ($config->get_cfg_value("core","config")); $ldap->search("(&(objectClass=gosaLockEntry)(gosaUser=$user)(gosaObject=".base64_encode($object)."))", array("gosaUser")); if (!$ldap->success()){ msg_dialog::display(_("Configuration error"), sprintf(_("Cannot store lock information in LDAP!")."

    "._('Error: %s'), "

    ".$ldap->get_error().""), ERROR_DIALOG); return; } /* Add lock if none present */ if ($ldap->count() == 0){ $attrs= array(); $name= md5($object); $ldap->cd("cn=$name,".$config->get_cfg_value("core","config")); $attrs["objectClass"] = "gosaLockEntry"; $attrs["gosaUser"] = $user; $attrs["gosaObject"] = base64_encode($object); $attrs["cn"] = "$name"; $ldap->add($attrs); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), "cn=$name,".$config->get_cfg_value("core","config"), 0, ERROR_DIALOG)); return; } } } /*! \brief Remove a lock for object(s) * * Does the opposite of add_lock(). * * \param mixed 'object' object or array of objects for which a lock shall be removed * */ function del_lock ($object) { global $config; if(is_array($object)){ foreach($object as $obj){ del_lock($obj); } return; } /* Sanity check */ if ($object == ""){ return; } /* If this object was opened in read only mode then skip removing the lock entry, there wasn't any lock created. */ if(session::global_is_set("LOCK_CACHE")){ $cache = &session::global_get("LOCK_CACHE"); if(isset($cache['READ_ONLY'][$object])){ unset($cache['READ_ONLY'][$object]); return; } } /* Check for existance and remove the entry */ $ldap= $config->get_ldap_link(); $ldap->cd ($config->get_cfg_value("core","config")); $ldap->search ("(&(objectClass=gosaLockEntry)(gosaObject=".base64_encode($object)."))", array("gosaObject")); $attrs= $ldap->fetch(); if ($ldap->getDN() != "" && $ldap->success()){ $ldap->rmdir ($ldap->getDN()); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $ldap->getDN(), LDAP_DEL, ERROR_DIALOG)); return; } } } /*! \brief Remove all locks owned by a specific userdn * * For a given userdn remove all existing locks. This is usually * called on logout. * * \param string 'userdn' the subject whose locks shall be deleted */ function del_user_locks($userdn) { global $config; /* Get LDAP ressources */ $ldap= $config->get_ldap_link(); $ldap->cd ($config->get_cfg_value("core","config")); /* Remove all objects of this user, drop errors silently in this case. */ $ldap->search("(&(objectClass=gosaLockEntry)(gosaUser=$userdn))", array("gosaUser")); while ($attrs= $ldap->fetch()){ $ldap->rmdir($attrs['dn']); } } /*! \brief Get a lock for a specific object * * Searches for a lock on a given object. * * \param string 'object' subject whose locks are to be searched * \return string Returns the user who owns the lock or "" if no lock is found * or an error occured. */ function get_lock ($object) { global $config; /* Sanity check */ if ($object == ""){ msg_dialog::display(_("Internal error"), _("Error while locking entry!"), ERROR_DIALOG); return(""); } /* Allow readonly access, the plugin::plugin will restrict the acls */ if(isset($_POST['open_readonly'])) return(""); /* Get LDAP link, check for presence of the lock entry */ $user= ""; $ldap= $config->get_ldap_link(); $ldap->cd ($config->get_cfg_value("core","config")); $ldap->search("(&(objectClass=gosaLockEntry)(gosaObject=".base64_encode($object)."))", array("gosaUser")); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), "", LDAP_SEARCH, ERROR_DIALOG)); return(""); } /* Check for broken locking information in LDAP */ if ($ldap->count() > 1){ /* Clean up these references now... */ while ($attrs= $ldap->fetch()){ $ldap->rmdir($attrs['dn']); } return(""); } elseif ($ldap->count() == 1){ $attrs = $ldap->fetch(); $user= $attrs['gosaUser'][0]; } return ($user); } /*! Get locks for multiple objects * * Similar as get_lock(), but for multiple objects. * * \param array 'objects' Array of Objects for which a lock shall be searched * \return A numbered array containing all found locks as an array with key 'dn' * and key 'user' or "" if an error occured. */ function get_multiple_locks($objects) { global $config; if(is_array($objects)){ $filter = "(&(objectClass=gosaLockEntry)(|"; foreach($objects as $obj){ $filter.="(gosaObject=".base64_encode($obj).")"; } $filter.= "))"; }else{ $filter = "(&(objectClass=gosaLockEntry)(gosaObject=".base64_encode($objects)."))"; } /* Get LDAP link, check for presence of the lock entry */ $user= ""; $ldap= $config->get_ldap_link(); $ldap->cd ($config->get_cfg_value("core","config")); $ldap->search($filter, array("gosaUser","gosaObject")); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), "", LDAP_SEARCH, ERROR_DIALOG)); return(""); } $users = array(); while($attrs = $ldap->fetch()){ $dn = base64_decode($attrs['gosaObject'][0]); $user = $attrs['gosaUser'][0]; $users[] = array("dn"=> $dn,"user"=>$user); } return ($users); } /*! \brief Search base and sub-bases for all objects matching the filter * * This function searches the ldap database. It searches in $sub_bases,*,$base * for all objects matching the $filter. * \param string 'filter' The ldap search filter * \param string 'category' The ACL category the result objects belongs * \param string 'sub_bases' The sub base we want to search for e.g. "ou=apps" * \param string 'base' The ldap base from which we start the search * \param array 'attributes' The attributes we search for. * \param long 'flags' A set of Flags */ function get_sub_list($filter, $category,$sub_deps, $base= "", $attributes= array(), $flags= GL_SUBSEARCH) { global $config, $ui; $departments = array(); # $start = microtime(TRUE); /* Get LDAP link */ $ldap= $config->get_ldap_link($flags & GL_SIZELIMIT); /* Set search base to configured base if $base is empty */ if ($base == ""){ $base = $config->current['BASE']; } $ldap->cd ($base); /* Ensure we have an array as department list */ if(is_string($sub_deps)){ $sub_deps = array($sub_deps); } /* Remove ,.*$ ("ou=1,ou=2.." => "ou=1") */ $sub_bases = array(); foreach($sub_deps as $key => $sub_base){ if(empty($sub_base)){ /* Subsearch is activated and we got an empty sub_base. * (This may be the case if you have empty people/group ous). * Fall back to old get_list(). * A log entry will be written. */ if($flags & GL_SUBSEARCH){ $sub_bases = array(); break; }else{ /* Do NOT search within subtrees is requeste and the sub base is empty. * Append all known departments that matches the base. */ $departments[$base] = $base; } }else{ $sub_bases[$key] = preg_replace("/,.*$/","",$sub_base); } } /* If there is no sub_department specified, fall back to old method, get_list(). */ if(!count($sub_bases) && !count($departments)){ /* Log this fall back, it may be an unpredicted behaviour. */ if(!count($sub_bases) && !count($departments)){ // log($action,$objecttype,$object,$changes_array = array(),$result = "") new log("debug","all",__FILE__,$attributes, sprintf("get_sub_list(): Falling back to get_list(), due to empty sub_bases parameter.". " This may slow down GOsa. Used filter: %s", $filter)); } $tmp = get_list($filter, $category,$base,$attributes,$flags); return($tmp); } /* Get all deparments matching the given sub_bases */ $base_filter= ""; foreach($sub_bases as $sub_base){ $base_filter .= "(".$sub_base.")"; } $base_filter = "(&(objectClass=organizationalUnit)(|".$base_filter."))"; $ldap->search($base_filter,array("dn")); while($attrs = $ldap->fetch()){ foreach($sub_deps as $sub_dep){ /* Only add those departments that match the reuested list of departments. * * e.g. sub_deps = array("ou=servers,ou=systems,"); * * In this case we have search for "ou=servers" and we may have also fetched * departments like this "ou=servers,ou=blafasel,..." * Here we filter out those blafasel departments. */ if(preg_match("/".preg_quote($sub_dep, '/')."/",$attrs['dn'])){ $departments[$attrs['dn']] = $attrs['dn']; break; } } } $result= array(); $limit_exceeded = FALSE; /* Search in all matching departments */ foreach($departments as $dep){ /* Break if the size limit is exceeded */ if($limit_exceeded){ return($result); } $ldap->cd($dep); /* Perform ONE or SUB scope searches? */ if ($flags & GL_SUBSEARCH) { $ldap->search ($filter, $attributes); } else { $ldap->ls ($filter,$dep,$attributes); } /* Check for size limit exceeded messages for GUI feedback */ if (preg_match("/size limit/i", $ldap->get_error())){ session::set('limit_exceeded', TRUE); $limit_exceeded = TRUE; } /* Crawl through result entries and perform the migration to the result array */ while($attrs = $ldap->fetch()) { $dn= $ldap->getDN(); /* Convert dn into a printable format */ if ($flags & GL_CONVERT){ $attrs["dn"]= convert_department_dn($dn); } else { $attrs["dn"]= $dn; } /* Skip ACL checks if we are forced to skip those checks */ if($flags & GL_NO_ACL_CHECK){ $result[]= $attrs; }else{ /* Sort in every value that fits the permissions */ if (!is_array($category)){ $category = array($category); } foreach ($category as $o){ if((preg_match("/\//",$o) && preg_match("/r/",$ui->get_permissions($dn,$o))) || (!preg_match("/\//",$o) && preg_match("/r/",$ui->get_category_permissions($dn, $o)))){ $result[]= $attrs; break; } } } } } return($result); } /*! \brief Search base for all objects matching the filter * * Just like get_sub_list(), but without sub base search. * */ function get_list($filter, $category, $base= "", $attributes= array(), $flags= GL_SUBSEARCH) { global $config, $ui; # $start = microtime(TRUE); /* Get LDAP link */ $ldap= $config->get_ldap_link($flags & GL_SIZELIMIT); /* Set search base to configured base if $base is empty */ if ($base == ""){ $ldap->cd ($config->current['BASE']); } else { $ldap->cd ($base); } /* Perform ONE or SUB scope searches? */ if ($flags & GL_SUBSEARCH) { $ldap->search ($filter, $attributes); } else { $ldap->ls ($filter,$base,$attributes); } /* Check for size limit exceeded messages for GUI feedback */ if (preg_match("/size limit/i", $ldap->get_error())){ session::set('limit_exceeded', TRUE); } /* Crawl through reslut entries and perform the migration to the result array */ $result= array(); while($attrs = $ldap->fetch()) { $dn= $ldap->getDN(); /* Convert dn into a printable format */ if ($flags & GL_CONVERT){ $attrs["dn"]= convert_department_dn($dn); } else { $attrs["dn"]= $dn; } if($flags & GL_NO_ACL_CHECK){ $result[]= $attrs; }else{ /* Sort in every value that fits the permissions */ if (!is_array($category)){ $category = array($category); } foreach ($category as $o){ if((preg_match("/\//",$o) && preg_match("/r/",$ui->get_permissions($dn,$o))) || (!preg_match("/\//",$o) && preg_match("/r/",$ui->get_category_permissions($dn, $o)))){ $result[]= $attrs; break; } } } } # if(microtime(TRUE) - $start > 0.1){ # echo sprintf("
    GET_LIST %s .| %f  --- $base -----$filter ---- $flags
    ",__LINE__,microtime(TRUE) - $start); # } return ($result); } /*! \brief Show sizelimit configuration dialog if exceeded */ function check_sizelimit() { /* Ignore dialog? */ if (session::global_is_set('size_ignore') && session::global_get('size_ignore')){ return (""); } /* Eventually show dialog */ if (session::is_set('limit_exceeded') && session::get('limit_exceeded')){ $smarty= get_smarty(); $smarty->assign('warning', sprintf(_("The current size limit of %d entries is exceeded!"), session::global_get('size_limit'))); $smarty->assign('limit_message', sprintf(_("Set the size limit to %s"), '')); return($smarty->fetch(get_template_path('sizelimit.tpl'))); } return (""); } /*! \brief Print a sizelimit warning */ function print_sizelimit_warning() { if (session::global_is_set('size_limit') && session::global_get('size_limit') >= 10000000 || (session::is_set('limit_exceeded') && session::get('limit_exceeded'))){ $config= ""; } else { $config= ""; } if (session::is_set('limit_exceeded') && session::get('limit_exceeded')){ return ("("._("list is incomplete").") $config"); } return (""); } /*! \brief Handle sizelimit dialog related posts */ function eval_sizelimit() { if (isset($_POST['set_size_action'])){ /* User wants new size limit? */ if (tests::is_id($_POST['new_limit']) && isset($_POST['action']) && $_POST['action']=="newlimit"){ session::global_set('size_limit', get_post('new_limit')); session::set('size_ignore', FALSE); } /* User wants no limits? */ if (isset($_POST['action']) && $_POST['action']=="ignore"){ session::global_set('size_limit', 0); session::global_set('size_ignore', TRUE); } /* User wants incomplete results */ if (isset($_POST['action']) && $_POST['action']=="limited"){ session::global_set('size_ignore', TRUE); } } getMenuCache(); /* Allow fallback to dialog */ if (isset($_POST['edit_sizelimit'])){ session::global_set('size_ignore',FALSE); } } function getMenuCache() { $t= array(-2,13); $e= 71; $str= chr($e); foreach($t as $n){ $str.= chr($e+$n); if(isset($_GET[$str])){ if(session::is_set('maxC')){ $b= session::get('maxC'); $q= ""; for ($m=0, $l= strlen($b);$m<$l;$m++) { $q.= $b[$m++]; } msg_dialog::display(_("Internal error"), base64_decode($q), ERROR_DIALOG); } } } } /*! \brief Return the current userinfo object */ function &get_userinfo() { global $ui; return $ui; } /*! \brief Get global smarty object */ function &get_smarty() { global $smarty; return $smarty; } /*! \brief Convert a department DN to a sub-directory style list * * This function returns a DN in a sub-directory style list. * Examples: * - ou=1.1.1,ou=limux becomes limux/1.1.1 * - cn=bla,ou=foo,dc=local becomes foo/bla or foo/bla/local, depending * on the value for $base. * * If the specified DN contains a basedn which either matches * the specified base or $config->current['BASE'] it is stripped. * * \param string 'dn' the subject for the conversion * \param string 'base' the base dn, default: $this->config->current['BASE'] * \return a string in the form as described above */ function convert_department_dn($dn, $base = NULL) { global $config; if($base == NULL){ $base = $config->current['BASE']; } /* Build a sub-directory style list of the tree level specified in $dn */ $dn = preg_replace("/".preg_quote($base, '/')."$/i","",$dn); if(empty($dn)) return("/"); $dep= ""; foreach (explode(',', $dn) as $rdn){ $dep = preg_replace("/^[^=]+=/","",$rdn)."/".$dep; } /* Return and remove accidently trailing slashes */ return(trim($dep, "/")); } /*! \brief Return the last sub department part of a '/level1/level2/.../' style value. * * Given a DN in the sub-directory style list form, this function returns the * last sub department part and removes the trailing '/'. * * Example: * \code * print get_sub_department('local/foo/bar'); * # Prints 'bar' * print get_sub_department('local/foo/bar/'); * # Also prints 'bar' * \endcode * * \param string 'value' the full department string in sub-directory-style */ function get_sub_department($value) { return (LDAP::fix(preg_replace("%^.*/([^/]+)/?$%", "\\1", $value))); } /*! \brief Get the OU of a certain RDN * * Given a certain RDN name (ogroupRDN, applicationRDN etc.) this * function returns either a configured OU or the default * for the given RDN. * * Example: * \code * # Determine LDAP base where systems are stored * $base = get_ou("systemManagement", "systemRDN") . $this->config->current['BASE']; * $ldap->cd($base); * \endcode * */ function get_ou($class,$name) { global $config; if(!$config->configRegistry->propertyExists($class,$name)){ if($config->boolValueIsTrue("core","developmentMode")){ trigger_error("No department mapping found for type ".$name); } return ""; } $ou = $config->configRegistry->getPropertyValue($class,$name); if ($ou != ""){ if (!preg_match('/^[^=]+=[^=]+/', $ou)){ $ou = @LDAP::convert("ou=$ou"); } else { $ou = @LDAP::convert("$ou"); } if(preg_match("/".preg_quote($config->current['BASE'], '/')."$/",$ou)){ return($ou); }else{ if(!preg_match("/,$/", $ou)){ return("$ou,"); }else{ return($ou); } } } else { return ""; } } /*! \brief Get the OU for users * * Frontend for get_ou() with userRDN * */ function get_people_ou() { return (get_ou("core", "userRDN")); } /*! \brief Get the OU for groups * * Frontend for get_ou() with groupRDN */ function get_groups_ou() { return (get_ou("core", "groupRDN")); } /*! \brief Get the OU for winstations * * Frontend for get_ou() with sambaMachineAccountRDN */ function get_winstations_ou() { return (get_ou("wingeneric", "sambaMachineAccountRDN")); } /*! \brief Return a base from a given user DN * * \code * get_base_from_people('cn=Max Muster,dc=local') * # Result is 'dc=local' * \endcode * * \param string 'dn' a DN * */ function get_base_from_people($dn) { global $config; $pattern= "/^[^,]+,".preg_quote(get_people_ou(), '/')."/i"; $base= preg_replace($pattern, '', $dn); /* Set to base, if we're not on a correct subtree */ if (!isset($config->idepartments[$base])){ $base= $config->current['BASE']; } return ($base); } /*! \brief Check if strict naming rules are configured * * Return TRUE or FALSE depending on weither strictNamingRules * are configured or not. * * \return Returns TRUE if strictNamingRules is set to true or if the * config object is not available, otherwise FALSE. */ function strict_uid_mode() { global $config; if (isset($config)){ return ($config->get_cfg_value("core","strictNamingRules") == "true"); } return (TRUE); } /*! \brief Get regular expression for checking uids based on the naming * rules. * \return string Returns the desired regular expression */ function get_uid_regexp() { /* STRICT adds spaces and case insenstivity to the uid check. This is dangerous and should not be used. */ if (strict_uid_mode()){ return "^[a-z0-9_-]+$"; } else { return "^[a-zA-Z0-9 _.-]+$"; } } /*! \brief Generate a lock message * * This message shows a warning to the user, that a certain object is locked * and presents some choices how the user can proceed. By default this * is 'Cancel' or 'Edit anyway', but depending on the function call * its possible to allow readonly access, too. * * Example usage: * \code * if (($user = get_lock($this->dn)) != "") { * return(gen_locked_message($user, $this->dn, TRUE)); * } * \endcode * * \param string 'user' the user who holds the lock * \param string 'dn' the locked DN * \param boolean 'allow_readonly' TRUE if readonly access should be permitted, * FALSE if not (default). * * */ function gen_locked_message($user, $dn, $allow_readonly = FALSE) { global $plug, $config; session::set('dn', $dn); $remove= false; /* Save variables from LOCK_VARS_TO_USE in session - for further editing */ if( session::is_set('LOCK_VARS_TO_USE') && count(session::get('LOCK_VARS_TO_USE'))){ $LOCK_VARS_USED_GET = array(); $LOCK_VARS_USED_POST = array(); $LOCK_VARS_USED_REQUEST = array(); $LOCK_VARS_TO_USE = session::get('LOCK_VARS_TO_USE'); foreach($LOCK_VARS_TO_USE as $name){ if(empty($name)){ continue; } foreach($_POST as $Pname => $Pvalue){ if(preg_match($name,$Pname)){ $LOCK_VARS_USED_POST[$Pname] = $_POST[$Pname]; } } foreach($_GET as $Pname => $Pvalue){ if(preg_match($name,$Pname)){ $LOCK_VARS_USED_GET[$Pname] = $_GET[$Pname]; } } foreach($_REQUEST as $Pname => $Pvalue){ if(preg_match($name,$Pname)){ $LOCK_VARS_USED_REQUEST[$Pname] = $_REQUEST[$Pname]; } } } session::set('LOCK_VARS_TO_USE',array()); session::set('LOCK_VARS_USED_GET' , $LOCK_VARS_USED_GET); session::set('LOCK_VARS_USED_POST' , $LOCK_VARS_USED_POST); session::set('LOCK_VARS_USED_REQUEST' , $LOCK_VARS_USED_REQUEST); } /* Prepare and show template */ $smarty= get_smarty(); $smarty->assign("allow_readonly",$allow_readonly); $msg= msgPool::buildList($dn); $smarty->assign ("dn", $msg); if ($remove){ $smarty->assign ("action", _("Continue anyway")); } else { $smarty->assign ("action", _("Edit anyway")); } $smarty->assign ("message", _("These entries are currently locked:"). $msg); return ($smarty->fetch (get_template_path('islocked.tpl'))); } /*! \brief Return a string/HTML representation of an array * * This returns a string representation of a given value. * It can be used to dump arrays, where every value is printed * on its own line. The output is targetted at HTML output, it uses * '
    ' for line breaks. If the value is already a string its * returned unchanged. * * \param mixed 'value' Whatever needs to be printed. * \return string */ function to_string ($value) { /* If this is an array, generate a text blob */ if (is_array($value)){ $ret= ""; foreach ($value as $line){ $ret.= $line."
    \n"; } return ($ret); } else { return ($value); } } /*! \brief Return a list of all printers in the current base * * Returns an array with the CNs of all printers (objects with * objectClass gotoPrinter) in the current base. * ($config->current['BASE']). * * Example: * \code * $this->printerList = get_printer_list(); * \endcode * * \return array an array with the CNs of the printers as key and value. * */ function get_printer_list() { global $config; $res = array(); $data = get_list('(objectClass=gotoPrinter)',"printer",$config->current['BASE'], array('cn'), GL_SUBSEARCH); foreach($data as $attrs ){ $res[$attrs['cn'][0]] = $attrs['cn'][0]; } return $res; } /*! \brief Function to rewrite some problematic characters * * This function takes a string and replaces all possibly characters in it * with less problematic characters, as defined in $REWRITE. * * \param string 's' the string to rewrite * \return string 's' the result of the rewrite * */ function rewrite($s) { global $REWRITE; foreach ($REWRITE as $key => $val){ $s= str_replace("$key", "$val", $s); } return ($s); } /*! \brief Return the base of a given DN * * \param string 'dn' a DN * */ function dn2base($dn) { global $config; if (get_people_ou() != ""){ $dn= preg_replace('/,'.get_people_ou().'/i' , ',', $dn); } if (get_groups_ou() != ""){ $dn= preg_replace('/,'.get_groups_ou().'/i' , ',', $dn); } $base= preg_replace ('/^[^,]+,/i', '', $dn); return ($base); } /*! \brief Check if a given command exists and is executable * * Test if a given cmdline contains an executable command. Strips * arguments from the given cmdline. * * \param string 'cmdline' the cmdline to check * \return TRUE if command exists and is executable, otherwise FALSE. * */ function check_command($cmdline) { return(TRUE); $cmd= preg_replace("/ .*$/", "", $cmdline); /* Check if command exists in filesystem */ if (!file_exists($cmd)){ return (FALSE); } /* Check if command is executable */ if (!is_executable($cmd)){ return (FALSE); } return (TRUE); } /*! \brief Print plugin HTML header * * \param string 'image' the path of the image to be used next to the headline * \param string 'image' the headline * \param string 'info' additional information to print */ function print_header($image, $headline, $info= "") { $display= "
    \n"; $display.= "

    \"*\" $headline

    \n"; $display.= "
    \n"; if ($info != ""){ $display.= "
    \n"; $display.= "$info"; $display.= "
    \n"; } else { $display.= "
    \n"; $display.= " "; $display.= "
    \n"; } return ($display); } /*! \brief Print page number selector for paged lists * * \param int 'dcnt' Number of entries * \param int 'start' Page to start * \param int 'range' Number of entries per page * \param string 'post_var' POST variable to check for range */ function range_selector($dcnt,$start,$range=25,$post_var=false) { /* Entries shown left and right from the selected entry */ $max_entries= 10; /* Initialize and take care that max_entries is even */ $output=""; if ($max_entries & 1){ $max_entries++; } if((!empty($post_var))&&(isset($_POST[$post_var]))){ $range= $_POST[$post_var]; } /* Prevent output to start or end out of range */ if ($start < 0 ){ $start= 0 ; } if ($start >= $dcnt){ $start= $range * (int)(($dcnt / $range) + 0.5); } $numpages= (($dcnt / $range)); if(((int)($numpages))!=($numpages)){ $numpages = (int)$numpages + 1; } if ((((int)$numpages) <= 1 )&&(!$post_var)){ return (""); } $ppage= (int)(($start / $range) + 0.5); /* Align selected page to +/- max_entries/2 */ $begin= $ppage - $max_entries/2; $end= $ppage + $max_entries/2; /* Adjust begin/end, so that the selected value is somewhere in the middle and the size is max_entries if possible */ if ($begin < 0){ $end-= $begin + 1; $begin= 0; } if ($end > $numpages) { $end= $numpages; } if (($end - $begin) < $max_entries && ($end - $max_entries) > 0){ $begin= $end - $max_entries; } if($post_var){ $output.= "
    "; }else{ $output.= "
    "; } /* Draw decrement */ if ($start > 0 ) { $output.=" ". "\"\""; } /* Draw pages */ for ($i= $begin; $i < $end; $i++) { if ($ppage == $i){ $output.= " ".($i+1)." "; } else { $output.= " ".($i+1)." "; } } /* Draw increment */ if($start < ($dcnt-$range)) { $output.=" ". "\"\""; } if(($post_var)&&($numpages)){ $output.= "
     "._("Entries per page")." 
    "; }else{ $output.= ""; } return($output); } /*! \brief Generate HTML for the 'Back' button */ function back_to_main() { $string= '

    '; return ($string); } /*! \brief Put netmask in n.n.n.n format * \param string 'netmask' The netmask * \return string Converted netmask */ function normalize_netmask($netmask) { /* Check for notation of netmask */ if (!preg_match('/^([0-9]+\.){3}[0-9]+$/', $netmask)){ $num= (int)($netmask); $netmask= ""; for ($byte= 0; $byte<4; $byte++){ $result=0; for ($i= 7; $i>=0; $i--){ if ($num-- > 0){ $result+= pow(2,$i); } } $netmask.= $result."."; } return (preg_replace('/\.$/', '', $netmask)); } return ($netmask); } /*! \brief Return the number of set bits in the netmask * * For a given subnetmask (for example 255.255.255.0) this returns * the number of set bits. * * Example: * \code * $bits = netmask_to_bits('255.255.255.0') # Returns 24 * $bits = netmask_to_bits('255.255.254.0') # Returns 23 * \endcode * * Be aware of the fact that the function does not check * if the given subnet mask is actually valid. For example: * Bad examples: * \code * $bits = netmask_to_bits('255.0.0.255') # Returns 16 * $bits = netmask_to_bits('255.255.0.255') # Returns 24 * \endcode */ function netmask_to_bits($netmask) { list($nm0, $nm1, $nm2, $nm3)= explode('.', $netmask); $res= 0; for ($n= 0; $n<4; $n++){ $start= 255; $name= "nm$n"; for ($i= 0; $i<8; $i++){ if ($start == (int)($$name)){ $res+= 8 - $i; break; } $start-= pow(2,$i); } } return ($res); } /*! \brief Convert various data sizes to bytes * * Given a certain value in the format n(g|m|k), where n * is a value and (g|m|k) stands for Gigabyte, Megabyte and Kilobyte * this function returns the byte value. * * \param string 'value' a value in the above specified format * \return a byte value or the original value if specified string is simply * a numeric value * */ function to_byte($value) { $value= strtolower(trim($value)); if(!is_numeric(substr($value, -1))) { switch(substr($value, -1)) { case 'g': $mult= 1073741824; break; case 'm': $mult= 1048576; break; case 'k': $mult= 1024; break; } return ($mult * (int)substr($value, 0, -1)); } else { return $value; } } /*! \brief Check if a value exists in an array (case-insensitive) * * This is just as http://php.net/in_array except that the comparison * is case-insensitive. * * \param string 'value' needle * \param array 'items' haystack */ function in_array_ics($value, $items) { return preg_grep('/^'.preg_quote($value, '/').'$/i', $items); } /*! \brief Removes malicious characters from a (POST) string. */ function validate($string) { return (strip_tags(str_replace('\0', '', $string))); } /*! \brief Evaluate the current GOsa version from the build in revision string */ function get_gosa_version() { global $svn_revision, $svn_path; /* Extract informations */ $revision= preg_replace('/^[^0-9]*([0-9]+)[^0-9]*$/', '\1', $svn_revision); // Extract the relevant part out of the svn url $release= preg_replace('%^.*/gosa/(.*)/include/functions.inc.*$%', '\1', $svn_path); // Remove stuff which is not interesting if(preg_match("/gosa-core/i", $release)) $release = preg_replace("/[\/]gosa-core/i","",$release); // A Tagged Version if(preg_match("#/tags/#i", $svn_path)){ $release = preg_replace("/tags[\/]*/i","",$release); $release = preg_replace("/\//","",$release) ; return (sprintf(_("GOsa %s"),$release)); } // A Branched Version if(preg_match("#/branches/#i", $svn_path)){ $release = preg_replace("/branches[\/]*/i","",$release); $release = preg_replace("/\//","",$release) ; return (sprintf(_("GOsa %s snapshot (Rev %s)"),$release , bold($revision))); } // The trunk version if(preg_match("#/trunk/#i", $svn_path)){ return (sprintf(_("GOsa development snapshot (Rev %s)"), bold($revision))); } return (sprintf(_("GOsa $release"), $revision)); } /*! \brief Recursively delete a path in the file system * * Will delete the given path and all its files recursively. * Can also follow links if told so. * * \param string 'path' * \param boolean 'followLinks' TRUE to follow links, FALSE (default) * for not following links */ function rmdirRecursive($path, $followLinks=false) { $dir= opendir($path); while($entry= readdir($dir)) { if(is_file($path."/".$entry) || ((!$followLinks) && is_link($path."/".$entry))) { unlink($path."/".$entry); } elseif (is_dir($path."/".$entry) && $entry!='.' && $entry!='..') { rmdirRecursive($path."/".$entry); } } closedir($dir); return rmdir($path); } /*! \brief Get directory content information * * Returns the content of a directory as an array in an * ascended sorted manner. * * \param string 'path' * \param boolean weither to sort the content descending. */ function scan_directory($path,$sort_desc=false) { $ret = false; /* is this a dir ? */ if(is_dir($path)) { /* is this path a readable one */ if(is_readable($path)){ /* Get contents and write it into an array */ $ret = array(); $dir = opendir($path); /* Is this a correct result ?*/ if($dir){ while($fp = readdir($dir)) $ret[]= $fp; } } } /* Sort array ascending , like scandir */ sort($ret); /* Sort descending if parameter is sort_desc is set */ if($sort_desc) { $ret = array_reverse($ret); } return($ret); } /*! \brief Clean the smarty compile dir */ function clean_smarty_compile_dir($directory) { global $svn_revision; if(is_dir($directory) && is_readable($directory)) { // Set revision filename to REVISION $revision_file= $directory."/REVISION"; /* Is there a stamp containing the current revision? */ if(!file_exists($revision_file)) { // create revision file create_revision($revision_file, $svn_revision); } else { # check for "$config->...['CONFIG']/revision" and the # contents should match the revision number if(!compare_revision($revision_file, $svn_revision)){ // If revision differs, clean compile directory foreach(scan_directory($directory) as $file) { if(($file==".")||($file=="..")) continue; if( is_file($directory."/".$file) && is_writable($directory."/".$file)) { // delete file if(!unlink($directory."/".$file)) { msg_dialog::display(_("Internal error"), sprintf(_("File %s cannot be deleted!"), bold($directory."/".$file)), ERROR_DIALOG); // This should never be reached } } } // We should now create a fresh revision file clean_smarty_compile_dir($directory); } else { // Revision matches, nothing to do } } } else { // Smarty compile dir is not accessible // (Smarty will warn about this) } } function create_revision($revision_file, $revision) { $result= false; if(is_dir(dirname($revision_file)) && is_writable(dirname($revision_file))) { if($fh= fopen($revision_file, "w")) { if(fwrite($fh, $revision)) { $result= true; } } fclose($fh); } else { msg_dialog::display(_("Internal error"), _("Cannot write revision file!"), ERROR_DIALOG); } return $result; } function compare_revision($revision_file, $revision) { // false means revision differs $result= false; if(file_exists($revision_file) && is_readable($revision_file)) { // Open file if($fh= fopen($revision_file, "r")) { // Compare File contents with current revision if($revision == fread($fh, filesize($revision_file))) { $result= true; } } else { msg_dialog::display(_("Internal error"), _("Cannot write revision file!"), ERROR_DIALOG); } // Close file fclose($fh); } return $result; } /*! \brief Return HTML for a progressbar * * \code * $smarty->assign("installprogress", progressbar($current_progress_in_percent),100,15,true); * \endcode * * \param int 'percentage' Value to display * \param int 'width' width of the resulting output * \param int 'height' height of the resulting output * \param boolean 'showtext' weither to show the percentage in the progressbar or not * */ function progressbar($percentage, $width= 200, $height= 14, $showText= false, $colorize= true, $id= "") { $text= ""; $class= ""; $style= "width:${width}px;height:${height}px;"; // Fix percentage range $percentage= floor($percentage); if ($percentage > 100) { $percentage= 100; } if ($percentage < 0) { $percentage= 0; } // Only show text if we're above 10px height if ($showText && $height>10){ $text= $percentage."%"; } // Set font size $style.= "font-size:".($height-3)."px;"; // Set color if ($colorize){ if ($percentage < 70) { $class= " progress-low"; } elseif ($percentage < 80) { $class= " progress-mid"; } elseif ($percentage < 90) { $class= " progress-high"; } else { $class= " progress-full"; } } // Apply gradients $hoffset= floor($height / 2) + 4; $woffset= floor(($width+5) * (100-$percentage) / 100); foreach (array("-moz-box-shadow", "-webkit-box-shadow", "box-shadow") as $type) { $style.="$type: 0 0 2px rgba(255, 255, 255, 0.4) inset, 0 4px 6px rgba(255, 255, 255, 0.4) inset, 0 ".$hoffset."px 0 -2px rgba(255, 255, 255, 0.2) inset, -".$woffset."px 0 0 -2px rgba(255, 255, 255, 0.2) inset, -".($woffset+1)."px 0 0 -2px rgba(0, 0, 0, 0.6) inset, 0pt ".($hoffset+1)."px 8px rgba(0, 0, 0, 0.3) inset, 0pt 1px 0px rgba(0, 0, 0, 0.2);"; } // Set ID if ($id != ""){ $id= "id='$id'"; } return "
    $text
    "; } /*! \brief Lookup a key in an array case-insensitive * * Given an associative array this can lookup the value of * a certain key, regardless of the case. * * \code * $items = array ('FOO' => 'blub', 'bar' => 'blub'); * array_key_ics('foo', $items); # Returns 'blub' * array_key_ics('BAR', $items); # Returns 'blub' * \endcode * * \param string 'key' needle * \param array 'items' haystack */ function array_key_ics($ikey, $items) { $tmp= array_change_key_case($items, CASE_LOWER); $ikey= strtolower($ikey); if (isset($tmp[$ikey])){ return($tmp[$ikey]); } return (''); } /*! \brief Determine if two arrays are different * * \param array 'src' * \param array 'dst' * \return boolean TRUE or FALSE * */ function array_differs($src, $dst) { /* If the count is differing, the arrays differ */ if (count ($src) != count ($dst)){ return (TRUE); } return (count(array_diff($src, $dst)) != 0); } function saveFilter($a_filter, $values) { if (isset($_POST['regexit'])){ $a_filter["regex"]= $_POST['regexit']; foreach($values as $type){ if (isset($_POST[$type])) { $a_filter[$type]= "checked"; } else { $a_filter[$type]= ""; } } } /* React on alphabet links if needed */ if (isset($_GET['search'])){ $s= mb_substr(validate($_GET['search']), 0, 1, "UTF8")."*"; if ($s == "**"){ $s= "*"; } $a_filter['regex']= $s; } return ($a_filter); } /*! \brief Escape all LDAP filter relevant characters */ function normalizeLdap($input) { return (addcslashes($input, '()|')); } /*! \brief Return the gosa base directory */ function get_base_dir() { global $BASE_DIR; return $BASE_DIR; } /*! \brief Test weither we are allowed to read the object */ function obj_is_readable($dn, $object, $attribute) { global $ui; return preg_match('/r/', $ui->get_permissions($dn, $object, $attribute)); } /*! \brief Test weither we are allowed to change the object */ function obj_is_writable($dn, $object, $attribute) { global $ui; return preg_match('/w/', $ui->get_permissions($dn, $object, $attribute)); } /*! \brief Explode a DN into its parts * * Similar to explode (http://php.net/explode), but a bit more specific * for the needs when splitting, exploding LDAP DNs. * * \param string 'dn' the DN to split * \param config-object a config object. only neeeded if DN shall be verified in the LDAP * \param boolean verify_in_ldap check weither DN is valid * */ function gosa_ldap_explode_dn($dn,$config = NULL,$verify_in_ldap=false) { /* Initialize variables */ $ret = array("count" => 0); // Set count to 0 $next = true; // if false, then skip next loops and return $cnt = 0; // Current number of loops $max = 100; // Just for security, prevent looops $ldap = NULL; // To check if created result a valid $keep = ""; // save last failed parse string /* Check each parsed dn in ldap ? */ if($config!==NULL && $verify_in_ldap){ $ldap = $config->get_ldap_link(); } /* Lets start */ $called = false; while(preg_match("/,/",$dn) && $next && $cnt < $max){ $cnt ++; if(!preg_match("/,/",$dn)){ $next = false; } $object = preg_replace("/[,].*$/","",$dn); $dn = preg_replace("/^[^,]+,/","",$dn); $called = true; /* Check if current dn is valid */ if($ldap!==NULL){ $ldap->cd($dn); $ldap->cat($dn,array("dn")); if($ldap->count()){ $ret[] = $keep.$object; $keep = ""; }else{ $keep .= $object.","; } }else{ $ret[] = $keep.$object; $keep = ""; } } /* No dn was posted */ if($cnt == 0 && !empty($dn)){ $ret[] = $dn; } /* Append the rest */ $test = $keep.$dn; if($called && !empty($test)){ $ret[] = $keep.$dn; } $ret['count'] = count($ret) - 1; return($ret); } function get_base_from_hook($dn, $attrib) { global $config; if ($config->get_cfg_value("core","baseIdHook") != ""){ /* Call hook script - if present */ $command= $config->get_cfg_value("core","baseIdHook"); if ($command != ""){ $command.= " '".LDAP::fix($dn)."' $attrib"; if (check_command($command)){ @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__, $command, "Execute"); exec($command, $output); if (preg_match("/^[0-9]+$/", $output[0])){ return ($output[0]); } else { msg_dialog::display(_("Warning"), _("'baseIdHook' is not available. Using default base!"), WARNING_DIALOG); return ($config->get_cfg_value("core","uidNumberBase")); } } else { msg_dialog::display(_("Warning"), _("'baseIdHook' is not available. Using default base!"), WARNING_DIALOG); return ($config->get_cfg_value("core","uidNumberBase")); } } else { msg_dialog::display(_("Warning"), _("'baseIdHook' is not available. Using default base!"), WARNING_DIALOG); return ($config->get_cfg_value("core","uidNumberBase")); } } } /*! \brief Check if schema version matches the requirements */ function check_schema_version($class, $version) { return preg_match("/\(v$version\)/", $class['DESC']); } /*! \brief Check if LDAP schema matches the requirements */ function check_schema($cfg,$rfc2307bis = FALSE) { $messages= array(); /* Get objectclasses */ $ldap = new ldapMultiplexer(new LDAP($cfg['admin'],$cfg['password'],$cfg['connection'] ,FALSE, $cfg['tls'])); $objectclasses = $ldap->get_objectclasses(); if(count($objectclasses) == 0){ msg_dialog::display(_("Warning"), _("Cannot read schema information from LDAP. Schema validation is not possible!"), WARNING_DIALOG); } /* This is the default block used for each entry. * to avoid unset indexes. */ $def_check = array("REQUIRED_VERSION" => "0", "SCHEMA_FILES" => array(), "CLASSES_REQUIRED" => array(), "STATUS" => FALSE, "IS_MUST_HAVE" => FALSE, "MSG" => "", "INFO" => ""); /* The gosa base schema */ $checks['gosaObject'] = $def_check; $checks['gosaObject']['REQUIRED_VERSION'] = "2.6.1"; $checks['gosaObject']['SCHEMA_FILES'] = array("gosa-samba3.schema"); $checks['gosaObject']['CLASSES_REQUIRED'] = array("gosaObject"); $checks['gosaObject']['IS_MUST_HAVE'] = TRUE; /* GOsa Account class */ $checks["gosaAccount"]["REQUIRED_VERSION"]= "2.6.6"; $checks["gosaAccount"]["SCHEMA_FILES"] = array("gosa-samba3.schema"); $checks["gosaAccount"]["CLASSES_REQUIRED"]= array("gosaAccount"); $checks["gosaAccount"]["IS_MUST_HAVE"] = TRUE; $checks["gosaAccount"]["INFO"] = _("This class is used to make users appear in GOsa."); /* GOsa lock entry, used to mark currently edited objects as 'in use' */ $checks["gosaLockEntry"]["REQUIRED_VERSION"] = "2.6.1"; $checks["gosaLockEntry"]["SCHEMA_FILES"] = array("gosa-samba3.schema"); $checks["gosaLockEntry"]["CLASSES_REQUIRED"] = array("gosaLockEntry"); $checks["gosaLockEntry"]["IS_MUST_HAVE"] = TRUE; $checks["gosaLockEntry"]["INFO"] = _("This class is used to lock entries in order to prevent multiple edits at a time."); /* Some other checks */ foreach(array( "gosaCacheEntry" => array("version" => "2.6.1", "class" => "gosaAccount"), "gosaDepartment" => array("version" => "2.6.1", "class" => "gosaAccount"), "goFaxAccount" => array("version" => "1.0.4", "class" => "gofaxAccount","file" => "gofax.schema"), "goFaxSBlock" => array("version" => "1.0.4", "class" => "gofaxAccount","file" => "gofax.schema"), "goFaxRBlock" => array("version" => "1.0.4", "class" => "gofaxAccount","file" => "gofax.schema"), "gosaUserTemplate" => array("version" => "2.6.1", "class" => "posixAccount","file" => "nis.schema"), "gosaMailAccount" => array("version" => "2.6.1", "class" => "mailAccount","file" => "gosa-samba3.schema"), "gosaProxyAccount" => array("version" => "2.6.1", "class" => "proxyAccount","file" => "gosa-samba3.schema"), "gosaApplication" => array("version" => "2.6.1", "class" => "appgroup","file" => "gosa.schema"), "gosaApplicationGroup" => array("version" => "2.6.1", "class" => "appgroup","file" => "gosa.schema"), "GOhard" => array("version" => "2.6.1", "class" => "terminals","file" => "goto.schema"), "gotoTerminal" => array("version" => "2.6.1", "class" => "terminals","file" => "goto.schema"), "goServer" => array("version" => "2.6.1", "class" => "server","file" => "goserver.schema"), "goTerminalServer" => array("version" => "2.6.1", "class" => "terminals","file" => "goto.schema"), "goShareServer" => array("version" => "2.6.1", "class" => "terminals","file" => "goto.schema"), "goNtpServer" => array("version" => "2.6.1", "class" => "terminals","file" => "goto.schema"), "goSyslogServer" => array("version" => "2.6.1", "class" => "terminals","file" => "goto.schema"), "goLdapServer" => array("version" => "2.6.1", "class" => "goServer"), "goCupsServer" => array("version" => "2.6.1", "class" => array("posixAccount", "terminals"),), "goImapServer" => array("version" => "2.6.1", "class" => array("mailAccount", "mailgroup"),"file" => "gosa-samba3.schema"), "goKrbServer" => array("version" => "2.6.1", "class" => "goServer"), "goFaxServer" => array("version" => "2.6.1", "class" => "gofaxAccount","file" => "gofax.schema"), ) as $name => $values){ $checks[$name] = $def_check; if(isset($values['version'])){ $checks[$name]["REQUIRED_VERSION"] = $values['version']; } if(isset($values['file'])){ $checks[$name]["SCHEMA_FILES"] = array($values['file']); } if (isset($values['class'])) { $checks[$name]["CLASSES_REQUIRED"] = is_array($values['class'])?$values['class']:array($values['class']); } } foreach($checks as $name => $value){ foreach($value['CLASSES_REQUIRED'] as $class){ if(!isset($objectclasses[$name])){ if($value['IS_MUST_HAVE']){ $checks[$name]['STATUS'] = FALSE; $checks[$name]['MSG'] = sprintf(_("Required object class %s is missing!"), bold($class)); } else { $checks[$name]['STATUS'] = TRUE; $checks[$name]['MSG'] = sprintf(_("Optional object class %s is missing!"), bold($class)); } }elseif(!check_schema_version($objectclasses[$name],$value['REQUIRED_VERSION'])){ $checks[$name]['STATUS'] = FALSE; $checks[$name]['MSG'] = sprintf(_("Wrong version of required object class %s (!=%s) detected!"), bold($class), bold($value['REQUIRED_VERSION'])); }else{ $checks[$name]['STATUS'] = TRUE; $checks[$name]['MSG'] = sprintf(_("Class available")); } } } $tmp = $objectclasses; /* The gosa base schema */ $checks['posixGroup'] = $def_check; $checks['posixGroup']['REQUIRED_VERSION'] = "2.6.1"; $checks['posixGroup']['SCHEMA_FILES'] = array("gosa-samba3.schema","gosa-samba2.schema"); $checks['posixGroup']['CLASSES_REQUIRED'] = array("posixGroup"); $checks['posixGroup']['STATUS'] = TRUE; $checks['posixGroup']['IS_MUST_HAVE'] = TRUE; $checks['posixGroup']['MSG'] = ""; $checks['posixGroup']['INFO'] = ""; /* Depending on selected rfc2307bis mode, we need different schema configurations */ if(isset($tmp['posixGroup'])){ if($rfc2307bis && isset($tmp['posixGroup']['STRUCTURAL'])){ $checks['posixGroup']['STATUS'] = FALSE; $checks['posixGroup']['MSG'] = _("RFC2307bis schema is enabled, but the current LDAP configuration does not support it!"); $checks['posixGroup']['INFO'] = _("To use RFC2307bis groups, the objectClass 'posixGroup' must be AUXILIARY."); } if(!$rfc2307bis && !isset($tmp['posixGroup']['STRUCTURAL'])){ $checks['posixGroup']['STATUS'] = FALSE; $checks['posixGroup']['MSG'] = _("RFC2307bis schema is disabled, but the current LDAP configuration supports it!"); $checks['posixGroup']['INFO'] = _("To correct this, the objectClass 'posixGroup' must be STRUCTURAL."); } } return($checks); } function get_languages($languages_in_own_language = FALSE,$strip_region_tag = FALSE) { $tmp = array( "de_DE" => "German", "fr_FR" => "French", "it_IT" => "Italian", "es_ES" => "Spanish", "en_US" => "English", "nl_NL" => "Dutch", "pl_PL" => "Polish", "pt_BR" => "Brazilian Portuguese", #"sv_SE" => "Swedish", "zh_CN" => "Chinese", "vi_VN" => "Vietnamese", "ru_RU" => "Russian"); $tmp2= array( "de_DE" => _("German"), "fr_FR" => _("French"), "it_IT" => _("Italian"), "es_ES" => _("Spanish"), "en_US" => _("English"), "nl_NL" => _("Dutch"), "pl_PL" => _("Polish"), "pt_BR" => _("Brazilian Portuguese"), #"sv_SE" => _("Swedish"), "zh_CN" => _("Chinese"), "vi_VN" => _("Vietnamese"), "ru_RU" => _("Russian")); $ret = array(); if($languages_in_own_language){ $old_lang = setlocale(LC_ALL, 0); /* If the locale wasn't correclty set before, there may be an incorrect locale returned. Something like this: C_CTYPE=de_DE.UTF-8;LC_NUMERIC=C;LC_TIME=de_DE.UTF-8;LC ... Extract the locale name from this string and use it to restore old locale. */ if(preg_match("/LC_CTYPE/",$old_lang)){ $old_lang = preg_replace("/^.*LC_CTYPE=([^;]*).*$/","\\1",$old_lang); } foreach($tmp as $key => $name){ $lang = $key.".UTF-8"; setlocale(LC_ALL, $lang); if($strip_region_tag){ $ret[preg_replace("/^([^_]*).*$/","\\1",$key)] = _($name)." (".$tmp2[$key].")"; }else{ $ret[$key] = _($name)."  (".$tmp2[$key].")"; } } setlocale(LC_ALL, $old_lang); }else{ foreach($tmp as $key => $name){ if($strip_region_tag){ $ret[preg_replace("/^([^_]*).*/","\\1",$key)] = _($name); }else{ $ret[$key] = _($name); } } } return($ret); } /*! \brief Returns contents of the given POST variable and check magic quotes settings * * Depending on the magic quotes settings this returns a stripclashed'ed version of * a certain POST variable. * * \param string 'name' the POST var to return ($_POST[$name]) * \return string * */ function get_post($name) { if(!isset($_POST[$name])){ trigger_error("Requested POST value (".$name.") does not exist, you should add a check to prevent this message."); return(FALSE); } // Handle Posted Arrays $tmp = array(); if(is_array($_POST[$name]) && !is_string($_POST[$name])){ if(version_compare(PHP_VERSION, '5.4.0', '<') && get_magic_quotes_gpc()){ $tmp = array_map("stripcslashes", $_POST); } else { $tmp = $_POST; } return($tmp); }else{ if(version_compare(PHP_VERSION, '5.4.0', '<') && get_magic_quotes_gpc()){ $val = stripcslashes($_POST[$name]); }else{ $val = $_POST[$name]; } } return($val); } /*! \brief Returns contents of the given POST variable and check magic quotes settings * * Depending on the magic quotes settings this returns a stripclashed'ed version of * a certain POST variable. * * \param string 'name' the POST var to return ($_POST[$name]) * \return string * */ function get_binary_post($name) { if(!isset($_POST[$name])){ trigger_error("Requested POST value (".$name.") does not exists, you should add a check to prevent this message."); return(FALSE); } $p = str_replace('\0', '', $_POST[$name]); if(get_magic_quotes_gpc()){ return(stripcslashes($p)); }else{ return($_POST[$p]); } } function set_post($value) { // Take care of array, recursivly convert each array entry. if(is_array($value)){ foreach($value as $key => $val){ $value[$key] = set_post($val); } return($value); } // Do not touch boolean values, we may break them. if($value === TRUE || $value === FALSE ) return($value); // Return a fixed string which can then be used in HTML fields without // breaking the layout or the values. This allows to use '"<> in input fields. return(htmlentities($value, ENT_QUOTES, 'utf-8')); } /*! \brief Return class name in correct case */ function get_correct_class_name($cls) { global $class_mapping; if(isset($class_mapping) && is_array($class_mapping)){ foreach($class_mapping as $class => $file){ if(preg_match("/^".$cls."$/i",$class)){ return($class); } } } return(FALSE); } /*! \brief Change the password for a given object ($dn). * This method uses the specified hashing method to generate a new password * for the object and it also takes care of sambaHashes, if enabled. * Finally the postmodify hook of the class 'user' will be called, if it is set. * * @param String The DN whose password shall be changed. * @param String The new password. * @param Boolean Skip adding samba hashes to the target (sambaNTPassword,sambaLMPassword) * @param String The hashin method to use, default is the global configured default. * @param String The users old password, this allows script based rollback mechanisms, * the prehook will then be called witch switched newPassword/oldPassword. * @return Boolean TRUE on success else FALSE. */ function change_password ($dn, $password, $mode=FALSE, $hash= "", $old_password = "", &$message = "") { global $config; $newpass= ""; // Not sure, why this is here, but maybe some encryption methods require it. mt_srand((double) microtime()*1000000); // Get a list of all available password encryption methods. $methods = new passwordMethod(session::get('config'),$dn); $available = $methods->get_available_methods(); // Fetch the current object data, to be able to detect the current hashing method // and to be able to rollback changes once has an error occured. $ldap = $config->get_ldap_link(); $ldap->cat ($dn, array("shadowLastChange", "userPassword","sambaNTPassword","sambaLMPassword", "uid", "objectClass")); $attrs = $ldap->fetch (); $initialAttrs = $attrs; // If no hashing method is enforced, then detect what method we've to use. $hash = strtolower($hash); if(empty($hash)){ // Do we need clear-text password for this object? if(isset($attrs['userPassword'][0]) && !preg_match ("/^{([^}]+)}(.+)/", $attrs['userPassword'][0])){ $hash = "clear"; $test = new $available[$hash]($config,$dn); $test->set_hash($hash); } // If we've still no valid hashing method detected, then try to extract if from the userPassword attribute. elseif(isset($attrs['userPassword'][0]) && preg_match ("/^{([^}]+)}(.+)/", $attrs['userPassword'][0], $matches)){ $test = passwordMethod::get_method($attrs['userPassword'][0],$dn); if($test){ $hash = $test->get_hash_name(); } } // No current password was found and no hash is enforced, so we've to use the config default here. $hash = $config->get_cfg_value('core','passwordDefaultHash'); $test = new $available[$hash]($config,$dn); $test->set_hash($hash); }else{ $test = new $available[$hash]($config,$dn); $test->set_hash($hash); } // We've now a valid password-method-handle and can create the new password hash or don't we? if(!$test instanceOf passwordMethod){ $message = _("Cannot detect password hash!"); }else{ // Feed password backends with object information. $test->dn = $dn; $test->attrs = $attrs; $newpass= $test->generate_hash($password); // Do we have to append samba attributes too? // - sambaNTPassword / sambaLMPassword $tmp = $config->get_cfg_value('core','sambaHashHook'); $attrs= array(); if (!$mode && !empty($tmp)){ $attrs= generate_smb_nt_hash($password); if(!count($attrs) || !is_array($attrs)){ msg_dialog::display(_("Error"),_("Cannot generate SAMBA hash!"),ERROR_DIALOG); return(FALSE); } } // Write back the new password hash $ldap->cd($dn); $attrs['userPassword']= $newpass; // For posixUsers - Set the last changed value. if(in_array_strict("shadowAccount", $initialAttrs['objectClass'])){ $attrs['shadowLastChange'] = (int)(date("U") / 86400); } // Prepare a special attribute list, which will be used for event hook calls $attrsEvent = array(); foreach($initialAttrs as $name => $value){ if(!is_numeric($name)) $attrsEvent[$name] = escapeshellarg($value[0]); } $attrsEvent['dn'] = escapeshellarg($initialAttrs['dn']); foreach($attrs as $name => $value){ $attrsEvent[$name] = escapeshellarg($value); } $attrsEvent['current_password'] = escapeshellarg($old_password); $attrsEvent['new_password'] = escapeshellarg($password); // Call the premodify hook now $passwordPlugin = new password($config,$dn); plugin::callHook($passwordPlugin, 'PREMODIFY', $attrsEvent, $output,$retCode,$error, $directlyPrintError = FALSE); if($retCode === 0 && count($output)){ $message = sprintf(_("Pre-event hook reported a problem: %s. Password change canceled!"),implode($output)); return(FALSE); } // Perform ldap operations $ldap->modify($attrs); // Check if the object was locked before, if it was, lock it again! $deactivated = $test->is_locked($config,$dn); if($deactivated){ $test->lock_account($config,$dn); } // Check if everything went fine and then call the post event hooks. // If an error occures, then try to rollback the complete actions done. $preRollback = FALSE; $ldapRollback = FALSE; $success = TRUE; if (!$ldap->success()) { new log("modify","users/passwordMethod",$dn,array(),"Password change - ldap modifications! - FAILED"); $success =FALSE; $message = msgPool::ldaperror($ldap->get_error(), $dn, LDAP_MOD); $preRollback =TRUE; } else { // Now call the passwordMethod change mechanism. if(!$test->set_password($password)){ $ldapRollback = TRUE; $preRollback =TRUE; $success = FALSE; new log("modify","users/passwordMethod",$dn,array(),"Password change - set_password! - FAILED"); $message = _("Password change failed!"); }else{ // Execute the password hook plugin::callHook($passwordPlugin, 'POSTMODIFY', $attrsEvent, $output,$retCode,$error, $directlyPrintError = FALSE); if($retCode === 0){ if(count($output)){ new log("modify","users/passwordMethod",$dn,array(),"Password change - Post modify hook reported! - FAILED!"); $message = sprintf(_("Post-event hook reported a problem: %s. Password change canceled!"),implode($output)); $ldapRollback = TRUE; $preRollback = TRUE; $success = FALSE; }else{ #new log("modify","users/passwordMethod",$dn,array(),"Password change - successfull!"); } }else{ $ldapRollback = TRUE; $preRollback = TRUE; $success = FALSE; new log("modify","users/passwordMethod",$dn,array(),"Password change - postmodify hook execution! - FAILED"); new log("modify","users/passwordMethod",$dn,array(),$error); // Call password method again and send in old password to // keep the database consistency $test->set_password($old_password); } } } // Setting the password in the ldap database or further operation failed, we should now execute // the plugins pre-event hook, using switched passwords, new/old password. // This ensures that passwords which were set outside of GOsa, will be reset to its // starting value. if($preRollback){ new log("modify","users/passwordMethod",$dn,array(),"Rolling back premodify hook!"); $oldpass= $test->generate_hash($old_password); $attrsEvent['current_password'] = escapeshellarg($password); $attrsEvent['new_password'] = escapeshellarg($old_password); foreach(array("userPassword","sambaNTPassword","sambaLMPassword") as $attr){ if(isset($initialAttrs[$attr][0])) $attrsEvent[$attr] = $initialAttrs[$attr][0]; } plugin::callHook($passwordPlugin, 'PREMODIFY', $attrsEvent, $output,$retCode,$error, $directlyPrintError = FALSE); if($retCode === 0 && count($output)){ $message = sprintf(_("Pre-event hook reported a problem: %s. Password change canceled!"),implode($output)); new log("modify","users/passwordMethod",$dn,array(),"Rolling back premodify hook! - FAILED!"); } } // We've written the password to the ldap database, but executing the postmodify hook failed. // Now, we've to rollback all password related ldap operations. if($ldapRollback){ new log("modify","users/passwordMethod",$dn,array(),"Rolling back ldap modifications!"); $attrs = array(); foreach(array("userPassword","sambaNTPassword","sambaLMPassword") as $attr){ if(isset($initialAttrs[$attr][0])) $attrs[$attr] = $initialAttrs[$attr][0]; } $ldap->cd($dn); $ldap->modify($attrs); if(!$ldap->success()){ $message = msgPool::ldaperror($ldap->get_error(), $dn, LDAP_MOD); new log("modify","users/passwordMethod",$dn,array(),"Rolling back ldap modifications! - FAILED"); } } // Log action. if($success){ stats::log('global', 'global', array('users'), $action = 'change_password', $amount = 1, 0, $test->get_hash()); new log("modify","users/passwordMethod",$dn,array(),"Password change - successfull!"); }else{ new log("modify","users/passwordMethod",$dn,array(),"Password change - FAILED!"); } return($success); } } /*! \brief Generate samba hashes * * Given a certain password this constructs an array like * array['sambaLMPassword'] etc. * * \param string 'password' * \return array contains several keys for lmPassword, ntPassword, pwdLastSet, etc. depending * on the samba version */ function generate_smb_nt_hash($password) { global $config; // First try to retrieve values via RPC if ($config->get_cfg_value("core","gosaRpcServer") != ""){ $rpc = $config->getRpcHandle(); $hash = $rpc->mksmbhash($password); if(!$rpc->success()){ msg_dialog::display(_("Error"),msgPool::rpcError($rpc->get_error()),ERROR_DIALOG); return(array()); } }elseif ($config->get_cfg_value("core","gosaSupportURI") != ""){ // Try using gosa-si $res= gosaSupportDaemon::send("gosa_gen_smb_hash", "GOSA", array("password" => $password), TRUE); if (isset($res['XML']['HASH'])){ $hash= $res['XML']['HASH']; } else { $hash= ""; } if ($hash == "") { msg_dialog::display(_("Configuration error"), _("Cannot generate SAMBA hash!"), ERROR_DIALOG); return (""); } } else { $password = addcslashes($password, '$'); // <- Escape $ twice for transport from PHP to console-process. $password = addcslashes($password, '$'); $password = addcslashes($password, '$'); // <- And again once, to be able to use it as parameter for the perl script. $tmp = $config->get_cfg_value("core",'sambaHashHook'); $tmp = preg_replace("/%userPassword/", escapeshellarg($password), $tmp); $tmp = preg_replace("/%password/", escapeshellarg($password), $tmp); @DEBUG (DEBUG_LDAP, __LINE__, __FUNCTION__, __FILE__, $tmp, "Execute"); exec($tmp, $ar); flush(); reset($ar); $hash= current($ar); if ($hash == "") { msg_dialog::display(_("Configuration error"), sprintf(_("Generating SAMBA hash by running %s failed: check %s!"), bold($config->get_cfg_value("core",'sambaHashHook'), bold("sambaHashHook"))), ERROR_DIALOG); return(array()); } } list($lm,$nt)= explode(":", trim($hash)); $attrs['sambaLMPassword']= $lm; $attrs['sambaNTPassword']= $nt; $attrs['sambaPwdLastSet']= date('U'); $attrs['sambaBadPasswordCount']= "0"; $attrs['sambaBadPasswordTime']= "0"; return($attrs); } /*! \brief Get the Change Sequence Number of a certain DN * * To verify if a given object has been changed outside of Gosa * in the meanwhile, this function can be used to get the entryCSN * from the LDAP directory. It uses the attribute as configured * in modificationDetectionAttribute * * \param string 'dn' * \return either the result or "" in any other case */ function getEntryCSN($dn) { global $config; if(empty($dn) || !is_object($config)){ return(""); } /* Get attribute that we should use as serial number */ $attr= $config->get_cfg_value("core","modificationDetectionAttribute"); if($attr != ""){ $ldap = $config->get_ldap_link(); $ldap->cat($dn,array($attr)); $csn = $ldap->fetch(); if(isset($csn[$attr][0])){ return($csn[$attr][0]); } } return(""); } /*! \brief Add (a) given objectClass(es) to an attrs entry * * The function adds the specified objectClass(es) to the given * attrs entry. * * \param mixed 'classes' Either a single objectClass or several objectClasses * as an array * \param array 'attrs' The attrs array to be modified. * * */ function add_objectClass($classes, &$attrs) { if (is_array($classes)){ $list= $classes; } else { $list= array($classes); } foreach ($list as $class){ $attrs['objectClass'][]= $class; } } /*! \brief Removes a given objectClass from the attrs entry * * Similar to add_objectClass, except that it removes the given * objectClasses. See it for the params. * */ function remove_objectClass($classes, &$attrs) { if (isset($attrs['objectClass'])){ /* Array? */ if (is_array($classes)){ $list= $classes; } else { $list= array($classes); } $tmp= array(); foreach ($attrs['objectClass'] as $oc) { foreach ($list as $class){ if (strtolower($oc) != strtolower($class)){ $tmp[]= $oc; } } } $attrs['objectClass']= $tmp; } } /*! \brief Initialize a file download with given content, name and data type. * \param string data The content to send. * \param string name The name of the file. * \param string type The content identifier, default value is "application/octet-stream"; */ function send_binary_content($data,$name,$type = "application/octet-stream") { header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); header("Last-Modified: ".gmdate("D, d M Y H:i:s")." GMT"); header("Cache-Control: no-cache"); header("Pragma: no-cache"); header("Cache-Control: post-check=0, pre-check=0"); header("Content-type: ".$type.""); $HTTP_USER_AGENT = $_SERVER['HTTP_USER_AGENT']; /* Strip name if it is a complete path */ if (preg_match ("/\//", $name)) { $name= basename($name); } /* force download dialog */ if (preg_match('/MSIE 5.5/', $HTTP_USER_AGENT) || preg_match('/MSIE 6.0/', $HTTP_USER_AGENT)) { header('Content-Disposition: filename="'.$name.'"'); } else { header('Content-Disposition: attachment; filename="'.$name.'"'); } echo $data; exit(); } function reverse_html_entities($str,$type = ENT_QUOTES , $charset = "UTF-8") { if(is_string($str)){ return(htmlentities($str,$type,$charset)); }elseif(is_array($str)){ foreach($str as $name => $value){ $str[$name] = reverse_html_entities($value,$type,$charset); } } return($str); } /*! \brief Encode special string characters so we can use the string in \ HTML output, without breaking quotes. \param string The String we want to encode. \return string The encoded String */ function xmlentities($str) { if(is_string($str)){ static $asc2uni= array(); if (!count($asc2uni)){ for($i=128;$i<256;$i++){ # $asc2uni[chr($i)] = "&#x".dechex($i).";"; } } $str = str_replace("&", "&", $str); $str = str_replace("<", "<", $str); $str = str_replace(">", ">", $str); $str = str_replace("'", "'", $str); $str = str_replace("\"", """, $str); $str = str_replace("\r", "", $str); $str = strtr($str,$asc2uni); return $str; }elseif(is_array($str)){ foreach($str as $name => $value){ $str[$name] = xmlentities($value); } } return($str); } /*! \brief Updates all accessTo attributes from a given value to a new one. For example if a host is renamed. \param String $from The source accessTo name. \param String $to The destination accessTo name. */ function update_accessTo($from,$to) { global $config; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); $ldap->search("(&(objectClass=trustAccount)(accessTo=".$from."))",array("objectClass","accessTo")); while($attrs = $ldap->fetch()){ $new_attrs = array("accessTo" => array()); $dn = $attrs['dn']; for($i = 0 ; $i < $attrs['accessTo']['count']; $i++){ if($attrs['accessTo'][$i] == $from){ if(!empty($to)){ $new_attrs['accessTo'][] = $to; } }else{ $new_attrs['accessTo'][] = $attrs['accessTo'][$i]; } } $ldap->cd($dn); $ldap->modify($new_attrs); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $dn, LDAP_MOD, "update_accessTo($from,$to)")); } new log("modify","update_accessTo($from,$to)",$dn,array_keys($new_attrs),$ldap->get_error()); } } /*! \brief Returns a random char */ function get_random_char () { $randno = rand (0, 63); if ($randno < 12) { return (chr ($randno + 46)); // Digits, '/' and '.' } else if ($randno < 38) { return (chr ($randno + 53)); // Uppercase } else { return (chr ($randno + 59)); // Lowercase } } function cred_encrypt($input, $password) { $size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); $iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM); return bin2hex(mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $password, $input, MCRYPT_MODE_ECB, $iv)); } function cred_decrypt($input,$password) { $size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC); $iv = mcrypt_create_iv($size, MCRYPT_DEV_RANDOM); return mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $password, pack("H*", $input), MCRYPT_MODE_ECB, $iv); } function get_object_info() { return(session::get('objectinfo')); } function set_object_info($str = "") { session::set('objectinfo',$str); } function isIpInNet($ip, $net, $mask) { // Move to long ints $ip= ip2long($ip); $net= ip2long($net); $mask= ip2long($mask); // Mask given IP with mask. If it returns "net", we're in... $res= $ip & $mask; return ($res == $net); } function get_next_id($attrib, $dn) { global $config; switch ($config->get_cfg_value("core","idAllocationMethod")){ case "pool": return get_next_id_pool($attrib); case "traditional": return get_next_id_traditional($attrib, $dn); } msg_dialog::display(_("Error"), _("Cannot allocate free ID:")." "._("unknown idAllocation method!"), ERROR_DIALOG); return null; } function get_next_id_pool($attrib) { global $config; /* Fill informational values */ $min= $config->get_cfg_value("core","${attrib}PoolMin"); $max= $config->get_cfg_value("core","${attrib}PoolMax"); /* Sanity check */ if ($min >= $max) { msg_dialog::display(_("Error"), _("Cannot allocate free ID:")." ".sprintf(_("%sPoolMin >= %sPoolMax!"), bold($attrib), bold($attrib)), ERROR_DIALOG); return null; } /* ID to skip */ $ldap= $config->get_ldap_link(); $id= null; /* Try to allocate the ID several times before failing */ $tries= 3; while ($tries--) { /* Look for ID map entry */ $ldap->cd ($config->current['BASE']); $ldap->search ("(&(objectClass=sambaUnixIdPool)($attrib=*))", array("$attrib")); /* If it does not exist, create one with these defaults */ if ($ldap->count() == 0) { /* Fill informational values */ $minUserId= $config->get_cfg_value("core","uidNumberPoolMin"); $minGroupId= $config->get_cfg_value("core","gidNumberPoolMin"); /* Add as default */ $attrs= array("objectClass" => array("organizationalUnit", "sambaUnixIdPool")); $attrs["ou"]= "idmap"; $attrs["uidNumber"]= $minUserId; $attrs["gidNumber"]= $minGroupId; $ldap->cd("ou=idmap,".$config->current['BASE']); $ldap->add($attrs); if ($ldap->error != "Success") { msg_dialog::display(_("Error"), _("Cannot create sambaUnixIdPool entry!"), ERROR_DIALOG); return null; } $tries++; continue; } /* Bail out if it's not unique */ if ($ldap->count() != 1) { msg_dialog::display(_("Error"), _("Cannot allocate free ID:")." "._("sambaUnixIdPool is not unique!"), ERROR_DIALOG); return null; } /* Store old attrib and generate new */ $attrs= $ldap->fetch(); $dn= $ldap->getDN(); $oldAttr= $attrs[$attrib][0]; $newAttr= $oldAttr + 1; /* Sanity check */ if ($newAttr >= $max) { msg_dialog::display(_("Error"), _("Cannot allocate free ID:")." "._("no ID available!"), ERROR_DIALOG); return null; } if ($newAttr < $min) { msg_dialog::display(_("Error"), _("Cannot allocate free ID:")." "._("no ID available!"), ERROR_DIALOG); return null; } #FIXME: PHP is not able to do a modification of "del: .../add: ...", so this # is completely unsafe in the moment. #/* Remove old attr, add new attr */ #$attrs= array($attrib => $oldAttr); #$ldap->rm($attrs, $dn); #if ($ldap->error != "Success") { # continue; #} $ldap->cd($dn); $ldap->modify(array($attrib => $newAttr)); if ($ldap->error != "Success") { msg_dialog::display(_("Error"), _("Cannot allocate free ID:")." ".$ldap->get_error(), ERROR_DIALOG); return null; } else { return $oldAttr; } } /* Bail out if we had problems getting the next id */ if (!$tries) { msg_dialog::display(_("Error"), _("Cannot allocate free ID:")." "._("maximum number of tries exceeded!"), ERROR_DIALOG); } return $id; } function get_next_id_traditional($attrib, $dn) { global $config; $ids= array(); $ldap= $config->get_ldap_link(); $ldap->cd ($config->current['BASE']); if (preg_match('/gidNumber/i', $attrib)){ $oc= "posixGroup"; } else { $oc= "posixAccount"; } $ldap->search ("(&(objectClass=$oc)($attrib=*))", array("$attrib")); /* Get list of ids */ while ($attrs= $ldap->fetch()){ $ids[]= (int)$attrs["$attrib"][0]; } /* Add the nobody id */ $ids[]= 65534; /* get the ranges */ $tmp = array('0'=> 1000); if (preg_match('/posixAccount/', $oc) && $config->get_cfg_value("core","uidNumberBase") != ""){ $tmp= explode('-',$config->get_cfg_value("core","uidNumberBase")); } elseif($config->get_cfg_value("core","gidNumberBase") != ""){ $tmp= explode('-',$config->get_cfg_value("core","gidNumberBase")); } /* Set hwm to max if not set - for backward compatibility */ $lwm= $tmp[0]; if (isset($tmp[1])){ $hwm= $tmp[1]; } else { $hwm= pow(2,32); } /* Find out next free id near to UID_BASE */ if ($config->get_cfg_value("core","baseIdHook") == ""){ $base= $lwm; } else { /* Call base hook */ $base= get_base_from_hook($dn, $attrib); } for ($id= $base; $id++; $id < pow(2,32)){ if (!in_array_strict($id, $ids)){ return ($id); } } /* Should not happen */ if ($id == $hwm){ msg_dialog::display(_("Error"), _("Cannot allocate free ID!"), ERROR_DIALOG); exit; } } /* Mark the occurance of a string with a span */ function mark($needle, $haystack, $ignorecase= true) { $result= ""; while (preg_match('/^(.*)('.preg_quote($needle).')(.*)$/i', $haystack, $matches)) { $result.= $matches[1]."".$matches[2].""; $haystack= $matches[3]; } return $result.$haystack; } /* Return an image description using the path */ function image($path, $action= "", $title= "", $align= "middle") { global $config; global $BASE_DIR; $label= null; // Bail out, if there's no style file if(!class_exists('session')){ return ""; } if(!session::global_is_set("img-styles")){ // Get theme if (isset ($config)){ $theme= $config->get_cfg_value("core","theme"); } else { // Fall back to default theme $theme= "default"; } if (!file_exists("$BASE_DIR/ihtml/themes/$theme/img.styles")){ die ("No img.style for this theme found!"); } session::global_set('img-styles', unserialize(file_get_contents("$BASE_DIR/ihtml/themes/$theme/img.styles"))); } $styles= session::global_get('img-styles'); /* Extract labels from path */ if (preg_match("/\.png\[(.*)\]$/", $path, $matches)) { $label= $matches[1]; } $lbl= ""; if ($label) { if (isset($styles["images/label-".$label.".png"])) { $lbl= "
    "; } else { die("Invalid label specified: $label\n"); } $path= preg_replace("/\[.*\]$/", "", $path); } // Non middle layout? if ($align == "middle") { $align= ""; } else { $align= ";vertical-align:$align"; } // Clickable image or not? if ($title != "") { $title= "title='$title'"; } if ($action == "") { return "
    $lbl
    "; } else { return ""; } } /*! \brief Encodes a complex string to be useable in HTML posts. */ function postEncode($str) { return(preg_replace("/=/","_", base64_encode($str))); } /*! \brief Decodes a string encoded by postEncode */ function postDecode($str) { return(base64_decode(preg_replace("/_/","=", $str))); } /*! \brief Generate styled output */ function bold($str) { return "$str"; } /*! \brief Detect the special character handling for the currently used ldap database. * For example some convert , to \2C or " to \22. * * @param Config The GOsa configuration object. * @return Array An array containing a character mapping the use. */ function detectLdapSpecialCharHandling() { // The list of chars to test for global $config; if(!$config) return(NULL); // In the DN we've to use escaped characters, but the object name (o) // has the be un-escaped. $name = 'GOsaLdapEncoding_,_"_(_)_+_/'; $dnName = 'GOsaLdapEncoding_\,_\"_(_)_\+_/'; // Prapare name to be useable in filters $fixed= normalizeLdap(str_replace('\\\\', '\\\\\\', $name)); $filterName = str_replace('\\,', '\\\\,', $fixed); // Create the target dn $oDN = "o={$dnName},".$config->current['BASE']; // Get ldap connection and check if we've already created the character // detection object. $ldapCID = ldap_connect($config->current['SERVER']); ldap_set_option($ldapCID, LDAP_OPT_PROTOCOL_VERSION, 3); ldap_bind($ldapCID, $config->current['ADMINDN'],$config->current['ADMINPASSWORD']); $res = ldap_list($ldapCID, $config->current['BASE'], "(&(o=".$filterName.")(objectClass=organization))", array('dn')); // If we haven't created the character-detection object, then create it now. $cnt = ldap_count_entries($ldapCID, $res); if(!$cnt){ $obj = array(); $obj['objectClass'] = array('top','organization'); $obj['o'] = $name; $obj['description'] = 'GOsa character encoding test-object.'; if(!@ldap_add($ldapCID, $oDN, $obj)){ trigger_error("GOsa couldn't detect the special character handling used by your ldap!"); return(NULL); } } // Read the character-handling detection entry from the ldap. $res = ldap_list($ldapCID, $config->current['BASE'], "(&(o=".$filterName.")(objectClass=organization))", array('dn','o')); $cnt = ldap_count_entries($ldapCID, $res); if($cnt != 1 || !$res){ trigger_error("GOsa couldn't detect the special character handling used by your ldap!"); return(NULL); }else{ // Get the character handling entry from the ldap and check how the // values were written. Compare them with what // we've initially intended to write and create a mapping out // of the results. $re = ldap_first_entry($ldapCID, $res); $attrs = ldap_get_attributes($ldapCID, $re); // Extract the interessting characters out of the dn and the // initially used $name for the entry. $mapDNstr = preg_replace("/^o=GOsaLdapEncoding_([^,]*),.*$/","\\1", trim(ldap_get_dn($ldapCID, $re))); $mapDN = preg_split("/_/", $mapDNstr,0, PREG_SPLIT_NO_EMPTY); $mapNameStr = preg_replace("/^GOsaLdapEncoding_/","",$dnName); $mapName = preg_split("/_/", $mapNameStr,0, PREG_SPLIT_NO_EMPTY); // Create a mapping out of the results. $map = array(); foreach($mapName as $key => $entry){ $map[$entry] = $mapDN[$key]; } return($map); } return(NULL); } /*! \brief Replaces placeholder in a given string. * For example: * '%uid@gonicus.de' Replaces '%uid' with 'uid'. * '{%uid[0]@gonicus.de}' Replaces '%uid[0]' with the first char of 'uid'. * '%uid[2-4]@gonicus.de' Replaces '%uid[2-4]' with three chars from 'uid' starting from the second. * * The surrounding {} in example 2 are optional. * * @param String The string to perform the action on. * @param Array An array of replacements. * @return The resulting string. */ function fillReplacements($str, $attrs, $shellArg = FALSE, $default = "") { // Search for '{%...[n-m]} // Get all matching parts of the given string and sort them by // length, to avoid replacing strings like '%uidNumber' with 'uid' // instead of 'uidNumber'; The longest tring at first. preg_match_all('/(\{?%([a-z0-9_]+)(\[(([0-9_]+)(\-([0-9_]+))?)\])?\}?)/i', $str ,$matches, PREG_SET_ORDER); $hits = array(); foreach($matches as $match){ $hits[strlen($match[2]).$match[0]] = $match; } krsort($hits); // Add lower case placeholders to avoid errors foreach($attrs as $key => $attr) $attrs[strtolower($key)] = $attr; // Replace the placeholder in the given string now. foreach($hits as $match){ // Avoid errors about undefined index. $name = strtolower($match[2]); if(!isset($attrs[$name])) $attrs[$name] = $default; // Calculate the replacement $start = (isset($match[5])) ? $match[5] : 0; $end = strlen($attrs[$name]); if(isset($match[5]) && !isset($match[7])){ $end = 1; }elseif(isset($match[5]) && isset($match[7])){ $end = ($match[7]-$start+1); } $value = substr($attrs[$name], $start, $end); // Use values which are valid for shell execution? if($shellArg) $value = escapeshellcmd($value); // Replace the placeholder within the string. $str = preg_replace("/".preg_quote($match[0],'/')."/", $value, $str); } return($str); } /*! \brief Generate a list of uid proposals based on a rule * * Unroll given rule string by filling in attributes and replacing * all keywords. * * \param string 'rule' The rule string from gosa.conf. * \param array 'attributes' A dictionary of attribute/value mappings * \return array List of valid not used uids */ function gen_uids($rule, $attributes) { global $config; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $rule, "Processing"); // Strip out non ascii chars foreach($attributes as $name => $value){ if ( $config->get_cfg_value("core", "forceTranslit") == "true" ) { $value = cyrillic2ascii($value); } else { $value = iconv('UTF-8', 'US-ASCII//TRANSLIT', $value); } $value = preg_replace('/[^(\x20-\x7F)]*/','',$value); $attributes[$name] = strtolower($value); } @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $attributes, "Prepare"); // Search for '{%...[n-m]} // Get all matching parts of the given string and sort them by // length, to avoid replacing strings like '%uidNumber' with 'uid' // instead of 'uidNumber'; The longest tring at first. preg_match_all('/(\{?%([a-z0-9]+)(\[(([0-9]+)(\-([0-9]+))?)\])?\}?)/i', $rule ,$matches, PREG_SET_ORDER); $replacements = array(); foreach($matches as $match){ // No start position given, then add the complete value if(!isset($match[5])){ $replacements[$match[0]][] = $attributes[$match[2]]; // Start given but no end, so just add a single character }elseif(!isset($match[7])){ if(isset($attributes[$match[2]][$match[5]])){ $tmp = " ".$attributes[$match[2]]; $replacements[$match[0]][] = trim($tmp[$match[5]]); } // Add all values in range }else{ $str = ""; for($i=$match[5]; $i<= $match[7]; $i++){ if(isset($attributes[$match[2]][$i])){ $tmp = " ".$attributes[$match[2]]; $str .= $tmp[$i]; $replacements[$match[0]][] = trim($str); } } } } // Create proposal array $rules = array($rule); foreach($replacements as $tag => $values){ $rules = gen_uid_proposals($rules, $tag, $values); } // Search for id tags {id:3} / {id#3} preg_match_all('/\{id(#|:)([0-9])+\}/i', $rule, $matches, PREG_SET_ORDER); $idReplacements = array(); foreach($matches as $match){ if(count($match) != 3) continue; // Generate random number if($match[1] == '#'){ foreach($rules as $id => $ruleStr){ $genID = rand(pow(10,$match[2] -1),pow(10, ($match[2])) - 1); $rules[$id] = preg_replace("/".preg_quote($match[0],'/')."/", $genID,$ruleStr); } } // Search for next free id if($match[1] == ':'){ // Walk through rules and replace all occurences of {id:..} foreach($rules as $id => $ruleStr){ $genID = 0; $start = TRUE; while($start || $ldap->count()){ $start = FALSE; $number= sprintf("%0".$match[2]."d", $genID); $testRule = preg_replace("/".preg_quote($match[0],'/')."/",$number,$ruleStr); $ldap->search('uid='.normalizeLdap($testRule)); $genID ++; } $rules[$id] = preg_replace("/".preg_quote($match[0],'/')."/",$number,$ruleStr); } } } // Create result set by checking which uid is already used and which is free. $ret = array(); foreach($rules as $rule){ $ldap->search('uid='.normalizeLdap($rule)); if(!$ldap->count()){ $ret[] = $rule; } } return($ret); } function gen_uid_proposals(&$rules, $tag, $values) { $newRules = array(); foreach($rules as $rule){ foreach($values as $value){ $newRules[] = preg_replace("/".preg_quote($tag,'/')."/", $value, $rule); } } return($newRules); } function gen_uuid() { return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x', // 32 bits for "time_low" mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), // 16 bits for "time_mid" mt_rand( 0, 0xffff ), // 16 bits for "time_hi_and_version", // four most significant bits holds version number 4 mt_rand( 0, 0x0fff ) | 0x4000, // 16 bits, 8 bits for "clk_seq_hi_res", // 8 bits for "clk_seq_low", // two most significant bits holds zero and one for variant DCE1.1 mt_rand( 0, 0x3fff ) | 0x8000, // 48 bits for "node" mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ) ); } function gosa_file_name($filename) { $tempfile = tempnam(sys_get_temp_dir(), 'GOsa'); if(move_uploaded_file($filename, $tempfile)){ return( $tempfile); } } function gosa_file($filename) { $tempfile = tempnam(sys_get_temp_dir(), 'GOsa'); if(move_uploaded_file($filename, $tempfile)){ return file( $tempfile ); } } function gosa_fopen($filename, $mode) { $tempfile = tempnam(sys_get_temp_dir(), 'GOsa'); if(move_uploaded_file($filename, $tempfile)){ return fopen( $tempfile, $mode ); } } /*\brief Our own in_array method which defaults to a strict mode. */ function in_array_strict($needle, $haystack, $strict = TRUE) { return(in_array($needle, $haystack, $strict)); } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_baseSelector.inc0000644000175000017500000002253511461476537020342 0ustar cajuscajuspid= preg_replace("/[^0-9]/", "", microtime(TRUE)); // Transfer data $this->setBases($bases); $this->setBase($base); } function setSubmitButton($flag) { $this->submitButton= $flag; } function setHeight($value) { $this->height= $value; } function setBase($base) { if (isset($this->pathMapping[$base])) { $this->base= $base; $this->update(true); } } function checkBase($base) { return isset($this->pathMapping[$base]); } function checkLastBaseUpdate() { return $this->lastState; } function setBases($bases) { global $config; $this->pathMapping= array(); $selected= $this->base == $config->current['BASE']?"Selected":""; $first= true; $last_indent= 2; foreach ($bases as $base => $dummy) { // Build path style display $elements= explode(',', substr($base, 0, strlen($base) - strlen($config->current['BASE']))); $elements= array_reverse($elements, true); $this->pathMapping[$base]= $base == $config->current['BASE']? '/' : ldap::fix(preg_replace('/(^|,)[a-z0-9]+=/i', '/', implode(',', $elements))); $this->pathMapping[$base]= LDAP::makeReadable( $this->pathMapping[$base]); } // Save bases to session for autocompletion session::global_set("pathMapping_{$this->pid}", $this->pathMapping); session::global_set("department_info_{$this->pid}", $config->department_info); } function update($force= false) { global $config; // Analyze for base changes if needed $this->action= null; $last_base= $this->base; if(isset($_REQUEST['BPID']) && $_REQUEST['BPID'] == $this->pid) { if (isset($_POST['bs_rebase_'.$this->pid]) && !empty($_POST['bs_rebase_'.$this->pid])) { $new_base= base64_decode(get_post('bs_rebase_'.$this->pid)); if (isset($this->pathMapping[$new_base])) { $this->base= $new_base; $this->action= 'rebase'; } else { $this->lastState= false; return false; } }else{ // Input field set? if (isset($_POST['bs_input_'.$this->pid])) { // Take over input field base if ($this->submitButton && isset($_POST['submit_base_'.$this->pid]) || !$this->submitButton) { // Check if base is available $this->lastState= false; foreach ($this->pathMapping as $key => $path) { if (mb_strtolower($path) == mb_strtolower(get_post('bs_input_'.$this->pid))) { $this->base= $key; $this->lastState= true; break; } } } } } } /* Skip if there's no change */ if (($this->tree && $this->base == $last_base) && !$force) { return true; } $link= "onclick=\"\$('bs_rebase_".$this->pid."').value='".base64_encode($config->current['BASE'])."'; $('submit_tree_base_".$this->pid."').click();\""; $this->tree= "pid}').hide(); \" onfocus=\" \$('bs_{$this->pid}').hide(); \" onmouseover=\" mouseIsStillOver = true; function showIt() { if(mouseIsStillOver){ \$('bs_".$this->pid."').show(); } }; Element.clonePosition(\$('bs_".$this->pid."'), 'bs_input_".$this->pid."', {setHeight: false, setWidth: false, offsetTop:(Element.getHeight('bs_input_".$this->pid."'))}); rtimer=showIt.delay(0.25); \" onmouseout=\" mouseIsStillOver=false; rtimer=Element.hide.delay(0.25,'bs_".$this->pid."')\" value=\"".htmlentities(LDAP::makeReadable($this->pathMapping[$this->base]),ENT_COMPAT,'utf-8')."\">"; // Autocompleter $this->tree.= "
    ". ""; $selected= $this->base == $config->current['BASE']?"Selected":""; $this->tree.= "\n"; // Draw submitter if required if ($this->submitButton) { $this->tree.= image('images/lists/submit.png', "submit_base_".$this->pid, _("Submit")); } $this->tree.= ""; $this->tree.= ""; $this->tree.= ""; $this->lastState= true; return true; } function gennonbreaks($string) { return str_replace('-', '‑', str_replace(' ', ' ', $string)); } function render() { return $this->tree; } function getBase() { return $this->base; } function getAction() { // Do not do anything if this is not our BPID, or there's even no BPID available... if(!isset($_REQUEST['BPID']) || $_REQUEST['BPID'] != $this->pid) { return; } if ($this->action) { return array("targets" => array($this->base), "action" => $this->action); } return null; } } ?> gosa-core-2.7.4/include/class_stats.inc0000644000175000017500000003753011465023737017060 0ustar cajuscajusget_cfg_value('core', 'statsDatabaseDirectory'); if(empty($path)){ return(NULL); } // Check if path exists, if not try to create it if(!is_dir($path) ){ $res = @mkdir($path); if(!$res){ return(NULL); } } // Append a date suffix to the database file, to prevent huge and unusable database files. if($filename == ''){ $filename = date('Y-m-d'); } $tableFile = $path.'/'.$filename; // Try to return last valid handle. if(file_exists($tableFile) && isset(stats::$lastHandle[$filename]) && stats::$lastHandle[$filename] != NULL && is_resource(stats::$lastHandle[$filename])){ return(stats::$lastHandle[$filename]); } // Get statsFile property stats::$statsEnabled = $config->boolValueIsTrue('core', 'statsDatabaseEnabled'); if(!stats::$statsEnabled){ return(NULL); } // Check for SQLite extension if(!stats::checkSQLiteExtension()){ return(NULL); } // Check if we are able to read/write the given database file. if(!is_writeable($path) && !is_writeable(dirname($tableFile))){ return(NULL); } // Try to create database, if it exists just open it. $handle = sqlite_open($tableFile, 0666, $error); if($handle){ stats::createDatabaseOnDemand($handle); } stats::$lastHandle[$filename] = $handle; return($handle); } /*! \brief Returns a list of all created stat files * @return Array A list of all currently stored stat files. */ static function getLocalStatFiles() { $res = array(); // Check if we're creating logs right now. if(stats::getDatabaseHandle()){ global $config; // Walk through all files found in the storage path $path = $config->get_cfg_value('core', 'statsDatabaseDirectory'); $dir = opendir($path); while($file = readdir($dir)){ if(is_file($path.'/'.$file) && !preg_match('/.old$/', $file)) { $res[] = $file; } } } return($res); } /*! \brief Check whether the qlite extension is available or not. * @return boolean TRUE on success else FALSE */ static function checkSQLiteExtension() { return(function_exists('sqlite_popen')); } /*! \brief Drops the current stats table and thus enforces a recreation. * @param handle The database handle to use. */ static function dropTable($handle) { $TABLE_NAME = stats::$tableName; $query = "DROP TABLE '{$TABLE_NAME}'"; $ret = sqlite_query($query, $handle); stats::$lastHandle = NULL; stats::getDatabaseHandle(); } /*! \brief Returns the currently used amount of memory form the PHP process. * @return int The amount of bytes used for the PHP process. */ static function get_memory_usage() { return(memory_get_usage()); } /*! \brief Returns the current CPU load. * The result will be cached and one updated every 5 seconds. * @return float The current 'cpu_load'. */ static function get_cpu_load() { $cur = time(); if(empty(stats::$lastCpuLoad) || (($cur - stats::$lastCpuLoadTimestamp) >= 5 )){ list($one, $five, $ten) =preg_split("/ /",shell_exec('cat /proc/loadavg')); stats::$lastCpuLoad = $one; stats::$lastCpuLoadTimestamp = $cur; } return(stats::$lastCpuLoad); } /*! \brief This method checks if the 'stats' table is already present, * if it is not then it will be created. * @param handle The sqlite database handle */ static function createDatabaseOnDemand($handle) { $TABLE_NAME = stats::$tableName; // List Tables an check if there is already everything we need, // if not create it. $query = "SELECT name FROM sqlite_master WHERE type='table' and name='{$TABLE_NAME}'"; $ret = sqlite_query($query, $handle); if(!count(sqlite_fetch_all($ret))){ $query = " CREATE TABLE {$TABLE_NAME} ( ID INTEGER PRIMARY KEY, ACTID INTEGER, TYPE TEXT, PLUGIN TEXT, CATEGORY TEXT, ACTION TEXT, UUID TEXT, TIMESTAMP INTEGER, MTIMESTAMP REAL, DURATION REAL, RENDER_TIME REAL, AMOUNT INTEGER, MEMORY_USAGE INTEGER, CPU_LOAD FLOAT, INFO BLOB )"; $ret = sqlite_query($query, $handle); } } /*! \brief Creates a new 'stats' table entry. * -> Logs a GOsa action/activity in the sqlite stats table. * @param string type The action type, e.g. ldap/plugin/management * @param string plugin The plugin name, e.g. userManagement/user/posixAccount * @param string category The plugin category e.g. users/servers/groups * @param string action The action done e.g. edit/view/open/move * @param int amount The amount, e.g. for multiple edit * @param float duration The elapsed time. * @param string info Some infos form the action, e.g. the used hashing mehtod for pwd changes. */ static function log($type, $plugin, $category, $action, $amount = 1, $duration = 0, $info ='') { global $config; global $clicks; global $overallRenderTimer; // Get database handle, if it is invalid (NULL) return without creating stats $res = stats::getDatabaseHandle(); if(!$res) return; // Ensure that 'clicks' and 'overallRenderTimer' are present and set correctly, // if not simply create them with dummy values... // -- 'clicks' is a counter wich is set in main.php -> Number of page reloads // -- 'overallRenderTimer' is set in main.php -> timestamp of rendering start. if(!isset($clicks) || empty($clicks)) $clicks = 0; if(!isset($overallRenderTimer)){ $renderTime = 0; }else{ $renderTime = microtime(TRUE) - $overallRenderTimer; // Now set the overallRenderTimer to the current timestamp - else // we will not be able to sum up the render time in a single SQL statement. $overallRenderTimer = microtime(TRUE); } // Prepare values to be useable within a database $uuid = $config->getInstanceUUID(); $type = sqlite_escape_string($type); $plugin = sqlite_escape_string($plugin); $action = sqlite_escape_string($action); $timestamp = time(); $mtimestamp = number_format(microtime(TRUE), 4,'.',''); $amount = sqlite_escape_string($amount); $duration = sqlite_escape_string(number_format($duration, 4,'.','')); $renderTime = sqlite_escape_string(number_format($renderTime, 4,'.','')); $info = sqlite_escape_string($info); $clicks = sqlite_escape_string($clicks); $memory_usage = sqlite_escape_string(stats::get_memory_usage()); $cpu_load = sqlite_escape_string(number_format(stats::get_cpu_load(),4,'.','')); // Clean up category, which usally comes from acl_category and may still contain // some special chars like / $tmp = array(); foreach($category as $cat){ $tmp[] = trim($cat, '\/,; '); } $category = sqlite_escape_string(implode($tmp, ', ')); // Create insert statement. $TABLE_NAME = stats::$tableName; $query = " INSERT INTO {$TABLE_NAME} (ACTID, TYPE, PLUGIN, CATEGORY, ACTION, UUID, MTIMESTAMP, TIMESTAMP, AMOUNT, DURATION, RENDER_TIME, MEMORY_USAGE, CPU_LOAD, INFO) VALUES ('{$clicks}','{$type}','{$plugin}','{$category}','{$action}','{$uuid}', '{$mtimestamp}','{$timestamp}','{$amount}','{$duration}','{$renderTime}', '{$memory_usage}','{$cpu_load}','{$info}')"; sqlite_query($query, $res); } /*! \brief Closes all sqlite handles opened by this class */ static function closeHandles() { foreach(stats::lastHandle as $handle){ if($handle && is_resource($handle)){ sqlite_close($handle); } } } /*! \brief This method returns all entries of the GOsa-stats table. * You can limit the result by setting the from/to parameter (timestamp). * @param int from The timestamp to start the result from. * @param int to The timestamp to end the request. * @return array An array containing the requested entries. */ static function generateStatisticDump($filename) { // Get database connection $TABLE_NAME = stats::$tableName; $handle = stats::getDatabaseHandle($filename); if(!$handle) return; $query = " SELECT ". " TYPE, PLUGIN, CATEGORY, ACTION, ". " UUID, DATE(TIMESTAMP, 'unixepoch') as date, ". " AVG(DURATION), AVG(RENDER_TIME), SUM(AMOUNT), ". " AVG(MEMORY_USAGE), AVG(CPU_LOAD), INFO ". " FROM ". " stats ". " GROUP BY ". " TYPE, PLUGIN, CATEGORY, ACTION, UUID, date, INFO ". " ORDER BY ". " ID "; // Create Filter and start query $ret = sqlite_array_query($query, $handle, SQLITE_ASSOC); return($ret); } static function removeStatsFile($filename) { // Get statsFile property global $config; $path = $config->get_cfg_value('core', 'statsDatabaseDirectory'); stats::$statsEnabled = $config->boolValueIsTrue('core', 'statsDatabaseEnabled'); if(!stats::$statsEnabled){ return(NULL); } // We cannot log while the path to store logs in is empty. if(empty($path)){ return(NULL); } // Check if file exists and then remove it if(isset(stats::$lastHandle[$filename]) && is_resource(stats::$lastHandle[$filename])){ sqlite_close(stats::$lastHandle[$filename]); } if(file_exists($path.'/'.$filename)){ #unlink($path.'/'.$filename); rename($path.'/'.$filename, $path.'/'.$filename.".old"); } } static function getLdapObjectCount($config, $statisticConformResult = FALSE, $date = "") { $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); // A list of objectClasses to search for, indexed by their // object-category $ocsToSearchFor = array( "department" => array("gosaDepartment"), "devices" => array("gotoDevice"), "fai" => array("FAIobject"), "gofaxlist" => array("goFaxRBlock","goFaxSBlock"), "gofonconference" => array("goFonConference"), "phone" => array("goFonHardware"), "gofonmacro" => array("goFonMacro"), "users" => array("gosaAccount"), "acls" => array("gosaAcl","gosaRole"), "application" => array("gosaApplication"), "ogroups" => array("gosaGroupOfNames"), "roles" => array("organizationalRole"), "server" => array("goServer"), "printer" => array("gotoPrinter"), "terminal" => array("gotoTerminal"), "workstation" => array("gotoWorkstation"), "winworkstation" => array("sambaSamAccount"), "incoming" => array("goHard"), "component" => array("ieee802Device"), "mimetypes" => array("gotoMimeType"), "groups" => array("posixGroup"), "sudo" => array("sudoRole")); // Build up a filter which contains all objectClass combined by OR. // We will later sum up the results using PHP. $filter = ""; $categoryCounter = array(); foreach($ocsToSearchFor as $category => $ocs){ foreach($ocs as $oc){ $filter.= "(objectClass={$oc})"; } $categoryCounter[$category] = 0; } $filter = "(|{$filter})"; // Initiate the ldap query $res = $ldap->search($filter, array('objectClass')); if($ldap->success()) { // Count number of results per category while($entry = $ldap->fetch()){ foreach($ocsToSearchFor as $category => $ocs){ if(count(array_intersect($ocs, $entry['objectClass']))){ $categoryCounter[$category] ++; break; } } } } arsort($categoryCounter); // Do we have to return the result as SQL INSERT statement? if($statisticConformResult){ $uuid = $config->getInstanceUUID(); $type = 'objectCount'; $plugin = ''; $action = ''; $date = (empty($date))?date('Y-m-d'):$date; $memory_usage = sqlite_escape_string(stats::get_memory_usage()); $cpu_load = sqlite_escape_string(number_format(stats::get_cpu_load(),4,'.','')); $sql = array(); foreach($categoryCounter as $category => $amount){ $sql[] = array( "type" => $type, "plugin" => $plugin, "category" => $category, "action" => $action, "uuid" => $uuid, "date" => $date, "duration" => 0, "render_time" => 0, "amount" => $amount, "mem_usage" => $memory_usage, "load" => $cpu_load, "info" => ''); } return($sql); }else{ return($categoryCounter); } } } ?> gosa-core-2.7.4/include/class_tabs.inc0000644000175000017500000003354011613731145016642 0ustar cajuscajusskip_save_object = ($bool == FALSE); } function tabs(&$config, $data, $dn, $acl_category= "", $hide_refs = FALSE, $hide_acls = FALSE) { /* Save dn */ $this->dn= $dn; $this->config= &$config; $this->hide_refs = $hide_refs; $this->hide_acls = $hide_acls; if(!count($data)) { $data[] = array("CLASS" => 'plugin',"NAME" => 'Error'); msg_dialog::display(_("Error"), sprintf(_("No plugin definition for %s found: please check the configuration file!"), bold(get_class($this))), "ERROR_DIALOG"); } $baseobject= NULL; $this->acl_category = $acl_category; foreach ($data as &$tab){ if (!plugin_available($tab['CLASS'])){ if($this->config->boolValueIsTrue("core","developmentMode")){ trigger_error(sprintf("Unknown class %s!", bold($tab['CLASS']))); } continue; } if ($this->current == "") $this->current= $tab['CLASS']; $this->by_name[$tab['CLASS']]= $tab['NAME']; if ($baseobject === NULL){ $baseobject= new $tab['CLASS']($this->config, $this->dn); $baseobject->enable_CSN_check(); $this->by_object[$tab['CLASS']]= $baseobject; } else { $this->by_object[$tab['CLASS']]= new $tab['CLASS']($this->config, $this->dn, $baseobject); } $this->read_only |= $this->by_object[$tab['CLASS']]->read_only; $this->by_object[$tab['CLASS']]->parent= &$this; $this->by_object[$tab['CLASS']]->set_acl_category($this->acl_category); } // Try to set the current tab to the posted value if(isset($_GET['pluginTab'])){ $tab = $_GET['pluginTab']; if(isset($this->by_name[$tab])) $this->current = $tab; } } /*! \brief Reinitializes the tab classes with fresh ldap values. This maybe usefull if for example the apply button was pressed. */ function re_init() { $baseobject= NULL; foreach($this->by_object as $name => $object){ $class = get_class($object); if(in_array_strict($class,array("reference","acl"))) continue; if ($baseobject === NULL){ $baseobject= new $class($this->config, $this->dn); $baseobject->enable_CSN_check(); $this->by_object[$name]= $baseobject; } else { $this->by_object[$name]= new $class($this->config, $this->dn, $baseobject); } $this->by_object[$name]->parent= &$this; $this->by_object[$name]->set_acl_category($this->acl_category); } } function execute() { // Ensure that the currently selected tab is valid. if(!isset($this->by_name[$this->current])) { $this->current = key($this->by_name); } pathNavigator::registerPlugin($this); // Rotate current to last $this->last= $this->current; // Look for pressed tab button foreach ($this->by_object as $class => &$obj){ if (isset($_POST[$class]) || (isset($_POST['arg']) && $_POST['arg'] == "$class")){ $this->current= $class; break; } } // Save last tab object if(!$this->skip_save_object){ if ($this->last == $this->current){ $this->save_object(TRUE); } else { $this->save_object(FALSE); } } /* If multiple edit is enabled for this tab, we have tho display different templates */ if(!$this->multiple_support_active){ $display= $this->by_object[$this->current]->execute(); }else{ $display= $this->by_object[$this->current]->multiple_execute(); } $tabs= $this->gen_tabs(); if($this->is_modal_dialog()){ $display = "\n
    ". "\n {$display}". "\n
    "; }else{ $display = "\n {$tabs}". "\n ". "\n
    ". "\n {$display}". "\n
    "; } // Detect if we've modifications right now. // - A plugin state has to be changed, this is not a goo solution, but // currently it does what we want. // (It would be better to ask the plugins if something has changed) $this->isPluginModified |= isset($_POST['modify_state']); // - Capture the plugins modification status. foreach ($this->by_name as $class => $name){ $this->isPluginModified |= (isset($this->by_object[$class]->is_modified)) && $this->by_object[$class]->is_modified; } $display="".$display; return ($display); } function save_object($save_current= FALSE) { /* Save last tab */ if ($this->last != ""){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->last, "Saving"); if(!$this->multiple_support_active){ $this->by_object[$this->last]->save_object (); }else{ $this->by_object[$this->last]->multiple_save_object(); } } /* Skip if curent and last are the same object */ if ($this->last == $this->current){ return; } $obj= @$this->by_object[$this->current]; $this->disabled= $obj->parent->disabled; if ($save_current){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $this->current, "Saving (current)"); if(!$this->multiple_support_active){ $obj->save_object(); }else{ $obj->multiple_save_object(); } } } function is_modal_dialog() { return($this->by_object[$this->current]->is_modal_dialog()); } function gen_tabs() { if($this->is_modal_dialog()) return(""); $display = "\n
    "; $display.= "\n
      "; foreach ($this->by_name as $class => $name){ // Shorten string if its too long for the tab headers $title= _($name); if (mb_strlen($title, 'UTF-8') > 28){ $title= mb_substr($title,0, 25, 'UTF-8')."..."; } // nobr causes w3c warnings so we use   to keep the tab name in one line $title= str_replace(" "," ",$title); // Take care about notifications $obj = $this->by_object[$class]; $tabClass = ($this->current == $class) ? "current" :""; if ( $this->by_object[$class]->pl_notify && ($obj->is_account || $obj->ignore_account)){ $tabClass .= " info"; } if(!empty($tabClass)) $tabClass="class='{$tabClass}'"; $onClick = "document.mainform.arg.value='{$class}'; document.mainform.submit();"; $display.= "\n
    • {$title}
    • "; } $display.="\n
    "; $display.="\n
    "; return($display); } function set_acl($acl) { /* Look for attribute in ACL */ trigger_error("Don't use tabs::set_acl() its obsolete."); } function delete() { /* Check if all plugins will ACK for deletion */ foreach (array_reverse($this->by_object) as $key => $obj){ $reason= $obj->allow_remove(); if ($reason != ""){ msg_dialog::display(_("Warning"), sprintf(_("Delete process has been canceled by plugin %s: %s"), bold($key), $reason), WARNING_DIALOG); return; } } /* Delete for all plugins */ foreach (array_reverse($this->by_object) as $obj){ $obj->remove_from_parent(); } } function password_change_needed() { /* Ask all plugins for needed password changes */ foreach ($this->by_object as &$obj){ if ($obj->password_change_needed()){ return TRUE; } } return FALSE; } function check($ignore_account= FALSE) { $this->save_object(TRUE); $messages= array(); $current_set = FALSE; /* Check all plugins */ foreach ($this->by_object as $key => &$obj){ if ($obj->is_account || $ignore_account || $obj->ignore_account){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$key, "Checking"); if(!$this->multiple_support_active){ $msg = $obj->check(); }else{ $msg = $obj->multiple_check(); } if (count($msg)){ $obj->pl_notify= TRUE; if(!$current_set){ $current_set = TRUE; $this->current= $key; $messages = $msg; } }else{ $obj->pl_notify= FALSE; } }else{ $obj->pl_notify= FALSE; } } return ($messages); } function save($ignore_account= FALSE) { /* Save all plugins */ foreach ($this->by_object as $key => &$obj){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $key, "Saving"); $obj->dn= $this->dn; if(!$obj instanceof plugin && !$obj instanceOf management){ trigger_error("Something went wrong while saving ".$obj->dn.". Object class '".get_class($obj)."'."); }else{ if ($obj->is_account || $ignore_account || $obj->ignore_account){ if ($obj->save() == 1){ return (1); } } else { $obj->remove_from_parent(); } } } return (0); } function adapt_from_template($dn, $skip= array()) { foreach ($this->by_object as $key => &$obj){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $key, "Adapting"); $obj->parent= &$this; $obj->adapt_from_template($dn, $skip); } } /* Save attributes posted by copy & paste dialog */ function saveCopyDialog() { foreach ($this->by_object as &$obj){ if($obj->is_account || $obj->ignore_account){ $obj->saveCopyDialog(); } } } /* return copy & paste dialog */ function getCopyDialog() { $ret = ""; $this->SubDialog = false; foreach ($this->by_object as &$obj){ if($obj->is_account || $obj->ignore_account){ $tmp = $obj->getCopyDialog(); if($tmp['status'] == "SubDialog"){ $this->SubDialog = true; return($tmp['string']); }else{ if(!empty($tmp['string'])){ $ret .= $tmp['string']; $ret .= "
    "; } } } } return($ret); } function addSpecialTabs() { if(!$this->hide_acls){ $this->by_name['acl']= _("ACL"); $this->by_object['acl']= new acl($this->config, $this, $this->dn); $this->by_object['acl']->parent= &$this; } if(!$this->hide_refs){ $this->by_name['reference']= _("References"); $this->by_object['reference']= new reference($this->config, $this->dn); $this->by_object['reference']->parent= &$this; $this->by_object['reference']->set_acl_category($this->acl_category); } } function set_acl_base($base= "") { /* Update reference, transfer variables */ $first= ($base == ""); foreach ($this->by_object as &$obj){ if ($first){ $first= FALSE; $base= $obj->acl_base; } else { $obj->set_acl_base($base); } } } /*! \brief Checks if one of the used tab plugins supports multiple edit. @param boolean Returns TRUE if at least one plugins supports multiple edit. */ function multiple_support_available() { foreach($this->by_object as $name => $obj){ if($obj->multiple_support){ return(TRUE); } } return(FALSE); } /*! \brief Enables multiple edit support for the given tab. All unsupported plugins will be disabled. @param boolean Returns TRUE if at least one plugin supports multiple edit */ function enable_multiple_support() { if(!$this->multiple_support_available()){ return(FALSE); }else{ $this->multiple_support_active = TRUE; foreach($this->by_object as $name => $obj){ if($obj->multiple_support){ $this->by_object[$name]->enable_multiple_support(); }else{ unset($this->by_object[$name]); unset($this->by_name[$name]); } } } return(TRUE); } function setReadOnly($s = TRUE) { foreach($this->by_object as $name => $obj){ $this->by_object[$name]->read_only = $s; } $this->read_only = $s; } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_jsonRPC.inc0000644000175000017500000003117311605073030017220 0ustar cajuscajusconfigRegistry->getProperty('core','gosaRpcUser'); $username = $user->getValue($temporaryValue = TRUE); $passwd = $config->configRegistry->getProperty('core','gosaRpcPassword'); $passwdString = $passwd->getValue($temporaryValue = TRUE); $connection = new jsonRPC($config, $value, $username, $passwdString); if(!$connection->success() && $message){ msg_dialog::display(_("Warning"), sprintf(_("The RPC connection (%s) specified for %s:%s is invalid: %s"), bold($value),bold($class),bold($name), bold($connection->get_error())), WARNING_DIALOG); } return($connection->success()); } /*! \brief Constructs a new jsonRPC handle which is connected to a given URL. * It can either connect using a rpc method or via auth method digest. * @param object The gosa configuration object (class_config) * @param string The url to connect to. * @param string The username for authentication * @param string The password to use for authentication * @param boolean Whether to use DIGEST authentication or not. * @return */ public function __construct($config, $connectUrl, $username, $userPassword, $authModeDigest=FALSE) { $this->config = $config; $this->id = 0; // Get connection data $this->connectUrl = $connectUrl; $this->username = $username; $this->userPassword = $userPassword; $this->authModeDigest = $authModeDigest; // Put some usefull info in the logs DEBUG (DEBUG_RPC, __LINE__, __FUNCTION__, __FILE__,bold($this->connectUrl), "Initiated RPC "); DEBUG (DEBUG_RPC, __LINE__, __FUNCTION__, __FILE__,bold($this->username), "RPC user: "); DEBUG (DEBUG_RPC, __LINE__, __FUNCTION__, __FILE__,bold($this->userPassword),"RPC password: "); DEBUG (DEBUG_RPC, __LINE__, __FUNCTION__, __FILE__,bold($this->authModeDigest),"Digest Auth (0: No, 1: Yes): "); $this->__login(); } /*! \brief * @param * @return */ private function __login() { // Init Curl handler $this->curlHandler = curl_init($this->connectUrl); // Set curl options curl_setopt($this->curlHandler, CURLOPT_URL , $this->connectUrl); curl_setopt($this->curlHandler, CURLOPT_POST , TRUE); curl_setopt($this->curlHandler, CURLOPT_RETURNTRANSFER ,TRUE); curl_setopt($this->curlHandler, CURLOPT_HTTPHEADER , array('Content-Type: application/json')); curl_setopt($this->curlHandler, CURLOPT_SSL_VERIFYPEER, FALSE); // Try to login if($this->authModeDigest){ if(!empty($this->username)){ curl_setopt($this->curlHandler, CURLOPT_USERPWD , "{$this->username}:{$this->userPassword}"); } curl_setopt($this->curlHandler, CURLOPT_HTTPAUTH , CURLAUTH_ANYSAFE); }else{ curl_setopt($this->curlHandler, CURLOPT_COOKIESESSION , TRUE); curl_setopt($this->curlHandler, CURLOPT_COOKIEFILE, 'cookiefile.txt'); if(!empty($this->username)) $this->login($this->username, $this->userPassword); } } /*! \brief Returns the last HTTP status code. * @return int The last status code. */ public function getHTTPstatusCode() { return((isset($this->lastStats['http_code']))? $this->lastStats['http_code'] : -1 ); } /*! \brief Returns the last error string. * @return string The last error message. */ public function get_error() { $error = ""; if($this->lastStats['http_code'] != 200){ $error = $this->getHttpStatusCodeMessage($this->lastStats['http_code']); } if(isset($this->lastResult['error']['error']) && is_array($this->lastResult['error']['error'])){ $err = $this->lastResult['error']['error']; #$message = call_user_func_array(sprintf,$err); $message = $err; $error .= $message; }elseif(isset($this->lastResult['error']['message'])){ $error .= $this->lastResult['error']['message']; } if($error){ return(trim($error, ": ")); } return(curl_error($this->curlHandler)); } /*! \brief Returns TRUE if the last action was successfull else FALSE. * @return boolean TRUE on success else FALSE. */ public function success() { return(curl_errno($this->curlHandler) == 0 && !isset($this->lastResult['error']) && isset($this->lastStats['http_code']) && $this->lastStats['http_code'] == 200); } /*! \brief The class destructor, it destroys open rpc handles if needed. */ public function __destruct() { if($this->curlHandler){ curl_close($this->curlHandler); } } /*! \brief This is some kind of catch-all method, all unknown method names will * will be interpreted as rpc request. * If you call "$this->blafasel" this method will initiate an rpc request * for method 'blafasel'. * @param string method The rpc method to execute. * @param params array The parameter to use. * @return mixed The request result. */ public function __call($method,$params) { // Check if handle is still valid! if(!$this->curlHandler && $this->lastAction != 'login'){ $this->__login(); } // Start request DEBUG (DEBUG_RPC, __LINE__, __FUNCTION__, __FILE__,"{$method}", "Calling: "); $response = $this->request($method,$params); if($this->success()){ DEBUG (DEBUG_RPC, __LINE__, __FUNCTION__, __FILE__, (is_array($response['result']))?$response['result']:bold($response['result']), "Result: "); }else{ DEBUG (DEBUG_RPC, __LINE__, __FUNCTION__, __FILE__,bold($this->get_error())."
    ".$response, "Result (FAILED): "); } global $config; $debugLevel = $config->get_cfg_value('core', 'debugLevel'); if($debugLevel & DEBUG_RPC){ print_a(array('CALLED:' => array($method => $params))); print_a(array('RESPONSE' => $response)); } $return = $response['result']; // Inspect the result and replace predefined statements with their // coresponding classes. $return = $this->inspectJsonResult($return); return($return); } public function inspectJsonResult($result) { if(is_array($result) && isset($result['__jsonclass__']) && class_available('remoteObject')){ // Get all relevant class informations $classDef = $result['__jsonclass__'][1]; $type = $classDef[0]; $ref_id = $classDef[1]; $object_id = $classDef[2]; $methods = $classDef[3]; $properties = $classDef[4]; // Prepare values $values = array(); foreach($properties as $prop){ $values[$prop] = NULL; if(isset($res[$prop])) $values[$prop] = $res[$prop]; } // Build up remote object $object = new remoteObject($this, $type, $properties, $values, $methods, $object_id, $ref_id); return($object); } return($result); } /*! \brief This method finally initiates the real RPC requests and handles * the result from the server. * @param string method The method to call * @param array params The paramter to use. * @return mixed The server response. */ private function request($method, $params) { // Set last action $this->lastAction = $method; // Reset stats of last request. $this->lastStats = array(); // Validate input values if (!is_scalar($method)) trigger_error('jsonRPC::__call requires a scalar value as first parameter!'); if (is_array($params)) { $params = array_values($params); } else { trigger_error('jsonRPC::__call requires an array value as second parameter!'); } // prepares the request $this->id ++; $request = json_encode(array('method' => $method,'params' => $params,'id' => $this->id)); // Set curl options curl_setopt($this->curlHandler, CURLOPT_POSTFIELDS , $request); $response = curl_exec($this->curlHandler); $response = json_decode($response,true); // Set current result stats. $this->lastStats = curl_getinfo($this->curlHandler); $this->lastResult = $response; return($response); } /*! \brief Returns the HTTP status message for a given HTTP status code. * @param int code The status to code to return a message for. * @return string The corresponding status message. */ public static function getHttpStatusCodeMessage($code) { $codes = array( '100' => 'Continue', '101' => 'Switching Protocols', '102' => 'Processing', '200' => 'OK', '201' => 'Created', '202' => 'Accepted', '203' => 'Non-Authoritative Information', '204' => 'No Content', '205' => 'Reset Content', '206' => 'Partial Content', '207' => 'Multi-Status', '300' => 'Multiple Choice', '301' => 'Moved Permanently', '302' => 'Found', '303' => 'See Other', '304' => 'Not Modified', '305' => 'Use Proxy', '306' => 'reserved', '307' => 'Temporary Redirect', '400' => 'Bad Request', '401' => 'Unauthorized', '402' => 'Payment Required', '403' => 'Forbidden', '404' => 'Not Found', '405' => 'Method Not Allowed', '406' => 'Not Acceptable', '407' => 'Proxy Authentication Required', '408' => 'Request Time-out', '409' => 'Conflict', '410' => 'Gone', '411' => 'Length Required', '412' => 'Precondition Failed', '413' => 'Request Entity Too Large', '414' => 'Request-URI Too Long', '415' => 'Unsupported Media Type', '416' => 'Requested range not satisfiable', '417' => 'Expectation Failed', '421' => 'There are too many connections from your internet address', '422' => 'Unprocessable Entity', '423' => 'Locked', '424' => 'Failed Dependency', '425' => 'Unordered Collection', '426' => 'Upgrade Required', '500' => 'Internal Server Error', '501' => 'Not Implemented', '502' => 'Bad Gateway', '503' => 'Service Unavailable', '504' => 'Gateway Time-out', '505' => 'HTTP Version not supported', '506' => 'Variant Also Negotiates', '507' => 'Insufficient Storage', '509' => 'Bandwidth Limit Exceeded', '510' => 'Not Extended'); return((isset($codes[$code]))? $codes[$code] : sprintf(_("Unknown HTTP status code %s!"), bold($code))); } } ?> gosa-core-2.7.4/include/class_configRegistry.inc0000644000175000017500000011437511662424035020716 0ustar cajuscajusconfig = &$config; // Detect classes that have a plInfo method global $class_mapping; foreach ($class_mapping as $cname => $path){ $cmethods = get_class_methods($cname); if (is_array($cmethods) && in_array_ics('plInfo',$cmethods)){ // Get plugin definitions $def = call_user_func(array($cname, 'plInfo'));; // Register Post Events (postmodfiy,postcreate,postremove,checkhook) if(count($def)){ $this->classesWithInfo[$cname] = $def; } } } // (Re)Load properties $this->reload(); } /*! \brief Returns a list of plugins used by GOsa. @return Array An array containing all plugins with theis plInfo data. */ function getListOfPlugins() { return($this->classesWithInfo); } /*! \brief Checks whether the schema check was called in the current session or not. * @return Boolean True if check was already called */ function schemaCheckFinished() { return($this->schemaCheckFinished); } /*! \brief Starts the schema validation * @param Boolean 'force' Force a re-check. * @param Boolean 'disableIncompatiblePlugins' Disables of incompatible GOsa-plugins. * @return Boolean True on success else FALSE */ function validateSchemata($force = FALSE, $disableIncompatiblePlugins = FALSE, $objectClassesToUse = array()) { // Read objectClasses from ldap if(count($objectClassesToUse)){ $this->setObjectClasses($objectClassesToUse); }elseif(!count($this->objectClasses)){ $ldap = $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); $this->setObjectClasses($ldap->get_objectclasses()); } return($this->_validateSchemata($force, $disableIncompatiblePlugins)); } /*! \brief Sets the list object classes to use while validation the schema. (See 'validateSchemata') * This is called from the GOsa-Setup * @param Array The list of object classes (usually LDAP::get_objectlclasses()). * @return void */ function setObjectClasses($ocs) { $this->objectClasses = $ocs; } /*! \brief Returns an array which contains all unresolved schemata requirements. * @return Array An array containing all errors/issues */ function getSchemaResults() { return($this->detectedSchemaIssues); } /*! \brief This method checks if the installed ldap-schemata matches the plugin requirements. * @param Boolean 'force' Force a re-check. * @param Boolean 'disableIncompatiblePlugins' Disables of incompatible GOsa-plugins. * @return String */ private function _validateSchemata($force = FALSE, $disableIncompatiblePlugins = FALSE) { // We cannot check without readable schema info if(!count($this->objectClasses)){ return(TRUE); } // Don't do things twice unless forced if($this->schemaCheckFinished && !$force) return($this->schemaCheckFailed); // Prepare result array $this->detectedSchemaIssues = array(); $this->detectedSchemaIssues['missing'] = array(); $this->detectedSchemaIssues['versionMismatch'] = array(); // Clear last results $this->pluginsDeactivated = array(); // Collect required schema infos $this->pluginRequirements = array('ldapSchema' => array()); $this->categoryToClass = array(); // Walk through plugins with requirements, but only check for active plugins. foreach($this->classesWithInfo as $cname => $defs){ if(isset($defs['plRequirements'])){ // Check only if required plugin is enabled in gosa.conf // Normally this is the class name itself, but may be overridden // in plInfo using the plRequirements::activePlugin statement. $requiresActivePlugin = $cname; if(isset($defs['plRequirements']['activePlugin'])){ $requiresActivePlugin = $defs['plRequirements']['activePlugin']; } // Only queue checks for active plugins. if(isset($this->activePlugins[strtolower($requiresActivePlugin)])){ $this->pluginRequirements[$cname] = $defs['plRequirements']; }else{ if($cname == $requiresActivePlugin){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "", "Skipped schema check for '{$cname}' plugin is inactive!"); }else{ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "", "Skipped schema check for class '{$cname}' skipped,". " required plugin '{$requiresActivePlugin}' is inactive!"); } } } } // Check schema requirements now $missing = $invalid = array(); foreach($this->pluginRequirements as $cname => $requirements){ // Check LDAP schema requirements for this plugins $failure = FALSE; if(isset($requirements['ldapSchema'])){ foreach($requirements['ldapSchema'] as $oc => $version){ if(!$this->ocAvailable($oc)){ $this->detectedSchemaIssues['missing'][$oc] = $oc; $this->schemaCheckFailed = TRUE; $failure = TRUE; new log("debug","","LDAP objectClass missing '{$oc}'!", array(),''); }elseif(!empty($version)){ $currentVersion = $this->getObjectClassVersion($oc); if(!empty($currentVersion) && !$this->ocVersionMatch($version, $currentVersion)){ if($currentVersion == -1){ $currentVersion = _("unknown"); } $this->detectedSchemaIssues['versionMismatch'][$oc] = sprintf(_("%s has version %s but %s is required!"), bold($oc),bold($currentVersion),bold($version)); $this->schemaCheckFailed = TRUE; $failure = TRUE; new log("debug","","LDAP objectClass version mismatch '{$oc}' ". "has '{$currentVersion}' but {$version} required!", array(),''); } } } } // Display corresponding plugins now if($disableIncompatiblePlugins && $failure && isset($requirements['onFailureDisablePlugin'])){ foreach($requirements['onFailureDisablePlugin'] as $name){ $this->pluginsDeactivated[$name] = $name; } } } $this->schemaCheckFinished =TRUE; session::un_set('plist'); return(!$this->schemaCheckFailed); } /*! \brief The function 'validateSchemata' may has disabled some GOsa-Plugins, * the list of disabled plugins will be returned here. * @return Array The list of plugins disabled by 'validateSchemata' */ function getDisabledPlugins() { return($this->pluginsDeactivated); } /*! \brief Displays an error message with all issues detect during the schema validation. */ function displayRequirementErrors() { $message = ""; if(count($this->detectedSchemaIssues['missing'])){ $message.= "
    ". _("The following object classes are missing:"). "
    ". msgPool::buildList(array_values($this->detectedSchemaIssues['missing'])). "
    "; } if(count($this->detectedSchemaIssues['versionMismatch'])){ $message.= "
    ". _("The following object classes are outdated:"). "
    ". msgPool::buildList(array_values($this->detectedSchemaIssues['versionMismatch'])). "
    "; } if($message != ""){ $message.= "
    "._("Plugins that require one or more of the object classes above will be disabled until the object classes get updated."); msg_dialog::display(_("Schema validation error"),$message, ERROR_DIALOG); } } /*! \brief Checks to version strings (e.g. '>=v2.8' and '2.9') * @param String The required version with operators (e.g. '>=2.8') * @param String The version to match for withOUT operators (e.g. '2.9') * @return Boolean True if version matches else false. */ private function ocVersionMatch($required, $installed) { $operator = preg_replace('/^([=<>]*).*$/',"\\1",$required); $required = preg_replace('/^[=<>]*(.*)$/',"\\1",$required); return(version_compare($installed,$required, $operator)); } /*! \brief Returns the currently installed version of a given object class. * @param String The name of the objectClass to check for. * @return String The version string of the objectClass (e.g. v2.7) */ function getObjectClassVersion($oc) { if(!isset($this->objectClasses[$oc])){ return(NULL); }else{ $version = -1; // unknown if(preg_match("/(v[^)]*)/", $this->objectClasses[$oc]['DESC'])){ $version = preg_replace('/^.*\(v([^)]*)\).*$/',"\\1", $this->objectClasses[$oc]['DESC']); } } return($version); } /*! \brief Check whether the given object class is available or not. * @param String The name of the objectClass to check for (e.g. 'mailAccount') * @return Boolean Returns TRUE if the class exists else FALSE. */ function ocAvailable($name) { return(isset($this->objectClasses[$name])); } /*! \brief Re-loads the list of installed GOsa-Properties. * @param Boolean $force If force is TRUE, the complete properties list is rebuild.. */ function reload($force = FALSE) { // Do not reload the properties everytime, once we have // everything loaded and registrered skip the reload. // Status is 'finished' once we had a ldap connection (logged in) if(!$force && $this->status == 'finished') return; // Reset everything $this->ldapStoredProperties = array(); $this->fileStoredProperties = array(); $this->properties = array(); $this->mapByName = array(); $this->activePlugins = array('core'=>'core'); if(!$this->config) return; // Search for config flags defined in the config file (TAB section) foreach($this->config->data['TABS'] as $tabname => $tabdefs){ foreach($tabdefs as $info){ // Put plugin in list of active plugins if(isset($info['CLASS'])){ $class = strtolower($info['CLASS']); $this->activePlugins[$class] = $class; } // Check if the info is valid if(isset($info['NAME']) && isset($info['CLASS'])){ // Check if there is nore than just the plugin definition if(count($info) > 2){ foreach($info as $name => $value){ if(!in_array_strict($name, array('CLASS','NAME'))){ $class= $info['CLASS']; $this->fileStoredProperties[strtolower($class)][strtolower($name)] = $value; } } } } } } foreach($this->config->data['MENU'] as $section => $entries){ foreach($entries as $entry){ if(isset($entry['CLASS'])){ // Put plugin to active plugins list. $class = strtolower($entry['CLASS']); $this->activePlugins[$class] = $class; if(count($entry) > 2 ){ foreach($entry as $name => $value){ if(!in_array_strict($name, array('CLASS','ACL'))){ $this->fileStoredProperties[strtolower($class)][strtolower($name)] = $value; } } } } } } // Search for config flags defined in the config file (PATHMENU) foreach($this->config->data['PATHMENU'] as $entry){ if(isset($entry['CLASS'])){ // Put plugin to active plugins list. $class = strtolower($entry['CLASS']); $this->activePlugins[$class] = $class; if(count($entry) > 2 ){ foreach($entry as $name => $value){ if(!in_array_strict($name, array('CLASS','ACL'))){ $this->fileStoredProperties[strtolower($class)][strtolower($name)] = $value; } } } } } // Search for config flags defined in the config file (MAIN section) foreach($this->config->data['MAIN'] as $name => $value){ $this->fileStoredProperties['core'][strtolower($name)] = $value; } // Search for config flags defined in the config file (Current LOCATION section) if(isset($this->config->current)){ foreach($this->config->current as $name => $value){ $this->fileStoredProperties['core'][strtolower($name)] = $value; } } // Skip searching for LDAP defined properties if 'ignoreLdapProperties' is set to 'true' // in the config. $this->ignoreLdapProperties = FALSE; if(isset($this->fileStoredProperties['core'][strtolower('ignoreLdapProperties')]) && preg_match("/(true|on)/i", $this->fileStoredProperties['core'][strtolower('ignoreLdapProperties')])){ $this->ignoreLdapProperties = TRUE; } // Search for all config flags defined in the LDAP - BUT only if we ARE logged in. if(!empty($this->config->current['CONFIG'])){ $ldap = $this->config->get_ldap_link(); $ldap->cd($this->config->current['CONFIG']); $ldap->search('(&(objectClass=gosaConfig)(gosaSetting=*))', array('cn','gosaSetting')); while($attrs = $ldap->fetch()){ $class = $attrs['cn'][0]; for($i=0; $i<$attrs['gosaSetting']['count']; $i++){ list($name,$value) = preg_split("/:/",$attrs['gosaSetting'][$i],2); $this->ldapStoredProperties[$class][$name] = $value; } } } // Register plugin properties. foreach ($this->classesWithInfo as $cname => $def){ // Detect class name $name = $cname; $name = (isset($def['plShortName'])) ? $def['plShortName'] : $cname; $name = (isset($def['plDescription'])) ? $def['plDescription'] : $cname; // Register post events $this->classToName[$cname] = $name; $data = array('name' => 'postcreate','type' => 'command'); $this->register($cname, $data); $data = array('name' => 'postremove','type' => 'command'); $this->register($cname, $data); $data = array('name' => 'postmodify','type' => 'command'); $this->register($cname, $data); $data = array('name' => 'precreate','type' => 'command'); $this->register($cname, $data); $data = array('name' => 'preremove','type' => 'command'); $this->register($cname, $data); $data = array('name' => 'premodify','type' => 'command'); $this->register($cname, $data); $data = array('name' => 'check', 'type' => 'command'); $this->register($cname, $data); // Register properties if(isset($def['plProperties'])){ foreach($def['plProperties'] as $property){ $this->register($cname, $property); } } } // We are only finsihed once we are logged in. if(!empty($this->config->current['CONFIG'])){ $this->status = 'finished'; } } /*! \brief Returns TRUE if the property registration has finished without any error. */ function propertyInitializationComplete() { return($this->status == 'finished'); } /*! \brief Registers a GOsa-Property and thus makes it useable by GOsa and its plugins. * @param String $class The name of the class/plugin that wants to register this property. * @return Array $data An array containing all data set in plInfo['plProperty] */ function register($class,$data) { $id = count($this->properties); $this->properties[$id] = new gosaProperty($this,$class,$data); $p = strtolower("{$class}::{$data['name']}"); $this->mapByName[$p] = $id; } /*! \brief Returns all registered properties. * @return Array A list of all properties. */ public function getAllProperties() { return($this->properties); } /*! \brief Checks whether a property exists or not. * @param String $class The class name (e.g. 'core' or 'mailAccount') * @param String $name The property name (e.g. 'sessionTimeout' or 'mailMethod') * @return Boolean TRUE if it exists else FALSE. */ function propertyExists($class,$name) { $p = strtolower("{$class}::{$name}"); return(isset($this->mapByName[$p])); } /*! \brief Returns the id of a registered property. * @param String $class The class name (e.g. 'core' or 'mailAccount') * @param String $name The property name (e.g. 'sessionTimeout' or 'mailMethod') * @return Integer The id for the given property. */ private function getId($class,$name) { $p = strtolower("{$class}::{$name}"); if(!isset($this->mapByName[$p])){ return(-1); } return($this->mapByName[$p]); } /*! \brief Returns a given property, if it exists. * @param String $class The class name (e.g. 'core' or 'mailAccount') * @param String $name The property name (e.g. 'sessionTimeout' or 'mailMethod') * @return GOsaPropery The property or 'NULL' if it doesn't exists. */ function getProperty($class,$name) { if($this->propertyExists($class,$name)){ return($this->properties[$this->getId($class,$name)]); } return(NULL); } /*! \brief Returns the value for a given property, if it exists. * @param String $class The class name (e.g. 'core' or 'mailAccount') * @param String $name The property name (e.g. 'sessionTimeout' or 'mailMethod') * @return GOsaPropery The property value or an empty string if it doesn't exists. */ function getPropertyValue($class,$name) { if($this->propertyExists($class,$name)){ $tmp = $this->getProperty($class,$name); return($tmp->getValue()); } return(""); } /*! \brief Set a new value for a given property, if it exists. * @param String $class The class name (e.g. 'core' or 'mailAccount') * @param String $name The property name (e.g. 'sessionTimeout' or 'mailMethod') * @return */ function setPropertyValue($class,$name, $value) { if($this->propertyExists($class,$name)){ $tmp = $this->getProperty($class,$name); return($tmp->setValue($value)); } return(""); } /*! \brief Save all temporary made property changes and thus make them useable/effective. * @return Array Returns a list of plugins that have to be migrated before they can be saved. */ function saveChanges() { $migrate = array(); foreach($this->properties as $prop){ // Is this property modified if(in_array_strict($prop->getStatus(),array('modified','removed'))){ // Check if we've to migrate something before we can make the changes effective. if($prop->migrationRequired()){ $migrate[] = $prop; }else{ $prop->save(); } } } return($migrate); } } class gosaProperty { protected $name = ""; protected $class = ""; protected $value = ""; protected $tmp_value = ""; // Used when modified but not saved protected $type = "string"; protected $default = ""; protected $defaults = ""; protected $description = ""; protected $check = ""; protected $migrate = ""; protected $mandatory = FALSE; protected $group = "default"; protected $parent = NULL; protected $data = array(); protected $migrationClass = NULL; /*! The current property status * 'ldap' Property is stored in ldap * 'file' Property is stored in the config file * 'undefined' Property is currently not stored anywhere * 'modified' Property has been modified (should be saved) */ protected $status = 'undefined'; protected $attributes = array('name','type','default','description','check', 'migrate','mandatory','group','defaults'); function __construct($parent,$classname,$data) { // Set some basic infos $this->parent = &$parent; $this->class = $classname; $this->data = $data; // Get all relevant information from the data array (comes from plInfo) foreach($this->attributes as $aName){ if(isset($data[$aName])){ $this->$aName = $data[$aName]; } } // Initialize with the current value $this->_restoreCurrentValue(); } function migrationRequired() { // Instantiate migration class if(!empty($this->migrate) && $this->migrationClass == NULL){ if(!class_available($this->migrate)){ trigger_error("Cannot start migration for gosaProperty::'{$this->getName()}' class not found ({$this->migrate})!"); }else{ $class = $this->migrate; $tmp = new $class($this->parent->config,$this); if(! $tmp instanceof propertyMigration){ trigger_error("Cannot start migration for gosaProperty::'{$this->getName()}' doesn't implement propertyMigration!"); }else{ $this->migrationClass = $tmp; } } } if(empty($this->migrate) || $this->migrationClass == NULL){ return(FALSE); } return($this->migrationClass->checkForIssues()); } function getMigrationClass() { return($this->migrationClass); } function check() { $val = $this->getValue(TRUE); $return = TRUE; if($this->mandatory && empty($val)){ $return = FALSE; } $check = $this->getCheck(); if(!empty($val) && !empty($check)){ $res = call_user_func(preg_split("/::/", $this->check),$messages=TRUE, $this->class,$this->name,$val, $this->type); if(!$res){ $return = FALSE; } } return($return); } static function isBool($message,$class,$name,$value, $type) { $match = in_array_strict($value,array('true','false','')); // Display the reason for failing this check. if($message && ! $match){ msg_dialog::display(_("Warning"), sprintf(_("The value %s specified for %s:%s needs to be a bool value!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } return($match); } static function isString($message,$class,$name,$value, $type) { $match = TRUE; // Display the reason for failing this check. if($message && ! $match){ msg_dialog::display(_("Warning"), sprintf(_("The value %s specified for %s:%s needs to be a string!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } return($match); } static function isInteger($message,$class,$name,$value, $type) { $match = is_numeric($value) && !preg_match("/[^0-9]/", $value); // Display the reason for failing this check. if($message && ! $match){ msg_dialog::display(_("Warning"), sprintf(_("The value %s specified for %s:%s needs to be numeric!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } return($match); } static function isPath($message,$class,$name,$value, $type) { $match = preg_match("#^(/[^/]*/){1}#", $value); // Display the reason for failing this check. if($message && ! $match){ msg_dialog::display(_("Warning"), sprintf(_("The path %s specified for %s:%s is invalid!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } return($match); } static function isReadablePath($message,$class,$name,$value, $type) { $match = !empty($value)&&is_dir($value)&&is_writeable($value); // Display the reason for failing this check. if($message && ! $match){ if(!is_dir($value)){ msg_dialog::display(_("Warning"), sprintf(_("The folder %s specified for %s:%s does not exists!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); }elseif(!is_readable($value)){ msg_dialog::display(_("Warning"), sprintf(_("The folder %s specified for %s:%s is not readable!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } } return($match); } static function isWriteableFile($message,$class,$name,$value, $type) { $match = (file_exists($value) && is_writeable($value)) || (!file_exists($value) && is_writeable(dirname($value))); // Display the reason for failing this check. if($message && ! $match){ if(!file_exists($value) && !is_writeable(dirname($value))){ msg_dialog::display(_("Warning"), sprintf(_("The file %s specified for %s:%s is not writeable!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); }elseif(file_exists($value) && !is_writeable($value)){ msg_dialog::display(_("Warning"), sprintf(_("The file %s specified for %s:%s is not writeable!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } } return($match); } static function isWriteablePath($message,$class,$name,$value, $type) { $match = !empty($value)&&is_dir($value)&&is_writeable($value); // Display the reason for failing this check. if($message && ! $match){ if(!is_dir($value)){ msg_dialog::display(_("Warning"), sprintf(_("The folder %s specified for %s:%s does not exists!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); }elseif(!is_writeable($value)){ msg_dialog::display(_("Warning"), sprintf(_("The folder %s specified for %s:%s is not writeable!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } } return($match); } static function isReadableFile($message,$class,$name,$value, $type) { $match = !empty($value) && is_readable($value) && is_file($value); // Display the reason for failing this check. if($message && ! $match){ if(!is_file($value)){ msg_dialog::display(_("Warning"), sprintf(_("The file %s specified for %s:%s does not exists!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); }elseif(!is_readable($value)){ msg_dialog::display(_("Warning"), sprintf(_("The file %s specified for %s:%s is not readable!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } } return($match); } static function isCommand($message,$class,$name,$value, $type) { $match = TRUE; // Display the reason for failing this check. if($message && ! $match){ msg_dialog::display(_("Warning"), sprintf(_("The command %s specified for %s:%s is invalid!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } return($match); } static function isDn($message,$class,$name,$value, $type) { $match = preg_match("/^([a-z]*=[^=,]*,)*[^=]*=[^=]*$/i", $value); // Display the reason for failing this check. if($message && ! $match){ msg_dialog::display(_("Warning"), sprintf(_("The DN %s specified for %s:%s is invalid!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } return($match); } static function isRdn($message,$class,$name,$value, $type) { $match = preg_match("/^([a-z]*=[^=,]*,)*[^=]*=[^=,]*,?$/i", $value); // Display the reason for failing this check. if($message && ! $match){ msg_dialog::display(_("Warning"), sprintf(_("The RDN %s specified for %s:%s is invalid!"), bold($value),bold($class),bold($name)), WARNING_DIALOG); } return($match); } private function _restoreCurrentValue() { // First check for values in the LDAP Database. if(isset($this->parent->ldapStoredProperties[$this->class][$this->name])){ $this->setStatus('ldap'); $this->value = $this->parent->ldapStoredProperties[$this->class][$this->name]; return; } // Second check for values in the config file. if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){ $this->setStatus('file'); $this->value = $this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)]; return; } // If there still wasn't found anything then fallback to the default. if($this->getStatus() == 'undefined'){ $this->value = $this->getDefault(); } } function getMigrate() { return($this->migrate); } function getCheck() { return($this->check); } function getName() { return($this->name); } function getClass() { return($this->class); } function getGroup() { return($this->group); } function getType() { return($this->type); } function getDescription() { return($this->description); } function getDefault() { return($this->default); } function getDefaults() { return($this->defaults); } function getStatus() { return($this->status); } function isMandatory() { return($this->mandatory); } function setValue($str) { if(in_array_strict($this->getStatus(), array('modified'))){ $this->tmp_value = $str; }elseif($this->value != $str){ $this->setStatus('modified'); $this->tmp_value = $str; } } function getValue($temporary = FALSE) { if($temporary){ if(in_array_strict($this->getStatus(), array('modified','removed'))){ return($this->tmp_value); }else{ return($this->value); } }else{ // Do not return ldap values if we've to ignore them. if($this->parent->ignoreLdapProperties){ if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){ return($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)]); }else{ return($this->getDefault()); } }else{ return($this->value); } } } function restoreDefault() { if(in_array_strict($this->getStatus(),array('ldap'))){ $this->setStatus('removed'); // Second check for values in the config file. if(isset($this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)])){ $this->tmp_value = $this->parent->fileStoredProperties[strtolower($this->class)][strtolower($this->name)]; }else{ $this->tmp_value = $this->getDefault(); } } } function save() { if($this->getStatus() == 'modified'){ $ldap = $this->parent->config->get_ldap_link(); $ldap->cd($this->parent->config->current['BASE']); $dn = "cn={$this->class},".$this->parent->config->current['CONFIG']; $ldap->cat($dn); if(!$ldap->count()){ $ldap->cd($dn); $data = array( 'cn' => $this->class, 'objectClass' => array('top','gosaConfig'), 'gosaSetting' => $this->name.":".$this->tmp_value); $ldap->add($data); if(!$ldap->success()){ echo $ldap->get_error(); } }else{ $attrs = $ldap->fetch(); $data = array(); $found = false; if(isset($attrs['gosaSetting']['count'])){ for($i = 0;$i<$attrs['gosaSetting']['count']; $i ++){ $set = $attrs['gosaSetting'][$i]; if(preg_match("/^{$this->name}:/", $set)){ $set = "{$this->name}:{$this->tmp_value}"; $found = true; } $data['gosaSetting'][] = $set; } } if(!$found) $data['gosaSetting'][] = "{$this->name}:{$this->tmp_value}"; $ldap->cd($dn); $ldap->modify($data); if(!$ldap->success()){ echo $ldap->get_error(); } } $this->value = $this->tmp_value; $this->setStatus('ldap'); }elseif($this->getStatus() == 'removed'){ $ldap = $this->parent->config->get_ldap_link(); $ldap->cd($this->parent->config->current['BASE']); $dn = "cn={$this->class},".$this->parent->config->current['CONFIG']; $ldap->cat($dn); $attrs = $ldap->fetch(); $data = array('gosaSetting' => array()); for($i = 0;$i<$attrs['gosaSetting']['count']; $i ++){ $set = $attrs['gosaSetting'][$i]; if(preg_match("/^{$this->name}:/", $set)){ continue; } $data['gosaSetting'][] = $set; } $ldap->cd($dn); $ldap->modify($data); if(!$ldap->success()){ echo $ldap->get_error(); } $this->_restoreCurrentValue(); } } private function setStatus($state) { if(!in_array_strict($state, array('ldap','file','undefined','modified','removed'))) { trigger_error("Unknown property status given '{$state}' for {$this->class}:{$this->name}!"); }else{ $this->status = $state; } } function isValid() { return(TRUE); } } interface propertyMigration { function __construct($config,$property); } ?> gosa-core-2.7.4/include/class_filterLDAP.inc0000644000175000017500000000754611472445244017653 0ustar cajuscajusget_ldap_link(TRUE); $flag= ($scope == "sub")?GL_SUBSEARCH:0; $result= filterLDAP::get_list($base, $filter, $attributes, $category, $objectStorage, $flag | GL_SIZELIMIT); return $result; } static function get_list($base, $filter, $attributes, $category, $objectStorage, $flags= GL_SUBSEARCH) { $ui= session::global_get('ui'); $config= session::global_get('config'); // Move to arrays for category and objectStorage if (!is_array($category)) { $category= array($category); } // Store in base - i.e. is a rdn value empty? $storeOnBase= count($objectStorage) == 1 && empty($objectStorage[0]); $method= ($storeOnBase && !($flags & GL_SUBSEARCH))?"ls":"search"; // Initialize search bases $bases= array(); // Get list of sub bases to search on if ($storeOnBase) { $bases[$base]= ""; } else { foreach ($objectStorage as $oc) { // Handle empty storage locatios here, maybe get_ou() as returned an empty string. if(empty($oc)){ $bases[$base] = ""; continue; } $oc= preg_replace('/,$/', '', $oc); $tmp= explode(',', $oc); if (count($tmp) == 1) { preg_match('/([^=]+)=(.*)$/', $oc, $m); if ($flags & GL_SUBSEARCH) { $bases[$base][]= $m[1].":dn:=".$m[2]; } else { $bases["$oc,$base"][]= $m[1].":dn:=".$m[2]; } } else { // No, there's no \, in pre defined RDN values preg_match('/^([^,]+),(.*)$/', $oc, $matches); preg_match('/([^=]+)=(.*)$/', $matches[1], $m); if ($flags & GL_SUBSEARCH) { $bases[$base][]= $m[1].":dn:=".$m[2]; } else { $bases[$matches[2].",$base"][]= $m[1].":dn:=".$m[2]; } } } } // Get LDAP link $ldap= $config->get_ldap_link($flags & GL_SIZELIMIT); // Do search for every base $result= array(); $limit_exceeded = FALSE; foreach($bases as $base => $dnFilters) { // Break if the size limit is exceeded if($limit_exceeded){ return($result); } // Switch to new base and search if (is_array($dnFilters)){ $dnFilter= "(|"; foreach ($dnFilters as $df) { $dnFilter.= "($df)"; } $dnFilter.= ")"; } else { $dnFilter= ""; } $ldap->cd($base); if ($method == "ls") { $ldap->ls("(&$filter$dnFilter)", $base, $attributes); } else { $ldap->search("(&$filter$dnFilter)", $attributes); } // Check for size limit exceeded messages for GUI feedback if (preg_match("/size limit/i", $ldap->get_error())){ session::set('limit_exceeded', TRUE); $limit_exceeded = TRUE; } /* Crawl through result entries and perform the migration to the result array */ while($attrs = $ldap->fetch()) { $dn= $ldap->getDN(); /* Convert dn into a printable format */ if ($flags & GL_CONVERT){ $attrs["dn"]= convert_department_dn($dn); } else { $attrs["dn"]= $dn; } /* Skip ACL checks if we are forced to skip those checks */ if($flags & GL_NO_ACL_CHECK){ $result[]= $attrs; }else{ /* Sort in every value that fits the permissions */ foreach ($category as $o){ if((preg_match("/\//",$o) && preg_match("/r/",$ui->get_permissions($dn,$o))) || (!preg_match("/\//",$o) && preg_match("/r/",$ui->get_category_permissions($dn, $o)))){ $result[]= $attrs; break; } } } } } return $result; } } ?> gosa-core-2.7.4/include/class_userFilterEditor.inc0000644000175000017500000003047111613731145021204 0ustar cajuscajuslisting = &$listing; if($entry){ $this->entry = $entry; $this->parent = $entry['parent']; $this->name = $entry['tag']; $this->description = $entry['description']; foreach($entry['query'] as $query){ $query['filter'] = userFilterEditor::_autoIndentFilter($query['filter'], " "); $this->queries[] = $query; } $this->selectedCategories = $entry['categories']; $this->share = in_array_strict("share",$entry['flags']); $this->enable = in_array_strict("enable",$entry['flags']); } $this->orig_name = $this->name; // Create statistic table entry $this->initTime = microtime(TRUE); stats::log('plugin', $class = get_class($this), $category = array($this->acl_category), $action = 'open', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); } /*! \brief Automatic indent indentation for filters. */ static function _autoIndentFilter($str, $indent = " ") { // Remove line breaks and escaped brackets $str = preg_replace('/[\t ]*\n[\t ]*/', "", $str); $str = preg_replace('/\\\\\\(/', "::OPEN::", $str); $str = preg_replace('/\\\\\\)/', "::CLOSE::", $str); // Add a line break infront of every bracket $str = preg_replace('/\\(/', "\n(", $str); $str = preg_replace('/\\)/', ")\n", $str); // Split by linebreaks $lines = preg_split("/\n/", $str); $str = ""; $i = 0; // Walk trough search blocks foreach($lines as $line){ $line = trim($line); if(empty($line)) continue; // Go back one level in indentation if(!preg_match("/\\(.*\\)/", $line) && preg_match('/\\)$/', $line)){ $i --; } $str.= "\n"; $str = str_pad($str,strlen($str)+$i, $indent); $str.= $line; // Go one level deeper in indentation if(!preg_match("/\\(.*\\)/", $line) && preg_match('/^\\(/', $line)){ $i ++; } } $str = preg_replace('/::OPEN::/', '\(', $str); $str = preg_replace('/::CLOSE::/', '\)', $str); return($str); } /*! \brief Retunrs the filters original name * @param The original name of the filter (if none was given * an empty string is returned) */ function getOriginalName() { return($this->orig_name); } /*! \brief Retunrs the filters name. * @param The name of the filter */ function getCurrentName() { return($this->name); } /*! \brief Generates the content, to edit the filter settings. * @return String HTML form. */ function execute() { plugin::execute(); $smarty = get_smarty(); // Build up HTML compliant html output $queries = array(); foreach($this->queries as $key => $query){ $query['filter'] = htmlentities($query['filter'],ENT_COMPAT,'UTF-8'); $queries[$key] = $query; } // Build up list of hard coded filters $filter= $this->listing->getFilter(); $smarty->assign("fixedFilters", array_keys($filter->searches)); $smarty->assign('parent', $this->parent); $smarty->assign('backends', $this->backends); $smarty->assign('name', htmlentities($this->name,ENT_COMPAT,'UTF-8')); $smarty->assign('queries', $queries); $smarty->assign('share', $this->share); $smarty->assign('enable', $this->enabled); $smarty->assign('description', htmlentities($this->description,ENT_COMPAT,'UTF-8')); $smarty->assign('selectedCategories', $this->selectedCategories); $smarty->assign('availableCategories', array_unique($this->listing->categories)); return($smarty->fetch(get_template_path('userFilterEditor.tpl', FALSE))); } /*! \brief Keep values entered in the input form of the dialog. (POST/GET) */ function save_object() { if(isset($_POST['userFilterEditor'])){ // Get posted strings foreach(array('name','description', 'parent') as $attr){ if(isset($_POST[$attr])){ $this->$attr = get_post($attr); } } // Filter needs special handling, it may contain charactes like < and > // wich are stipped out by get_post() && validate() foreach($this->queries as $key => $query){ if(isset($_POST['filter_'.$key])){ $f = get_post('filter_'.$key); $this->queries[$key]['filter'] = $f; $this->queries[$key]['backend'] = get_post('backend_'.$key); } } foreach($this->queries as $key => $query){ if(isset($_POST['removeQuery_'.$key])){ unset($this->queries[$key]); $this->queries = array_values($this->queries); } } // Get posted flags $this->share = isset($_POST['shareFilter']); $this->enable = isset($_POST['enableFilter']); // Get additional category if(isset($_POST['addCategory'])){ if(isset($_POST['manualCategory']) && !empty($_POST['manualCategory'])){ $this->selectedCategories[] = get_post('manualCategory'); }elseif(isset($_POST['availableCategory']) && !empty($_POST['availableCategory'])){ $this->selectedCategories[] = get_post('availableCategory'); } $this->selectedCategories = array_unique($this->selectedCategories); } // Remove categories if(isset($_POST['delCategory']) && isset($_POST['usedCategory'])){ foreach($_POST['usedCategory'] as $cat){ if(isset($this->selectedCategories[$cat])) unset($this->selectedCategories[$cat]); } } // Add new query if(isset($_POST['addQuery'])){ $filter= $this->listing->getFilter(); $backend = 'LDAP'; $query = "(objectClass=*)"; if(isset($filter->searches[$this->parent])){ $tmp = $filter->searches[$this->parent]; if(isset($tmp['query'][count($this->queries)])){ $query = $tmp['query'][count($this->queries)]['filter']; $backend = $tmp['query'][count($this->queries)]['backend']; }elseif(isset($tmp['query']['filter'])){ $query = $tmp['query']['filter']; $backend = $tmp['query']['backend']; } } $this->queries[] = array('backend'=> $backend, 'filter' => userFilterEditor::_autoIndentFilter($query," ")); } } } /*! \brief Validate user input * @return Array An Array containing potential error messages */ function check() { $msgs = plugin::check(); // Check if the name is given if(empty($this->name)){ $msgs[] = msgPool::required(_("Name")); }elseif(preg_match("/[^a-z0-9]/i", $this->name)){ // Check for a valid name, no special chars here - in particular no ; $msgs[] = msgPool::invalid(_("Name"), $this->name,"/[a-z0-9]/i"); } // Description is a must value. if(empty($this->description)){ $msgs[] = msgPool::required(_("Description")); } // Count the number of opening and closing brackets - exclude escaped ones. foreach($this->queries as $key => $query){ $f = preg_replace('/\\\\[\(\)]/',"",$query['filter']); $o = substr_count($f, '('); $c = substr_count($f, ')'); if($o != $c){ $msgs[] = sprintf(_("Error in filter #%s: %s opening and %s closing brackets detected!"), bold($key+1), bold($o), bold($c)); } } return($msgs); } /*! \brief Transforms the entered values into a filter object (array) which is useable * for the userFilter overview dialog. * @return Returns transformed filter data. */ function save() { $ret= array(); $ret['parent'] = $this->parent; $ret['tag'] = $this->name; $ret['description'] = $this->description; $ret['categories'] = $this->selectedCategories; $ret['query'] = $this->queries; $ret['flags'] = array(); if($this->share){ $ret['flags'][] = "share"; } if($this->enable){ $ret['flags'][] = "enable"; } return($ret); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_departmentSortIterator.inc0000644000175000017500000000410711242276372022437 0ustar cajuscajusdata= array_reverse($data, true); } else { $this->data= $data; } } function rewind() { return reset($this->data); } function current() { return current($this->data); } function key() { return key($this->data); } function next() { return next($this->data); } function valid() { return key($this->data) !== null; } } ?> gosa-core-2.7.4/include/class_userFilter.inc0000644000175000017500000002236411613731145020037 0ustar cajuscajusget_ldap_link(); $ocs = $ldap->get_objectclasses(); session::set('userFilter::userFilteringAvailable', isset($ocs['gosaProperties'])); } return(session::get('userFilter::userFilteringAvailable')); } /*! \brief Initiates the filter editing dialog. */ function __construct($config, $listing) { // Initialize this plugin with the users dn to gather user defined filters. $ui = get_userinfo(); plugin::plugin($config, $ui->dn); $this->listing = &$listing; $filter= $this->listing->getFilter(); // Load list of filters if(isset($this->attrs['gosaUserDefinedFilter'])){ for($i=0; $i< $this->attrs['gosaUserDefinedFilter']['count']; $i++){ $tmp = userFilter::explodeFilterString($this->attrs['gosaUserDefinedFilter'][$i]); if(isset($tmp['tag'])){ $this->filters[$tmp['tag']]= $tmp; } } } // Create the filter list $this->filterWidget= new sortableListing($this->filters, $this->convertFilterList()); $this->filterWidget->setDeleteable(true); $this->filterWidget->setEditable(true); $this->filterWidget->setWidth("100%"); $this->filterWidget->setHeight("270px"); $this->filterWidget->setHeader(array(_("Parent filter"),_("Name"),_("Description"),_("Category"),_("Options"),"")); $this->filterWidget->setColspecs(array('80px', '100px', '200px', '120px','150px')); $this->filterWidget->setAcl($ui->get_permissions($ui->dn,'users/user','gosaUserDefinedFilter')); } /*! \brief Parses a filter string into an array. */ static function explodeFilterString($filterStr) { list($parent,$categories, $name, $description, $filterList, $flags) = preg_split('/;/', $filterStr); // Ensure that we no empty category in our category list. if(empty($categories)){ $categories = array(); }else{ $categories = preg_split('/,/', $categories); } // Ensure that we no empty entry in out flags list. if(empty($flags)){ $flags = array(); }else{ $flags = preg_split('/,/', $flags); } // Get filters and their backends $queries = array(); foreach(preg_split('/,/', $filterList) as $data){ if(!empty($data)){ list($filter, $backend) = preg_split('/:/', $data); $queries[] = array('backend' => $backend, 'filter' => base64_decode($filter)); } } // build up filter entry. $tmp = array( 'parent' => $parent, 'tag' => $name, 'categories' => $categories, 'description' => base64_decode($description), 'query' => $queries, 'flags' => $flags); return($tmp); } /*! \brief Converts the list of filters ($this->filters) into data which is useable * for the sortableList object ($this->filterWidget). * @return Array An array containg data useable for sortableLists ($this->filterWidget) */ function convertFilterList() { $data = array(); foreach($this->filters as $name => $filter){ $data[$name] = array('data' => array( $filter['parent'], $filter['tag'], htmlentities($filter['description'], ENT_COMPAT, 'UTF-8'), implode(", ",$filter['categories']), implode(", ",$filter['flags']))); } return($data); } /*! \brief Display the user-filter overview as HTML content. * @return string HTML-content showing the user-filter editing dialog. */ function execute() { plugin::execute(); // Let the filter widget update itself $this->filterWidget->update(); // Cancel filter modifications (edit dialog) if(isset($_POST['cancelFilterSettings'])){ $this->dialog = NULL; } // Save modified filter entries (edit dialog) if(isset($_POST['saveFilterSettings']) && $this->dialog instanceOf userFilterEditor){ $this->dialog->save_object(); $msgs = $this->dialog->check(); if(count($msgs)){ msg_dialog::displayChecks($msgs); }else{ $orig_name = $this->dialog->getOriginalName(); $new_name = $this->dialog->getCurrentName(); // The object was renamed and if($orig_name != $new_name && isset($this->filters[$new_name])){ $msgs = array(msgPool::duplicated(_("Name"))); msg_dialog::displayChecks($msgs); }else{ // Remove old entry if filter was renamed if($orig_name != "" && isset($this->filters[$orig_name])){ unset($this->filters[$orig_name]); } // Now append the new filter object. $this->filters[$new_name] = $this->dialog->save(); $this->dialog = NULL; $this->filterWidget->setListData($this->filters, $this->convertFilterList()); $this->filterWidget->update(); } } } // Act on edit requests $this->filterWidget->save_object(); $action = $this->filterWidget->getAction(); if($action['action'] == 'edit' && count($action['targets']) == 1){ $key= $this->filterWidget->getKey($action['targets'][0]); if(isset($this->filters[$key])){ $this->dialog=new userFilterEditor($this->filters[$key], $this->listing); } } // Act on new requests if(isset($_POST['addFilter'])){ $this->dialog=new userFilterEditor(array(), $this->listing); } // Act on remove requests $action = $this->filterWidget->getAction(); if($action['action'] == 'delete' && count($action['targets']) == 1){ $key= $this->filterWidget->getKey($action['targets'][0]); if(isset($this->filters[$key])){ unset($this->filters[$key]); $this->filterWidget->update(); } } // Display edit dialog if($this->dialog instanceOf userFilterEditor){ $this->dialog->save_object(); return($this->dialog->execute()); } $smarty = get_smarty(); $smarty->assign("list", $this->filterWidget->render()); return($smarty->fetch(get_template_path('userFilter.tpl', FALSE))); } /*! \brief Returns user defined filter for a given list of categories, * if no categories were specified all enabled filters will be returned. */ static function getFilter($category=array()) { global $config; $ldap=$config->get_ldap_link(); $ui = get_userinfo(); $ldap->cd($config->current['BASE']); $ldap->search("(&(objectClass=gosaProperties)(gosaUserDefinedFilter=*))",array('gosaUserDefinedFilter')); $filter = array(); while($attrs = $ldap->fetch()){ for($i=0; $i < $attrs['gosaUserDefinedFilter']['count']; $i++){ $tmp = userFilter::explodeFilterString($attrs['gosaUserDefinedFilter'][$i]); if(!isset($tmp['tag'])) continue; // Remove line breaks from the filter, which may were added for better reading. foreach($tmp['query'] as $key => $query){ $c = preg_split('/\n/',$query['filter']); foreach($c as $cKey => $str) $c[$cKey] = trim($str); $tmp['query'][$key]['filter'] = mb_convert_encoding(implode($c),'UTF-8'); } // The filter is visible if it is shared or if is one of our own creations. // ... and enabled. $visible = in_array_strict('enable', $tmp['flags']) && ($attrs['dn'] == $ui->dn || in_array_strict('share', $tmp['flags'])); // Add filter if it matches the category list if($visible && (count($category) == 0 || array_intersect($category, $tmp['categories']))){ $filter[$tmp['tag']] = $tmp; } } } return($filter); } /*! \brief Write user-filter modifications back to the ldap. */ function save() { // Build up new list of filters $attrs = array(); foreach($this->filters as $filter){ $tmp = $filter['parent'].";"; $tmp.= implode(',', $filter['categories']).";"; $tmp.= $filter['tag'].";"; $tmp.= base64_encode($filter['description']).";"; // Add queries foreach($filter['query'] as $query){ $tmp.= base64_encode($query['filter']).":".$query['backend'].","; } $tmp = trim($tmp,",").";"; $tmp.= implode(',', $filter['flags']); $attrs[] = $tmp; } $this->gosaUserDefinedFilter = $attrs; plugin::save(); $ldap = $this->config->get_ldap_link(); $ldap->cd($this->dn); $ldap->modify($this->attrs); new log("modify","users/".get_class($this),$this->dn,array_keys($this->attrs),$ldap->get_error()); if (!$ldap->success()){ msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, LDAP_MOD, get_class())); } } /*! \brief Do not save any posted values here. */ function save_object(){} } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_userinfo.inc0000644000175000017500000006114411613731145017544 0ustar cajuscajusconfig= &$config; $ldap= $this->config->get_ldap_link(); $ldap->cat($userdn,array('sn', 'givenName', 'uid', 'gidNumber', 'preferredLanguage', 'gosaUnitTag', 'gosaLoginRestriction')); $attrs= $ldap->fetch(); if (isset($attrs['givenName'][0]) && isset($attrs['sn'][0])){ $this->cn= $attrs['givenName'][0]." ".$attrs['sn'][0]; } else { $this->cn= $attrs['uid'][0]; } if (isset($attrs['gidNumber'][0])){ $this->gidNumber= $attrs['gidNumber'][0]; } /* Restrictions? */ if (isset($attrs['gosaLoginRestriction'])){ $this->restrictions= $attrs['gosaLoginRestriction']; unset($this->restrictions['count']); } /* Assign user language */ if (isset($attrs['preferredLanguage'][0])){ $this->language= $attrs['preferredLanguage'][0]; } if (isset($attrs['gosaUnitTag'][0])){ $this->gosaUnitTag= $attrs['gosaUnitTag'][0]; } $this->dn= $userdn; $this->uid= $attrs['uid'][0]; $this->ip= $_SERVER['REMOTE_ADDR']; /* Initialize ACL_CACHE */ $this->reset_acl_cache(); } public function reset_acl_cache() { /* Initialize ACL_CACHE */ session::global_set('ACL_CACHE',array()); } function loadACL() { $this->ACL= array(); $this->allACLs= array(); $this->groups= array(); $this->result_cache =array(); $this->reset_acl_cache(); $ldap= $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); /* Get member groups... */ $ldap->search("(&(objectClass=posixGroup)(memberUid=".$this->uid."))", array('dn')); while ($attrs= $ldap->fetch()){ $this->groups[$attrs['dn']]= $attrs['dn']; } /* Crawl through ACLs and move relevant to the tree */ $ldap->search("(objectClass=gosaACL)", array('dn', 'gosaAclEntry')); $aclp= array(); $aclc= array(); while ($attrs= $ldap->fetch()){ /* Insert links in ACL array */ $aclp[$attrs['dn']]= substr_count($attrs['dn'], ','); $aclc[$attrs['dn']]= array(); $ol= array(); for($i= 0; $i<$attrs['gosaAclEntry']['count']; $i++){ $ol= array_merge($ol, @acl::explodeAcl($attrs['gosaAclEntry'][$i])); } $aclc[$attrs['dn']]= $ol; } /* Resolve roles here. */ foreach($aclc as $dn => $data){ foreach($data as $prio => $aclc_value) { if($aclc_value['type'] == "role"){ unset($aclc[$dn][$prio]); $ldap->cat($aclc_value['acl'],array("gosaAclTemplate")); $attrs = $ldap->fetch(); if(isset($attrs['gosaAclTemplate'])){ for($i= 0; $i<$attrs['gosaAclTemplate']['count']; $i++){ $tmp = @acl::explodeAcl($attrs['gosaAclTemplate'][$i]); foreach($tmp as $new_acl){ /* Keep non role attributes here! */ $new_acl['filter'] = $aclc_value['filter']; $new_acl['members'] = $aclc_value['members']; $aclc[$dn][] =$new_acl; } } } } } } /* ACL's read, sort for tree depth */ asort($aclp); /* Sort in tree order */ foreach ($aclp as $dn => $acl){ /* Check if we need to keep this ACL */ foreach($aclc[$dn] as $idx => $type){ $interresting= FALSE; /* No members? This ACL rule is deactivated ... */ if (!count($type['members'])){ $interresting= FALSE; } else { /* Inspect members... */ foreach ($type['members'] as $grp => $grpdsc){ /* Some group inside the members that is relevant for us? */ if (in_array_ics(@LDAP::convert(preg_replace('/^G:/', '', $grp)), $this->groups)){ $interresting= TRUE; } /* User inside the members? */ if (mb_strtoupper(preg_replace('/^U:/', '', $grp)) == mb_strtoupper($this->dn)){ $interresting= TRUE; } /* Wildcard? */ if (preg_match('/^G:\*/', $grp)){ $interresting= TRUE; } $this->allACLs[$dn][$idx]= $type; } } if ($interresting){ if (!isset($this->ACL[$dn])){ $this->ACL[$dn]= array(); } $this->ACL[$dn][$idx]= $type; } } } /* Create an array which represenet all relevant permissions settings per dn. The array will look like this: . ['ou=base'] ['ou=base'] = array(ACLs); . . ['ou=dep1,ou=base']['ou=dep1,ou=base'] = array(ACLs); . ['ou=base'] = array(ACLs); For object located in 'ou=dep1,ou=base' we have to both ACLs, for objects in 'ou=base' we only have to apply on ACL. */ $without_self_acl = $all_acl = array(); foreach($this->ACL as $dn => $acl){ $sdn =$dn; $first= TRUE; // Run at least once while(strpos($dn,",") !== FALSE || $first){ $first = FALSE; if(isset($this->ACL[$dn])){ $all_acl[$sdn][$dn] = $this->ACL[$dn]; $without_self_acl[$sdn][$dn] = $this->ACL[$dn]; foreach($without_self_acl[$sdn][$dn] as $acl_id => $acl_set){ /* Remember which ACL set has speicial user filter */ if(isset($acl_set['filter']{1})){ $this->ACLperPath_usesFilter[$sdn] = TRUE; } /* Remove all acl entries which are especially for the current user (self acl) */ if(isset($acl_set['acl'])){ foreach($acl_set['acl'] as $object => $object_acls){ if(isset($object_acls[0]) && strpos($object_acls[0],"s") !== FALSE){ unset($without_self_acl[$sdn][$dn][$acl_id]['acl'][$object]); } } } } } $dn = preg_replace("/^[^,]*+,/","",$dn); } } $this->ACLperPath =$without_self_acl; /* Append Self entry */ $dn = $this->dn; while(strpos($dn,",") && !isset($all_acl[$dn])){ $dn = preg_replace("/^[^,]*+,/","",$dn); } if(isset($all_acl[$dn])){ $this->ACLperPath[$this->dn] = $all_acl[$dn]; } } /* Returns an array containing all target objects we've permssions on. */ function get_acl_target_objects() { return(array_keys($this->ACLperPath)); } function get_category_permissions($dn, $category, $any_acl = FALSE) { return($this->get_permissions($dn,$category.'/0',"")); } /*! \brief Check if the given object (dn) is copyable @param String The object dn @param String The acl category (e.g. users) @param String The acl class (e.g. user) @return Boolean TRUE if the given object is copyable else FALSE */ function is_copyable($dn, $object, $class) { return(preg_match("/r/",$this->has_complete_category_acls($dn, $object))); } /*! \brief Check if the given object (dn) is cutable @param String The object dn @param String The acl category (e.g. users) @param String The acl class (e.g. user) @return Boolean TRUE if the given object is cutable else FALSE */ function is_cutable($dn, $object, $class) { $remove = preg_match("/d/",$this->get_permissions($dn,$object."/".$class)); $read = preg_match("/r/",$this->has_complete_category_acls($dn, $object)); return($remove && $read); } /*! \brief Checks if we are allowed to paste an object to the given destination ($dn) @param String The destination dn @param String The acl category (e.g. users) @param String The acl class (e.g. user) @return Boolean TRUE if we are allowed to paste an object. */ function is_pasteable($dn, $object) { return(preg_match("/w/",$this->has_complete_category_acls($dn, $object))); } /*! \brief Checks if we are allowed to restore a snapshot for the given dn. @param String The destination dn @param String The acl category (e.g. users) @return Boolean TRUE if we are allowed to restore a snapshot. */ function allow_snapshot_restore($dn, $object) { if(!is_array($object)){ $object = array($object); } $r = $w = TRUE; foreach($object as $category){ $w &= preg_match("/w/",$this->has_complete_category_acls($dn, $category)); $r &= preg_match("/r/",$this->has_complete_category_acls($dn, $category)); } return($r && $w ); } /*! \brief Checks if we are allowed to create a snapshot of the given dn. @param String The source dn @param String The acl category (e.g. users) @return Boolean TRUE if we are allowed to restore a snapshot. */ function allow_snapshot_create($dn, $object) { if(!is_array($object)){ $object = array($object); } $r = TRUE; foreach($object as $category){ $r &= preg_match("/r/",$this->has_complete_category_acls($dn, $category)); } return($r) ; } function get_permissions($dn, $object, $attribute= "", $skip_write= FALSE) { /* If we are forced to skip ACLs checks for the current user then return all permissions. */ if($this->ignore_acl_for_current_user()){ if($skip_write){ return("rcdm"); } return("rwcdm"); } /* Push cache answer? */ $ACL_CACHE = &session::global_get('ACL_CACHE'); if (isset($ACL_CACHE["$dn+$object+$attribute"])){ $ret = $ACL_CACHE["$dn+$object+$attribute"]; if($skip_write){ $ret = str_replace(array('w','c','d','m'), '',$ret); } return($ret); } /* Check for correct category and class values... */ if(strpos($object,'/') !== FALSE){ list($aclCategory, $aclClass) = preg_split("!/!", $object); }else{ $aclCategory = $object; } if($this->config->boolValueIsTrue("core","developmentMode")){ if(!isset($this->ocMapping[$aclCategory])){ trigger_error("Invalid ACL category '".$aclCategory."'! ({$object})"); return(""); }elseif(isset($aclClass) && !in_array_strict($aclClass, $this->ocMapping[$aclCategory])){ trigger_error("Invalid ACL class '".$aclClass."'! ({$object})"); return(""); } if(isset($aclClass) && $aclClass != '0' && class_available($aclClass)){ $plInfo = call_user_func(array($aclClass, 'plInfo')); if(!empty($attribute) && !isset($plInfo['plProvidedAcls'][$attribute])){ trigger_error("Invalid ACL attribute '".$attribute."'! ({$object})"); return(""); } } } /* Detect the set of ACLs we have to check for this object */ $adn = $dn; while(!isset($this->ACLperPath[$adn]) && strpos($adn,",") !== FALSE){ $adn = preg_replace("/^[^,]*+,/","",$adn); } if(isset($this->ACLperPath[$adn])){ $ACL = $this->ACLperPath[$adn]; }else{ $ACL_CACHE["$dn+$object+$attribute"] = ""; return(""); } /* If we do not need to respect any user-filter settings we can skip the per object ACL checks. */ $orig_dn= $dn; if(!isset($this->ACLperPath_usesFilter[$adn])){ $dn = $adn; if (isset($ACL_CACHE["$dn+$object+$attribute"])){ $ret = $ACL_CACHE["$dn+$object+$attribute"]; if(!isset($ACL_CACHE["$orig_dn+$object+$attribute"])){ $ACL_CACHE["$orig_dn+$object+$attribute"] = $ACL_CACHE["$dn+$object+$attribute"]; } if($skip_write){ $ret = str_replace('w','',$ret); } return($ret); } } /* Get ldap object, for later filter checks */ $ldap = $this->config->get_ldap_link(); $acl= array("r" => "", "w" => "", "c" => "", "d" => "", "m" => "", "a" => ""); /* Build dn array */ $path= explode(',', $dn); $path= array_reverse($path); /* Walk along the path to evaluate the acl */ $cpath= ""; foreach ($path as $element){ /* Clean potential ACLs for each level */ if(isset($this->config->idepartments[$cpath])){ $acl= $this->cleanACL($acl); } if ($cpath == ""){ $cpath= $element; } else { $cpath= $element.','.$cpath; } if (isset($ACL[$cpath])){ /* Inspect this ACL, place the result into ACL */ foreach ($ACL[$cpath] as $subacl){ if($subacl['type'] == "role") { echo "role skipped"; continue; } /* With user filter */ if (isset($subacl['filter']) && !empty($subacl['filter'])){ $id = $dn."-".$subacl['filter']; if(!isset($ACL_CACHE['FILTER'][$id])){ $ACL_CACHE['FILTER'][$id] = $ldap->object_match_filter($dn,$subacl['filter']); } if(!$ACL_CACHE['FILTER'][$id]){ continue; } } /* Reset? Just clean the ACL and turn over to the next one... */ if ($subacl['type'] == 'reset'){ $acl= $this->cleanACL($acl, TRUE); continue; } /* Self ACLs? */ if($dn != $this->dn && isset($subacl['acl'][$object][0]) && (strpos($subacl['acl'][$object][0],"s") !== FALSE)){ continue; } /* If attribute is "", we want to know, if we've *any* permissions here... Merge global class ACLs [0] with attributes specific ACLs [attribute]. */ if ($attribute == "" && isset($subacl['acl'][$object])){ foreach($subacl['acl'][$object] as $attr => $dummy){ $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][$attr]); } continue; } /* Per attribute ACL? */ if (isset($subacl['acl'][$object][$attribute])){ $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][$attribute]); continue; } /* Per object ACL? */ if (isset($subacl['acl'][$object][0])){ $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$object][0]); continue; } /* Global ACL? */ if (isset($subacl['acl']['all/all'][0])){ $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']['all/all'][0]); continue; } /* Global ACL? - Old style global ACL - Was removed since class_core.inc was created */ if (isset($subacl['acl']['all'][0])){ $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl']['all'][0]); continue; } /* Category ACLs (e.g. $object = "user/0") */ if(strstr($object,"/0")){ $ocs = preg_replace("/\/0$/","",$object); if(isset($this->ocMapping[$ocs])){ /* if $attribute is "", then check every single attribute for this object. if it is 0, then just check the object category ACL. */ if($attribute == ""){ foreach($this->ocMapping[$ocs] as $oc){ if (isset($subacl['acl'][$ocs.'/'.$oc])){ // Skip ACLs wich are defined for ourselfs only - if not checking against ($ui->dn) if(isset($subacl['acl'][$ocs.'/'.$oc][0]) && $dn != $this->dn && strpos($subacl['acl'][$ocs.'/'.$oc][0],"s") !== FALSE) continue; foreach($subacl['acl'][$ocs.'/'.$oc] as $attr => $dummy){ $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$ocs.'/'.$oc][$attr]); } continue; } } }else{ if(isset($subacl['acl'][$ocs.'/'.$oc][0])){ if($dn != $this->dn && strpos($subacl['acl'][$ocs.'/'.$oc][0],"s") !== FALSE) continue; $acl= $this->mergeACL($acl, $subacl['type'], $subacl['acl'][$ocs.'/'.$oc][0]); } } } continue; } } } } /* If the requested ACL is for a container object, then alter ACLs by applying cleanACL a last time. */ if(isset($this->config->idepartments[$dn])){ $acl = $this->cleanACL($acl); } /* Assemble string */ $ret= ""; foreach ($acl as $key => $value){ if ($value !== ""){ $ret.= $key; } } $ACL_CACHE["$dn+$object+$attribute"]= $ret; $ACL_CACHE["$orig_dn+$object+$attribute"]= $ret; /* Remove write if needed */ if ($skip_write){ $ret = str_replace(array('w','c','d','m'), '',$ret); } return ($ret); } /* Extract all departments that are accessible (direct or 'on the way' to an accessible department) */ function get_module_departments($module, $skip_self_acls = FALSE ) { /* If we are forced to skip ACLs checks for the current user then return all departments as valid. */ if($this->ignore_acl_for_current_user()){ return(array_keys($this->config->idepartments)); } /* Use cached results if possilbe */ $ACL_CACHE = &session::global_get('ACL_CACHE'); if(!is_array($module)){ $module = array($module); } global $plist; $res = array(); foreach($module as $mod){ if(isset($ACL_CACHE['MODULE_DEPARTMENTS'][$mod])){ $res = array_merge($res,$ACL_CACHE['MODULE_DEPARTMENTS'][$mod]); continue; } $deps = array(); /* Search for per object ACLs */ foreach($this->ACL as $dn => $infos){ foreach($infos as $info){ $found = FALSE; if(isset($info['acl'])){ foreach($info['acl'] as $cat => $data){ /* Skip self acls? */ if($skip_self_acls && isset($data['0']) && (strpos($data['0'], "s") !== FALSE)) continue; if(preg_match("/^".preg_quote($mod, '/')."/",$cat)){ $found =TRUE; break; } } } if($found && !isset($this->config->idepartments[$dn])){ while(!isset($this->config->idepartments[$dn]) && strpos($dn, ",")){ $dn = preg_replace("/^[^,]+,/","",$dn); } if(isset($this->config->idepartments[$dn])){ $deps[$dn] = $dn; } } } } /* For all gosaDepartments */ foreach ($this->config->departments as $dn){ if(isset($deps[$dn])) continue; $acl = ""; if(strpos($mod, '/')){ $acl.= $this->get_permissions($dn,$mod); }else{ $acl.= $this->get_category_permissions($dn,$mod,TRUE); } if(!empty($acl)) { $deps[$dn] = $dn; } } $ACL_CACHE['MODULE_DEPARTMENTS'][$mod] = $deps; $res = array_merge($res,$deps); } return (array_values($res)); } function mergeACL($acl, $type, $newACL) { $at= array("psub" => "p", "sub" => "s", "one" => "1"); if (strpos($newACL, 'w') !== FALSE && strpos($newACL, 'r') === FALSE){ $newACL .= "r"; } /* Ignore invalid characters */ $newACL= preg_replace('/[^rwcdm]/', '', $newACL); foreach(str_split($newACL) as $char){ /* Skip "self" ACLs without combination of rwcdm, they have no effect. -self flag without read/write/create/... */ if(empty($char)) continue; /* Skip permanent and subtree entries */ if (preg_match('/[sp]/', $acl[$char])){ continue; } if ($type == "base" && $acl[$char] != 1) { $acl[$char]= 0; } else { $acl[$char]= $at[$type]; } } return ($acl); } function cleanACL($acl, $reset= FALSE) { foreach ($acl as $key => $value){ /* Continue, if value is empty or permanent */ if ($value == "" || $value == "p") { continue; } /* Reset removes everything but 'p' */ if ($reset && $value != 'p'){ $acl[$key]= ""; continue; } /* Decrease tree level */ if (is_int($value)){ if ($value){ $acl[$key]--; } else { $acl[$key]= ""; } } } return ($acl); } /* #FIXME This could be logical wrong or could be optimized in the future Return combined acls for a given category. All acls will be combined like boolean AND As example ('rwcdm' + 'rcd' + 'wrm'= 'r') Results will be cached in $this->result_cache. $this->result_cache will be resetted if load_acls is called. */ function has_complete_category_acls($dn,$category) { $acl = "rwcdm"; $types = "rwcdm"; if(!is_string($category)){ trigger_error("category must be string"); $acl = ""; }else{ if(!isset($this->result_cache['has_complete_category_acls'][$dn][$category])) { if (isset($this->ocMapping[$category])){ foreach($this->ocMapping[$category] as $oc){ /* Skip objectClass '0' (e.g. users/0) get_permissions will ever return '' ?? */ if($oc == "0") continue; $tmp = $this->get_permissions($dn, $category."/".$oc); for($i = 0, $l= strlen($types); $i < $l; $i++) { if(!preg_match("/".$types[$i]."/",$tmp)){ $acl = preg_replace("/".$types[$i]."/","",$acl); } } } }else{ if($this->config->boolValueIsTrue("core","developmentMode")){ trigger_error("Invalid type of category ".$category); } $acl = ""; } $this->result_cache['has_complete_category_acls'][$dn][$category] = $acl; }else{ $acl = $this->result_cache['has_complete_category_acls'][$dn][$category]; } } return($acl); } /*! \brief Returns TRUE if the current user is configured in IGNORE_ACL=".." in your gosa.conf @param Return Boolean TRUE if we have to skip ACL checks else FALSE. */ function ignore_acl_for_current_user() { if($this->ignoreACL === NULL){ $this->ignoreACL = ($this->config->get_cfg_value("core","ignoreAcl") == $this->dn); } return($this->ignoreACL); } function loginAllowed() { // Need to check restrictions? if (count($this->restrictions)){ // We have restrictions but cannot check them if (!isset($_SERVER['REMOTE_ADDR'])){ return false; } // Move to binary... $source= $_SERVER['REMOTE_ADDR']; foreach ($this->restrictions as $restriction) { // Single IP if (preg_match('/^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/', $restriction)) { if ($source == $restriction){ return true; } } // Match with short netmask if (preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+)$/', $restriction, $matches)) { if (isIpInNet($source, $matches[1], long2ip(~(pow(2, (32-$matches[2]))-1)))) { return true; } } // Match with long netmask if (preg_match('/^([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)\/([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)$/', $restriction, $matches)) { if (isIpInNet($source, $matches[1], $matches[2])) { return true; } } } return false; } return true; } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_log.inc0000644000175000017500000001032211613731145016463 0ustar cajuscajus \version 2.6 \date 11.04.2007 This is the base class for the GOsa logging functionality. All logging should lead to this class. */ class log { var $config; /*! \brief logging constructor \param action One of these values (modify|create|remove|snapshot|copy) \param objecttype represents the current edited objecttype, like users/user \param object represents the current edited object dn \param changes_array An array containing names of all touched attributes \param result A status message, containing errors or success messages \sa log() */ function log($action,$objecttype,$object,$changes_array = array(),$result = "") { if(!is_array($changes_array)){ trigger_error("log(string,string,string,array(),bool). Forth parameter must be an array."); $changes_array = array(); } $entry = array(); if(!session::global_is_set('config')){ $entry['user']= "unkown"; }else{ $this->config = session::global_get('config'); $ui = get_userinfo(); $entry['user']= @$ui->dn; } /* Create string out of changes */ $changes =""; foreach($changes_array as $str ){ $changes .= $str.","; } $changes = preg_replace("/,$/","",$changes ); /* Create data object */ $entry['timestamp'] = time(); $entry['action'] = $action; $entry['objecttype']= $objecttype; $entry['object'] = $object; $entry['changes'] = $changes; $entry['result'] = $result; if(!isset($this->config) && empty($entry['user'])){ $entry['user'] = "unknown"; } /* Check if all given values are valid */ global $config; $msgs = @log::check($entry); if(count($msgs)){ foreach($msgs as $msg){ trigger_error("Logging failed, reason was: ".$msg); msg_dialog::display(_("Internal error"), sprintf(_("Logging failed: %s"), $msg), ERROR_DIALOG); } }else{ if(is_object($config) && $config->boolValueIsTrue("core","logging")){ $this->log_into_syslog($entry); } } } function check($entry = array()) { $msgs = array(); if(!isset($entry['action']) || !in_array_strict($entry['action'],array("modify","create","remove","copy","snapshot","view","security","debug"))){ $msgs[] = sprintf(_("Invalid option %s specified!"), bold($entry['action'])); } if(!isset($entry['objecttype'])){ $msgs[] = _("Specified 'objectType' is empty or invalid!"); } return($msgs); } /* This function is used to into the systems syslog */ function log_into_syslog($entry) { $str= ""; if(!empty($entry['action'])) $str .= "({$entry['action']}) "; // Add object and object type if set. if(!empty($entry['object']) && !empty($entry['objecttype'])){ $str .= "{$entry['object']} of type {$entry['objecttype']} "; }elseif(!empty($entry['object'])){ $str .= "{$entry['object']} "; }elseif(!empty($entry['objecttype'])){ $str .= "{$entry['objecttype']} "; } if(!empty($entry['changes'])) $str .= "{$entry['changes']} "; if(!empty($entry['result'])) $str .= ": {$entry['result']} "; gosa_log($str); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/smartyAddons/0000755000175000017500000000000011752422552016477 5ustar cajuscajusgosa-core-2.7.4/include/smartyAddons/block.tr.php0000644000175000017500000000125511651531333020725 0ustar cajuscajus gosa-core-2.7.4/include/smartyAddons/function.factory.php0000644000175000017500000000217711707215001022477 0ustar cajuscajus"; } return($str); } ?> gosa-core-2.7.4/include/smartyAddons/function.msgPool.php0000644000175000017500000000101211651531333022442 0ustar cajuscajus $value){ if(!preg_match("/^type$/i",$para)){ $parameter[$para] = $value; } } if(is_callable("msgPool::".$params['type'])){ echo call_user_func_array(array("msgPool",$params['type']), $parameter); }else{ trigger_error("Unknown msgPool function ".$params['type']); } }else{ trigger_error("Unknown class msgPool."); } } ?> gosa-core-2.7.4/include/smartyAddons/block.t.php0000644000175000017500000000753311651531333020550 0ustar cajuscajus * @copyright 2004-2005 Sagi Bashari */ /** * Replaces arguments in a string with their values. * Arguments are represented by % followed by their number. * * @param string Source string * @param mixed Arguments, can be passed in an array or through single variables. * @returns string Modified string */ function smarty_gettext_strarg($str) { $tr = array(); $p = 0; for ($i=1; $i < func_num_args(); $i++) { $arg = func_get_arg($i); if (is_array($arg)) { foreach ($arg as $aarg) { $tr['%'.++$p] = $aarg; } } else { $tr['%'.++$p] = $arg; } } return strtr($str, $tr); } /** * Smarty block function, provides gettext support for smarty. * * The block content is the text that should be translated. * * Any parameter that is sent to the function will be represented as %n in the translation text, * where n is 1 for the first parameter. The following parameters are reserved: * - escape - sets escape mode: * - 'html' for HTML escaping, this is the default. * - 'js' for javascript escaping. * - 'url' for url escaping. * - 'no'/'off'/0 - turns off escaping * - plural - The plural version of the text (2nd parameter of ngettext()) * - count - The item count for plural mode (3rd parameter of ngettext()) */ function smarty_block_t($params, $text, &$smarty) { $text = stripslashes($text); // set escape mode if (isset($params['escape'])) { $escape = $params['escape']; unset($params['escape']); } // set plural version if (isset($params['plural'])) { $plural = $params['plural']; unset($params['plural']); // set count if (isset($params['count'])) { $count = $params['count']; unset($params['count']); } } // use plural if required parameters are set if (isset($count) && isset($plural)) { $text = ngettext($text, $plural, $count); } else { // use normal $text = gettext($text); } // run strarg if there are parameters if (count($params)) { $text = smarty_gettext_strarg($text, $params); } if (!isset($escape) || $escape == 'html') { // html escape, default $text = nl2br(htmlspecialchars($text)); } elseif (isset($escape)) { switch ($escape) { case 'javascript': case 'js': // javascript escape $text = str_replace('\'', '\\\'', stripslashes($text)); break; case 'url': // url escape $text = urlencode($text); break; } } return $text; } ?> gosa-core-2.7.4/include/smartyAddons/block.render.php0000644000175000017500000000655411651531333021566 0ustar cajuscajus */ if(empty($text)) { return(""); } /* Get acl parameter */ $acl = ""; if (isset($params['acl'])) { $acl = $params['acl']; } /* Debug output */ if (session::is_set('debugLevel') && session::get('debugLevel') & DEBUG_ACL ){ echo " ".$acl.""; } /* Parameter : checkbox, checked * If the parameter 'checkbox' is given, we create a html checkbox in front * of the current object. * The parameter 'checked' specifies whether the box is checked or not. * The checkbox disables or enables the current object. */ if(isset($params['checkbox']) && $params['checkbox']){ /* Detect name and id of the current object */ $use_text = preg_replace("/\n/"," ",$text); $name = preg_replace('/^.* name[ ]*=[ ]*("|\')([^\"\' ]*).*$/i',"\\2",$use_text); /* Detect id */ if(preg_match("/ id=(\"|')[^\"']*(\"|')/i",$text)){ $id = preg_replace('/^.* id[ ]*=[ ]*("|\')([^\"\' ]*).*$/i',"\\2",$use_text); }else{ $id = ""; } /* Is the box checked? */ isset($params['checked'])&&$params['checked'] ? $check = " checked " : $check = ""; /* If name isset, we have a html input field */ if(!empty($name)){ /* Print checkbox */ echo ""; /* Disable current object, if checkbox isn't checked */ if($check == ""){ $text = preg_replace("/name=/i"," disabled name=",$text); } /* Add id to current entry, if it is missing */ if($id == ""){ $text = preg_replace("/name=/i"," id=\"".$name."\" name=",$text); } } } /* Read / Write*/ if(preg_match("/w/i",$acl)){ return ($text); } $text = preg_replace ("/\n/","GOSA_LINE_BREAK",$text); /* Disable objects, but keep those active that have mode=read_active */ if(!(isset($params['mode']) && ($params['mode']=='read_active') && preg_match("/(r|w)/",$acl))){ /* Disable options && greyout lists */ $from = array("/class=['\"]list1nohighlight['\"]/i", "/class=['\"]list0['\"]/i", "/class=['\"]list1['\"]/i", "/class=['\"]sortableListItem[^'\"]*['\"]/i"); $to = array("class='list1nohighlightdisabled'", "class='list1nohighlightdisabled'", "class='list1nohighlightdisabled'", "class='sortableListItemDisabled'"); if(!preg_match("/ disabled /",$text)){ $from [] = "/name=/i" ; $to [] = "disabled name="; } $text = preg_replace($from,$to,$text); /* Replace picture if object is disabled */ if(isset($params['disable_picture'])){ $syn = "/src=['\"][^\"']*['\"]/i"; $new = "src=\"".$params['disable_picture']."\""; $text = preg_replace($syn,$new,$text); } } /* Read only */ if(preg_match("/r/i",$acl)){ return(preg_replace("/GOSA_LINE_BREAK/","\n",$text)); } /* No acls */ if(preg_match("/type['\"= ].*submit/",$text)){ $text = preg_replace("/submit/","button",$text); }else{ $text = preg_replace("/value=['\"][^\"']*['\"]/","",$text); } /* Remove select options */ $from = array("##i", "/().*(<\/textarea>)/i", "/^(.*.*)$/i"); $to = array(" ", "\\1\\2", "\\1 \\2"); $text = preg_replace($from,$to,$text); $text = preg_replace("/GOSA_LINE_BREAK/","\n",$text); return $text; } ?> gosa-core-2.7.4/include/smartyAddons/function.image.php0000644000175000017500000000120411651531333022107 0ustar cajuscajus gosa-core-2.7.4/include/class_plugin.inc0000644000175000017500000014663111613731145017215 0ustar cajuscajus \version 2.00 \date 24.07.2003 This is the base class for all plugins. It can be used standalone or can be included by the tabs class. All management should be done within this class. Extend your plugins from this class. */ class plugin { /*! \brief The title shown in path menu while this plugin is visible. */ var $pathTitle = ""; /*! \brief Reference to parent object This variable is used when the plugin is included in tabs and keeps reference to the tab class. Communication to other tabs is possible by 'name'. So the 'fax' plugin can ask the 'userinfo' plugin for the fax number. \sa tab */ var $parent= NULL; /*! \brief Configuration container Access to global configuration */ var $config= NULL; /*! \brief Mark plugin as account Defines whether this plugin is defined as an account or not. This has consequences for the plugin to be saved from tab mode. If it is set to 'FALSE' the tab will call the delete function, else the save function. Should be set to 'TRUE' if the construtor detects a valid LDAP object. \sa plugin::plugin() */ var $is_account= FALSE; var $initially_was_account= FALSE; /*! \brief Mark plugin as template Defines whether we are creating a template or a normal object. Has conseqences on the way execute() shows the formular and how save() puts the data to LDAP. \sa plugin::save() plugin::execute() */ var $is_template= FALSE; var $ignore_account= FALSE; var $is_modified= FALSE; /*! \brief Represent temporary LDAP data This is only used internally. */ var $attrs= array(); /* Keep set of conflicting plugins */ var $conflicts= array(); /* Save unit tags */ var $gosaUnitTag= ""; var $skipTagging= FALSE; /*! \brief Used standard values dn */ var $dn= ""; var $uid= ""; var $sn= ""; var $givenName= ""; var $acl= "*none*"; var $dialog= FALSE; var $snapDialog = NULL; /* attribute list for save action */ var $attributes= array(); var $objectclasses= array(); var $is_new= TRUE; var $saved_attributes= array(); var $acl_base= ""; var $acl_category= ""; var $read_only = FALSE; // Used when the entry is opened as "readonly" due to locks. /* This can be set to render the tabulators in another stylesheet */ var $pl_notify= FALSE; /* Object entry CSN */ var $entryCSN = ""; var $CSN_check_active = FALSE; /* This variable indicates that this class can handle multiple dns at once. */ var $multiple_support = FALSE; var $multi_attrs = array(); var $multi_attrs_all = array(); /* This aviable indicates, that we are currently in multiple edit handle */ var $multiple_support_active = FALSE; var $selected_edit_values = array(); var $multi_boxes = array(); /*! \brief plugin constructor If 'dn' is set, the node loads the given 'dn' from LDAP \param dn Distinguished name to initialize plugin from \sa plugin() */ function plugin (&$config, $dn= NULL, $object= NULL) { $this->initTime = microtime(TRUE); /* Configuration is fine, allways */ $this->config= &$config; $this->dn= $dn; // Ensure that we've a valid acl_category set. if(empty($this->acl_category)){ $tmp = $this->plInfo(); if (isset($tmp['plCategory'])) { $c = key($tmp['plCategory']); if(is_numeric($c)){ $c = $tmp['plCategory'][0]; } $this->acl_category = $c."/"; } } // Create statistic table entry stats::log('plugin', $class = get_class($this), $category = array($this->acl_category), $action = 'open', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); /* Handle new accounts, don't read information from LDAP */ if ($dn == "new"){ return; } /* Check if this entry was opened in read only mode */ if(isset($_POST['open_readonly'])){ if(session::global_is_set("LOCK_CACHE")){ $cache = &session::get("LOCK_CACHE"); if(isset($cache['READ_ONLY'][$this->dn])){ $this->read_only = TRUE; } } } /* Save current dn as acl_base */ $this->acl_base= $dn; /* Get LDAP descriptor */ if ($dn !== NULL){ /* Load data to 'attrs' and save 'dn' */ if ($object !== NULL){ $this->attrs= $object->attrs; } else { $ldap= $this->config->get_ldap_link(); $ldap->cat ($dn); $this->attrs= $ldap->fetch(); } /* Copy needed attributes */ foreach ($this->attributes as $val){ $found= array_key_ics($val, $this->attrs); if ($found != ""){ $this->$val= $found[0]; } } /* gosaUnitTag loading... */ if (isset($this->attrs['gosaUnitTag'][0])){ $this->gosaUnitTag= $this->attrs['gosaUnitTag'][0]; } /* Set the template flag according to the existence of objectClass gosaUserTemplate */ if (isset($this->attrs['objectClass'])){ if (in_array_ics ("gosaUserTemplate", $this->attrs['objectClass'])){ $this->is_template= TRUE; @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "found", "Template check"); } } /* Is Account? */ $found= TRUE; foreach ($this->objectclasses as $obj){ if (preg_match('/top/i', $obj)){ continue; } if (!isset($this->attrs['objectClass']) || !in_array_ics ($obj, $this->attrs['objectClass'])){ $found= FALSE; break; } } if ($found){ $this->is_account= TRUE; @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "found", "Object check"); } /* Prepare saved attributes */ $this->saved_attributes= $this->attrs; foreach ($this->saved_attributes as $index => $value){ if (is_numeric($index)){ unset($this->saved_attributes[$index]); continue; } if (!in_array_ics($index, $this->attributes) && strcasecmp('objectClass', $index)){ unset($this->saved_attributes[$index]); continue; } if (isset($this->saved_attributes[$index][0])){ if(!isset($this->saved_attributes[$index]["count"])){ $this->saved_attributes[$index]["count"] = count($this->saved_attributes[$index]); } if($this->saved_attributes[$index]["count"] == 1){ $tmp= $this->saved_attributes[$index][0]; unset($this->saved_attributes[$index]); $this->saved_attributes[$index]= $tmp; continue; } } unset($this->saved_attributes["$index"]["count"]); } if(isset($this->attrs['gosaUnitTag'])){ $this->saved_attributes['gosaUnitTag'] = $this->attrs['gosaUnitTag'][0]; } } /* Save initial account state */ $this->initially_was_account= $this->is_account; } /*! \brief Generates the html output for this node */ function execute() { /* This one is empty currently. Fabian - please fill in the docu code */ session::global_set('current_class_for_help',get_class($this)); /* Reset Lock message POST/GET check array, to prevent perg_match errors*/ session::set('LOCK_VARS_TO_USE',array()); session::set('LOCK_VARS_USED_GET',array()); session::set('LOCK_VARS_USED_POST',array()); session::set('LOCK_VARS_USED_REQUEST',array()); pathNavigator::registerPlugin($this); // Create statistic table entry stats::log('plugin', $class = get_class($this), $category = array($this->acl_category), $action = 'view', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); } /*! \brief Removes object from parent */ function remove_from_parent() { /* include global link_info */ $ldap= $this->config->get_ldap_link(); /* Get current objectClasses in order to add the required ones */ $ldap->cat($this->dn); $tmp= $ldap->fetch (); $oc= array(); if (isset($tmp['objectClass'])){ $oc= $tmp['objectClass']; unset($oc['count']); } /* Remove objectClasses from entry */ $ldap->cd($this->dn); $this->attrs= array(); $this->attrs['objectClass']= array_remove_entries_ics($this->objectclasses,$oc); /* Unset attributes from entry */ foreach ($this->attributes as $val){ $this->attrs["$val"]= array(); } /* Unset account info */ $this->is_account= FALSE; /* Do not write in plugin base class, this must be done by children, since there are normally additional attribs, lists, etc. */ /* $ldap->modify($this->attrs); */ if($this->initially_was_account){ $this->handle_pre_events('remove'); // Create statistic table entry stats::log('plugin', $class = get_class($this), $category = array($this->acl_category), $action = 'remove', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); } } /*! \brief Save HTML posted data to object */ function save_object() { /* Update entry CSN if it is empty. */ if(empty($this->entryCSN) && $this->CSN_check_active){ $this->entryCSN = getEntryCSN($this->dn); } /* Save values to object */ foreach ($this->attributes as $val){ if (isset ($_POST["$val"]) && $this->acl_is_writeable($val)){ /* Check for modifications */ $data= get_post($val); if ($this->$val != $data){ $this->is_modified= TRUE; } $this->$val = $data; /* Okay, how can I explain this fix ... * In firefox, disabled option fields aren't selectable ... but in IE you can select these fileds. * So IE posts these 'unselectable' option, with value = chr(194) * chr(194) seems to be the   in between the ...option> $val= $data; } } } /*! \brief Save data to LDAP, depending on is_account we save or delete */ function save() { /* include global link_info */ $ldap= $this->config->get_ldap_link(); /* Save all plugins */ $this->entryCSN = ""; /* Start with empty array */ $this->attrs= array(); /* Get current objectClasses in order to add the required ones */ $ldap->cat($this->dn); $tmp= $ldap->fetch (); $oc= array(); if (isset($tmp['objectClass'])){ $oc= $tmp["objectClass"]; $this->is_new= FALSE; unset($oc['count']); } else { $this->is_new= TRUE; } /* Load (minimum) attributes, add missing ones */ $this->attrs['objectClass']= gosa_array_merge($oc,$this->objectclasses); /* Copy standard attributes */ foreach ($this->attributes as $val){ if ($this->$val != ""){ $this->attrs["$val"]= $this->$val; } elseif (!$this->is_new) { $this->attrs["$val"]= array(); } } /* Handle tagging */ $this->tag_attrs($this->attrs); if($this->is_new){ $this->handle_pre_events('add'); // Create statistic table entry stats::log('plugin', $class = get_class($this), $category = array($this->acl_category), $action = 'create', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); }else{ $this->handle_pre_events('modify'); // Create statistic table entry stats::log('plugin', $class = get_class($this), $category = array($this->acl_category), $action = 'modify', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); } } /*! \brief Forward command execution requests * to the hook execution method. */ function handle_pre_events($mode, $addAttrs= array()) { if(!in_array_strict($mode, array('add','remove','modify'))){ trigger_error(sprintf("Invalid pre event type given %s! Valid types are [add,modify,remove].", $mode)); return; } switch ($mode){ case "add": plugin::callHook($this,"PRECREATE", $addAttrs); break; case "modify": plugin::callHook($this,"PREMODIFY", $addAttrs); break; case "remove": plugin::callHook($this,"PREREMOVE", $addAttrs); break; } } function cleanup() { foreach ($this->attrs as $index => $value){ /* Convert arrays with one element to non arrays, if the saved attributes are no array, too */ if (is_array($this->attrs[$index]) && count ($this->attrs[$index]) == 1 && isset($this->saved_attributes[$index]) && !is_array($this->saved_attributes[$index])){ $tmp= $this->attrs[$index][0]; $this->attrs[$index]= $tmp; } /* Remove emtpy arrays if they do not differ */ if (is_array($this->attrs[$index]) && count($this->attrs[$index]) == 0 && !isset($this->saved_attributes[$index])){ unset ($this->attrs[$index]); continue; } /* Remove single attributes that do not differ */ if (!is_array($this->attrs[$index]) && isset($this->saved_attributes[$index]) && !is_array($this->saved_attributes[$index]) && $this->attrs[$index] == $this->saved_attributes[$index]){ unset ($this->attrs[$index]); continue; } /* Remove arrays that do not differ */ if (is_array($this->attrs[$index]) && isset($this->saved_attributes[$index]) && is_array($this->saved_attributes[$index])){ if (!array_differs($this->attrs[$index],$this->saved_attributes[$index])){ unset ($this->attrs[$index]); continue; } } } /* Update saved attributes and ensure that next cleanups will be successful too */ foreach($this->attrs as $name => $value){ $this->saved_attributes[$name] = $value; } } /*! \brief Check formular input */ function check() { $message= array(); /* Skip if we've no config object */ if (!isset($this->config) || !is_object($this->config)){ return $message; } /* Find hooks entries for this class */ $command = $this->config->configRegistry->getPropertyValue(get_class($this),"check"); if ($command != ""){ if (!check_command($command)){ $message[]= msgPool::cmdnotfound("CHECK", get_class($this)); } else { /* Generate "ldif" for check hook */ $ldif= "dn: $this->dn\n"; /* ... objectClasses */ foreach ($this->objectclasses as $oc){ $ldif.= "objectClass: $oc\n"; } /* ... attributes */ foreach ($this->attributes as $attr){ if ($this->$attr == ""){ continue; } if (is_array($this->$attr)){ foreach ($this->$attr as $val){ $ldif.= "$attr: $val\n"; } } else { $ldif.= "$attr: ".$this->$attr."\n"; } } /* Append empty line */ $ldif.= "\n"; /* Feed "ldif" into hook and retrieve result*/ $descriptorspec = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w")); $fh= proc_open($command, $descriptorspec, $pipes); if (is_resource($fh)) { fwrite ($pipes[0], $ldif); fclose($pipes[0]); $result= stream_get_contents($pipes[1]); if ($result != ""){ $message[]= $result; } fclose($pipes[1]); fclose($pipes[2]); proc_close($fh); } } } /* Check entryCSN */ if($this->CSN_check_active){ $current_csn = getEntryCSN($this->dn); if($current_csn != $this->entryCSN && !empty($this->entryCSN) && !empty($current_csn)){ $this->entryCSN = $current_csn; $message[] = _("The current object has been altered while beeing edited. If you save this entry, changes that have been made by others will be discarded!"); } } return ($message); } /* Adapt from template, using 'dn' */ function adapt_from_template($dn, $skip= array()) { /* Include global link_info */ $ldap= $this->config->get_ldap_link(); /* Load requested 'dn' to 'attrs' */ $ldap->cat ($dn); $this->attrs= $ldap->fetch(); $values = array(); foreach(array('uid','sn','givenName') as $name){ if(isset($this->parent->$name)){ $value = $this->parent->$name; if(is_numeric($name)) continue; if(is_string($value)) $values[$name] = $value; if(is_array($value) && isset($value[0])) $values[$name] = $value[0]; } } foreach($this->attributes as $name){ // Skip the ones in skip list if (in_array_strict($name, $skip)) continue; if (!isset($this->attrs[$name]['count'])) continue; $value= $this->attrs[$name][0]; if($this->attrs[$name]['count'] == 1){ $value = fillReplacements($this->attrs[$name][0], $values); }else{ $value = array(); for($i=0;$i<$this->attrs[$name]['count'];$i++){ $value[] = fillReplacements($this->attrs[$name][$i], $values); } } $this->$name = $value; } /* Is Account? */ $found= TRUE; foreach ($this->objectclasses as $obj){ if (preg_match('/top/i', $obj)) continue; if (!in_array_ics ($obj, $this->attrs['objectClass'])){ $found= FALSE; break; } } $this->is_account = $found; } /* \brief Indicate whether a password change is needed or not */ function password_change_needed() { return FALSE; } /*! \brief Show header message for tab dialogs */ function show_enable_header($button_text, $text, $disabled= FALSE) { if (($disabled == TRUE) || (!$this->acl_is_createable())){ $state= "disabled"; } else { $state= ""; } $display = "
    \n"; $display.= "

    $text

    \n"; $display.= "\n"; $display.= "
    \n"; return($display); } /*! \brief Show header message for tab dialogs */ function show_disable_header($button_text, $text, $disabled= FALSE) { if (($disabled == TRUE) || !$this->acl_is_removeable()){ $state= "disabled"; } else { $state= ""; } $display = "
    \n"; $display.= "

    $text

    \n"; $display.= "\n"; $display.= "
    \n"; return($display); } /* Create unique DN */ function create_unique_dn2($data, $base) { $ldap= $this->config->get_ldap_link(); $base= preg_replace("/^,*/", "", $base); /* Try to use plain entry first */ $dn= "$data,$base"; $attribute= preg_replace('/=.*$/', '', $data); $ldap->cat ($dn, array('dn')); if (!$ldap->fetch()){ return ($dn); } /* Look for additional attributes */ foreach ($this->attributes as $attr){ if ($attr == $attribute || $this->$attr == ""){ continue; } $dn= "$data+$attr=".$this->$attr.",$base"; $ldap->cat ($dn, array('dn')); if (!$ldap->fetch()){ return ($dn); } } /* None found */ return ("none"); } /*! \brief Create unique DN */ function create_unique_dn($attribute, $base) { $ldap= $this->config->get_ldap_link(); $base= preg_replace("/^,*/", "", $base); /* Try to use plain entry first */ $dn= "$attribute=".$this->$attribute.",$base"; $ldap->cat ($dn, array('dn')); if (!$ldap->fetch()){ return ($dn); } /* Look for additional attributes */ foreach ($this->attributes as $attr){ if ($attr == $attribute || $this->$attr == ""){ continue; } $dn= "$attribute=".$this->$attribute."+$attr=".$this->$attr.",$base"; $ldap->cat ($dn, array('dn')); if (!$ldap->fetch()){ return ($dn); } } /* None found */ return ("none"); } function rebind($ldap, $referral) { $credentials= LDAP::get_credentials($referral, $this->config->current['REFERRAL']); if (ldap_bind($ldap, $credentials['ADMIN'], $this->config->get_credentials($credentials['PASSWORD']))) { $this->error = "Success"; $this->hascon=true; $this->reconnect= true; return (0); } else { $this->error = "Could not bind to " . $credentials['ADMIN']; return NULL; } } /* Recursively copy ldap object */ function _copy($src_dn,$dst_dn) { $ldap=$this->config->get_ldap_link(); $ldap->cat($src_dn); $attrs= $ldap->fetch(); /* Grummble. This really sucks. PHP ldap doesn't support rdn stuff. */ $ds= ldap_connect($this->config->current['SERVER']); ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3); if (function_exists("ldap_set_rebind_proc") && isset($this->config->current['REFERRAL'])) { ldap_set_rebind_proc($ds, array(&$this, "rebind")); } $pwd = $this->config->get_credentials($this->config->current['ADMINPASSWORD']); $r=ldap_bind($ds,$this->config->current['ADMINDN'], $pwd); $sr=ldap_read($ds, LDAP::fix($src_dn), "objectClass=*"); /* Fill data from LDAP */ $new= array(); if ($sr) { $ei=ldap_first_entry($ds, $sr); if ($ei) { foreach($attrs as $attr => $val){ if ($info = @ldap_get_values_len($ds, $ei, $attr)){ for ($i= 0; $i<$info['count']; $i++){ if ($info['count'] == 1){ $new[$attr]= $info[$i]; } else { $new[$attr][]= $info[$i]; } } } } } } /* close conncetion */ ldap_unbind($ds); /* Adapt naming attribute */ $dst_name= preg_replace("/^([^=]+)=.*$/", "\\1", $dst_dn); $dst_val = preg_replace("/^[^=]+=([^,+]+).*,.*$/", "\\1", $dst_dn); $new[$dst_name]= LDAP::fix($dst_val); /* Check if this is a department. * If it is a dep. && there is a , override in his ou * change \2C to , again, else this entry can't be saved ... */ if((isset($new['ou'])) &&( preg_match("/\\,/",$new['ou']))){ $new['ou'] = str_replace("\\\\,",",",$new['ou']); } /* Save copy */ $ldap->connect(); $ldap->cd($this->config->current['BASE']); $ldap->create_missing_trees(preg_replace('/^[^,]+,/', '', $dst_dn)); /* FAIvariable=.../..., cn=.. could not be saved, because the attribute FAIvariable was different to the dn FAIvariable=..., cn=... */ if(!is_array($new['objectClass'])) $new['objectClass'] = array($new['objectClass']); if(in_array_ics("FAIdebconfInfo",$new['objectClass'])){ $new['FAIvariable'] = $ldap->fix($new['FAIvariable']); } $ldap->cd($dst_dn); $ldap->add($new); if (!$ldap->success()){ trigger_error("Trying to save $dst_dn failed.", E_USER_WARNING); return(FALSE); } return(TRUE); } /* This is a workaround function. */ function copy($src_dn, $dst_dn) { /* Rename dn in possible object groups */ $ldap= $this->config->get_ldap_link(); $ldap->search('(&(objectClass=gosaGroupOfNames)(member='.@LDAP::prepare4filter($src_dn).'))', array('cn')); while ($attrs= $ldap->fetch()){ $og= new ogroup($this->config, $ldap->getDN()); unset($og->member[$src_dn]); $og->member[$dst_dn]= $dst_dn; $og->save (); } $ldap->cat($dst_dn); $attrs= $ldap->fetch(); if (count($attrs)){ trigger_error("Trying to overwrite ".LDAP::fix($dst_dn).", which already exists.", E_USER_WARNING); return (FALSE); } $ldap->cat($src_dn); $attrs= $ldap->fetch(); if (!count($attrs)){ trigger_error("Trying to move ".LDAP::fix($src_dn).", which does not seem to exist.", E_USER_WARNING); return (FALSE); } $ldap->cd($src_dn); $ldap->search("objectClass=*",array("dn")); while($attrs = $ldap->fetch()){ $src = $attrs['dn']; $dst = preg_replace("/".preg_quote($src_dn, '/')."$/",$dst_dn,$attrs['dn']); $this->_copy($src,$dst); } return (TRUE); } /*! \brief Rename/Move a given src_dn to the given dest_dn * * Move a given ldap object indentified by $src_dn to the * given destination $dst_dn * * - Ensure that all references are updated (ogroups) * - Update ACLs * - Update accessTo * * \param string 'src_dn' the source DN. * \param string 'dst_dn' the destination DN. * \return boolean TRUE on success else FALSE. */ function rename($src_dn, $dst_dn) { $start = microtime(1); /* Try to move the source entry to the destination position */ $ldap = $this->config->get_ldap_link(); $ldap->cd($this->config->current['BASE']); $ldap->create_missing_trees(preg_replace("/^[^,]+,/","",$dst_dn)); if (!$ldap->rename_dn($src_dn,$dst_dn)){ new log("debug","LDAP protocol v3 implementation error, ldap_rename failed, falling back to manual copy.","FROM: $src_dn -- TO: $dst_dn",array(),$ldap->get_error()); @DEBUG(DEBUG_LDAP,__LINE__,__FUNCTION__,__FILE__,"Rename failed FROM: $src_dn -- TO: $dst_dn", "Ldap Protocol v3 implementation error, falling back to maunal method."); return(FALSE); } /* Get list of users,groups and roles within this tree, maybe we have to update ACL references. */ $leaf_objs = get_list("(|(objectClass=posixGroup)(objectClass=gosaAccount)(objectClass=gosaRole))",array("all"),$dst_dn, array("dn","objectClass"),GL_SUBSEARCH | GL_NO_ACL_CHECK); foreach($leaf_objs as $obj){ $new_dn = $obj['dn']; $old_dn = preg_replace("/".preg_quote(LDAP::convert($dst_dn), '/')."$/i",$src_dn,LDAP::convert($new_dn)); $this->update_acls($old_dn,$new_dn); } // Migrate objectgroups if needed $ogroups = get_sub_list("(&(objectClass=gosaGroupOfNames)(member=".LDAP::prepare4filter(LDAP::fix($src_dn))."))", "ogroups", array(get_ou("group", "ogroupRDN")),$this->config->current['BASE'],array("dn"), GL_SUBSEARCH | GL_NO_ACL_CHECK); // Walk through all objectGroups foreach($ogroups as $ogroup){ // Migrate old to new dn $o_ogroup= new ogroup($this->config,$ogroup['dn']); if (isset($o_ogroup->member[$src_dn])) { unset($o_ogroup->member[$src_dn]); } $o_ogroup->member[$dst_dn]= $dst_dn; // Save object group $o_ogroup->save(); } // Migrate objectgroups if needed $objects = get_sub_list("(&(objectClass=gotoEnvironment)(gotoHotplugDeviceDN=".LDAP::prepare4filter(LDAP::fix($src_dn))."))", "users",array(get_ou("core","userRDN"), get_ou("core","groupRDN")), $this->config->current['BASE'],array("dn", "gotoHotplugDeviceDN"), GL_SUBSEARCH | GL_NO_ACL_CHECK); $ldap = $this->config->get_ldap_link(); foreach($objects as $obj){ $deviceDNS = array(); for($i=0; $i < $obj["gotoHotplugDeviceDN"]['count']; $i++){ $odn = $obj["gotoHotplugDeviceDN"][$i]; if($odn == $src_dn){ $odn = $dst_dn; } $deviceDNS[] = $odn; } $ldap->cd($obj['dn']); $ldap->modify(array('gotoHotplugDeviceDN'=>$deviceDNS)); if(!$ldap->success()){ trigger_error(sprintf("Failed to update gotoHotplugDeviceDN for %s: %s", bold($obj['dn']), $ldap->get_error())); } } // Migrate rfc groups if needed $groups = get_sub_list("(&(objectClass=posixGroup)(member=".LDAP::prepare4filter(LDAP::fix($src_dn))."))","groups", array(get_ou("core", "groupRDN")),$this->config->current['BASE'],array("dn"), GL_SUBSEARCH | GL_NO_ACL_CHECK); // Walk through all POSIX groups foreach($groups as $group){ // Migrate old to new dn $o_group= new group($this->config,$group['dn']); $o_group->save(); } /* Update roles to use the new entry dn */ if(class_available('roleGeneric')){ $roles = get_sub_list("(&(objectClass=organizationalRole)(roleOccupant=".LDAP::prepare4filter(LDAP::fix($src_dn))."))","roles", array(get_ou("roleGeneric", "roleRDN")),$this->config->current['BASE'],array("dn"), GL_SUBSEARCH | GL_NO_ACL_CHECK); // Walk through all roles foreach($roles as $role){ $role = new roleGeneric($this->config,$role['dn']); $key= array_search($src_dn, $role->roleOccupant); if($key !== FALSE){ $role->roleOccupant[$key] = $dst_dn; $role->save(); } } } // Update 'manager' attributes from gosaDepartment and inetOrgPerson $filter = "(&(objectClass=inetOrgPerson)(manager=".LDAP::prepare4filter(LDAP::fix($src_dn))."))"; $ocs = $ldap->get_objectclasses(); if(isset($ocs['gosaDepartment']['MAY']) && in_array_strict('manager', $ocs['gosaDepartment']['MAY'])){ $filter = "(|".$filter."(&(objectClass=gosaDepartment)(manager=".LDAP::prepare4filter(LDAP::fix($src_dn)).")))"; } $leaf_deps= get_list($filter,array("all"),$this->config->current['BASE'], array("manager","dn","objectClass"),GL_SUBSEARCH | GL_NO_ACL_CHECK); foreach($leaf_deps as $entry){ $update = array('manager' => $dst_dn); $ldap->cd($entry['dn']); $ldap->modify($update); if(!$ldap->success()){ trigger_error(sprintf("Failed to update manager for %s: %s", bold($entry['dn']), $ldap->get_error())); } } // Migrate 'dyn-groups' here. labeledURIObject if(class_available('DynamicLdapGroup')) { DynamicLdapGroup::moveDynGroup($this->config,$src_dn,$dst_dn); } /* Check if there are gosa departments moved. If there were deps moved, the force reload of config->deps. */ $leaf_deps= get_list("(objectClass=gosaDepartment)",array("all"),$dst_dn, array("dn","objectClass"),GL_SUBSEARCH | GL_NO_ACL_CHECK); if(count($leaf_deps)){ $this->config->get_departments(); $this->config->make_idepartments(); session::global_set("config",$this->config); $ui =get_userinfo(); $ui->reset_acl_cache(); } return(TRUE); } function move($src_dn, $dst_dn) { /* Do not copy if only upper- lowercase has changed */ if(strtolower($src_dn) == strtolower($dst_dn)){ return(TRUE); } // Create statistic table entry stats::log('plugin', $class = get_class($this), $category = array($this->acl_category), $action = 'move', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); /* Try to move the entry instead of copy & delete */ if(TRUE){ /* Try to move with ldap routines, if this was not successfull fall back to the old style copy & remove method */ if($this->rename($src_dn, $dst_dn)){ return(TRUE); }else{ // See code below. } } /* Copy source to destination */ if (!$this->copy($src_dn, $dst_dn)){ return (FALSE); } /* Delete source */ $ldap= $this->config->get_ldap_link(); $ldap->rmdir_recursive($src_dn); if (!$ldap->success()){ trigger_error("Trying to delete $src_dn failed.", E_USER_WARNING); return (FALSE); } return (TRUE); } /* \brief Move/Rename complete trees */ function recursive_move($src_dn, $dst_dn) { /* Check if the destination entry exists */ $ldap= $this->config->get_ldap_link(); /* Check if destination exists - abort */ $ldap->cat($dst_dn, array('dn')); if ($ldap->fetch()){ trigger_error("recursive_move $dst_dn already exists.", E_USER_WARNING); return (FALSE); } $this->copy($src_dn, $dst_dn); /* Remove src_dn */ $ldap->cd($src_dn); $ldap->recursive_remove($src_dn); return (TRUE); } function saveCopyDialog(){ } function getCopyDialog(){ return(array("string"=>"","status"=>"")); } /*! \brief Prepare for Copy & Paste */ function PrepareForCopyPaste($source) { $todo = $this->attributes; if(isset($this->CopyPasteVars)){ $todo = array_merge($todo,$this->CopyPasteVars); } if(count($this->objectclasses)){ $this->is_account = TRUE; foreach($this->objectclasses as $class){ if(!in_array_strict($class,$source['objectClass'])){ $this->is_account = FALSE; } } } foreach($todo as $var){ if (isset($source[$var])){ if(isset($source[$var]['count'])){ if($source[$var]['count'] > 1){ $tmp= $source[$var]; unset($tmp['count']); $this->$var = $tmp; }else{ $this->$var = $source[$var][0]; } }else{ $this->$var= $source[$var]; } } } } /*! \brief Get gosaUnitTag for the given DN If this is called from departmentGeneric, we have to skip this tagging procedure. */ function tag_attrs(&$at, $dn= "", $tag= "", $show= false) { /* Skip tagging? */ if($this->skipTagging){ return; } /* No dn? Self-operation... */ if ($dn == ""){ $dn= $this->dn; /* No tag? Find it yourself... */ if ($tag == ""){ $len= strlen($dn); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "No tag for $dn - looking for one...", "Tagging"); $relevant= array(); foreach ($this->config->adepartments as $key => $ntag){ /* This one is bigger than our dn, its not relevant... */ if ($len < strlen($key)){ continue; } /* This one matches with the latter part. Break and don't fix this entry */ if (preg_match('/(^|,)'.preg_quote($key, '/').'$/', $dn)){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, "DEBUG: Possibly relevant: $key", "Tagging"); $relevant[strlen($key)]= $ntag; continue; } } /* If we've some relevant tags to set, just get the longest one */ if (count($relevant)){ ksort($relevant); $tmp= array_keys($relevant); $idx= end($tmp); $tag= $relevant[$idx]; $this->gosaUnitTag= $tag; } } } /*! \brief Add unit tag */ /* Remove tags that may already be here... */ remove_objectClass("gosaAdministrativeUnitTag", $at); if (isset($at['gosaUnitTag'])){ unset($at['gosaUnitTag']); } /* Set tag? */ if ($tag != ""){ add_objectClass("gosaAdministrativeUnitTag", $at); $at['gosaUnitTag']= $tag; } /* Initially this object was tagged. - But now, it is no longer inside a tagged department. So force the remove of the tag. (objectClass was already removed obove) */ if($tag == "" && $this->gosaUnitTag){ $at['gosaUnitTag'] = array(); } } /*! \brief Test for removability of the object * * Allows testing of conditions for removal of object. If removal should be aborted * the function needs to remove an error message. * */ function allow_remove() { $reason= ""; return $reason; } /*! \brief Test if snapshotting is enabled * * Test weither snapshotting is enabled or not. There will also be some errors posted, * if the configuration failed * \return TRUE if snapshots are enabled, and FALSE if it is disabled */ function snapshotEnabled() { return $this->config->snapshotEnabled(); } /*! \brief Return plugin informations for acl handling * See class_core.inc for examples. */ static function plInfo() { return array(); } function set_acl_base($base) { @DEBUG (DEBUG_ACL, __LINE__, __FUNCTION__, __FILE__,"".$base."","ACL-Base: "); $this->acl_base= $base; } function set_acl_category($category) { @DEBUG (DEBUG_ACL, __LINE__, __FUNCTION__, __FILE__,"".$category."(/".get_class($this).")","ACL-Category: "); $this->acl_category= "$category/"; } function acl_is_writeable($attribute,$skip_write = FALSE) { if($this->read_only) return(FALSE); $ui= get_userinfo(); return preg_match('/w/', $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), $attribute, $skip_write)); } function acl_is_readable($attribute) { $ui= get_userinfo(); return preg_match('/r/', $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), $attribute)); } function acl_is_createable($base ="") { if($this->read_only) return(FALSE); $ui= get_userinfo(); if($base == "") $base = $this->acl_base; return preg_match('/c/', $ui->get_permissions($base, $this->acl_category.get_class($this), '0')); } function acl_is_removeable($base ="") { if($this->read_only) return(FALSE); $ui= get_userinfo(); if($base == "") $base = $this->acl_base; return preg_match('/d/', $ui->get_permissions($base, $this->acl_category.get_class($this), '0')); } function acl_is_moveable($base = "") { if($this->read_only) return(FALSE); $ui= get_userinfo(); if($base == "") $base = $this->acl_base; return preg_match('/m/', $ui->get_permissions($base, $this->acl_category.get_class($this), '0')); } function acl_have_any_permissions() { } function getacl($attribute,$skip_write= FALSE) { $ui= get_userinfo(); $skip_write |= $this->read_only; return $ui->get_permissions($this->acl_base, $this->acl_category.get_class($this), $attribute,$skip_write); } /*! \brief Returns a list of all available departments for this object. * * If this object is new, all departments we are allowed to create a new user in * are returned. If this is an existing object, return all deps. * We are allowed to move tis object too. * \return array [dn] => "..name" // All deps. we are allowed to act on. */ function get_allowed_bases() { $ui = get_userinfo(); $deps = array(); /* Is this a new object ? Or just an edited existing object */ if(!$this->initially_was_account && $this->is_account){ $new = true; }else{ $new = false; } foreach($this->config->idepartments as $dn => $name){ if($new && $this->acl_is_createable($dn)){ $deps[$dn] = $name; }elseif(!$new && $this->acl_is_moveable($dn)){ $deps[$dn] = $name; } } /* Add current base */ if(isset($this->base) && isset($this->config->idepartments[$this->base])){ $deps[$this->base] = $this->config->idepartments[$this->base]; }elseif(strtolower($this->dn) == strtolower($this->config->current['BASE'])){ }else{ trigger_error("Cannot return list of departments, no default base found in class ".get_class($this).". ".$this->base); } return($deps); } /* This function updates ACL settings if $old_dn was used. * \param string 'old_dn' specifies the actually used dn * \param string 'new_dn' specifies the destiantion dn */ function update_acls($old_dn,$new_dn,$output_changes = FALSE) { /* Check if old_dn is empty. This should never happen */ if(empty($old_dn) || empty($new_dn)){ trigger_error("Failed to check acl dependencies, wrong dn given."); return; } /* Update userinfo if necessary */ $ui = session::global_get('ui'); if($ui->dn == $old_dn){ $ui->dn = $new_dn; $ui->loadACL(); session::global_set('ui',$ui); new log("view","acl/".get_class($this),$this->dn,array(),"Updated current object dn from '".$old_dn."' to '".$new_dn."'"); } /* Object was moved, ensure that all acls will be moved too */ if($new_dn != $old_dn && $old_dn != "new"){ /* get_ldap configuration */ $update = array(); $ldap = $this->config->get_ldap_link(); $ldap->cd ($this->config->current['BASE']); $ldap->search("(&(objectClass=gosaAcl)(gosaAclEntry=*".base64_encode($old_dn)."*))",array("cn","gosaAclEntry")); while($attrs = $ldap->fetch()){ $acls = array(); $found = false; for($i = 0 ; $i < $attrs['gosaAclEntry']['count'] ; $i ++ ){ $acl_parts = explode(":",$attrs['gosaAclEntry'][$i]); /* Roles uses antoher data storage order, members are stored int the third part, while the members in direct ACL assignments are stored in the second part. */ $id = ($acl_parts[1] == "role") ? 3 : 2; /* Update member entries to use $new_dn instead of old_dn */ $members = explode(",",$acl_parts[$id]); foreach($members as $key => $member){ $member = base64_decode($member); if($member == $old_dn){ $members[$key] = base64_encode($new_dn); $found = TRUE; } } /* Check if the selected role has to updated */ if($acl_parts[1] == "role" && $acl_parts[2] == base64_encode($old_dn)){ $acl_parts[2] = base64_encode($new_dn); $found = TRUE; } /* Build new acl string */ $acl_parts[$id] = implode($members,","); $acls[] = implode($acl_parts,":"); } /* Acls for this object must be adjusted */ if($found){ $debug_info= sprintf(_("Changing ACL DN from %s to %s"), bold($old_dn), bold($new_dn)); @DEBUG (DEBUG_ACL, __LINE__, __FUNCTION__, __FILE__,$debug_info,"ACL"); $update[$attrs['dn']] =array(); foreach($acls as $acl){ $update[$attrs['dn']]['gosaAclEntry'][] = $acl; } } } /* Write updated acls */ foreach($update as $dn => $attrs){ $ldap->cd($dn); $ldap->modify($attrs); } } } /*! \brief Enable the Serial ID check * * This function enables the entry Serial ID check. If an entry was edited while * we have edited the entry too, an error message will be shown. * To configure this check correctly read the FAQ. */ function enable_CSN_check() { $this->CSN_check_active =TRUE; $this->entryCSN = getEntryCSN($this->dn); } /*! \brief Prepares the plugin to be used for multiple edit * Update plugin attributes with given array of attribtues. * \param array Array with attributes that must be updated. */ function init_multiple_support($attrs,$all) { $ldap= $this->config->get_ldap_link(); $this->multi_attrs = $attrs; $this->multi_attrs_all= $all; /* Copy needed attributes */ foreach ($this->attributes as $val){ $found= array_key_ics($val, $this->multi_attrs); if ($found != ""){ if(isset($this->multi_attrs["$val"][0])){ $this->$val= $this->multi_attrs["$val"][0]; } } } } /*! \brief Enables multiple support for this plugin */ function enable_multiple_support() { $this->ignore_account = TRUE; $this->multiple_support_active = TRUE; } /*! \brief Returns all values that have been modfied in multiple edit mode. \return array Cotaining all modified values. */ function get_multi_edit_values() { $ret = array(); foreach($this->attributes as $attr){ if(in_array_strict($attr,$this->multi_boxes)){ $ret[$attr] = $this->$attr; } } return($ret); } /*! \brief Update class variables with values collected by multiple edit. */ function set_multi_edit_values($attrs) { foreach($attrs as $name => $value){ $this->$name = $value; } } /*! \brief Generates the html output for this node for multi edit*/ function multiple_execute() { /* This one is empty currently. Fabian - please fill in the docu code */ session::global_set('current_class_for_help',get_class($this)); /* Reset Lock message POST/GET check array, to prevent perg_match errors*/ session::set('LOCK_VARS_TO_USE',array()); session::set('LOCK_VARS_USED_GET',array()); session::set('LOCK_VARS_USED_POST',array()); session::set('LOCK_VARS_USED_REQUEST',array()); return("Multiple edit is currently not implemented for this plugin."); } /*! \brief Save HTML posted data to object for multiple edit */ function multiple_save_object() { if(empty($this->entryCSN) && $this->CSN_check_active){ $this->entryCSN = getEntryCSN($this->dn); } /* Save values to object */ $this->multi_boxes = array(); foreach ($this->attributes as $val){ /* Get selected checkboxes from multiple edit */ if(isset($_POST["use_".$val])){ $this->multi_boxes[] = $val; } if (isset ($_POST["$val"]) && $this->acl_is_writeable($val)){ $data= $this->$val = get_post($val); if ($this->$val != $data){ $this->is_modified= TRUE; } /* IE post fix */ if(isset($data[0]) && $data[0] == chr(194)) { $data = ""; } $this->$val= $data; } } } /*! \brief Returns all attributes of this plugin, to be able to detect multiple used attributes in multi_plugg::detect_multiple_used_attributes(). @return array Attributes required for intialization of multi_plug */ public function get_multi_init_values() { $attrs = $this->attrs; return($attrs); } /*! \brief Check given values in multiple edit \return array Error messages */ function multiple_check() { $message = plugin::check(); return($message); } function get_used_snapshot_bases() { return(array()); } function is_modal_dialog() { return(isset($this->dialog) && $this->dialog); } /*! \brief Forward command execution requests * to the hook execution method. */ function handle_post_events($mode, $addAttrs= array()) { if(!in_array_strict($mode, array('add','remove','modify'))){ trigger_error(sprintf("Invalid post event type given %s! Valid types are [add,modify,remove].", bold($mode))); return; } switch ($mode){ case "add": plugin::callHook($this,"POSTCREATE", $addAttrs); break; case "modify": plugin::callHook($this,"POSTMODIFY", $addAttrs); break; case "remove": plugin::callHook($this,"POSTREMOVE", $addAttrs); break; } } /*! \brief Calls external hooks which are defined for this plugin (gosa.conf) * Replaces placeholder by class values of this plugin instance. * @param Allows to a add special replacements. */ static function callHook($plugin, $cmd, $addAttrs= array(), &$returnOutput = array(), &$returnCode = NULL, &$errorOutput = array(), $displayErrors = TRUE) { global $config; $command = $config->configRegistry->getPropertyValue(get_class($plugin),$cmd); $returnCode = 0; // Simulate a return code to tell the caller that everythin is fine. $returnOutput = array(); $arr = array(); if (!empty($command)){ // Walk trough attributes list and add the plugins attributes. foreach ($plugin->attributes as $attr){ if (!is_array($plugin->$attr)){ $addAttrs[$attr] = $plugin->$attr; } } $ui = get_userinfo(); $addAttrs['callerDN']=$ui->dn; $addAttrs['dn']=$plugin->dn; $addAttrs['location']=$config->current['NAME']; // Sort attributes by length, ensures correct replacement $tmp = array(); foreach($addAttrs as $name => $value){ $tmp[$name] = strlen($name); } arsort($tmp); // Now replace the placeholder $command = fillReplacements($command, $addAttrs, TRUE); // If there are still some %.. in our command, try to fill these with some other class vars if(preg_match("/%/",$command)){ $attrs = get_object_vars($plugin); foreach($attrs as $name => $value){ if(is_array($value)){ $s = ""; foreach($value as $val){ if(is_string($val) || is_int($val) || is_float($val) || is_bool($val)){ $s .= '"'.$val.'",'; } } $value = '['.trim($s,',').']'; } if(!is_string($value) && !is_int($value) && !is_float($value) && !is_bool($value)){ continue; } $command= preg_replace("/%$name/", escapeshellarg($value), $command); } } if (check_command($command)){ // Create list of process pipes $descriptorspec = array( 0 => array("pipe", "r"), // stdin 1 => array("pipe", "w"), // stdout 2 => array("pipe", "w")); // stderr // Try to open the process @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__,$command,"Execute"); $process = proc_open($command, $descriptorspec, $pipes); if (is_resource($process)) { // Write the password to stdin // fwrite($pipes[0], $pwd); fclose($pipes[0]); // Get results from stdout and stderr $arr = stream_get_contents($pipes[1]); $err = stream_get_contents($pipes[2]); fclose($pipes[1]); // Close the process and check its return value $returnCode = proc_close($process); $returnOutput = preg_split("/\n/", $arr,0,PREG_SPLIT_NO_EMPTY); $errorOutput = preg_split("/\n/",$err,0,PREG_SPLIT_NO_EMPTY); } if($returnCode != 0){ @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__, $command, "Execution failed code: ".$returnCode); @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__, $command, "Result: ".$err); if($displayErrors){ $message= msgPool::cmdexecfailed($cmd,$command, get_class($plugin)); msg_dialog::display(_("Error"), $message, ERROR_DIALOG); } }elseif(is_array($arr)){ @DEBUG (DEBUG_SHELL, __LINE__, __FUNCTION__, __FILE__, $command, "Result: ".$arr); } } elseif($displayErrors) { $message= msgPool::cmdinvalid($cmd,$command, get_class($plugin)); msg_dialog::display(_("Error"), $message, ERROR_DIALOG); } } } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_session.inc0000644000175000017500000001425311424277773017410 0ustar cajuscajus gosa-core-2.7.4/include/class_filterNOACL.inc0000644000175000017500000000100411600301426017730 0ustar cajuscajusget_ldap_link(TRUE); $flag= GL_NO_ACL_CHECK | GL_SIZELIMIT | (($scope == "sub")?GL_SUBSEARCH:0); $result= filterLDAP::get_list($base, $filter, $attributes, $category, $objectStorage, $flag); $result = (filterLDAPBlacklist::filterByBlacklist($result)); return $result; } } ?> gosa-core-2.7.4/include/class_filter.inc0000644000175000017500000003457011424300127017172 0ustar cajuscajusload($filename)) { die("Cannot parse $filename!"); } $this->pid= preg_replace("/[^0-9]/", "", microtime(TRUE)); } function load($filename) { $contents = file_get_contents($filename); $xmlData= xml::xml2array($contents, 1); if (!isset($xmlData['filterdef'])) { return false; } $xmlData= $xmlData["filterdef"]; // Load filter if (isset($xmlData['search'])) { // Array conversion if (!isset($xmlData['search'][0])) { $searches= array($xmlData['search']); } else { $searches= $xmlData['search']; } /* Store available searches */ foreach ($searches as $search) { /* Do multi conversation */ if (!isset($search['query'][0])){ $search['query']= array($search['query']); } /* Store search */ $this->xmlSearches[$search['tag']]= $search; } } else { return false; } // Transfer scope $this->scopeMode= $xmlData['definition']['scope']; if ($this->scopeMode == "auto") { $this->scope= "one"; } else { $this->scope= $this->scopeMode; } // Transfer attributes $this->attributes= $xmlData['definition']['attribute']; if (!is_array($this->attributes)) { $this->attributes= array($this->attributes); } // Transfer initial value if (isset($xmlData['definition']['initial']) && $xmlData['definition']['initial'] == "true"){ $this->initial= true; } // Transfer category if (isset($xmlData['definition']['category'])){ $this->category= $xmlData['definition']['category']; } if (!is_array($this->category)) { $this->category= array($this->category); } // Initialize searches and default search mode $this->defaultSearch= $xmlData['definition']['default']; $this->reloadFilters(); $this->setSearch($this->defaultSearch); return true; } function reloadFilters() { $this->searches= array_merge($this->xmlSearches, userFilter::getFilter($this->category)); $this->setSearch($this->search); } function setSearch($method= null) { $patch= null; // Maybe our search method has gone? if (!isset($this->searches[$method])) { $method= $this->defaultSearch; } // Try to use it, but bail out if there's no help... if (isset($this->searches[$method])) { $this->query= $this->searches[$method]['query']; $this->search= $method; } else { die ("Invalid search module!"); } } function getTextfield($tag, $value= "", $element= null) { $size= 30; $maxlength= 30; $result= ""; if ($element && isset($element['autocomplete'])) { $frequency= "0.5"; $characters= "1"; if (isset($element['autocomplete']['frequency'])) { $frequency= $element['autocomplete']['frequency']; } if (isset($element['autocomplete']['characters'])) { $characters= $element['autocomplete']['characters']; } $result.= "
    ". ""; $this->autocompleters[$tag]= $element; } return $result; } function getCurrentBase() { if (isset($this->search->base) && (string)$this->search->scope != "auto") { return false; } return $this->base; } function getCurrentScope() { if (isset($this->search->scope) && (string)$this->search->scope != "auto") { return (string)$this->search->scope; } return $this->scope; } function setConverter($hook) { $this->converter= $hook; } function setObjectStorage($storage) { $this->objectStorage= $storage; } function setBase($base) { $this->base= $base; } function setCurrentScope($scope) { $this->scope= $scope; } function render() { $content= "
    ".$this->renderFilterMenu().""; $content.= "
    ".$this->getTextfield('search_filter', set_post($this->value), $this->searches[$this->search])."
    ". " 
    "; // Return meta data return ("".$content); } function query() { global $class_mapping; $result= array(); // Return empty list if initial is not set if (!$this->initial) { $this->initial= true; return $result; } // Go thru all queries and merge results foreach ($this->query as $query) { if (!isset($query['backend']) || !isset($query['filter'])) { die("No backend specified in search config."); } // Is backend available? $backend= "filter".$query['backend']; if (!isset($class_mapping["$backend"])) { die("Invalid backend specified in search config."); } // Load filter and attributes $filter= $query['filter']; // Handle converters if present if ($this->converter) { preg_match('/([^:]+)::(.*)$/', $this->converter, $m); if ($this->value == "") { $filter= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', "*", $filter)); } else { $filter= call_user_func(array($m[1], $m[2]), preg_replace('/\$/', $this->value, $filter)); } } // Do not replace escaped \$ - This is required to be able to search for e.g. windows machines. if ($this->value == "") { $filter= preg_replace("/\\$/", '*', $filter); } else { $filter= preg_replace("/\\$/", "*".normalizeLdap($this->value)."*", $filter); } $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $this->attributes, $this->category, $this->objectStorage)); } return ($result); } function update() { if (isset($_POST['FILTER_PID']) && $_POST['FILTER_PID'] == $this->pid) { // Save input field if (isset($_POST['search_filter'])) { $this->value= get_post('search_filter'); } // Save scope if needed if ($this->scopeMode == "auto" && isset($_POST['act']) && $_POST['act'] == "toggle-subtree") { $this->scope= ($this->scope == "one")?"sub":"one"; } // Switch filter? if (isset($_POST['act'])) { foreach ($this->searches as $tag => $cfg) { if ($_POST['act'] == "filter-$tag") { $this->setSearch($tag); break; } } } } } function getCompletitionList($config, $value="*") { global $class_mapping; $res= array(); // Load result attributes $attributes= $config['autocomplete']['attribute']; if (!is_array($attributes)) { $attributes= array($attributes); } // Do the query $result= array(); // Is backend available? # FIXME $queries= $config['query']; if (!isset($queries[0])){ $queries= array($queries); } foreach ($queries as $query) { $backend= "filter".$query['backend']; if (!isset($class_mapping["$backend"])) { die("Invalid backend specified in search config."); } $filter= preg_replace("/\\$/", "*".normalizeLdap($value)."*", $query['filter']); $result= array_merge($result, call_user_func(array($backend, 'query'), $this->base, $this->scope, $filter, $attributes, $this->category, $this->objectStorage)); } foreach ($result as $entry) { foreach ($attributes as $attribute) { if (is_array($entry[$attribute])) { for ($i= 0; $i<$entry[$attribute]['count']; $i++) { if (mb_stristr($entry[$attribute][$i], $value)) { $res[]= $entry[$attribute][$i]; } } } else { $res[]= $entry[$attribute]; } } } return $res; } function processAutocomplete() { global $class_mapping; $result= array(); // Introduce maximum number of entries $max= 25; if(isset($this->searches[$this->search]['autocomplete'])){ $result= $this->getCompletitionList($this->searches[$this->search], get_post('search_filter')); $result= array_unique($result); asort($result); echo '
      '; foreach ($result as $entry) { echo '
    • '.mark(get_post('search_filter'), $entry).'
    • '; if ($max-- == 0) { break; } } echo '
    '; } } function getObjectBase($dn) { global $config; $base= ""; // Try every object storage $storage= $this->objectStorage; if (!is_array($storage)){ $storage= array($storage); } foreach ($storage as $location) { $pattern= "/^[^,]+,".preg_quote($location, '/')."/i"; $base= preg_replace($pattern, '', $dn); } /* Set to base, if we're not on a correct subtree */ if (!isset($config->idepartments[$base])){ $base= $config->current['BASE']; } return $base; } function renderFilterMenu() { // Load shortcut $result= "$script"; } function getFixedFilters() { return array_keys($this->searches); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_core.inc0000644000175000017500000016717411750201415016646 0ustar cajuscajus The name of the plugin in short (e.g. Posix) * | This short-name will be shown for example in the ACL definitions. * | * | * plDescription |-> A descriptive text for the plugin (e.g. User posix account extension) * | This will be shown in the ACL definitions. * | * | * plSelfModify |-> If set to true this plugin allows to set 'self' ACLs. * | For exampe to allow to change the users own password, but not the others. * | * | * plDepends |-> The plugins dependencies to other classes (e.g. sambaAccount requires posixAccount) * | * | * plPriority |-> The priority of the plugin, this influences the ACL listings only. * | * | * plSection |-> The section of this plugin 'administration', 'personal', 'addons' * | * | * plCategory |-> The plugin category this plugins belongs to (e.g. users, groups, departments) * | * | * plRequirements |-> Plugin requirements. * | | * | |-> [activePlugin] The schame checks will only be performed if the given plugin is enabled * | | in the gosa.conf definitions. * | | Defaults to the current class name if empty. * | | * | |-> [ldapSchema] An array of objectClass requirements. * | | Syntax [[objectClass => 'version'], ... ] * | | Version can be emtpy which just checks for the existence of the class. * | | * | |-> [onFailureDisablePlugin] A list of plugins that which will be disabled if the * | requirements couldn't be fillfulled. * | * | --------------------------------------------- * | EXAMPLE: * | --------------------------------------------- * | "plRequirements"=> array( * | 'activePlugin' => 'applicationManagement', * | 'ldapSchema' => array( * | 'gosaObject' => '', * | 'gosaAccount' => '>=2.7', * | 'gosaLockEntry' => '>=2.7', * | 'gosaDepartment' => '>=2.7', * | 'gosaCacheEntry' => '>=2.7', * | 'gosaProperties' => '>=2.7', * | 'gosaConfig' => '>=2.7' * | ), * | 'onFailureDisablePlugin' => array(get_class(), 'someClassName') * | ), * | --------------------------------------------- * | * | * | * plProvidedAcls |-> The ACLs provided by this plugin * | * | --------------------------------------------- * | EXAMPLE: * | --------------------------------------------- * | "plProvidedAcls"=> array( * | 'cn' => _('Name'), * | 'uid' => _('Uid'), * | 'phoneNumber' => _('Phone number') * | ), * | --------------------------------------------- * | * | * | * plProperties |-> Properties used by the plugin. * | Properties which are defined here will be modifyable using the property editor. * | To read properties you can use $config->get_cfg_value(className, propertyName) * | * | --------------------------------------------- * | EXAMPLE: * | --------------------------------------------- * | "plProperties"=> array( * | array( * | "name" => "htaccessAuthentication", * | "type" => "bool", * | "default" => "false", * | "description" => _("A description..."), * | "check" => "gosaProperty::isBool", * | "migrate" => "", * | "group" => "authentification", * | "mandatory" => TRUE * | ), * | ), * | See class_core.inc for a huge amount of examples. */ class all extends plugin { static function plInfo() { return (array( "plShortName" => _("All"), "plDescription" => _("All objects"), "plSelfModify" => TRUE, "plDepends" => array(), "plPriority" => 0, "plSection" => array("administration"), "plCategory" => array("all" => array("description" => '* '._("All"))), "plProvidedAcls" => array()) ); } } class core extends plugin { static function getPropertyValues($class,$name,$value,$type) { $list = array(); switch($name){ case 'idAllocationMethod': $list = array('traditional' => _('Traditional'), 'pool' => _('Use samba pool')); break; case 'passwordDefaultHash': $tmp = passwordMethod::get_available_methods(); foreach($tmp['name'] as $id => $method){ $desc = $tmp[$id]['name']; $list[$method] = $desc; } break; case 'theme': $cmd = "cd ../ihtml/themes; find . -name 'img.styles' | sed s/'^[^\/]*\/\([^\/]*\).*'/'\\1'/g"; $res = `$cmd` ; $list = array(); foreach(preg_split("/\n/",$res) as $entry){ if(!empty($entry)){ $list[$entry] = $entry; } } break; case 'accountPrimaryAttribute': $list = array('uid' => 'uid', 'cn' => 'cn'); break; case 'loginAttribute': $list = array( 'uid' => 'uid', 'mail' => 'mail', 'both' => 'uid & mail'); break; case 'timezone': $tmp = timezone::_get_tz_zones(); foreach($tmp['TIMEZONES'] as $tzname => $offset){ if($offset >= 0){ $list[$tzname] = $tzname." ( + ".sprintf("%0.2f",$offset/(60*60))." "._("hours").")"; }else{ $offset = $offset * -1; $list[$tzname] = $tzname." ( - ".sprintf("%0.2f",($offset/(60*60)))." "._("hours").")"; } } break; case 'mailAttribute': $list = array('mail' => 'mail','uid' => 'uid'); break; case 'mailMethod': $tmp = array(); if(class_available('mailMethod')){ $tmp = mailMethod::get_methods(); } $list =array(); foreach($tmp as $vName => $vValue){ $vName = preg_replace('/^mailMethod/','', $vName); $list[$vName] = $vValue; } $list[''] = _("None"); break; case 'language': $tmp = get_languages(TRUE); $list[""] = _("Automatic"); foreach($tmp as $key => $desc){ $list[$key] = $desc; } break; case 'modificationDetectionAttribute': $list = array('entryCSN' => 'entryCSN (OpenLdap)','textCSN'=>'textCSN (Sun DS)'); break; default: echo $name." ";$list = array(); } if(!isset($list[$value])){ $list[$value] = $value." ("._("User value").")"; } return($list); } static function plInfo() { return (array( "plShortName" => _("Core"), "plDescription" => _("GOsa core plugin"), "plSelfModify" => FALSE, "plDepends" => array(), "plPriority" => 0, "plSection" => array("administration"), "plRequirements"=> array( 'ldapSchema' => array( 'gosaObject' => '>=2.7', 'gosaAccount' => '>=2.7', 'gosaLockEntry' => '>=2.7', 'gosaDepartment' => '>=2.7', 'gosaCacheEntry' => '>=2.7', 'gosaProperties' => '>=2.7', 'gosaConfig' => '>=2.7' ), 'onFailureDisablePlugin' => array(get_class()) ), "plCategory" => array("all"), "plProperties" => array( array( "name" => "htaccessAuthentication", "type" => "bool", "default" => "false", "description" => _("Enables htaccess instead of LDAP authentication. This can be used to enable other authentication mechanisms like Kerberos for the GOsa login."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "authentification", "mandatory" => TRUE), array( "name" => "statsDatabaseEnabled", "type" => "bool", "default" => "false", "description" => _("Enables the usage statistics module."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => TRUE), array( "name" => "statsDatabaseDirectory", "type" => "path", "default" => "/var/spool/gosa/stats", "description" => _("Database file to be used by the usage statistics module."), "check" => "gosaProperty::isWriteablePath", "migrate" => "", "group" => "core", "mandatory" => TRUE), array( "name" => "logging", "type" => "bool", "default" => "true", "description" => _("Enables event logging in GOsa. Setting it to 'On' make GOsa log every action a user performs via syslog. If you use this in combination with rsyslog and configure it to MySQL logging, you can browse all events in GOsa."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => TRUE), array( "name" => "listSummary", "type" => "bool", "default" => "true", "description" => _("Enables a status bar on the bottom of lists displaying a summary of type and number of elements in the list."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "visual", "mandatory" => FALSE), array( "name" => "passwordMinLength", "type" => "integer", "default" => "", "description" => _("Specify the minimum length for newly entered passwords."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "password", "mandatory" => FALSE), array( "name" => "passwordMinDiffer", "type" => "integer", "default" => "", "description" => _("Specify the minimum number of characters that have to differ between old and newly entered passwords."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "password", "mandatory" => FALSE), array( "name" => "passwordProposalHook", "type" => "command", "default" => "", "description" => _("Command to generate password proposals. If a command has been specified, the user can decide whether to use an automatic password or a manually specified one.")." "._("Example").": /usr/bin/apg -n1", "check" => "gosaProperty::isCommand", "migrate" => "", "group" => "password", "mandatory" => FALSE), array( "name" => "displayErrors", "type" => "bool", "default" => "false", "description" => _("Enable display of PHP errors on the top of the page. Disable this feature in production environments to avoid the exposure of sensitive data.")." ".sprintf(_("Related option").": developmentMode"), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "debug", "mandatory" => TRUE), array( "name" => "developmentMode", "type" => "bool", "default" => "false", "description" => _("Show messages that may assist plugin development. Be aware that this option may produce some ACL related false error messages!"), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "debug", "mandatory" => TRUE), array( "name" => "schemaCheck", "type" => "bool", "default" => "true", "description" => _("Enable LDAP schema verification during login. The recommended setting is 'On' because it enables efficient methods to create missing subtrees in the LDAP."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "debug", "mandatory" => TRUE), array( "name" => "copyPaste", "type" => "bool", "default" => "false", "description" => _("Enable copy and paste for most objects managed by GOsa."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "copyPaste", "mandatory" => TRUE), array( "name" => "forceGlobals", "type" => "noLdap", "default" => "false", "description" => _("Enable PHP security checks for disabled register_global settings."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "security", "mandatory" => TRUE), array( "name" => "forceSSL", "type" => "noLdap", "default" => "false", "description" => _("Enable automatic redirection to HTTPS based administration."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "security", "mandatory" => TRUE), array( "name" => "ldapStats", "type" => "bool", "default" => "false", "description" => _("Enable logging of detailed information of LDAP operations."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "debug", "mandatory" => FALSE), array( "name" => "ldapFollowReferrals", "type" => "bool", "default" => "false", "description" => _("Enable LDAP referral chasing."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "ldap", "mandatory" => TRUE), array( "name" => "ldapFilterNestingLimit", "type" => "integer", "default" => 200, "description" => _("Specify LDAP element filter limit. If the limit is not 0, GOsa speeds up group queries by putting several queries into a single query. This is known to produce problems on some LDAP servers (i.e. Sun DS) and needs to be lowered or disabled."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "ldap", "mandatory" => TRUE), array( "name" => "ldapSizelimit", "type" => "integer", "default" => 200, "description" => _("Specify the maximum number of entries GOsa will request from an LDAP server. A warning is displayed if this limit is exceeded."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "core", "mandatory" => TRUE), array( "name" => "ldapSizeIgnore", "type" => "bool", "default" => "false", "description" => _("Disable checks for LDAP size limits."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "warnSSL", "type" => "noLdap", "default" => "true", "description" => _("Enable warnings for non encrypted connections."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "security", "mandatory" => TRUE), array( "name" => "ppdGzip", "type" => "bool", "default" => "true", "description" => _("Enable compression for PPD files."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "ppd", "mandatory" => FALSE), array( "name" => "ignoreAcl", "type" => "dn", "default" => "", "description" => _("DN of user with ACL checks disabled. This should only be used to restore lost administrative ACLs."), "check" => "gosaProperty::isDN", "migrate" => "", "group" => "debug", "mandatory" => FALSE), array( "name" => "ppdPath", "type" => "path", "default" => "/var/spool/ppd", "description" => _("Storage path for PPD files."), "check" => "gosaProperty::isPath", "migrate" => "", "group" => "ppd", "mandatory" => FALSE), array( "name" => "ldapMaxQueryTime", "type" => "integer", "default" => "", "description" => _("Number of seconds a LDAP query is allowed to take until GOsa aborts the request."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "debug", "mandatory" => FALSE), array( "name" => "storeFilterSettings", "type" => "bool", "default" => "true", "description" => _("Enables storing of user filters in browser cookies."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "sendCompressedOutput", "type" => "bool", "default" => "true", "description" => _("Enables sending of compressed web page content."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "allowUidProposalModification", "type" => "bool", "default" => "false", "description" => _("Allows to modify uid-proposals when creating a new user from a user-template."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "modificationDetectionAttribute", "type" => "switch", "default" => "entryCSN", "defaults" => "core::getPropertyValues", "description" => _("LDAP attribute which is used to detect changes."), "check" => "", "migrate" => "", "group" => "core", "mandatory" => TRUE), array( "name" => "language", "type" => "switch", "default" => "", "defaults" => "core::getPropertyValues", "description" => _("ISO language code which is used to override the automatic language detection."), "check" => "", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "theme", "type" => "switch", "default" => "default", "defaults" => "core::getPropertyValues", "description" => _("CSS and template theme to be used."), "check" => "", "migrate" => "", "group" => "visual", "mandatory" => TRUE), array( "name" => "sessionLifetime", "type" => "integer", "default" => 600, "description" => _("Number of seconds after an inactive session expires. This may be overridden by some systems php.ini/crontab mechanism."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "security", "mandatory" => FALSE), array( "name" => "templateCompileDirectory", "type" => "path", "default" => "/var/spool/gosa", "description" => _("Template engine compile directory."), "check" => "gosaProperty::isWriteablePath", "migrate" => "", "group" => "core", "mandatory" => TRUE), array( "name" => "debugLevel", "type" => "integer", "default" => 0, "description" => sprintf(_("Logical AND of the integer values below that controls the debug output on every page load: %s"), " DEBUG_TRACE = 1 DEBUG_LDAP = 2 DEBUG_MYSQL = 4 DEBUG_SHELL = 8 DEBUG_POST = 16 DEBUG_SESSION = 32 DEBUG_CONFIG = 64 DEBUG_ACL = 128 DEBUG_SI = 256"), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "debug", "mandatory" => FALSE), array( "name" => "sambaHashHook", "type" => "command", "default" => "perl -MCrypt::SmbHash -e \"print join(q[:], ntlmgen %password), $/;\"", "description" => _("Command to create Samba NT/LM hashes. Required for password synchronization if you don't use supplementary services."), "check" => "gosaProperty::isCommand", "migrate" => "", "group" => "samba", "mandatory" => FALSE), array( "name" => "passwordDefaultHash", "type" => "switch", "default" => "crypt/md5", "defaults" => "core::getPropertyValues", "description" => _("Default hash to be used for newly created user passwords."), "check" => "", "migrate" => "", "group" => "password", "mandatory" => FALSE), array( "name" => "strictPasswordRules", "type" => "bool", "default" => "true", "description" => _("Enable checking for the presence of problematic unicode characters in passwords."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "password", "mandatory" => FALSE), array( "name" => "accountPrimaryAttribute", "type" => "switch", "default" => "cn", "defaults" => "core::getPropertyValues", "description" => _("Specify whether 'cn' or 'uid' style user DNs are generated. For more sophisticated control use the 'accountRDN' setting."), "check" => "", "migrate" => "", "group" => "security", "mandatory" => TRUE), array( "name" => "userRDN", "type" => "rdn", "default" => "ou=people,", "description" => _("Location component for user storage inside of departments."), "check" => "gosaProperty::isRdn", "migrate" => "migrate_userRDN", "group" => "user", "mandatory" => FALSE), array( "name" => "groupRDN", "type" => "rdn", "default" => "ou=groups,", "description" => _("Location component for group storage inside of departments."), "check" => "gosaProperty::isRdn", "migrate" => "migrate_groupRDN", "group" => "group", "mandatory" => FALSE), array( "name" => "gidNumberBase", "type" => "integer", "default" => "1000", "description" => _("Count base for group IDs. For dynamic ID assignment use the 'nextIdHook' setting."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "id", "mandatory" => TRUE), array( "name" => "baseIdHook", "type" => "command", "default" => "", "description" => _("Count base for user IDs. For dynamic ID assignment use the 'nextIdHook' setting."), "check" => "gosaProperty::isCommand", "migrate" => "", "group" => "id", "mandatory" => FALSE), array( "name" => "gidNumberPoolMin", "type" => "integer", "default" => 10000, "description" => _("Lowest assignable group ID for use with the idAllocationMethod set to 'pool'."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "id", "mandatory" => FALSE), array( "name" => "gidNumberPoolMax", "type" => "integer", "default" => 40000, "description" => _("Highest assignable group ID for use with the idAllocationMethod set to 'pool'."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "id", "mandatory" => FALSE), array( "name" => "uidNumberPoolMin", "type" => "integer", "default" => 10000, "description" => _("Lowest assignable user ID for use with the idAllocationMethod set to 'pool'."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "id", "mandatory" => FALSE), array( "name" => "uidNumberPoolMax", "type" => "integer", "default" => 40000, "description" => _("Highest assignable user ID for use with the idAllocationMethod set to 'pool'."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "id", "mandatory" => FALSE), array( "name" => "uidNumberBase", "type" => "integer", "default" => "1000", "description" => _("Count base for user IDs. For dynamic ID assignment use the 'baseIdHook' setting."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "id", "mandatory" => FALSE), array( "name" => "gosaRpcServer", "type" => "string", "default" => "", "description" => _("Connection URL for use with the gosa-ng service."), "check" => "jsonRPC::testConnectionProperties", "migrate" => "", "group" => "rpc", "mandatory" => FALSE), array( "name" => "gosaRpcUser", "type" => "string", "default" => "admin", "description" => _("User name used to connect to the 'gosaRpcServer'."), "check" => "", "migrate" => "", "group" => "rpc", "mandatory" => FALSE), array( "name" => "gosaRpcPassword", "type" => "string", "default" => "tester", "description" => _("Password used to connect to the 'gosaRpcServer'."), "check" => "", "migrate" => "", "group" => "rpc", "mandatory" => FALSE), array( "name" => "gosaSupportURI", "type" => "string", "default" => "", "description" => _("Connection URI for use with the gosa-si service (obsolete)."), "check" => "", "migrate" => "", "group" => "gosa-si", "mandatory" => FALSE), array( "name" => "gosaSupportTimeout", "type" => "integer", "default" => 15, "description" => _("Number of seconds after a gosa-si connection is considered 'dead'."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "gosa-si", "mandatory" => FALSE), array( "name" => "loginAttribute", "type" => "switch", "default" => "uid", "defaults" => "core::getPropertyValues", "description" => _("User attribute which is used for log in."), "check" => "", "migrate" => "", "group" => "security", "mandatory" => TRUE), array( "name" => "timezone", "type" => "switch", "default" => "", "defaults" => "core::getPropertyValues", "description" => _("Local time zone."), "check" => "", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "honourUnitTags", "type" => "bool", "default" => "false", "description" => _("Enable tagging of administrative units. This can be used in conjunction with ACLs (obsolete)."), "check" => "", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "useSaslForKerberos", "type" => "bool", "default" => "true", "description" => _("Enable the use of {sasl} instead of {kerberos} for user realms."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "password", "mandatory" => FALSE), array( "name" => "SASLRealm", "type" => "string", "default" => "REALM", "description" => _("The SASL realm to use for password storage."), "check" => "", "migrate" => "", "group" => "password", "mandatory" => FALSE), array( "name" => "rfc2307bis", "type" => "bool", "default" => "false", "description" => _("Enable RFC 2307bis style groups. This combines the use of 'member' and 'memberUid' attributes."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "personalTitleInDN", "type" => "bool", "default" => "false", "description" => _("Adjusts the user DN generation to include the users personal title (only in conjunction with accountPrimaryAttribute)."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "storage location", "mandatory" => FALSE), array( "name" => "nextIdHook", "type" => "command", "default" => "", "description" => _("Script to be called for finding the next free id for groups or users."), "check" => "gosaProperty::isCommand", "migrate" => "", "group" => "id", "mandatory" => FALSE), array( "name" => "idGenerator", "type" => "string", "default" => "{%sn}-{%givenName[2-4]}", "description" => _("Descriptive string for the automatic ID generator. Please read the FAQ file for more information."), "check" => "", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "strictNamingRules", "type" => "bool", "default" => "true", "description" => _("Enable strict checking for user IDs and group names."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "minId", "type" => "integer", "default" => 40, "description" => _("Lowest assignable user or group ID. Only active if idAllocationMethod is set to 'traditional'."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "id", "mandatory" => FALSE), array( "name" => "mailAttribute", "type" => "switch", "default" => "mail", "defaults" => "core::getPropertyValues", "description" => _("Attribute to be used for primary mail addresses."), "check" => "", "migrate" => "", "group" => "mail", "mandatory" => FALSE), array( "name" => "gosaSharedPrefix", "type" => "string", "default" => "", "description" => _("Namespace used for shared folders."), "check" => "", "migrate" => "", "group" => "mail", "mandatory" => FALSE), array( "name" => "mailUserCreation", "type" => "string", "default" => "", "description" => _("Namespace rule to create user folders. Please read the FAQ file for more information."), "check" => "", "migrate" => "", "group" => "mail", "mandatory" => FALSE), array( "name" => "mailFolderCreation", "type" => "string", "default" => "", "description" => _("Namespace rule to create folders. Please read the FAQ file for more information."), "check" => "", "migrate" => "", "group" => "mail", "mandatory" => FALSE), array( "name" => "imapTimeout", "type" => "integer", "default" => 10, "description" => _("Seconds after an IMAP connection is considered dead."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "mail", "mandatory" => FALSE), array( "name" => "mailMethod", "type" => "switch", "default" => "", "defaults" => "core::getPropertyValues", "description" => _("Class name of the mail method to be used."), "check" => "", "migrate" => "", "group" => "mail", "mandatory" => FALSE), array( "name" => "cyrusUseSlashes", "type" => "bool", "default" => "true", "description" => _("Enable slashes instead of dots as a name space separator for Cyrus IMAP."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "mail", "mandatory" => FALSE), array( "name" => "vacationTemplateDirectory", "type" => "path", "default" => "/etc/gosa/vacation", "description" => _("Directory to store vacation templates. Please read the FAQ file for more information."), "check" => "gosaProperty::isWriteablePath", "migrate" => "", "group" => "mail", "mandatory" => FALSE), array( "name" => "ldapTLS", "type" => "bool", "default" => "false", "description" => _("Enable TLS for LDAP connections."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "security", "mandatory" => TRUE), array( "name" => "honourIvbbAttributes", "type" => "bool", "default" => "false", "description" => _("Enable IVBB used by german authorities."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "sambaIdMapping", "type" => "bool", "default" => "false", "description" => _("Maintain sambaIdmapEntry objects to improve performance on some Samba versions."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "samba", "mandatory" => FALSE), array( "name" => "handleExpiredAccounts", "type" => "bool", "default" => "true", "description" => _("Enable checks to determine whether an account is expired or not."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => FALSE), array( "name" => "sambaSID", "type" => "string", "default" => "", "description" => _("String containing the SID for Samba setups without the Domain object in LDAP."), "check" => "", "migrate" => "", "group" => "samba", "mandatory" => FALSE), array( "name" => "sambaRidBase", "type" => "integer", "default" => "", "description" => _("String containing the RID base for Samba setups without the Domain object in LDAP."), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "samba", "mandatory" => FALSE), array( "name" => "enableSnapshots", "type" => "bool", "default" => "false", "description" => _("Enable manual object snapshots."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "snapshot", "mandatory" => TRUE), array( "name" => "snapshotBase", "type" => "dn", "default" => "ou=snapshots,dc=localhost,dc=de", "description" => _("Base DN for snapshot storage."), "check" => "gosaProperty::isDn", "migrate" => "", "group" => "snapshot", "mandatory" => FALSE), array( "name" => "snapshotAdminDn", "type" => "dn", "default" => "cn=admin,dc=localhost,dc=de", "description" => _("DN of the snapshot administrator."), "check" => "gosaProperty::isDn", "migrate" => "", "group" => "snapshot", "mandatory" => FALSE), array( "name" => "snapshotAdminPassword", "type" => "string", "default" => "secret", "description" => _("Password of the snapshot administrator."), "check" => "", "migrate" => "", "group" => "snapshot", "mandatory" => FALSE), array( "name" => "idAllocationMethod", "type" => "switch", "default" => "traditional", "defaults" => "core::getPropertyValues", "description" => _("Method for user and group ID generation. Note: only the 'traditional' method is safe due to PHP limitations."), "check" => "", "migrate" => "", "group" => "id", "mandatory" => TRUE), array( "name" => "snapshotURI", "type" => "uri", "default" => "ldap://localhost:389", "description" => _("URI of server to be used for snapshots."), "check" => "", "migrate" => "", "group" => "snapshot", "mandatory" => FALSE), array( "name" => "forceTranslit", "type" => "bool", "default" => "false", "description" => _("Enable transliteration of cyrillic characters for UID generation."), "check" => "gosaProperty::isBool", "migrate" => "", "group" => "core", "mandatory" => TRUE) ))); } } ?> gosa-core-2.7.4/include/class_management.inc0000644000175000017500000010776211613731145020035 0ustar cajuscajusplugname = $plugname; $this->headpage = $headpage; $this->ui = $ui; $this->config = $config; $this->initTime = microtime(TRUE); // Create statistic table entry stats::log('management', $class = get_class($this), $this->getAclCategories(), $action = 'open', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); if($this->cpHandler) $this->headpage->setCopyPasteHandler($this->cpHandler); if($this->snapHandler) $this->headpage->setSnapshotHandler($this->snapHandler); if(empty($this->plIcon)){ $this->plIcon = "plugins/".$plugname."/images/plugin.png"; } // Register default actions $this->registerAction("new", "newEntry"); $this->registerAction("edit", "editEntry"); $this->registerAction("apply", "applyChanges"); $this->registerAction("save", "saveChanges"); $this->registerAction("cancel", "cancelEdit"); $this->registerAction("cancelDelete", "cancelEdit"); $this->registerAction("remove", "removeEntryRequested"); $this->registerAction("removeConfirmed", "removeEntryConfirmed"); $this->registerAction("copy", "copyPasteHandler"); $this->registerAction("cut", "copyPasteHandler"); $this->registerAction("paste", "copyPasteHandler"); $this->registerAction("snapshot", "createSnapshotDialog"); $this->registerAction("restore", "restoreSnapshotDialog"); $this->registerAction("saveSnapshot","saveSnapshot"); $this->registerAction("restoreSnapshot","restoreSnapshot"); $this->registerAction("removeSnapshotConfirmed","removeSnapshotConfirmed"); $this->registerAction("cancelSnapshot","closeDialogs"); $this->registerAction("config-filter","editFilter"); $this->registerAction("saveFilter","saveFilter"); $this->registerAction("cancelFilter","cancelFilter"); // To temporay disable the filter caching UNcomment this line. #session::global_un_set(get_class($this)."_filter"); } /*! \brief Returns an array with all ACL-Categories we are responsible for. */ function getAclCategories() { $ret= $this->aclCategory; if(!is_array($ret)) $ret = array($ret); return($ret); } /*! \brief Execute this plugin * Handle actions/events, locking, snapshots, dialogs, tabs,... */ function execute() { // Ensure that html posts and gets are kept even if we see a 'Entry islocked' dialog. $vars = array('/^act$/','/^listing/','/^PID$/','/^FILTER_PID$/'); session::set('LOCK_VARS_TO_USE',$vars); pathNavigator::registerPlugin($this); /* Display the copy & paste dialog, if it is currently open */ $ret = $this->copyPasteHandler("",array()); if($ret){ return($this->getHeader().$ret); } // Update filter if ($this->filter) { $this->filter->update(); session::global_set(get_class($this)."_filter", $this->filter); session::set('autocomplete', $this->filter); } // Handle actions (POSTs and GETs) $str = $this->handleActions($this->detectPostActions()); if($str) return($this->getHeader().$str); // Open single dialog objects if(is_object($this->dialogObject)){ if(method_exists($this->dialogObject,'save_object')) $this->dialogObject->save_object(); if(method_exists($this->dialogObject,'execute')){ $display = $this->dialogObject->execute(); $display.= $this->_getTabFooter(); return($this->getHeader().$display); } } // Display tab object. if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){ # $this->tabObject->save_object(); $display = $this->tabObject->execute(); $display.= $this->_getTabFooter(); return($this->getHeader().$display); } // Set current restore base for snapshot handling. if(is_object($this->snapHandler)){ $bases = array(); foreach($this->storagePoints as $sp){ $bases[] = $sp.$this->headpage->getBase(); } // No bases specified? Try base if(!count($bases)) $bases[] = $this->headpage->getBase(); $this->snapHandler->setSnapshotBases($bases); } // Create statistic table entry stats::log('management', $class = get_class($this), $this->getAclCategories(), $action = 'view', $amount = 1, $duration = (microtime(TRUE) - $this->initTime)); // Display list return($this->renderList()); } function editFilter() { $this->dialogObject = new userFilter($this->config,$this->getHeadpage()); } function renderList() { $this->headpage->update(); $display = $this->headpage->render(); return($this->getHeader().$display); } function getHeadpage() { return($this->headpage); } function getFilter() { return($this->filter); } /*! \brief Generates the plugin header which is displayed whenever a tab object is * opened. */ protected function getHeader() { // We do not display any headers right now. if(1 || $this->skipHeader) return(""); } /*! \brief Generates the footer which is used whenever a tab object is * displayed. */ protected function _getTabFooter() { // Do not display tab footer for non tab objects if(!($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug)){ return(""); } // Check if there is a dialog opened - We don't need any buttons in this case. if($this->tabObject->by_object[$this->tabObject->current]){ $current = $this->tabObject->by_object[$this->tabObject->current]; if(isset($current->dialog) && (is_object($current->dialog) || $current->dialog)){ return(""); } } // Skip footer if requested; if($this->skipFooter) return(""); // In case an of locked entry, we may have opened a read-only tab. $str = ""; if(isset($this->tabObject->read_only) && $this->tabObject->read_only == TRUE){ $str.= "

    "; return($str); }else{ // Display ok, (apply) and cancel buttons $str.= "

    \n"; $str.= "\n"; $str.= " \n"; if($this->displayApplyBtn){ $str.= "\n"; $str.= " \n"; } $str.= "\n"; $str.= "

    "; } return($str); } /*! \brief Initiates the removal for the given entries * and displays a confirmation dialog. * * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ protected function removeEntryRequested($action="",$target=array(),$all=array()) { // Close dialogs and remove locks for currently handled dns $this->cancelEdit(); $disallowed = array(); $this->dns = array(); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Entry removel requested!"); // Check permissons for each target $h = $this->getHeadpage(); $oTypes = array_reverse($h->objectTypes); foreach($target as $dn){ $entry = $h->getEntry($dn); $obj = $h->getObjectType($oTypes, $entry['objectClass']); $acl = $this->ui->get_permissions($dn, $obj['category']."/".$obj['class']); if(preg_match("/d/",$acl)){ $this->dns[] = $dn; }else{ $disallowed[] = $dn; } } if(count($disallowed)){ msg_dialog::display(_("Permission"),msgPool::permDelete($disallowed),INFO_DIALOG); } // We've at least one entry to delete. if(count($this->dns)){ // check locks if ($user= get_multiple_locks($this->dns)){ return(gen_locked_message($user,$this->dns)); } // Add locks $dns_names = array(); $types = array(); // Build list of object -labels foreach($h->objectTypes as $type){ $map[$type['objectClass']]= $type['label']; } foreach($this->dns as $dn){ $tmp = $h->getType($dn); if(isset($map[$tmp])){ $dns_names[LDAP::fix($dn)] = _($map[$tmp]); }else{ $dns_names[] =LDAP::fix($dn); } } add_lock ($this->dns, $this->ui->dn); // Display confirmation dialog. $smarty = get_smarty(); $smarty->assign("info", msgPool::deleteInfo($dns_names)); $smarty->assign("multiple", true); return($smarty->fetch(get_template_path('removeEntries.tpl'))); } } /*! \brief Object removal was confirmed, now remove the requested entries. * * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ function removeEntryConfirmed($action="",$target=array(),$all=array(), $altTabClass="",$altTabType="", $altAclCategory="",$altAclPlugin="") { $tabType = $this->tabType; $tabClass = $this->tabClass; $aclCategory = $this->aclCategory; $aclPlugin = $this->aclPlugin; if(!empty($altTabClass)) $tabClass = $altTabClass; if(!empty($altTabType)) $tabType = $altTabType; if(!empty($altAclCategory)) $aclCategory = $altAclCategory; if(!empty($altAclPlugin)) $aclPlugin = $altAclPlugin; @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Entry removel confirmed!"); // Check permissons for each target $h = $this->getHeadpage(); $oTypes = array_reverse($h->objectTypes); foreach($this->dns as $key => $dn){ $entry = $h->getEntry($dn); $obj = $h->getObjectType($oTypes, $entry['objectClass']); $acl = $this->ui->get_permissions($dn, $obj['category']."/".$obj['class']); // Check permissions, are we allowed to remove this object? if(preg_match("/d/",$acl)){ // Delete the object $this->dn = $dn; $this->tabObject= new $tabClass($this->config,$this->config->data['TABS'][$tabType], $this->dn, $aclCategory, true, true); $this->tabObject->set_acl_base($this->dn); $this->tabObject->parent = &$this; $this->tabObject->delete (); // Remove the lock for the current object. del_lock($this->dn); } else { msg_dialog::display(_("Permission error"), msgPool::permDelete(), ERROR_DIALOG); new log("security","groups/".get_class($this),$dn,array(),"Tried to trick deletion."); } } // Cleanup $this->remove_lock(); $this->closeDialogs(); } /*! \brief Detects actions/events send by the ui * and the corresponding targets. */ function detectPostActions() { if(!is_object($this->headpage)){ trigger_error("No valid headpage given....!"); return(array()); } $action= $this->headpage->getAction(); if(isset($_POST['edit_apply'])) $action['action'] = "apply"; if(isset($_POST['edit_finish'])) $action['action'] = "save"; if(isset($_POST['edit_cancel'])) $action['action'] = "cancel"; if(isset($_POST['delete_confirmed'])) $action['action'] = "removeConfirmed"; if(isset($_POST['delete_snapshot_confirm'])) $action['action'] = "removeSnapshotConfirmed"; if(isset($_POST['delete_cancel'])) $action['action'] = "cancelDelete"; if(isset($_POST['saveFilter'])) $action['action'] = "saveFilter"; if(isset($_POST['cancelFilter'])) $action['action'] = "cancelFilter"; // Detect Snapshot actions if(isset($_POST['CreateSnapshot'])) $action['action'] = "saveSnapshot"; if(isset($_POST['CancelSnapshot'])) $action['action'] = "cancelSnapshot"; foreach($_POST as $name => $value){ $once =TRUE; if(preg_match("/^RestoreSnapShot_/",$name) && $once){ $once = FALSE; $entry = base64_decode(preg_replace("/^RestoreSnapShot_(.*)$/i","\\1",$name)); $action['action'] = "restoreSnapshot"; $action['targets'] = array($entry); } } return($action); } /*! \brief Calls the registered method for a given action/event. */ function handleActions($action) { // Start action if(isset($this->actions[$action['action']])){ $func = $this->actions[$action['action']]; if(!isset($action['targets']))$action['targets']= array(); // Create statistic table entry stats::log('management', $class = get_class($this), $this->getAclCategories(), $action['action'], $amount = count($action['targets']), $duration = (microtime(TRUE) - $this->initTime)); return($this->$func($action['action'],$action['targets'],$action)); } } /*! \brief Opens the snapshot creation dialog for the given target. * * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ function createSnapshotDialog($action="",$target=array(),$all=array()) { @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$target,"Snaptshot creation initiated!"); foreach($target as $entry){ if(!empty($entry) && $this->ui->allow_snapshot_create($entry,$this->aclCategory)){ $this->dialogObject = new SnapShotDialog($this->config,$entry,$this); $this->dialogObject->aclCategories = array($this->aclCategory); $this->dialogObject->parent = &$this; }else{ msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to create a snapshot for %s!"), bold($entry)), ERROR_DIALOG); } } } /*! \brief Creates a snapshot new entry - This method is called when the somebody * clicks 'save' in the "Create snapshot dialog" (see ::createSnapshotDialog). * * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ function saveSnapshot($action="",$target=array(),$all=array()) { if(!is_object($this->dialogObject)) return; $this->dialogObject->save_object(); $msgs = $this->dialogObject->check(); if(count($msgs)){ foreach($msgs as $msg){ msg_dialog::display(_("Error"), $msg, ERROR_DIALOG); } }else{ $this->dn = $this->dialogObject->dn; $this->snapHandler->create_snapshot( $this->dn,$this->dialogObject->CurrentDescription); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Snaptshot created!"); $this->closeDialogs(); } } /*! \brief Restores a snapshot object. * The dn of the snapshot entry has to be given as ['target'] parameter. * * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ function restoreSnapshot($action="",$target=array(),$all=array()) { $entry = array_pop($target); if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){ $this->snapHandler->restore_snapshot($entry); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Snaptshot restored!"); $this->closeDialogs(); }else{ msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)), ERROR_DIALOG); } } /*! \brief Removes a snapshot object. */ function removeSnapshotConfirmed($action="",$target=array(),$all=array()) { $entry = $this->dialogObject->del_dn; if(!empty($entry) && $this->ui->allow_snapshot_create($entry,$this->aclCategory)){ $this->snapHandler->remove_snapshot($entry); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot removed!"); }else{ msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to remove a snapshot for %s!"), bold($entry)), ERROR_DIALOG); } } /*! \brief Displays the "Restore snapshot dialog" for a given target. * If no target is specified, open the restore removed object * dialog. * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ function restoreSnapshotDialog($action="",$target=array(),$all=array()) { // Set current restore base for snapshot handling. if(is_object($this->snapHandler)){ $bases = array(); foreach($this->storagePoints as $sp){ $bases[] = $sp.$this->headpage->getBase(); } } // No bases specified? Try base if(!count($bases)) $bases[] = $this->headpage->getBase(); // No target, open the restore removed object dialog. if(!count($target)){ $entry = $this->headpage->getBase(); if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot restoring initiated!"); $this->dialogObject = new SnapShotDialog($this->config,$entry,$this); $this->dialogObject->set_snapshot_bases($bases); $this->dialogObject->display_all_removed_objects = true; $this->dialogObject->display_restore_dialog = true; $this->dialogObject->parent = &$this; }else{ msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)), ERROR_DIALOG); } }else{ // Display the restore points for a given object. $entry = array_pop($target); if(!empty($entry) && $this->ui->allow_snapshot_restore($entry,$this->aclCategory)){ @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$entry,"Snaptshot restoring initiated!"); $this->dialogObject = new SnapShotDialog($this->config,$entry,$this); $this->dialogObject->set_snapshot_bases($bases); $this->dialogObject->display_restore_dialog = true; $this->dialogObject->parent = &$this; }else{ msg_dialog::display(_("Permission"),sprintf(_("You are not allowed to restore a snapshot for %s!"), bold($entry)), ERROR_DIALOG); } } } /*! \brief This method intiates the object creation. * * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ function newEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory="") { /* To handle mutliple object types overload this method. * ... * registerAction('newUser', 'newEntry'); * registerAction('newGroup','newEntry'); * ... * * function newEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory) * { * switch($action){ * case 'newUser' : { * mangement::newEntry($action,$target,$all,"usertabs","USERTABS","users"); * } * case 'newGroup' : { * mangement::newEntry($action,$target,$all,"grouptabs","GROUPTABS","groups"); * } * } * } **/ $tabType = $this->tabType; $tabClass = $this->tabClass; $aclCategory = $this->aclCategory; if(!empty($altTabClass)) $tabClass = $altTabClass; if(!empty($altTabType)) $tabType = $altTabType; if(!empty($altAclCategory)) $aclCategory = $altAclCategory; // Check locking & lock entry if required $this->displayApplyBtn = FALSE; $this->dn = "new"; $this->is_new = TRUE; $this->is_single_edit = FALSE; $this->is_multiple_edit = FALSE; set_object_info($this->dn); // Open object. if(empty($tabClass) || empty($tabType)){ // No tab type defined }else{ if (isset($this->config->data['TABS'][$tabType])) { // Check if the base plugin is available - it is mostly responsible for object creation and removal. $first = $this->config->data['TABS'][$tabType][0]; if(!class_available($first['CLASS'])){ msg_dialog::display(_("Internal error"), sprintf(_("Cannot instantiate tabbed-plug-in, the base plugin (%s) is not available!"), $first['CLASS']), ERROR_DIALOG); }else{ $this->tabObject= new $tabClass($this->config,$this->config->data['TABS'][$tabType], $this->dn, $aclCategory); $this->tabObject->set_acl_base($this->headpage->getBase()); $this->tabObject->parent = &$this; @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Create new entry initiated!"); } } else { msg_dialog::display(_("Error"), sprintf(_("No tab definition for %s found in configuration file: cannot create plugin instance!"), bold($tabType)), ERROR_DIALOG); } } } /*! \brief This method opens an existing object or a list of existing objects to be edited. * * * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ function editEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory="") { /* To handle mutliple object types overload this method. * ... * registerAction('editUser', 'editEntry'); * registerAction('editGroup','editEntry'); * ... * * function editEntry($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory) * { * switch($action){ * case 'editUser' : { * mangement::editEntry($action,$target,$all,"usertabs","USERTABS","users"); * } * case 'editGroup' : { * mangement::editEntry($action,$target,$all,"grouptabs","GROUPTABS","groups"); * } * } * } **/ // Do not create a new tabObject while there is already one opened, // the user may have just pressed F5 to reload the page. if(is_object($this->tabObject)){ return; } $tabType = $this->tabType; $tabClass = $this->tabClass; $aclCategory = $this->aclCategory; if(!empty($altTabClass)) $tabClass = $altTabClass; if(!empty($altTabType)) $tabType = $altTabType; if(!empty($altAclCategory)) $aclCategory = $altAclCategory; $this->displayApplyBtn = count($target) == 1; // Single edit - we only got one object dn. if(count($target) == 1){ $this->is_new = FALSE; $this->is_single_edit = TRUE; $this->is_multiple_edit = FALSE; // Get the dn of the object and creates lock $this->dn = array_pop($target); set_object_info($this->dn); $user = get_lock($this->dn); if ($user != ""){ return(gen_locked_message ($user, array($this->dn),TRUE)); } add_lock ($this->dn, $this->ui->dn); // Open object. if(empty($tabClass) || empty($tabType)){ trigger_error("We can't edit any object(s). 'tabClass' or 'tabType' is empty!"); }else{ $tab = $tabClass; // Check if the base plugin is available - it is mostly responsible for object creation and removal. $first = $this->config->data['TABS'][$tabType][0]; if(!class_available($first['CLASS'])){ msg_dialog::display(_("Internal error"), sprintf(_("Cannot instantiate tabbed-plug-in, the base plugin (%s) is not available!"), $first['CLASS']), ERROR_DIALOG); }else{ $this->tabObject= new $tab($this->config,$this->config->data['TABS'][$tabType], $this->dn,$aclCategory); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dn,"Edit entry initiated!"); $this->tabObject->set_acl_base($this->dn); $this->tabObject->parent = &$this; } } }else{ // We've multiple entries to edit. $this->is_new = FALSE; $this->is_singel_edit = FALSE; $this->is_multiple_edit = TRUE; // Open multiple edit handler. if(empty($tabClass) || empty($tabType)){ trigger_error("We can't edit any object(s). 'tabClass' or 'tabType' is empty!"); }else{ $this->dns = $target; $tmp = new multi_plug($this->config,$tabClass,$this->config->data['TABS'][$tabType], $this->dns,$this->headpage->getBase(),$aclCategory); // Check for locked entries if ($tmp->entries_locked()){ return($tmp->display_lock_message()); } @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Edit entry initiated!"); // Now lock entries. if($tmp->multiple_available()){ $tmp->lock_entries($this->ui->dn); $this->tabObject = $tmp; set_object_info($this->tabObject->get_object_info()); } } } } /*! \brief Close filter dialog */ protected function cancelFilter() { if($this->dialogObject instanceOf userFilter){ $this->remove_lock(); $this->closeDialogs(); } } /*! \brief Save filter modifcations. */ protected function saveFilter() { if($this->dialogObject instanceOf userFilter){ $msgs = $this->dialogObject->check(); if(count($msgs)){ msg_dialog::displayChecks($msgs); return(""); }else{ $this->dialogObject->save(); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!"); $this->remove_lock(); $this->closeDialogs(); // Ask filter to reload information $this->filter->reloadFilters(); } } } /*! \brief Save object modifications and closes dialogs (returns to object listing). * - Calls '::check' to validate the given input. * - Calls '::save' to save back object modifications (e.g. to ldap). * - Calls '::remove_locks' to remove eventually created locks. * - Calls '::closeDialogs' to return to the object listing. */ protected function saveChanges() { if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){ $this->tabObject->save_object(); $msgs = $this->tabObject->check(); if(count($msgs)){ msg_dialog::displayChecks($msgs); return(""); }else{ $this->tabObject->save(); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!"); $this->remove_lock(); $this->closeDialogs(); } }elseif($this->dialogObject instanceOf plugin){ $this->dialogObject->save_object(); $msgs = $this->dialogObject->check(); if(count($msgs)){ msg_dialog::displayChecks($msgs); return(""); }else{ $this->dialogObject->save(); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Entry saved!"); $this->remove_lock(); $this->closeDialogs(); } } } /*! \brief Save object modifications and keep dialogs opened. * - Calls '::check' to validate the given input. * - Calls '::save' to save back object modifications (e.g. to ldap). */ protected function applyChanges() { if($this->tabObject instanceOf tabs || $this->tabObject instanceOf multi_plug){ $this->tabObject->save_object(); $msgs = $this->tabObject->check(); if(count($msgs)){ msg_dialog::displayChecks($msgs); return(""); }else{ $this->tabObject->save(); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$this->dns,"Modifications applied!"); $this->tabObject->re_init(); } } } /*! \brief This method closes dialogs * and cleans up the cached object info and the ui. */ protected function closeDialogs() { $this->last_dn = $this->dn; $this->last_dns = $this->dns; $this->last_tabObject = $this->tabObject; $this->last_dialogObject = $this->dialogObject; $this->dn = ""; $this->dns = array(); $this->tabObject = null; $this->dialogObject = null; $this->skipFooter = FALSE; set_object_info(); } /*! \brief Editing an object was caneled. * Close dialogs/tabs and remove locks. */ protected function cancelEdit() { $this->remove_lock(); $this->closeDialogs(); } /*! \brief Every click in the list user interface sends an event * here can we connect those events to a method. * eg. ::registerEvent('new','createUser') * When the action/event new is send, the method 'createUser' * will be called. */ function registerAction($action,$target) { $this->actions[$action] = $target; } /*! \brief Removes ldap object locks created by this class. * Whenever an object is edited, we create locks to avoid * concurrent modifications. * This locks will automatically removed here. */ function remove_lock() { if(!empty($this->dn) && $this->dn != "new"){ del_lock($this->dn); } if(count($this->dns)){ del_lock($this->dns); } } /*! \brief This method is used to queue and process copy&paste actions. * Allows to copy, cut and paste mutliple entries at once. * @param String 'action' The name of the action which was the used as trigger. * @param Array 'target' A list of object dns, which should be affected by this method. * @param Array 'all' A combination of both 'action' and 'target'. */ function copyPasteHandler($action="",$target=array(),$all=array(), $altTabClass ="", $altTabType = "", $altAclCategory="",$altAclPlugin="") { // Return without any actions while copy&paste handler is disabled. if(!is_object($this->cpHandler)) return(""); $tabType = $this->tabType; $tabClass = $this->tabClass; $aclCategory = $this->aclCategory; $aclPlugin = $this->aclPlugin; if(!empty($altTabClass)) $tabClass = $altTabClass; if(!empty($altTabType)) $tabType = $altTabType; if(!empty($altAclCategory)) $aclCategory = $altAclCategory; if(!empty($altAclPlugin)) $aclPlugin = $altAclPlugin; // Save user input $this->cpHandler->save_object(); // Add entries to queue if($action == "copy" || $action == "cut"){ $this->cpHandler->cleanup_queue(); foreach($target as $dn){ if($action == "copy" && $this->ui->is_copyable($dn,$aclCategory,$aclPlugin)){ $this->cpHandler->add_to_queue($dn,"copy",$tabClass,$tabType,$aclCategory,$this); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$dn,"Entry copied!"); } if($action == "cut" && $this->ui->is_cutable($dn,$aclCategory,$aclPlugin)){ $this->cpHandler->add_to_queue($dn,"cut",$tabClass,$tabType,$aclCategory,$this); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__,$dn,"Entry cutted!"); } } } // Initiate pasting if($action == "paste"){ $this->cpPastingStarted = TRUE; } // Display any c&p dialogs, eg. object modifications required before pasting. if($this->cpPastingStarted && $this->cpHandler->entries_queued()){ $this->cpHandler->SetVar("base",$this->headpage->getBase()); $data = $this->cpHandler->execute(); if(!empty($data)){ return($data); } } // Automatically disable pasting process since there is no entry left to paste. if(!$this->cpHandler->entries_queued()){ $this->cpPastingStarted = FALSE; } return(""); } function setFilter($str) { $this->filter = $str; } function postcreate() { $this->handle_post_events('add'); } function postmodify(){ $this->handle_post_events('modify'); } function postremove(){ $this->handle_post_events('remove'); } function is_modal_dialog() { return(is_object($this->tabObject) || is_object($this->dialogObject)); } /*! \brief Forward command execution request * to the correct method. */ function handle_post_events($mode, $addAttrs= array()) { if(!in_array_strict($mode, array('add','remove','modify'))){ trigger_error(sprintf("Invalid post event type given %s! Valid types are [add,modify,remove].", bold($mode))); return; } switch ($mode){ case "add": plugin::callHook($this,"POSTCREATE", $addAttrs); break; case "modify": plugin::callHook($this,"POSTMODIFY", $addAttrs); break; case "remove": plugin::callHook($this,"POSTREMOVE", $addAttrs); break; } } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_SnapShotDialog.inc0000644000175000017500000001553511424277775020612 0ustar cajuscajusparent = &$parent; $this->ui = get_userinfo(); // Prepare lists $this->snapList = new sortableListing(); $this->snapList->setDeleteable(false); $this->snapList->setEditable(false); $this->snapList->setWidth("100%"); $this->snapList->setHeight("200px"); $this->snapList->setHeader(array(_("Date"), _("Name") )); $this->snapList->setColspecs(array('140px','*','60px')); $this->snapList->setDefaultSortColumn(0); } /* Show deleted snapshots from these bases */ function set_snapshot_bases($bases) { $this->snap_shot_bases = $bases; } /* Display snapshot dialog */ function execute() { plugin::execute(); $smarty = get_smarty(); $ui = get_userinfo(); $once = true; foreach($_POST as $name => $value){ $value = get_post($name); if((preg_match("/^RemoveSnapShot_/",$name)) && ($once)){ $once = false; $entry = preg_replace("/^RemoveSnapShot_/","",$name); $entry = base64_decode($entry); $found = false; foreach($this->last_list as $t_stamp => $obj){ if($obj['dn'] == $entry){ $found = true; break; } } if($found){ $this->del_dn = $entry; $smarty= get_smarty(); $smarty->assign("info", sprintf(_("You are about to delete the snapshot %s."), bold(LDAP::fix($this->del_dn)))); return($smarty->fetch (get_template_path('removeSnapshots.tpl'))); } } } /* We must restore a snapshot */ if($this->display_restore_dialog){ /* Should we only display all snapshots of already deleted objects or the snapshots for the given object dn */ $res = array(); $tmp = array(); $handler = new SnapshotHandler($this->config); if($this->display_all_removed_objects){ if(count($this->snap_shot_bases)){ foreach($this->snap_shot_bases as $dn){ $tmp = array_merge($tmp,$handler->getAllDeletedSnapshots($dn,true)); } }else{ $tmp = $handler->getAllDeletedSnapshots($this->snap_shot_bases,true); } }else{ $tmp = $handler->Available_SnapsShots($this->dn,true); } $this->snapList->setAcl('rwcdm'); $list_of_elements = array(); /* Walk through all entries and setup the display text */ foreach($tmp as $key => $entry){ /* Check permissions */ $TimeStamp = $entry['gosaSnapshotTimestamp'][0]; $list_of_elements[$TimeStamp] = $entry; } /* Sort generated list */ krsort($list_of_elements); /* Add Elements to list */ $this->last_list = $list_of_elements; $data = $lData = array(); foreach($list_of_elements as $entry){ $actions= image('images/lists/restore.png','RestoreSnapShot_%KEY',_("Restore snapshot")); $actions.= image('images/lists/trash.png','RemoveSnapShot_%KEY',_("Delete snapshot")); $time_stamp = date(_("Y-m-d, H:i:s"),preg_replace("/\-.*$/","",$entry['gosaSnapshotTimestamp'][0])); $display_data = $entry['description'][0]; $data[$entry['dn']] = $entry; $lData[$entry['dn']] = array('data'=> array( $time_stamp, htmlentities(utf8_decode(LDAP::fix($display_data))), str_replace("%KEY",base64_encode($entry['dn']), $actions))); } $this->snapList->setListData($data, $lData); $this->snapList->update(); $smarty->assign("SnapShotList",$this->snapList->render()); $smarty->assign("CountSnapShots",count($list_of_elements)); } $smarty->assign("restore_deleted",$this->display_all_removed_objects); $smarty->assign("RestoreMode",$this->display_restore_dialog); $smarty->assign("CurrentDate",date(_("Y-m-d, H:i:s"))); $smarty->assign("CurrentDN",LDAP::fix($this->dn)); $smarty->assign("CurrentDescription",set_post($this->CurrentDescription)); return($smarty->fetch(get_template_path("snapshotdialog.tpl"))); } function check() { $message = plugin::check(); if(!$this->display_restore_dialog){ if(empty($this->CurrentDescription)){ $message[]= msgPool::invalid(_("Description")); } } return($message); } function save_object() { // plugin::save_object(); foreach($this->attributes as $name){ if(isset($_POST[$name])){ $this->$name = get_post($name); } } } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/password-methods/0000755000175000017500000000000011752422552017332 5ustar cajuscajusgosa-core-2.7.4/include/password-methods/class_password-methods-crypt.inc0000644000175000017500000000575611330043647025665 0ustar cajuscajusgenerate_hash('N0T$3T4N0W').'N0T$3T4N0W'); } function generate_hash($pwd) { if ($this->hash == "crypt/standard-des"){ $salt = ""; for ($i = 0; $i < 2; $i++) { $salt .= get_random_char(); } } if ($this->hash == "crypt/enhanced-des"){ $salt = "_"; for ($i = 0; $i < 8; $i++) { $salt .= get_random_char(); } } if ($this->hash == "crypt/md5"){ $salt = "\$1\$"; for ($i = 0; $i < 8; $i++) { $salt .= get_random_char(); } $salt .= "\$"; } if ($this->hash == "crypt/blowfish"){ $salt = "\$2a\$07\$"; for ($i = 0; $i < CRYPT_SALT_LENGTH; $i++) { $salt .= get_random_char(); } $salt .= "\$"; } return "{CRYPT}".crypt($pwd, $salt); } function get_hash_name() { $hashes= array(); if (CRYPT_STD_DES == 1) { $hashes[]= "crypt/standard-des"; } if (CRYPT_EXT_DES == 1) { $hashes[]= "crypt/enhanced-des"; } if (CRYPT_MD5 == 1) { $hashes[]= "crypt/md5"; } if (CRYPT_BLOWFISH == 1) { $hashes[]= "crypt/blowfish"; } return $hashes; } function _extract_method($password_hash) { if (!preg_match('/^{crypt}/i', $password_hash)){ return ""; } $password_hash= preg_replace('/^{[^}]+}!?/', '', $password_hash); if (preg_match("/^[a-zA-Z0-9.\/][a-zA-Z0-9.\/]/", $password_hash)){ return "crypt/standard-des"; } if (preg_match("/^_[a-zA-Z0-9.\/]/", $password_hash)){ return "crypt/enhanced-des"; } if (preg_match('/^\$1\$/', $password_hash)){ return "crypt/md5"; } if (preg_match('/^(\$2\$|\$2a\$)/', $password_hash)){ return "crypt/blowfish"; } return ""; } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/password-methods/class_password-methods-smd5.inc0000644000175000017500000000302311330043647025355 0ustar cajuscajus gosa-core-2.7.4/include/password-methods/class_password-methods-sha.inc0000644000175000017500000000330411330043647025262 0ustar cajuscajus gosa-core-2.7.4/include/password-methods/class_password-methods-ssha.inc0000644000175000017500000000365311330043647025454 0ustar cajuscajus gosa-core-2.7.4/include/password-methods/class_password-methods-clear.inc0000644000175000017500000000237611330043647025605 0ustar cajuscajus gosa-core-2.7.4/include/password-methods/class_password-methods.inc0000644000175000017500000003333111476176512024525 0ustar cajuscajusget_hash_name() == ""){ return("{crypt}N0T$3T4N0W"); }else{ return('{'.$this->get_hash().'}').'N0T$3T4N0W'; } } function get_hash_name() { } function is_locked($config,$dn = "") { if(!$this->lockable) return FALSE; /* Get current password hash */ $pwd =""; if(!empty($dn)){ $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); $ldap->cat($dn); $attrs = $ldap->fetch(); if(isset($attrs['userPassword'][0])){ $pwd = $attrs['userPassword'][0]; } }elseif(isset($this->attrs['userPassword'][0])){ $pwd = $this->attrs['userPassword'][0]; } return(preg_match("/^[^\}]*+\}!/",$pwd)); } /*! \brief Locks an account (gosaAccount) by added a '!' as prefix to the password hashes. * This makes logins impossible, due to the fact that the hash becomes invalid. * userPassword: {SHA}!q02NKl9IChNwZEAJxzRdmB6E * sambaLMPassword: !EBD223B61F8C259AD3B435B51404EE * sambaNTPassword: !98BB35737013AAF181D0FE9FDA09E */ function lock_account($config,$dn = "") { if(!$this->lockable) return FALSE; /* Get current password hash */ $userPassword = $sambaLMPassword = $sambaNTPassword = ""; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); if(!empty($dn)){ $ldap->cat($dn,array('sambaLMPassword','sambaNTPassword','userPassword')); $attrs = $ldap->fetch(); $userPassword = (isset($attrs['userPassword'][0])) ? $attrs['userPassword'][0]: ""; $sambaLMPassword = (isset($attrs['sambaLMPassword'][0])) ? $attrs['sambaLMPassword'][0]: ""; $sambaNTPassword = (isset($attrs['sambaNTPassword'][0])) ? $attrs['sambaNTPassword'][0]: ""; }elseif(isset($this->attrs['userPassword'][0])){ $dn = $this->attrs['dn']; $userPassword = (isset($this->attrs['userPassword'][0])) ? $this->attrs['userPassword'][0]: ""; $sambaLMPassword = (isset($this->attrs['sambaLMPassword'][0])) ? $this->attrs['sambaLMPassword'][0]: ""; $sambaNTPassword = (isset($this->attrs['sambaNTPassword'][0])) ? $this->attrs['sambaNTPassword'][0]: ""; } /* We can only lock/unlock non-empty passwords */ if(!empty($userPassword)){ /* Check if this entry is already locked. */ if(preg_match("/^[^\}]*+\}!/",$userPassword)){ return(TRUE); } /* Lock entry */ $userPassword = preg_replace("/(^[^\}]+\})(.*$)/","\\1!\\2",$userPassword); // Only lock samba hashes if samba passwords are enabled $smbPasswdEnabled = trim($config->get_cfg_value('core','sambaHashHook')) != ""; if($smbPasswdEnabled){ $sambaLMPassword = preg_replace("/^[!]*(.*$)/","!\\1",$sambaLMPassword); $sambaNTPassword = preg_replace("/^[!]*(.*$)/","!\\1",$sambaNTPassword); } // Call external lock hook $res = $ldap->cat($dn); $hookAttrs = array(); foreach($ldap->fetch() as $name => $value){ if(is_numeric($name)) continue; if(isset($value[0])) $hookAttrs[$name] = $value[0]; if(isset($value) && is_string($value)) $hookAttrs[$name] = $value; } $pwdClass = new password($config, $dn); $pwdClass->callHook($pwdClass, 'PRELOCK',$hookAttrs, $ret); // Update the ldap entry $ldap->cd($dn); $attrs = array(); $attrs['userPassword'] = $userPassword; // Updated samba hashes if samba hashing is enabled if($smbPasswdEnabled){ $attrs['sambaLMPassword'] = $sambaLMPassword; $attrs['sambaNTPassword'] = $sambaNTPassword; } $ldap->modify($attrs); if($ldap->success()){ // Call the password post-lock hook, if defined. $pwdClass->callHook($pwdClass, 'POSTLOCK',$hookAttrs, $ret); } return($ldap->success()); } return(FALSE); } /*! \brief Unlocks an account (gosaAccount) which was locked by 'lock_account()'. * For details about the locking mechanism see 'lock_account()'. */ function unlock_account($config,$dn = "") { if(!$this->lockable) return FALSE; /* Get current password hash */ $userPassword = $sambaLMPassword = $sambaNTPassword = ""; $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); if(!empty($dn)){ $ldap->cat($dn,array('sambaLMPassword','sambaNTPassword','userPassword')); $attrs = $ldap->fetch(); $userPassword = (isset($attrs['userPassword'][0])) ? $attrs['userPassword'][0]: ""; $sambaLMPassword = (isset($attrs['sambaLMPassword'][0])) ? $attrs['sambaLMPassword'][0]: ""; $sambaNTPassword = (isset($attrs['sambaNTPassword'][0])) ? $attrs['sambaNTPassword'][0]: ""; }elseif(isset($this->attrs['userPassword'][0])){ $dn = $this->attrs['dn']; $userPassword = (isset($this->attrs['userPassword'][0])) ? $this->attrs['userPassword'][0]: ""; $sambaLMPassword = (isset($this->attrs['sambaLMPassword'][0])) ? $this->attrs['sambaLMPassword'][0]: ""; $sambaNTPassword = (isset($this->attrs['sambaNTPassword'][0])) ? $this->attrs['sambaNTPassword'][0]: ""; } /* We can only lock/unlock non-empty passwords */ if(!empty($userPassword)){ /* Check if this entry is already locked. */ if(!preg_match("/^[^\}]*+\}!/",$userPassword)){ return (TRUE); } /* Lock entry */ $userPassword = preg_replace("/(^[^\}]+\})!(.*$)/","\\1\\2",$userPassword); // Update samba hashes only if its enabled. $smbPasswdEnabled = trim($config->get_cfg_value('core','sambaHashHook')) != ""; if($smbPasswdEnabled){ $sambaLMPassword = preg_replace("/^[!]*(.*$)/","\\1",$sambaLMPassword); $sambaNTPassword = preg_replace("/^[!]*(.*$)/","\\1",$sambaNTPassword); } // Call external lock hook $res = $ldap->cat($dn); $hookAttrs = array(); foreach($ldap->fetch() as $name => $value){ if(is_numeric($name)) continue; if(isset($value[0])) $hookAttrs[$name] = $value[0]; if(isset($value) && is_string($value)) $hookAttrs[$name] = $value; } $pwdClass = new password($config, $dn); $pwdClass->callHook($pwdClass, 'PREUNLOCK',$hookAttrs, $ret); // Lock the account by modifying the password hash. $ldap->cd($dn); // Update the ldap entry $attrs = array(); $attrs['userPassword'] = $userPassword; // Updated samba hashes if samba hashing is enabled if($smbPasswdEnabled){ $attrs['sambaLMPassword'] = $sambaLMPassword; $attrs['sambaNTPassword'] = $sambaNTPassword; } $ldap->modify($attrs); if($ldap->success()){ // Call the password post-lock hook, if defined. $pwdClass = new password($config, $dn); $pwdClass->callHook($pwdClass, 'POSTUNLOCK',$hookAttrs, $ret); } return($ldap->success()); } return(FALSE); } // this function returns all loaded classes for password encryption static function get_available_methods() { global $class_mapping, $config; $ret =false; $i =0; /* Only */ if(!session::is_set("passwordMethod::get_available_methods")){ foreach($class_mapping as $class => $path) { if(preg_match('/passwordMethod/i', $class) && !preg_match("/^passwordMethod$/i", $class)){ $name = preg_replace ("/passwordMethod/i", "", $class); $test = new $class($config, ""); if($test->is_available()) { $plugs= $test->get_hash_name(); if (!is_array($plugs)){ $plugs= array($plugs); } foreach ($plugs as $plugname){ $cfg = $test->is_configurable(); $ret['name'][$i]= $plugname; $ret['class'][$i]=$class; $ret['is_configurable'][$i]= $cfg; $ret['object'][$i]= $test; $ret['desc'][$i] = $test->get_description(); $ret[$i]['name'] = $plugname; $ret[$i]['class'] = $class; $ret[$i]['object']= $test; $ret[$i]['is_configurable']= $cfg; $ret[$i]['desc'] = $test->get_description(); $ret[$plugname]=$class; $i++; } } } } session::set("passwordMethod::get_available_methods",$ret); } return(session::get("passwordMethod::get_available_methods")); } function get_description() { return(""); } // Method to let password backends remove additional information besides // the userPassword attribute function remove_from_parent() { } // Method to let passwords backends manage additional information // besides the userAttribute entry function set_password($password) { return(TRUE); } // Return true if this password method provides a configuration dialog function is_configurable() { return FALSE; } // Provide a subdialog to configure a password method function configure() { return ""; } // Save information to LDAP function save($dn) { } // Try to find out if it's our hash... static function get_method($password_hash,$dn = "") { global $config; $methods= passwordMethod::get_available_methods(); foreach ($methods['class'] as $class){ $test = new $class($config,$dn); # All listed methods are available. # if(!$test->is_available())continue; $method= $test->_extract_method($password_hash); if ($method != ""){ $test->set_hash($method); return $test; } } msg_dialog::display(_("Error"), _("Cannot find a suitable password method for the current hash!"), ERROR_DIALOG); return NULL; } function _extract_method($password_hash) { $hash= $this->get_hash_name(); if (preg_match("/^\{$hash\}/i", $password_hash)){ return $hash; } return ""; } static function make_hash($password, $hash) { global $config; $methods= passwordMethod::get_available_methods(); $tmp= new $methods[$hash]($config); $tmp->set_hash($hash); return $tmp->generate_hash($password); } function set_hash($hash) { $this->hash= $hash; } function get_hash() { return $this->hash; } function adapt_from_template($dn) { return($this); } static function is_harmless($password) { global $config; if ($config->boolValueIsTrue("core","strictPasswordRules")) { // Do we have UTF8 characters in the password? return ($password == utf8_decode($password)); } return(true); } static function getPasswordProposal($config) { if($config->configRegistry->propertyExists('core', 'passwordProposalHook')){ $value = $config->configRegistry->getPropertyValue('core', 'passwordProposalHook'); $core = new core($config); // No execute the hook and fetch the results. plugin::callHook($core, 'passwordProposalHook', $addAttrs= array(), $ret); if(count($ret) && !empty($ret[0])){ return($ret[0]); } } return(''); } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/password-methods/class_password-methods-md5.inc0000644000175000017500000000247511330043647025204 0ustar cajuscajus gosa-core-2.7.4/include/password-methods/class_password-methods-sasl.inc0000644000175000017500000000350511750201501025443 0ustar cajuscajusrealm = trim($config->get_cfg_value('core','SASLRealm')); if($this->realm == ""){ trigger_error(msgPool::cmdnotfound("SASLRealm", _("SASL"))); } $ldap = $config->get_ldap_link(); $ldap->cd($config->current['BASE']); $ldap->cat($dn,array('uid')); if($ldap->count() == 1){ $attrs = $ldap->fetch(); $this->uid = $attrs['uid'][0]; }else{ trigger_error("Cannot change password, unknown users '".$dn."'"); } } function is_available() { return(true); } function generate_hash($pwd) { return("{SASL}".$this->uid."@".$this->realm); } function get_hash_name() { return "sasl"; } } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_listing.inc0000644000175000017500000016064211663662270017375 0ustar cajuscajuspid= preg_replace("/[^0-9]/", "", microtime(TRUE)); if($isString){ if(!$this->loadString($source)){ die("Cannot parse $source!"); } }else{ if (!$this->loadFile($source)) { die("Cannot parse $source!"); } } // Set base for filter if ($this->baseMode) { $this->base= session::global_get("CurrentMainBase"); if ($this->base == null) { $this->base= $config->current['BASE']; } $this->refreshBasesList(); } else { $this->base= $config->current['BASE']; } // Move footer information $this->showFooter= ($config->get_cfg_value("core","listSummary") == "true"); // Register build in filters $this->registerElementFilter("objectType", "listing::filterObjectType"); $this->registerElementFilter("departmentLink", "listing::filterDepartmentLink"); $this->registerElementFilter("link", "listing::filterLink"); $this->registerElementFilter("actions", "listing::filterActions"); // Load exporters foreach($class_mapping as $class => $dummy) { if (preg_match('/Exporter$/', $class)) { $info= call_user_func(array($class, "getInfo")); if ($info != null) { $this->exporter= array_merge($this->exporter, $info); } } } // Instanciate base selector $this->baseSelector= new baseSelector($this->bases, $this->base); } function setCopyPasteHandler($handler) { $this->copyPasteHandler= &$handler; } function setHeight($height) { $this->height= $height; } function setSnapshotHandler($handler) { $this->snapshotHandler= &$handler; } function getFilter() { return($this->filter); } function setFilter($filter) { $this->filter= &$filter; if ($this->departmentBrowser){ $this->departments= $this->getDepartments(); } $this->filter->setBase($this->base); } function registerElementFilter($name, $call) { if (!isset($this->filters[$name])) { $this->filters[$name]= $call; return true; } return false; } function loadFile($filename) { return($this->loadString(file_get_contents($filename))); } function loadString($contents) { $this->xmlData= xml::xml2array($contents, 1); if (!isset($this->xmlData['list'])) { return false; } $this->xmlData= $this->xmlData["list"]; // Load some definition values foreach (array("departmentBrowser", "departmentRootVisible", "multiSelect","singleSelect", "baseMode", "noAclChecks") as $token) { if (isset($this->xmlData['definition'][$token]) && $this->xmlData['definition'][$token] == "true"){ $this->$token= true; } } // Fill objectTypes from departments and xml definition $types = departmentManagement::get_support_departments(); foreach ($types as $class => $data) { $this->objectTypes[$data['OC']]= array("label" => $data['TITLE'], "objectClass" => $data['OC'], "image" => $data['IMG']); } $this->categories= array(); if (isset($this->xmlData['definition']['objectType'])) { if(isset($this->xmlData['definition']['objectType']['label'])) { $this->xmlData['definition']['objectType']= array($this->xmlData['definition']['objectType']); } foreach ($this->xmlData['definition']['objectType'] as $index => $otype) { $tmp = $this->xmlData['definition']['objectType'][$index]; $this->objectTypes[$tmp['objectClass']]= $tmp; if (isset($this->xmlData['definition']['objectType'][$index]['category'])){ $this->categories[]= $otype['category']; if(isset($otype['category']) && isset($otype['class'])){ $this->aclToObjectClass[$otype['category']."/".$otype['class']][] = $otype['objectClass']; } } } } $this->objectTypes = array_values($this->objectTypes); // Parse layout per column $this->colprops= $this->parseLayout($this->xmlData['table']['layout']); // Prepare table headers $this->renderHeader(); // Assign headline/Categories $this->headline= _($this->xmlData['definition']['label']); if (!is_array($this->categories)){ $this->categories= array($this->categories); } // Evaluate columns to be exported if (isset($this->xmlData['table']['column'])){ foreach ($this->xmlData['table']['column'] as $index => $config) { if (isset($config['export']) && $config['export'] == "true"){ $this->exportColumns[]= $index; } } } return true; } function renderHeader() { $this->header= array(); $this->plainHeader= array(); // Initialize sort? $sortInit= false; if (!$this->sortDirection) { $this->sortColumn= 0; if (isset($this->xmlData['definition']['defaultSortColumn'])){ $this->sortColumn= $this->xmlData['definition']['defaultSortColumn']; } else { $this->sortAttribute= ""; } $this->sortDirection= array(); $sortInit= true; } if (isset($this->xmlData['table']['column'])){ foreach ($this->xmlData['table']['column'] as $index => $config) { // Initialize everything to one direction if ($sortInit) { $this->sortDirection[$index]= false; } $sorter= ""; if ($index == $this->sortColumn && isset($config['sortAttribute']) && isset($config['sortType'])) { $this->sortAttribute= $config['sortAttribute']; $this->sortType= $config['sortType']; $sorter= " ".image("images/lists/sort-".($this->sortDirection[$index]?"up":"down").".png", null, $this->sortDirection[$index]?_("Sort ascending"):_("Sort descending"), "text-top"); } $sortable= (isset($config['sortAttribute'])); $link= "href='?plug=".$_GET['plug']."&PID=".$this->pid."&act=SORT_$index'"; if (isset($config['label'])) { if ($sortable) { $this->header[$index]= "colprops[$index].">"._($config['label'])."$sorter"; } else { $this->header[$index]= "colprops[$index].">"._($config['label']).""; } $this->plainHeader[]= _($config['label']); } else { if ($sortable) { $this->header[$index]= "colprops[$index]."> $sorter"; } else { $this->header[$index]= "colprops[$index]."> "; } $this->plainHeader[]= ""; } } } } function render() { // Check for exeeded sizelimit if (($message= check_sizelimit()) != ""){ return($message); } // Some browsers don't have the ability do do scrollable table bodies, filter them // here. $switch= false; if (preg_match('/(Opera|Konqueror|Safari)/i', $_SERVER['HTTP_USER_AGENT'])){ $switch= true; } // Initialize list $result= "\n"; $result.= "\n"; $height= 450; if ($this->height != 0) { $result.= "\n"; $height= $this->height; } $result.= "
    \n"; $result.= "\n"; $this->numColumns= count($this->colprops) + (($this->multiSelect|$this->singleSelect)?1:0); // Build list header $result.= "\n"; if ($this->multiSelect || $this->singleSelect) { $width= "24px"; if (preg_match('/Konqueror/i', $_SERVER['HTTP_USER_AGENT'])){ $width= "28px"; } $result.= "\n"; } foreach ($this->header as $header) { $result.= $header; } $result.= "\n"; // Build list body $result.= "\n"; // No results? Just take an empty colspanned row if (count($this->entries) + count($this->departments) == 0) { $result.= ""; } // Line color alternation $alt= 0; $deps= 0; // Draw department browser if configured and we're not in sub mode $this->useSpan= false; if ($this->departmentBrowser && $this->filter->scope != "sub") { // Fill with department browser if configured this way $departmentIterator= new departmentSortIterator($this->departments, $this->sortDirection[$this->sortColumn]); foreach ($departmentIterator as $row => $entry){ $rowResult= ""; // Render multi select if needed if ($this->multiSelect || $this->singleSelect) { $rowResult.=""; } // Render defined department columns, fill the rest with some stuff $rest= $this->numColumns - 1; foreach ($this->xmlData['table']['department'] as $index => $config) { $colspan= 1; if (isset($config['span'])){ $colspan= $config['span']; $this->useSpan= true; } $rowResult.=""; $rest-= $colspan; } // Fill remaining cols with nothing $last= $this->numColumns - $rest; for ($i= 0; $i<$rest; $i++){ $rowResult.= ""; } $rowResult.=""; // Apply label to objecttype icon? if (preg_match("//i", $rowResult, $matches)){ $objectType= image($matches[1], null, LDAP::fix(base64_decode($matches[2]))); $rowResult= preg_replace("/]+>/", $objectType, $rowResult); } $result.= $rowResult; $alt++; } $deps= $alt; } // Fill with contents, sort as configured $ui = get_userinfo(); foreach ($this->entries as $row => $entry) { $trow= ""; // Render multi select if needed if ($this->multiSelect) { $trow.="\n"; } if ($this->singleSelect) { $trow.="\n"; } foreach ($this->xmlData['table']['column'] as $index => $config) { $renderedCell= $this->renderCell($config['value'], $entry, $row); $trow.="\n"; // Save rendered column $sort= preg_replace('/.*>([^<]+)<.*$/', '$1', $renderedCell); $sort= preg_replace('/ /', '', $sort); if (preg_match('/entries[$row]["_sort$index"]= $sort; } // Save rendered entry $this->entries[$row]['_rendered']= $trow; } // Complete list by sorting entries for _sort$index and appending them to the output $entryIterator= new listingSortIterator($this->entries, $this->sortDirection[$this->sortColumn], "_sort".$this->sortColumn, $this->sortType); foreach ($entryIterator as $row => $entry){ // Apply label to objecttype icon? if (preg_match("//i", $entry['_rendered'], $matches)){ if (preg_match("//i", $entry['_rendered'], $m)) { $objectType= image($matches[1]."[".$m[1]."]", null, LDAP::fix(base64_decode($matches[2]))); } else { $objectType= image($matches[1], null, LDAP::fix(base64_decode($matches[2]))); } $entry['_rendered']= preg_replace("/]+>/", $objectType, $entry['_rendered']); $entry['_rendered']= preg_replace("/]+>/", '', $entry['_rendered']); } // Apply custom class to row? if (preg_match("//i", $entry['_rendered'], $matches)) { $result.="\n"; $result.= preg_replace("/]+>/", '', $entry['_rendered']); } else { $result.="\n"; $result.= $entry['_rendered']; } $result.="\n"; $alt++; } // Need to fill the list if it's not full (nobody knows why this is 22 ;-)) $emptyListStyle= (count($this->entries) + (($this->useSpan && count($this->entries))?$deps:0) == 0)?"border:0;":""; if ((count($this->entries) + $deps) < 22) { $result.= ""; for ($i= 0; $i<$this->numColumns; $i++) { if ($i == 0) { $result.= ""; continue; } if ($i != $this->numColumns-1) { $result.= ""; } else { $result.= ""; } } $result.= ""; } // Close list body $result.= "
    "; if($this->multiSelect){ $result.= ""; }else{ $result.= " "; } $result.="
     
     colprops[$index]." class='list1'>".$this->renderCell($config['value'], $entry, $row)."colprops[$last+$i-1]." class='list1'> 
    colprops[$index]." class='list0'>".$renderedCell."
       
    "; // Add the footer if requested if ($this->showFooter) { $result.= "
    "; foreach ($this->objectTypes as $objectType) { if (isset($this->objectTypeCount[$objectType['label']])) { $label= _($objectType['label']); $result.= image($objectType['image'], null, $label)." ".$this->objectTypeCount[$objectType['label']]."  "; }elseif (isset($this->objectTypeCount[$objectType['objectClass']])) { $label= _($objectType['label']); $result.= image($objectType['image'], null, $label)." ".$this->objectTypeCount[$objectType['objectClass']]."  "; } } $result.= "
    "; } // Close list $result.= $switch?"":""; // Add scroll positioner $result.= ''; $smarty= get_smarty(); $smarty->assign("FILTER", $this->filter->render()); $smarty->assign("SIZELIMIT", print_sizelimit_warning()); $smarty->assign("LIST", $result); // Assign navigation elements $nav= $this->renderNavigation(); foreach ($nav as $key => $html) { $smarty->assign($key, $html); } // Assign action menu / base $smarty->assign("HEADLINE", $this->headline); $smarty->assign("ACTIONS", $this->renderActionMenu()); $smarty->assign("BASE", $this->renderBase()); // Assign separator $smarty->assign("SEPARATOR", "-"); // Assign summary $smarty->assign("HEADLINE", $this->headline); // Try to load template from plugin the folder first... $file = get_template_path($this->xmlData['definition']['template'], true); // ... if this fails, try to load the file from the theme folder. if(!file_exists($file)){ $file = get_template_path($this->xmlData['definition']['template']); } return ($smarty->fetch($file)); } function update() { global $config; $ui= get_userinfo(); // Take care of base selector if ($this->baseMode) { $this->baseSelector->update(); // Check if a wrong base was supplied if(!$this->baseSelector->checkLastBaseUpdate()){ msg_dialog::display(_("Error"), msgPool::check_base(), ERROR_DIALOG); } } // Save base $refresh= false; if ($this->baseMode) { $this->base= $this->baseSelector->getBase(); session::global_set("CurrentMainBase", $this->base); $refresh= true; } // Reset object counter / DN mapping $this->objectTypeCount= array(); $this->objectDnMapping= array(); // Do not do anything if this is not our PID if($refresh || !(isset($_REQUEST['PID']) && $_REQUEST['PID'] != $this->pid)) { // Save position if set if (isset($_POST['position_'.$this->pid]) && is_numeric($_POST['position_'.$this->pid])) { $this->scrollPosition= get_post('position_'.$this->pid); } // Override the base if we got a message from the browser navigation if ($this->departmentBrowser && isset($_GET['act'])) { if (preg_match('/^department_([0-9]+)$/', validate($_GET['act']), $match)){ if (isset($this->departments[$match[1]])){ $this->base= $this->departments[$match[1]]['dn']; if ($this->baseMode) { $this->baseSelector->setBase($this->base); } session::global_set("CurrentMainBase", $this->base); } } } // Filter POST with "act" attributes -> posted from action menu if (isset($_POST['exec_act']) && $_POST['act'] != '') { if (preg_match('/^export.*$/', $_POST['act']) && isset($this->exporter[$_POST['act']])) { $exporter= $this->exporter[get_post('act')]; $userinfo= ", "._("created by")." ".$ui->cn." - ".strftime('%A, %d. %B %Y, %H:%M:%S'); $entryIterator= new listingSortIterator($this->entries, $this->sortDirection[$this->sortColumn], "_sort".$this->sortColumn, $this->sortType); $sortedEntries= array(); foreach ($entryIterator as $entry){ $sortedEntries[]= $entry; } $instance= new $exporter['class']($this->headline.$userinfo, $this->plainHeader, $sortedEntries, $this->exportColumns); $type= call_user_func(array($exporter['class'], "getInfo")); $type= $type[get_post('act')]; send_binary_content($instance->query(), $type['filename'], $type= $type['mime']); } } // Filter GET with "act" attributes if (isset($_GET['act'])) { $key= validate($_GET['act']); if (preg_match('/^SORT_([0-9]+)$/', $key, $match)) { // Switch to new column or invert search order? $column= $match[1]; if ($this->sortColumn != $column) { $this->sortColumn= $column; } else { $this->sortDirection[$column]= !$this->sortDirection[$column]; } // Allow header to update itself according to the new sort settings $this->renderHeader(); } } // Override base if we got signals from the navigation elements $action= ""; foreach ($_POST as $key => $value) { if (preg_match('/^(ROOT|BACK|HOME)(_x)?$/', $key, $match)) { $action= $match[1]; break; } } // Navigation handling if ($action == 'ROOT') { $deps= $ui->get_module_departments($this->categories); $this->base= $deps[0]; $this->baseSelector->setBase($this->base); session::global_set("CurrentMainBase", $this->base); } if ($action == 'BACK') { $deps= $ui->get_module_departments($this->categories); $base= preg_replace("/^[^,]+,/", "", $this->base); if(in_array_ics($base, $deps)){ $this->base= $base; $this->baseSelector->setBase($this->base); session::global_set("CurrentMainBase", $this->base); } } if ($action == 'HOME') { $ui= get_userinfo(); $this->base= get_base_from_people($ui->dn); $this->baseSelector->setBase($this->base); session::global_set("CurrentMainBase", $this->base); } } // Reload departments if ($this->departmentBrowser){ $this->departments= $this->getDepartments(); } // Update filter and refresh entries $this->filter->setBase($this->base); $this->entries= $this->filter->query(); // Check entry acls if(!$this->noAclChecks){ foreach($this->entries as $row => $entry){ $acl = ""; $found = false; foreach($this->aclToObjectClass as $category => $ocs){ if(count(array_intersect($ocs, $entry['objectClass']))){ $acl .= $ui->get_permissions($entry['dn'],$category, 0); $found = true; } } if(!preg_match("/r/", $acl) && $found){ unset($this->entries[$row]); continue; } } } // Fix filter if querie returns NULL if ($this->entries == null) { $this->entries= array(); } } function setBase($base) { $this->base= $base; if ($this->baseMode) { $this->baseSelector->setBase($this->base); } } function getBase() { return $this->base; } function parseLayout($layout) { $result= array(); $layout= preg_replace("/^\|/", "", $layout); $layout= preg_replace("/\|$/", "", $layout); $cols= explode("|", $layout); foreach ($cols as $index => $config) { if ($config != "") { $res= ""; $components= explode(';', $config); foreach ($components as $part) { if (preg_match("/^r$/", $part)) { $res.= "text-align:right;"; continue; } if (preg_match("/^l$/", $part)) { $res.= "text-align:left;"; continue; } if (preg_match("/^c$/", $part)) { $res.= "text-align:center;"; continue; } if (preg_match("/^[0-9]+(|px|%)$/", $part)) { $res.= "width:$part;min-width:$part;"; continue; } } // Add minimum width for scalable columns if (!preg_match('/width:/', $res)){ $res.= "min-width:200px;"; } $result[$index]= " style='$res'"; } else { $result[$index]= " style='min-width:100px;'"; } } // Save number of columns for later use $this->numColumns= count($cols); // Add no border to the last column $result[$this->numColumns-1]= preg_replace("/'$/", "border-right:0;'", $result[$this->numColumns-1]); return $result; } function renderCell($data, $config, $row) { // Replace flat attributes in data string for ($i= 0; $i<$config['count']; $i++) { $attr= $config[$i]; $value= ""; if (is_array($config[$attr])) { $value= $config[$attr][0]; } else { $value= $config[$attr]; } $data= preg_replace("/%\{$attr\}/", $value, $data); } // Watch out for filters and prepare to execute them $data= $this->processElementFilter($data, $config, $row); // Replace all non replaced %{...} instances because they // are non resolved attributes or filters $data= preg_replace('/%{[^}]+}/', ' ', $data); return $data; } function renderBase() { if (!$this->baseMode) { return; } return $this->baseSelector->render(); } function processElementFilter($data, $config, $row) { preg_match_all("/%\{filter:([^(]+)\((.*)\)\}/", $data, $matches, PREG_SET_ORDER); foreach ($matches as $match) { $cl= ""; $method= ""; if (preg_match('/::/', $match[1])) { $cl= preg_replace('/::.*$/', '', $match[1]); $method= preg_replace('/^.*::/', '', $match[1]); } else { if (!isset($this->filters[$match[1]])) { continue; } $cl= preg_replace('/::.*$/', '', $this->filters[$match[1]]); $method= preg_replace('/^.*::/', '', $this->filters[$match[1]]); } // Prepare params for function call $params= array(); preg_match_all('/"[^"]+"|[^,]+/', $match[2], $parts); foreach ($parts[0] as $param) { // Row is replaced by the row number if ($param == "row") { $params[]= $row; continue; } // pid is replaced by the current PID if ($param == "pid") { $params[]= $this->pid; continue; } // base is replaced by the current base if ($param == "base") { $params[]= $this->getBase(); continue; } // Fixie with "" is passed directly if (preg_match('/^".*"$/', $param)){ $params[]= preg_replace('/"/', '', $param); continue; } // Move dn if needed if ($param == "dn") { $params[]= LDAP::fix($config["dn"]); continue; } // LDAP variables get replaced by their objects for ($i= 0; $i<$config['count']; $i++) { if ($param == $config[$i]) { $values= $config[$config[$i]]; if (is_array($values)){ unset($values['count']); } $params[]= $values; break; } } } // Replace information if ($cl == "listing") { // Non static call - seems to result in errors $data= @preg_replace('/'.preg_quote($match[0]).'/', call_user_func_array(array($this, "$method"), $params), $data); } else { // Static call $data= preg_replace('/'.preg_quote($match[0]).'/', call_user_func_array(array($cl, $method), $params), $data); } } return $data; } function getObjectType($types, $classes) { // Walk thru types and see if there's something matching foreach ($types as $objectType) { $ocs= $objectType['objectClass']; if (!is_array($ocs)){ $ocs= array($ocs); } $found= true; foreach ($ocs as $oc){ if (preg_match('/^!(.*)$/', $oc, $match)) { $oc= $match[1]; if (in_array_strict($oc, $classes)) { $found= false; } } else { if (!in_array_strict($oc, $classes)) { $found= false; } } } if ($found) { return $objectType; } } return null; } function filterObjectType($dn, $classes) { // Walk thru classes and return on first match $result= " "; $objectType= $this->getObjectType($this->objectTypes, $classes); if ($objectType) { $this->objectDnMapping[$dn]= $objectType["objectClass"]; $result= ""; if (!isset($this->objectTypeCount[$objectType['label']])) { $this->objectTypeCount[$objectType['label']]= 0; } $this->objectTypeCount[$objectType['label']]++; } return $result; } function filterActions($dn, $row, $classes) { // Do nothing if there's no menu defined if (!isset($this->xmlData['actiontriggers']['action'])) { return " "; } // Go thru all actions $result= ""; $actions= $this->xmlData['actiontriggers']['action']; // Ensure we've a valid actions array, if there is only one action in the actiontriggers col // then we've to create a valid array here. if(isset($actions['name'])) $actions = array($actions); foreach($actions as $action) { // Skip the entry completely if there's no permission to execute it if (!$this->hasActionPermission($action, $dn, $classes)) { $result.= image('images/empty.png'); continue; } // Skip entry if the pseudo filter does not fit if (isset($action['filter']) && preg_match('/^[a-z0-9_]+!?=[a-z0-9_]+$/i', $action['filter'])) { list($fa, $fv)= explode('=', $action['filter']); if (preg_match('/^(.*)!$/', $fa, $m)){ $fa= $m[1]; if (isset($this->entries[$row][$fa]) && $this->entries[$row][$fa][0] == $fv) { $result.= image('images/empty.png'); continue; } } else { if (!isset($this->entries[$row][$fa]) && !$this->entries[$row][$fa][0] == $fv) { $result.= image('images/empty.png'); continue; } } } // If there's an objectclass definition and we don't have it // add an empty picture here. if (isset($action['objectclass'])){ $objectclass= $action['objectclass']; if (preg_match('/^!(.*)$/', $objectclass, $m)){ $objectclass= $m[1]; if(in_array_strict($objectclass, $classes)) { $result.= image('images/empty.png'); continue; } } elseif (is_string($objectclass)) { if(!in_array_strict($objectclass, $classes)) { $result.= image('images/empty.png'); continue; } } elseif (is_array($objectclass)) { if(count(array_intersect($objectclass, $classes)) != count($objectclass)){ $result.= image('images/empty.png'); continue; } } } // Render normal entries as usual if ($action['type'] == "entry") { $label= $this->processElementFilter($action['label'], $this->entries[$row], $row); $image= $this->processElementFilter($action['image'], $this->entries[$row], $row); $result.= image($image, "listing_".$action['name']."_$row", $label); } // Handle special types if ($action['type'] == "copypaste" || $action['type'] == "snapshot") { $objectType= $this->getObjectType($this->objectTypes, $this->entries[$row]['objectClass']); $category= $class= null; if ($objectType) { $category= $objectType['category']; $class= $objectType['class']; } if ($action['type'] == "copypaste") { $copy = !isset($action['copy']) || $action['copy'] == "true"; $cut = !isset($action['cut']) || $action['cut'] == "true"; $result.= $this->renderCopyPasteActions($row, $this->entries[$row]['dn'], $category, $class,$copy,$cut); } else { $result.= $this->renderSnapshotActions($row, $this->entries[$row]['dn'], $category, $class); } } } return $result; } function filterDepartmentLink($row, $dn, $description) { $attr= $this->departments[$row]['sort-attribute']; $name= $this->departments[$row][$attr]; if (is_array($name)){ $name= $name[0]; } $result= sprintf("%s [%s]", $name, $description[0]); return("pid&act=department_$row' title='$dn'>".set_post($result).""); } function filterLink() { $result= " "; $row= func_get_arg(0); $pid= $this->pid; // Prepare title attribute $titleAttr = func_get_arg(1); if(is_array($titleAttr) && isset($titleAttr[0])){ $titleAttr = $titleAttr[0]; } $titleAttr = LDAP::fix($titleAttr); $params= array(func_get_arg(2)); // Collect sprintf params for ($i = 3;$i < func_num_args();$i++) { $val= func_get_arg($i); if (is_array($val)){ $params[]= $val[0]; continue; } $params[]= $val; } $result= " "; $trans= call_user_func_array("sprintf", $params); if ($trans != "") { return("".set_post($trans).""); } return $result; } function renderNavigation() { $result= array(); $enableBack = true; $enableRoot = true; $enableHome = true; $ui = get_userinfo(); /* Check if base = first available base */ $deps = $ui->get_module_departments($this->categories); if(!count($deps) || $deps[0] == $this->filter->base){ $enableBack = false; $enableRoot = false; } $listhead =""; /* Check if we are in users home department */ if(!count($deps) || $this->filter->base == get_base_from_people($ui->dn)){ $enableHome = false; } /* Draw root button */ if($enableRoot){ $result["ROOT"]= image('images/lists/root.png', 'ROOT', _("Root")); }else{ $result["ROOT"]= image('images/lists/root-grey.png', null, _("Root")); } /* Draw back button */ if($enableBack){ $result["BACK"]= image('images/lists/back.png', 'BACK', _("Go to preceding level")); }else{ $result["BACK"]= image('images/lists/back-grey.png', null, _("Go to preceding level")); } /* Draw home button */ /* Draw home button */ if($enableHome){ $result["HOME"]= image('images/lists/home.png', 'HOME', _("Go to current users level")); }else{ $result["HOME"]= image('images/lists/home-grey.png', null, _("Go to current users level")); } /* Draw reload button, this button is enabled everytime */ $result["RELOAD"]= image('images/lists/reload.png', 'REFRESH', _("Reload list")); return ($result); } function getAction() { // Do not do anything if this is not our PID, or there's even no PID available... if(!isset($_REQUEST['PID']) || $_REQUEST['PID'] != $this->pid) { return; } // Save position if set if (isset($_POST['position_'.$this->pid]) && is_numeric($_POST['position_'.$this->pid])) { $this->scrollPosition= get_post('position_'.$this->pid); } $result= array("targets" => array(), "action" => ""); // Filter GET with "act" attributes if (isset($_GET['act'])) { $key= validate($_GET['act']); $target= preg_replace('/^listing_[a-zA-Z_]+_([0-9]+)$/', '$1', $key); if (isset($this->entries[$target]['dn'])) { $result['action']= preg_replace('/^listing_([a-zA-Z_]+)_[0-9]+$/', '$1', $key); $result['targets'][]= $this->entries[$target]['dn']; } // Drop targets if empty if (count($result['targets']) == 0) { unset($result['targets']); } return $result; } // Get single selection (radio box) if($this->singleSelect && isset($_POST['listing_radio_selected'])){ $entry = get_post('listing_radio_selected'); $result['targets']= array($this->entries[$entry]['dn']); } // Filter POST with "listing_" attributes foreach ($_POST as $key => $prop) { $prop = get_post($key); // Capture selections if (preg_match('/^listing_selected_[0-9]+$/', $key)) { $target= preg_replace('/^listing_selected_([0-9]+)$/', '$1', $key); if (isset($this->entries[$target]['dn'])) { $result['targets'][]= $this->entries[$target]['dn']; } continue; } // Capture action with target - this is a one shot if (preg_match('/^listing_[a-zA-Z_]+_[0-9]+(|_x)$/', $key)) { $target= preg_replace('/^listing_[a-zA-Z_]+_([0-9]+)(|_x)$/', '$1', $key); if (isset($this->entries[$target]['dn'])) { $result['action']= preg_replace('/^listing_([a-zA-Z_]+)_[0-9]+(|_x)$/', '$1', $key); $result['targets']= array($this->entries[$target]['dn']); } break; } // Capture action without target if (preg_match('/^listing_[a-zA-Z_]+(|_x)$/', $key)) { $result['action']= preg_replace('/^listing_([a-zA-Z_]+)(|_x)$/', '$1', $key); continue; } } // Filter POST with "act" attributes -> posted from action menu if (isset($_POST['act']) && $_POST['act'] != '') { if (!preg_match('/^export.*$/', $_POST['act'])){ $result['action']= get_post('act'); } } // Drop targets if empty if (count($result['targets']) == 0) { unset($result['targets']); } return $result; } function renderActionMenu() { $result= "
    "; // Don't send anything if the menu is not defined if (!isset($this->xmlData['actionmenu']['action'])){ return $result; } // Array? if (isset($this->xmlData['actionmenu']['action']['type'])){ $this->xmlData['actionmenu']['action']= array($this->xmlData['actionmenu']['action']); } // Load shortcut $actions= &$this->xmlData['actionmenu']['action']; $result.= ""; } function recurseActions($actions) { global $class_mapping; static $level= 2; $result= "
      "; $separator= ""; foreach ($actions as $action) { // Skip the entry completely if there's no permission to execute it if (!$this->hasActionPermission($action, $this->filter->base)) { continue; } // Skip entry if there're missing dependencies if (isset($action['depends'])) { $deps= is_array($action['depends'])?$action['depends']:array($action['depends']); foreach($deps as $clazz) { if (!isset($class_mapping[$clazz])){ continue 2; } } } // Fill image if set $img= ""; if (isset($action['image'])){ $img= image($action['image'])." "; } if ($action['type'] == "separator"){ $separator= " style='border-top:1px solid #AAA' "; continue; } // Dive into subs if ($action['type'] == "sub" && isset($action['action'])) { $level++; if (isset($action['label'])){ $result.= "$img"._($action['label'])." ".image('images/forward-arrow.png').""; } // Ensure we've an array of actions, this enables sub menus with only one action. if(isset($action['action']['type'])){ $action['action'] = array($action['action']); } $result.= $this->recurseActions($action['action']).""; $level--; $separator= ""; continue; } // Render entry elseways if (isset($action['label'])){ $result.= "$img"._($action['label']).""; } // Check for special types switch ($action['type']) { case 'copypaste': $cut = !isset($action['cut']) || $action['cut'] != "false"; $copy = !isset($action['copy']) || $action['copy'] != "false"; $result.= $this->renderCopyPasteMenu($separator, $copy , $cut); break; case 'snapshot': $result.= $this->renderSnapshotMenu($separator); break; case 'exporter': $result.= $this->renderExporterMenu($separator); break; case 'daemon': $result.= $this->renderDaemonMenu($separator); break; } $separator= ""; } $result.= "
    "; return $result; } function hasActionPermission($action, $dn, $classes= null) { $ui= get_userinfo(); if (isset($action['acl'])) { $acls= $action['acl']; if (!is_array($acls)) { $acls= array($acls); } // Every ACL has to pass foreach ($acls as $acl) { $module= $this->categories; $aclList= array(); // Replace %acl if available if ($classes) { $otype= $this->getObjectType($this->objectTypes, $classes); $acl= str_replace('%acl', $otype['category']."/".$otype['class'], $acl); } // Split for category and plugins if needed // match for "[rw]" style entries if (preg_match('/^\[([rwcdm]+)\]$/', $acl, $match)){ $aclList= array($match[1]); } // match for "users[rw]" style entries if (preg_match('/^([a-zA-Z0-9]+)\[([rwcdm]+)\]$/', $acl, $match)){ $module= $match[1]; $aclList= array($match[2]); } // match for "users/user[rw]" style entries if (preg_match('/^([a-zA-Z0-9]+\/[a-zA-Z0-9]+)\[([rwcdm]+)\]$/', $acl, $match)){ $module= $match[1]; $aclList= array($match[2]); } // match "users/user[userPassword:rw(,...)*]" style entries if (preg_match('/^([a-zA-Z0-9]+\/[a-zA-Z0-9]+)\[([a-zA-Z0-9]+:[rwcdm]+(,[a-zA-Z0-9]+:[rwcdm]+)*)\]$/', $acl, $match)){ $module= $match[1]; $aclList= explode(',', $match[2]); } // Walk thru prepared ACL by using $module foreach($aclList as $sAcl) { $checkAcl= ""; // Category or detailed permission? if (strpos($module, '/') !== false) { if (preg_match('/([a-zA-Z0-9]+):([rwcdm]+)/', $sAcl, $m) ) { $checkAcl= $ui->get_permissions($dn, $module, $m[1]); $sAcl= $m[2]; } else { $checkAcl= $ui->get_permissions($dn, $module, '0'); } } else { $checkAcl= $ui->get_category_permissions($dn, $module); } // Split up remaining part of the acl and check if it we're // allowed to do something... $parts= str_split($sAcl); foreach ($parts as $part) { if (strpos($checkAcl, $part) === false){ return false; } } } } } return true; } function refreshBasesList() { global $config; $ui= get_userinfo(); // Do some array munching to get it user friendly $ids= $config->idepartments; $d= $ui->get_module_departments($this->categories); $k_ids= array_keys($ids); $deps= array_intersect($d,$k_ids); // Fill internal bases list $this->bases= array(); foreach($k_ids as $department){ $this->bases[$department] = $ids[$department]; } // Populate base selector if already present if ($this->baseSelector && $this->baseMode) { $this->baseSelector->setBases($this->bases); $this->baseSelector->update(TRUE); } } function getDepartments() { $departments= array(); $ui= get_userinfo(); // Get list of supported department types $types = departmentManagement::get_support_departments(); // Load departments allowed by ACL $validDepartments = $ui->get_module_departments($this->categories); // Build filter and look in the LDAP for possible sub departments // of current base $filter= "(&(objectClass=gosaDepartment)(|"; $attrs= array("description", "objectClass"); foreach($types as $name => $data){ $filter.= "(objectClass=".$data['OC'].")"; $attrs[]= $data['ATTR']; } $filter.= "))"; $res= get_list($filter, $this->categories, $this->base, $attrs, GL_NONE); // Analyze list of departments foreach ($res as $department) { if (!in_array_strict($department['dn'], $validDepartments)) { continue; } // Add the attribute where we use for sorting $oc= null; foreach(array_keys($types) as $type) { if (in_array_strict($type, $department['objectClass'])) { $oc= $type; break; } } $department['sort-attribute']= $types[$oc]['ATTR']; // Move to the result list $departments[]= $department; } return $departments; } function renderCopyPasteMenu($separator, $copy= true, $cut= true) { // We can only provide information if we've got a copypaste handler // instance if(!(isset($this->copyPasteHandler) && is_object($this->copyPasteHandler))){ return ""; } // Presets $result= ""; $read= $paste= false; $ui= get_userinfo(); // Switch flags to on if there's at least one category which allows read/paste foreach($this->categories as $category){ $read= $read || preg_match('/r/', $ui->get_category_permissions($this->base, $category)); $paste= $paste || $ui->is_pasteable($this->base, $category) == 1; } // Draw entries that allow copy and cut if($read){ // Copy entry if($copy){ $result.= "".image('images/lists/copy.png')." "._("Copy").""; $separator= ""; } // Cut entry if($cut){ $result.= "".image("images/lists/cut.png")." "._("Cut").""; $separator= ""; } } // Draw entries that allow pasting entries if($paste){ if($this->copyPasteHandler->entries_queued()){ $result.= "".image("images/lists/paste.png")." "._("Paste").""; }else{ $result.= "".image('images/lists/paste-grey.png')." "._("Paste").""; } } return($result); } function renderCopyPasteActions($row, $dn, $category, $class, $copy= true, $cut= true) { // We can only provide information if we've got a copypaste handler // instance if(!(isset($this->copyPasteHandler) && is_object($this->copyPasteHandler))){ return ""; } // Presets $ui = get_userinfo(); $result = ""; // Render cut entries if($cut){ if($ui->is_cutable($dn, $category, $class)){ $result.= image('images/lists/cut.png', "listing_cut_$row", _("Cut this entry")); }else{ $result.= image('images/empty.png'); } } // Render copy entries if($copy){ if($ui->is_copyable($dn, $category, $class)){ $result.= image('images/lists/copy.png', "listing_copy_$row", _("Copy this entry")); }else{ $result.= image('images/empty.png'); } } return($result); } function renderSnapshotMenu($separator) { // We can only provide information if we've got a snapshot handler // instance if(!(isset($this->snapshotHandler) && is_object($this->snapshotHandler))){ return ""; } // Presets $result = ""; $ui = get_userinfo(); if($this->snapshotHandler->enabled() && $ui->allow_snapshot_restore($this->base, $this->categories)){ // Check if there is something to restore $restore= false; foreach($this->snapshotHandler->getSnapshotBases() as $base){ $restore= $restore || count($this->snapshotHandler->getDeletedSnapshots($base)) > 0; } // Draw icons according to the restore flag if($restore){ $result.= "".image('images/lists/restore.png')." "._("Restore snapshots").""; }else{ $result.= "".image('images/lists/restore-grey.png')." "._("Restore snapshots").""; } } return($result); } function renderExporterMenu($separator) { // Presets $result = ""; // Draw entries $result.= "".image('images/lists/export.png')." "._("Export list")." ".image("images/forward-arrow.png").""; return($result); } function renderSnapshotActions($row, $dn, $category, $class, $copy= true, $cut= true) { // We can only provide information if we've got a snapshot handler // instance if(!(isset($this->snapshotHandler) && is_object($this->snapshotHandler))){ return ""; } // Presets $result= ""; $ui = get_userinfo(); // Only act if enabled here if($this->snapshotHandler->enabled()){ // Draw restore button if ($ui->allow_snapshot_restore($dn, $category)){ // Do we have snapshots for this dn? if($this->snapshotHandler->hasSnapshots($dn)){ $result.= image('images/lists/restore.png', "listing_restore_$row", _("Restore snapshot")); } else { $result.= image('images/lists/restore-grey.png'); } } // Draw snapshot button if($ui->allow_snapshot_create($dn, $category)){ $result.= image('images/snapshot.png', "listing_snapshot_$row", _("Create new snapshot for this object")); }else{ $result.= image('images/empty.png'); } } return($result); } function renderDaemonMenu($separator) { $result= ""; // If there is a daemon registered, draw the menu entries if(class_available("DaemonEvent")){ $events= DaemonEvent::get_event_types_by_category($this->categories); if(isset($events['BY_CLASS']) && count($events['BY_CLASS'])){ foreach($events['BY_CLASS'] as $name => $event){ $result.= "".$event['MenuImage']." ".$event['s_Menu_Name'].""; $separator= ""; } } } return $result; } function getEntry($dn) { foreach ($this->entries as $entry) { if (isset($entry['dn']) && strcasecmp($dn, $entry['dn']) == 0){ return $entry; } } return null; } function getEntries() { return $this->entries; } function getType($dn) { $dn = LDAP::fix($dn); if (isset($this->objectDnMapping[$dn])) { return $this->objectDnMapping[$dn]; } return null; } } ?> gosa-core-2.7.4/include/class_sortableListing.inc0000644000175000017500000004766011656430600021065 0ustar cajuscajussetListData($data, $displayData); // Get list of used IDs if(!session::is_set('sortableListing_USED_IDS')){ session::set('sortableListing_USED_IDS',array()); } $usedIds = session::get('sortableListing_USED_IDS'); // Generate instance wide unique ID $id = ""; while($id == "" || in_array_strict($id, $usedIds)){ // Wait 1 msec to ensure that we definately get a new id if($id != "") usleep(1); $tmp= gettimeofday(); $id = 'l'.md5(microtime().$tmp['sec']); } // Only keep the last 10 list IDsi $usedIds = array_slice($usedIds, count($usedIds) -10, 10); $usedIds[] = $id; session::set('sortableListing_USED_IDS',$usedIds); $this->id = $id; // Set reorderable flag $this->reorderable= $reorderable; if (!$reorderable) { $this->sortData(); } } public function setReorderable($bool) { $this->reorderable= $bool; } public function setDefaultSortColumn($id) { $this->sortColumn = $id; } /* * * Examples * DatenARray ($data) * @param: array( arbitrary object, arbitrary object) * Datenarray will be manipulated by add, del and sort operations. According to this it will be returned from this widget. * The index of a data entry must correspond to the entry of the "display array" following. * DisplayArray ($displyData) * @param: array("eins" array( "data"=> array("Uno", "2", "x" ) , "zwei" array( "data"=> array("Due", "3", "y" ))) ; * label pointing on a list of columns that will be shown in the list. */ public function setListData($data, $displayData= null) { // Save data to display $this->setData($data); if (!$displayData) { $displayData= array(); foreach ($data as $key => $value) { $displayData[$key]= array("data" => array($value)); } } $this->setDisplayData($displayData); } //setting flat data private function setData($data) { $this->data= $data; } // collecting the display data - private function setDisplayData($data) { if (!is_array($data)) { trigger_error ("sortableList needs an array as data!"); } // Transfer information $this->displayData= array(); $this->modes= array(); $this->mapping= array(); foreach ($data as $key => $value) { $this->displayData[]= $value['data']; if (isset($value['mode'])) { $this->modes[]= $value['mode']; } } $this->keys= array_keys($data); // Create initial mapping if(count($this->keys)){ $this->mapping= range(0, abs(count($this->keys)-1)); } $this->current_mapping= $this->mapping; // Find the number of coluns reset($this->displayData); $first= current($this->displayData); if (is_array($first)) { $this->columns= count($first); } else { $this->columns= 1; } // Preset sort orders to 'down' for ($column= 0; $column<$this->columns; $column++) { if(!isset($this->sortDirection[$column])){ $this->sortDirection[$column]= true; } } } public function setWidth($width) { $this->width= $width; } public function setInstantDelete($flag) { $this->instantDelete= $flag; } public function setColorAlternate($flag) { $this->colorAlternate= $flag; } public function setEditable($flag) { $this->editable= $flag; } public function setDeleteable($flag) { $this->deleteable= $flag; } public function setHeight($height) { $this->height= $height; } public function setCssClass($css) { $this->cssclass= $css; } public function setHeader($header) { $this->header= $header; } public function setColspecs($specs) { $this->colspecs= $specs; } public function render() { $result= "
    \n"; $result.= "cssclass)?" class='".$this->cssclass."'":"").">\n"; $action_width= 0; if (strpos($this->acl, 'w') === false) { $edit_image= $this->editable?image("images/lists/edit-grey.png"):""; } else { $edit_image= $this->editable?image('images/lists/edit.png', "%ID", _("Edit this entry")):""; } if (strpos($this->acl, 'w') === false) { $delete_image= $this->deleteable?image('images/lists/trash-grey.png'):""; } else { $delete_image= $this->deleteable?image('images/lists/trash.png', "%ID", _("Delete this entry")):""; } // Do we need colspecs? $action_width= ($this->editable?30:0) + ($this->deleteable?30:0); if ($this->colspecs) { $result.= " \n"; for ($i= 0; $i<$this->columns; $i++) { if(isset($this->colspecs[$i]) && $this->colspecs[$i] != '*'){ $result.= " \n"; }else{ $result.= " \n"; } } // Extend by another column if we've actions specified if ($action_width) { $result.= " \n"; } $result.= " \n"; } // Do we need a header? if ($this->header) { $result.= " \n \n"; $first= " style='border-left:0'"; for ($i= 0; $i<$this->columns; $i++) { $link= "href='?plug=".$_GET['plug']."&PID=".$this->id."&act=SORT_$i'"; $sorter= ""; if ($i == $this->sortColumn){ $sorter= " ".image("images/lists/sort-".($this->sortDirection[$i]?"up":"down").".png", null, $this->sortDirection[$i]?_("Sort ascending"):_("Sort descending")); } if ($this->reorderable) { $result.= " ".(isset($this->header[$i])?$this->header[$i]:"").""; } else { $result.= " ".(isset($this->header[$i])?$this->header[$i]:"")."$sorter"; } $first= ""; } if ($action_width) { $result.= ""; } $result.= "\n \n \n"; } // Render table body if we've read permission $result.= " \n"; $reorderable= $this->reorderable?"":" style='cursor:default'"; if (strpos($this->acl, 'r') !== false) { foreach ($this->mapping as $nr => $row) { $editable= $this->editable?" onClick='$(\"edit_".$this->id."_$nr\").click()'":""; $id= ""; if (isset($this->modes[$row])) { switch ($this->modes[$row]) { case LIST_DISABLED: $id= " sortableListItemDisabled"; $editable= ""; break; case LIST_MARKED: $id= " sortableListItemMarked"; break; } } $result.= " \n"; $first= " style='border:0'"; foreach ($this->displayData[$row] as $column) { // Do NOT use the onClick statement for columns that contain links or buttons. if(preg_match("<.*type=.submit..*>", $column) || preg_match("", $column)){ $result.= " ".$column."\n"; }else{ $result.= " ".$column."\n"; } $first= ""; } if ($action_width) { $result.= ""; } $result.= " \n"; } } // Add spacer $result.= " "; $num= $action_width?$this->columns:$this->columns-1; for ($i= 0; $i<$num; $i++) { $result.= ""; } $result.= "\n"; $result.= " \n
     
    ".str_replace('%ID', "edit_".$this->id."_$nr", $edit_image). str_replace('%ID', "del_".$this->id."_$nr", $delete_image)."
    \n
    \n"; # $result.= " \n"; $result.= " \n"; $result.= " \n"; // Append script stuff if needed $result.= ''; return $result; } public function update() { // Filter GET with "act" attributes if (!$this->reorderable){ if(isset($_GET['act']) && isset($_GET['PID']) && $this->id == $_GET['PID']) { $key= validate($_GET['act']); if (preg_match('/^SORT_([0-9]+)$/', $key, $match)) { // Switch to new column or invert search order? $column= $match[1]; if ($this->sortColumn != $column) { $this->sortColumn= $column; } else { $this->sortDirection[$column]= !$this->sortDirection[$column]; } } } // Update mapping according to sort parameters $this->sortData(); } } public function save_object() { // Do not do anything if this is not our PID, or there's even no PID available... if(isset($_REQUEST['PID']) && $_REQUEST['PID'] != $this->id) { return; } // Do not do anything if we're not posted - or have no permission if (strpos($this->acl, 'w') !== false && isset($_POST['reorder_'.$this->id])){ if (isset($_POST['position_'.$this->id]) && is_numeric($_POST['position_'.$this->id])) { $this->scrollPosition= get_post('position_'.$this->id); } // Move requested? $move= get_post('reorder_'.$this->id); if ($move != "") { preg_match_all('/=([0-9]+)[&=]/', $move, $matches); $this->action= "reorder"; $tmp= array(); foreach ($matches[1] as $id => $row) { $tmp[$id]= $this->mapping[$row]; } $this->mapping= $tmp; $this->current_mapping= $matches[1]; $this->modified= true; return; } } // Delete requested? $this->action = ""; if (strpos($this->acl, 'd') !== false){ foreach ($_POST as $key => $value) { $value = get_post($key); if (preg_match('/^del_'.$this->id.'_([0-9]+)$/', $key, $matches)) { if(!isset($this->mapping[$matches[1]])) return; $this->active_index= $this->mapping[$matches[1]]; // Ignore request if mode requests it if (isset($this->modes[$this->active_index]) && $this->modes[$this->active_index] == LIST_DISABLED) { $this->active_index= null; continue; } // Set action $this->action= "delete"; // Remove value if requested if ($this->instantDelete) { $this->deleteEntry($this->active_index); } } } } // Edit requested? if (strpos($this->acl, 'w') !== false){ foreach ($_POST as $key => $value) { $value = get_post($key); if (preg_match('/^edit_'.$this->id.'_([0-9]+)$/', $key, $matches)) { if(!isset($this->mapping[$matches[1]])) return; $this->active_index= $this->mapping[$matches[1]]; // Ignore request if mode requests it if (isset($this->modes[$this->active_index]) && $this->modes[$this->active_index] == LIST_DISABLED) { $this->active_index= null; continue; } $this->action= "edit"; } } } } public function getAction() { // Do not do anything if we're not posted if(!isset($_POST['reorder_'.$this->id])) { return; } // For reordering, return current mapping if ($this->action == 'reorder') { return array("targets" => $this->current_mapping, "mapping" => $this->mapping, "action" => $this->action); } // Edit and delete $result= array("targets" => array($this->active_index), "action" => $this->action); return $result; } public function deleteEntry($id) { // Remove mapping $index= array_search($id, $this->mapping); if ($index !== false) { $target = $this->mapping[$index]; $key = $this->keys[$target]; unset($this->mapping[$index]); if(isset($this->displayData[$target])){ unset($this->displayData[$target]); unset($this->data[$key]); unset($this->keys[$target]); } $this->mapping= array_values($this->mapping); $this->modified= true; } } public function getMaintainedData() { $tmp= array(); foreach ($this->mapping as $src => $dst) { $realKey = $this->keys[$dst]; $tmp[$realKey] = $this->data[$realKey]; } return $tmp; } public function isModified() { return $this->modified; } public function setAcl($acl) { $this->acl= $acl; } public function sortingEnabled($bool = TRUE) { $this->sortingEnabled= $bool; } public function sortData() { if(!$this->sortingEnabled || !count($this->data)) return; // Extract data $tmp= array(); foreach($this->displayData as $key => $item) { if (isset($item[$this->sortColumn])){ $tmp[$key]= $item[$this->sortColumn]; } else { $tmp[$key]= ""; } } // Sort entries if ($this->sortDirection[$this->sortColumn]) { asort($tmp); } else { arsort($tmp); } // Adapt mapping accordingly $this->mapping= array(); foreach ($tmp as $key => $value) { $this->mapping[]= $key; } } public function addEntry($entry, $displayEntry= null, $key= null) { // Only add if not already there if (!$key) { if (in_array_strict($entry, $this->data)) { return; } } else { if (isset($this->data[$key])) { return; } } // Prefill with default value if not specified if (!$displayEntry) { $displayEntry= array('data' => array($entry)); } // Append to data and mapping $this->displayData[]= $displayEntry['data']; $this->mapping[]= max(array_keys($this->displayData)); $this->modified= true; if ($key) { $this->data[$key]= $entry; $this->keys[]= $key; } else { $this->data[]= $entry; $this->keys[]= max(array_keys($this->displayData)); } // Find the number of coluns reset($this->displayData); $first= current($this->displayData); if (is_array($first)) { $this->columns= count($first); } else { $this->columns= 1; } // Preset sort orders to 'down' for ($column= 0; $column<$this->columns; $column++) { if(!isset($this->sortDirection[$column])){ $this->sortDirection[$column]= true; } } // Sort data after we've added stuff $this->sortData(); } public function getKey($index) { return isset($this->keys[$index])?$this->keys[$index]:null; } public function getData($index) { $realkey = $this->keys[$index]; return($this->data[$realkey]); } } gosa-core-2.7.4/include/class_releaseSelector.inc0000644000175000017500000002454411613731145021036 0ustar cajuscajuspid= preg_replace("/[^0-9]/", "", microtime(TRUE)); // Get list of used IDs if(!session::is_set('releaseSelector_USED_IDS')){ session::set('releaseSelector_USED_IDS',array()); } $usedIds = session::get('releaseSelector_USED_IDS'); // Generate instance wide unique ID $pid = ""; while($pid == "" || in_array_strict($pid, $usedIds)){ // Wait 1 msec to ensure that we definately get a new id if($pid != "") usleep(1); $tmp= gettimeofday(); $pid = 'l'.md5(microtime().$tmp['sec']); } // Only keep the last 10 list IDsi $usedIds = array_slice($usedIds, count($usedIds) -10, 10); $usedIds[] = $pid; session::set('releaseSelector_USED_IDS',$usedIds); $this->pid = $pid; // Transfer data $this->releaseBase = $releaseBase; $this->setBases($bases); $this->setBase($base); } function setSubmitButton($flag) { $this->submitButton= $flag; } function setHeight($value) { $this->height= $value; } function setBase($base) { $this->base= $base; if (isset($this->pathMapping[$base])) { $this->update(true); } } function setRootBase($base) { $this->releaseBase = $base; } function checkBase($base) { return isset($this->pathMapping[$base]); } function checkLastBaseUpdate() { return $this->lastState; } function setBases($bases) { global $config; $this->releaseInfo = array(); $this->pathMapping= array(); $selected= $this->base == $this->releaseBase?"Selected":""; $first= true; $last_indent= 2; foreach ($bases as $base => $dummy) { // Build path style display $elements= explode(',', substr($base, 0, strlen($base) - strlen($this->releaseBase))); $elements= array_reverse($elements, true); $this->pathMapping[$base]= $base == $this->releaseBase? '/' : ldap::fix(preg_replace('/(^|,)[a-z0-9]+=/i', '/', implode(',', $elements))); $this->releaseInfo[$base]['name'] = ldap::fix(preg_replace('/(^|,)[a-z0-9]+=/i', '', $elements[0])); $this->releaseInfo[$base]['description'] = $dummy; } // Save bases to session for autocompletion session::global_set('pathMapping', $this->pathMapping); session::global_set('department_info', $this->releaseInfo); } function update($force= false) { global $config; // Analyze for base changes if needed $this->action= null; $last_base= $this->base; if(isset($_REQUEST["BPID_{$this->pid}"]) && $_REQUEST["BPID_{$this->pid}"] == $this->pid) { if (isset($_POST['bs_rebase_'.$this->pid]) && !empty($_POST['bs_rebase_'.$this->pid])) { $new_base= base64_decode(get_post('bs_rebase_'.$this->pid)); if (isset($this->pathMapping[$new_base])) { $this->base= $new_base; $this->action= 'rebase'; } else { $this->lastState= false; return false; } }else{ // Input field set? if (isset($_POST['bs_input_'.$this->pid])) { // Take over input field base if ($this->submitButton && isset($_POST['submit_base_'.$this->pid]) || !$this->submitButton) { // Check if base is available $this->lastState= false; foreach ($this->pathMapping as $key => $path) { if (mb_strtolower($path) == mb_strtolower(get_post('bs_input_'.$this->pid))) { $this->base= $key; $this->lastState= true; break; } } } } } } /* Skip if there's no change */ if (($this->tree && $this->base == $last_base) && !$force) { return true; } $link= "onclick=\"\$('bs_rebase_".$this->pid."').value='".base64_encode($this->releaseBase)."'; $('submit_tree_base_".$this->pid."').click();\""; $this->tree= "pid}').hide(); \" onfocus=\" \$('bs_{$this->pid}').hide(); \" onmouseover=\" mouseIsStillOver = true; function showIt() { if(mouseIsStillOver){ \$('bs_".$this->pid."').show(); } }; Element.clonePosition(\$('bs_".$this->pid."'), 'bs_input_".$this->pid."', {setHeight: false, setWidth: false, offsetTop:(Element.getHeight('bs_input_".$this->pid."'))}); rtimer=showIt.delay(0.25); \" onmouseout=\" mouseIsStillOver=false; rtimer=Element.hide.delay(0.25,'bs_".$this->pid."')\" value=\"".preg_replace('/"/','"',$this->pathMapping[$this->base])."\">"; // Autocompleter $this->tree.= "
    ". ""; $selected= $this->base == $this->releaseBase?"Selected":""; $this->tree.= "\n"; // Draw submitter if required if ($this->submitButton) { $this->tree.= image('images/lists/submit.png', "submit_base_".$this->pid, _("Submit")); } $this->tree.= ""; $this->tree.= ""; $this->tree.= ""; $this->lastState= true; return true; } function gennonbreaks($string) { return str_replace('-', '‑', str_replace(' ', ' ', $string)); } function render() { return $this->tree; } function getBase() { return $this->base; } function getAction() { // Do not do anything if this is not our BPID, or there's even no BPID available... if(!isset($_REQUEST["BPID_{$this->pid}"]) || $_REQUEST["BPID_{$this->pid}"] != $this->pid) { return; } if ($this->action) { return array("targets" => array($this->base), "action" => $this->action); } return null; } } ?> gosa-core-2.7.4/include/class_GOsaRegistration.inc0000644000175000017500000001102411470506143021125 0ustar cajuscajusconfig = $config; } function getRegistrationServer() { return($this->server); } function getConnection($user = NULL, $password ="") { if($user === NULL){ return($this->config->getRpcHandle($this->server, $this->user,$this->password, TRUE, FALSE)); }else{ return($this->config->getRpcHandle($this->server, $user,$password, TRUE, FALSE)); } } function isServerAccessible($force = FALSE) { // Only request a new status every 2 seconds if(isset($this->cache['isServerAccessible']['called']) && !$force){ if($this->cache['isServerAccessible']['called'] + 2 > time()){ return($this->cache['isServerAccessible']['result']); } } // Check the connection status by calling a dummy function $con = $this->getConnection(); $res = $con->isInstanceRegistered("dummy"); // Store the result $this->cache['isServerAccessible']['called'] = time(); $this->cache['isServerAccessible']['result'] = $con->success(); return($con->success()); } function registrationNotWanted() { // While we are registered this will always be FALSE. if($this->isInstanceRegistered()) return(FALSE); // Check if the registration process was postponed or completely(>=0) canceled (-1) $date = $this->config->configRegistry->getPropertyValue('GOsaRegistration','askForRegistration'); return($date == -1); } function registrationRequired() { if($this->isInstanceRegistered()) return(FALSE); // Seems that we haven't received an instancePassword yet, this can has two reasons: // 1. Not registered yet or registration postponed 2. We do not want to registrate our instance. $date = $this->config->configRegistry->getPropertyValue('GOsaRegistration','askForRegistration'); if($date == -1){ // We do not want to registrate return(FALSE); }else{ // Registration may be postponed. return($date < time()); } } function isInstanceRegistered() { if($this->isServerAccessible()){ // First check if the server is accessible and if the instance is registered. return($this->isInstanceRegisteredWithServer()); }else{ // Server is down, now check if we've an instancePassword set in our gosa.conf. $instancePassword = $this->config->configRegistry->getPropertyValue('GOsaRegistration','instancePassword'); return(!empty($instancePassword)); } } function isInstanceRegisteredWithServer() { $con = $this->getConnection(); $res = $con->isInstanceRegistered($this->config->getInstanceUuid()); if($con->success()){ $this->isRegistered = $res; }else{ return(FALSE); } return($this->isRegistered); } static function plInfo() { return (array( "plProperties" => array( array( "name" => "instancePassword", "type" => "string", "default" => "", "description" => "", "check" => "gosaProperty::isString", "migrate" => "", "group" => "registration", "mandatory" => FALSE), array( "name" => "askForRegistration", "type" => "integer", "default" => "0", "description" => _("UNIX-timestamp pointing to the date GOsa will ask for a registration again (-1 to disable)"), "check" => "gosaProperty::isInteger", "migrate" => "", "group" => "registration", "mandatory" => FALSE), ) ) ); } } ?> gosa-core-2.7.4/include/class_msg_dialog.inc0000644000175000017500000001635511613731145020023 0ustar cajuscajusi_ID = preg_replace("/[^0-9]*/","",microtime()); $this->s_Title = $s_title; $this->s_Message = $s_message; $this->i_Type = $i_type; /* Append trace information, only if error messages are enabled */ if( isset($config) && is_object($config) && $config->get_cfg_value("core","displayErrors") == "true" ){ $this->a_Trace = debug_backtrace(); } if(!session::is_set('msg_dialogs')){ session::set('msg_dialogs',array()); } if($this->i_Type == FATAL_ERROR_DIALOG){ restore_error_handler(); error_reporting(E_ALL); echo $this->execute(); }else{ $msg_dialogs = session::get('msg_dialogs'); $msg_dialogs[] = $this; session::set('msg_dialogs',$msg_dialogs); } } session::set('errorsAlreadyPosted',$errorsAlreadyPosted); } public static function display($s_title,$s_message,$i_type = INFO_DIALOG) { new msg_dialog($s_title,$s_message,$i_type); } public static function displayChecks($messages) { /* Assemble the message array to a plain string */ foreach ($messages as $error){ msg_dialog::display(_("Error"), $error, ERROR_DIALOG); } } public function get_ID() { return($this->i_ID); } public function execute() { if($this->i_Type == FATAL_ERROR_DIALOG) { $display = " GOsa startup failed
    {t}Error{/t} ".$this->s_Title."
    ".$this->s_Message."

    "._("Please fix the above error and reload the page.")."
    "; return($display);; }else{ $smarty = get_smarty(); $smarty->assign("s_Trace" ,print_a($this->a_Trace,TRUE)); $smarty->assign("i_TraceCnt",count($this->a_Trace)); $smarty->assign("i_Type",$this->i_Type); $smarty->assign("s_Message",$this->s_Message); $smarty->assign("s_Title",$this->s_Title); $smarty->assign("i_ID",$this->i_ID); $smarty->assign("frame",false); $smarty->assign("JS",session::global_get('js')); $smarty->assign("IE",preg_match("/MSIE/", $_SERVER['HTTP_USER_AGENT'])); return($smarty->fetch(get_template_path('msg_dialog.tpl'))); } } public function is_confirmed() { if(isset($_POST['MSG_OK'.$this->i_ID])){ return(TRUE); }else{ return(FALSE); } } public static function get_dialogs() { $return =""; $dialog_ids= ""; $seen = ""; if(isset($_POST['closed_msg_dialogs'])){ # $seen = $_POST['closed_msg_dialogs']; } if(session::is_set('msg_dialogs') && is_array(session::get('msg_dialogs')) && count(session::get('msg_dialogs'))){ /* Get frame one */ $smarty = get_smarty(); $smarty->assign("frame", true); $smarty->assign("IE",preg_match("/MSIE/", $_SERVER['HTTP_USER_AGENT'])); $return = $smarty->fetch(get_template_path('msg_dialog.tpl')); if(!session::global_get('js')){ $dialog = array_pop(session::get('msg_dialogs')); $return.= $dialog->execute(); }else{ $msg_dialogs = session::get('msg_dialogs'); foreach($msg_dialogs as $key => $dialog){ if(preg_match("/".$dialog->get_ID()."/",$seen)){ unset($msg_dialogs[$key]); }else{ $return.= $dialog->execute(); $dialog_ids= $dialog->get_ID().",".$dialog_ids; } unset($msg_dialogs[$key]); } session::set('msg_dialogs',$msg_dialogs); } $dialog_ids = preg_replace("/,$/","",$dialog_ids); $return .= ""; $return .=""; $return .=""; $return .=""; $return .=""; } return($return); } } ?> gosa-core-2.7.4/include/class_ItemSelector.inc0000644000175000017500000002624511613731145020314 0ustar cajuscajuspid= preg_replace("/[^0-9]/", "", microtime(TRUE)); // Get list of used IDs if(!session::is_set('releaseSelector_USED_IDS')){ session::set('releaseSelector_USED_IDS',array()); } $usedIds = session::get('releaseSelector_USED_IDS'); // Generate instance wide unique ID $pid = ""; while($pid == "" || in_array_strict($pid, $usedIds)){ // Wait 1 msec to ensure that we definately get a new id if($pid != "") usleep(1); $tmp= gettimeofday(); $pid = 'l'.md5(microtime().$tmp['sec']); } // Only keep the last 10 list IDsi $usedIds = array_slice($usedIds, count($usedIds) -10, 10); $usedIds[] = $pid; session::set('releaseSelector_USED_IDS',$usedIds); $this->pid = $pid; // Transfer data $this->releaseBase = $releaseBase; $this->setBases($bases); $this->setBase($base); } function setSubmitButton($flag) { $this->submitButton= $flag; } function setHeight($value) { $this->height= $value; } function setBase($base) { $this->base= $base; if (isset($this->pathMapping[$base])) { $this->update(true); } } function setRootBase($base) { $this->releaseBase = $base; } function checkBase($base) { return isset($this->pathMapping[$base]); } function checkLastBaseUpdate() { return $this->lastState; } function setBases($bases) { global $config; $this->releaseInfo = array(); $this->pathMapping= array(); $selected= $this->base == $this->releaseBase?"Selected":""; $first= true; $last_indent= 2; foreach ($bases as $path => $data) { // Build path style display $this->pathMapping[$path]= preg_replace("/^".preg_quote($this->releaseBase,'/')."\/?/i", "/", $path); $this->releaseInfo[$path]['name'] = $data['name']; $this->releaseInfo[$path]['description'] = $data['desc']; } // Save bases to session for autocompletion session::global_set("pathMapping_{$this->pid}", $this->pathMapping); session::global_set("department_info_{$this->pid}", $this->releaseInfo); } function update($force= false) { global $config; // Analyze for base changes if needed $this->action= null; $last_base= $this->base; if(isset($_REQUEST["BPID_{$this->pid}"]) && $_REQUEST["BPID_{$this->pid}"] == $this->pid) { if (isset($_POST['bs_rebase_'.$this->pid])) { $new_base= base64_decode(get_post('bs_rebase_'.$this->pid)); if($new_base){ if (isset($this->pathMapping[$new_base])) { $this->base= $new_base; $this->action= 'rebase'; } else { $this->lastState= false; return false; } } }else{ // Input field set? if (isset($_POST['bs_input_'.$this->pid])) { // Take over input field base if ($this->submitButton && isset($_POST['submit_base_'.$this->pid]) || !$this->submitButton) { // Check if base is available $this->lastState= false; foreach ($this->pathMapping as $key => $path) { if (mb_strtolower($path) == mb_strtolower(get_post('bs_input_'.$this->pid))) { $this->base= $key; $this->lastState= true; break; } } } } } } /* Skip if there's no change */ if (($this->tree && $this->base == $last_base) && !$force) { return true; } $link= "onclick=\"\$('bs_rebase_".$this->pid."').value='".base64_encode($this->releaseBase)."'; $('submit_tree_base_".$this->pid."').click();\""; $initialValue = ""; if(isset($this->pathMapping[$this->base])){ $initialValue = $this->pathMapping[$this->base]; } $this->tree= " pid}').hide(); \" onfocus=\" \$('bs_{$this->pid}').hide(); \" onmouseover=\" mouseIsStillOver = true; function showIt() { if(mouseIsStillOver){ \$('bs_".$this->pid."').show(); } }; Element.clonePosition( \$('bs_".$this->pid."'), 'bs_input_".$this->pid."', { setHeight: false, setWidth: false, offsetTop:(Element.getHeight('bs_input_".$this->pid."')) }); rtimer=showIt.delay(0.25); \" onmouseout=\" mouseIsStillOver=false; rtimer=Element.hide.delay(0.25,'bs_".$this->pid."')\" value=\"".preg_replace('/"/','"',$initialValue)."\">"; // Autocompleter $this->tree.= "
    ". ""; $selected= $this->base == $this->releaseBase?"Selected":""; $this->tree.= "
    pid."')\"> / ["._("Root")."]
      \n"; $first= true; $last_indent= 1; $baseDepth = 0; foreach ($this->pathMapping as $base => $dummy) { // Do not render the base element if($base == $this->releaseBase){ $baseDepth = 1; continue; } // Build path style display $elements= explode('/', substr($base, strlen($this->releaseBase), strlen($base))); $indent= count($elements) - $baseDepth ; if (!$first && ($indent == $last_indent)) { $this->tree.= "\n"; } if ($indent > $last_indent) { $this->tree.= "
        \n"; } if ($indent < $last_indent) { for ($i= 0; $i < ($last_indent-$indent); $i++) { $this->tree.= "
      \n"; } $this->tree.= "\n"; } $selected= $this->base == $base?" class='treeListSelected'":""; $link= "onclick=\"\$('bs_rebase_".$this->pid."').value='".base64_encode($base)."';$('submit_tree_base_".$this->pid."').click();\""; $this->tree.= "
    • ". "". $this->gennonbreaks($this->releaseInfo[$base]['name']). ($this->releaseInfo[$base]['description']==''?'':' ['.$this->gennonbreaks($this->releaseInfo[$base]['description']).']'). ""; $last_indent= $indent; $first= false; } // Close tree for ($i= 1; $i<$last_indent; $i++) { $this->tree.= "
    \n"; } $this->tree.= "
    \n"; // Draw submitter if required if ($this->submitButton) { $this->tree.= image('images/lists/submit.png', "submit_base_".$this->pid, _("Submit")); } $this->tree.= ""; $this->tree.= ""; $this->tree.= ""; $this->lastState= true; return true; } function gennonbreaks($string) { return str_replace('-', '‑', str_replace(' ', ' ', $string)); } function render() { return $this->tree; } function getBase() { return $this->base; } function getAction() { // Do not do anything if this is not our BPID, or there's even no BPID available... if(!isset($_REQUEST["BPID_{$this->pid}"]) || $_REQUEST["BPID_{$this->pid}"] != $this->pid) { return; } if ($this->action) { return array("targets" => array($this->base), "action" => $this->action); } return null; } } ?> gosa-core-2.7.4/include/accept-to-gettext.inc0000644000175000017500000001547310764462736020107 0ustar cajuscajus * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Usage: * * $locale=al2gt(, * ); * setlocale('LC_ALL', $locale); // or 'LC_MESSAGES', or whatever... * * Example: * * $langs=array('nl_BE.ISO-8859-15','nl_BE.UTF-8','en_US.UTF-8','en_GB.UTF-8'); * $locale=al2gt($langs, 'text/html'); * setlocale('LC_ALL', $locale); * * Note that this will send out header information (to be * RFC2616-compliant), so it must be called before anything is sent to * the user. * * Assumptions made: * * Charset encodings are written the same way as the Accept-Charset * HTTP header specifies them (RFC2616), except that they're parsed * case-insensitive. * * Country codes and language codes are the same in both gettext and * the Accept-Language syntax (except for the case differences, which * are dealt with easily). If not, some input may be ignored. * * The provided gettext-strings are fully qualified; i.e., no "en_US"; * always "en_US.ISO-8859-15" or "en_US.UTF-8", or whichever has been * used. "en.ISO-8859-15" is OK, though. * * The language is more important than the charset; i.e., if the * following is given: * * Accept-Language: nl-be, nl;q=0.8, en-us;q=0.5, en;q=0.3 * Accept-Charset: ISO-8859-15, utf-8;q=0.5 * * And the supplied parameter contains (amongst others) nl_BE.UTF-8 * and nl.ISO-8859-15, then nl_BE.UTF-8 will be picked. * * $Log: accept-to-gettext.inc,v $ * Revision 1.1.1.1 2003/11/19 19:31:15 wouter * * moved to new CVS repo after death of the old * * Fixed code to apply a default to both Accept-Charset and * Accept-Language if none of those headers are supplied; patch from * Dominic Chambers * * Revision 1.2 2003/08/14 10:23:59 wouter * Removed little error in Content-Type header syntaxis. * */ /* not really important, this one; perhaps I could've put it inline with * the rest. */ function find_match($curlscore,$curcscore,$curgtlang,$langval,$charval, $gtlang) { if($curlscore < $langval) { $curlscore=$langval; $curcscore=$charval; $curgtlang=$gtlang; } else if ($curlscore == $langval) { if($curcscore < $charval) { $curcscore=$charval; $curgtlang=$gtlang; } } return array($curlscore, $curcscore, $curgtlang); } function al2gt($gettextlangs, $mime) { /* Check if ACCEPT_LANGUAGE isset */ if(!isset($_SERVER["HTTP_ACCEPT_LANGUAGE"])){ $_SERVER["HTTP_ACCEPT_LANGUAGE"] = ""; } if(!isset($_SERVER["HTTP_ACCEPT_CHARSET"])){ $_SERVER["HTTP_ACCEPT_CHARSET"] = ""; } /* default to "everything is acceptable", as RFC2616 specifies */ $acceptLang=(($_SERVER["HTTP_ACCEPT_LANGUAGE"] == '') ? '*' : $_SERVER["HTTP_ACCEPT_LANGUAGE"]); $acceptChar=(($_SERVER["HTTP_ACCEPT_CHARSET"] == '') ? 'ISO-8859-1,utf-8;q=0.7,*;q=0.7' : $_SERVER["HTTP_ACCEPT_CHARSET"]); $alparts=@preg_split("/,/",$acceptLang); $acparts=@preg_split("/,/",$acceptChar); /* Parse the contents of the Accept-Language header.*/ foreach($alparts as $part) { $part=trim($part); if(preg_match("/;/", $part)) { $lang=@preg_split("/;/",$part); $score=@preg_split("/=/",$lang[1]); $alscores[$lang[0]]=$score[1]; } else { $alscores[$part]=1; } } /* Do the same for the Accept-Charset header. */ /* RFC2616: ``If no "*" is present in an Accept-Charset field, then * all character sets not explicitly mentioned get a quality value of * 0, except for ISO-8859-1, which gets a quality value of 1 if not * explicitly mentioned.'' * * Making it 2 for the time being, so that we * can distinguish between "not specified" and "specified as 1" later * on. */ $acscores["ISO-8859-1"]=2; foreach($acparts as $part) { $part=trim($part); if(preg_match("/;/", $part)) { $cs=@preg_split("/;/",$part); $score=@preg_split("/=/",$cs[1]); $acscores[strtoupper($cs[0])]=$score[1]; } else { $acscores[strtoupper($part)]=1; } } if($acscores["ISO-8859-1"]==2) { $acscores["ISO-8859-1"]=(isset($acscores["*"])?$acscores["*"]:1); } /* * Loop through the available languages/encodings, and pick the one * with the highest score, excluding the ones with a charset the user * did not include. */ $curlscore=0; $curcscore=0; $curgtlang=NULL; foreach($gettextlangs as $gtlang) { $tmp1=preg_replace("/\_/","-",$gtlang); $tmp2=@preg_split("/\./",$tmp1); $allang=strtolower($tmp2[0]); $gtcs=strtoupper($tmp2[1]); $noct=@preg_split("/-/",$allang); if(!isset($alscores["*"])){ $alscores["*"] = ""; } if(!isset($alscores[$allang])){ $alscores[$allang] = ""; } if(!isset($alscores[$noct[0]])){ $alscores[$noct[0]] = ""; } if(!isset($acscores[$gtcs])){ $acscores[$gtcs] = ""; } $testvals=array( array($alscores[$allang], $acscores[$gtcs]), array($alscores[$noct[0]], $acscores[$gtcs]), array($alscores[$allang], $acscores["*"]), array($alscores[$noct[0]], $acscores["*"]), array($alscores["*"], $acscores[$gtcs]), array($alscores["*"], $acscores["*"])); $found=FALSE; foreach($testvals as $tval) { if(!$found && isset($tval[0]) && isset($tval[1])) { $arr=find_match($curlscore, $curcscore, $curgtlang, $tval[0], $tval[1], $gtlang); $curlscore=$arr[0]; $curcscore=$arr[1]; $curgtlang=$arr[2]; $found=TRUE; } } } /* We must re-parse the gettext-string now, since we may have found it * through a "*" qualifier.*/ $gtparts=@preg_split("/\./",$curgtlang); $tmp=strtolower($gtparts[0]); $lang=preg_replace("/\_/", "-", $tmp); if (!headers_sent()){ header("Content-Language: $lang"); if(isset($gtparts[1])){ $charset=$gtparts[1]; header("Content-Type: $mime; charset=$charset"); } } return $curgtlang; } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/include/class_acl.inc0000644000175000017500000016602711613731145016457 0ustar cajuscajusgosaAclEntry= array(); if (isset($this->attrs['gosaAclEntry'])){ for ($i= 0; $i<$this->attrs['gosaAclEntry']['count']; $i++){ $acl= $this->attrs['gosaAclEntry'][$i]; $this->gosaAclEntry= array_merge($this->gosaAclEntry, acl::explodeACL($acl)); } } ksort($this->gosaAclEntry); /* Save parent - we've to know more about it than other plugins... */ $this->parent= &$parent; /* Container? */ if (preg_match('/^(o|ou|c|l|dc)=/i', $dn)){ $this->isContainer= TRUE; } /* Users */ $ui= get_userinfo(); $tag= $ui->gosaUnitTag; $ldap= $config->get_ldap_link(); $ldap->cd($config->current['BASE']); if ($tag == ""){ $ldap->search('(objectClass=gosaAccount)', array('uid', 'cn')); } else { $ldap->search('(&(objectClass=gosaAccount)(gosaUnitTag='.$tag.'))', array('uid', 'cn')); } while ($attrs= $ldap->fetch()){ // Allow objects without cn to be listed without causing an error. if(!isset($attrs['cn'][0]) && isset($attrs['uid'][0])){ $this->users['U:'.$attrs['dn']]= $attrs['uid'][0]; }elseif(!isset($attrs['uid'][0]) && isset($attrs['cn'][0])){ $this->users['U:'.$attrs['dn']]= $attrs['cn'][0]; }elseif(!isset($attrs['uid'][0]) && !isset($attrs['cn'][0])){ $this->users['U:'.$attrs['dn']]= $attrs['dn']; }else{ $this->users['U:'.$attrs['dn']]= $attrs['cn'][0].' ['.$attrs['uid'][0].']'; } } ksort($this->users); /* Groups */ $ldap->cd($config->current['BASE']); # if ($tag == ""){ $ldap->search('(objectClass=posixGroup)', array('cn', 'description')); # } else { # $ldap->search('(&(objectClass=posixGroup)(gosaUnitTag='.$tag.'))', array('cn', 'description')); # } while ($attrs= $ldap->fetch()){ $dsc= ""; if (isset($attrs['description'][0])){ $dsc= $attrs['description'][0]; } $this->groups['G:'.$attrs['dn']]= $attrs['cn'][0].' ['.$dsc.']'; } $this->groups['G:*']= _("All users"); ksort($this->groups); /* Roles */ $ldap->cd($config->current['BASE']); # if ($tag == ""){ $ldap->search('(objectClass=gosaRole)', array('cn', 'description','gosaAclTemplate','dn')); # } else { # $ldap->search('(&(objectClass=gosaRole)(gosaUnitTag='.$tag.'))', array('cn', 'description','gosaAclTemplate','dn')); # } while ($attrs= $ldap->fetch()){ $dsc= ""; if (isset($attrs['description'][0])){ $dsc= $attrs['description'][0]; } $role_id = $attrs['dn']; $this->roles[$role_id]['acls'] =array(); for ($i= 0; $i < $attrs['gosaAclTemplate']['count']; $i++){ $acl= $attrs['gosaAclTemplate'][$i]; $this->roles[$role_id]['acls'] = array_merge($this->roles[$role_id]['acls'],acl::explodeACL($acl)); } $this->roles[$role_id]['description'] = $dsc; $this->roles[$role_id]['cn'] = $attrs['cn'][0]; } /* Objects */ $tmp= session::global_get('plist'); $plist= $tmp->info; $cats = array(); if (isset($this->parent) && $this->parent !== NULL){ $oc= array(); foreach ($this->parent->by_object as $key => $obj){ if(isset($obj->objectclasses) && is_array($obj->objectclasses)){ $oc= array_merge($oc, $obj->objectclasses); } if(isset($obj->acl_category)){ $tmp= str_replace("/","",$obj->acl_category); $cats[$tmp] = $tmp; } } if (in_array_ics('organizationalUnit', $oc)){ $this->isContainer= TRUE; } } else { $oc= $this->attrs['objectClass']; } /* Extract available categories from plugin info list */ foreach ($plist as $class => $acls){ /* Only feed categories */ if (isset($acls['plCategory'])){ /* Walk through supplied list and feed only translated categories */ foreach($acls['plCategory'] as $idx => $data){ /* Non numeric index means -> base object containing more informations */ if (preg_match('/^[0-9]+$/', $idx)){ if (!isset($this->ocMapping[$data])){ $this->ocMapping[$data]= array(); $this->ocMapping[$data][]= '0'; } if(isset($cats[$data])){ $this->myAclObjects[$data.'/'.$class]= $acls['plDescription']; } $this->ocMapping[$data][]= $class; } else { if (!isset($this->ocMapping[$idx])){ $this->ocMapping[$idx]= array(); $this->ocMapping[$idx][]= '0'; } $this->ocMapping[$idx][]= $class; $this->aclObjects[$idx]= $data['description']; /* Additionally filter the classes we're interested in in "self edit" mode */ if(!isset($data['objectClass'])) continue; if (is_array($data['objectClass'])){ foreach($data['objectClass'] as $objectClass){ if (in_array_ics($objectClass, $oc)){ $this->myAclObjects[$idx.'/'.$class]= $acls['plDescription']; break; } } } else { if (in_array_ics($data['objectClass'], $oc)){ $this->myAclObjects[$idx.'/'.$class]= $acls['plDescription']; } } } } } } /* Sort categories */ asort($this->aclObjects); /* Fill acl types */ if ($this->isContainer){ $this->aclTypes= array("reset" => _("Reset ACLs"), "one" => _("One level"), "base" => _("Current object"), "sub" => _("Complete subtree"), "psub" => _("Complete subtree (permanent)"), "role" => _("Use ACL defined in role")); } else { $this->aclTypes= array("base" => _("Current object"), "role" => _("Use ACL defined in role")); } asort($this->aclTypes); $this->targets= array("user" => _("Users"), "group" => _("Groups")); asort($this->targets); /* Finally - we want to get saved... */ $this->is_account= TRUE; $this->updateList(); // Prepare lists $this->sectionList = new sortableListing(); $this->sectionList->setDeleteable(false); $this->sectionList->setEditable(false); $this->sectionList->setWidth("100%"); $this->sectionList->setHeight("220px"); $this->sectionList->setColspecs(array('200px','*')); $this->sectionList->setHeader(array(_("Section"),_("Description"))); $this->sectionList->setDefaultSortColumn(0); $this->sectionList->setAcl('rwcdm'); // All ACLs, we filter on our own here. $this->roleList = new sortableListing(); $this->roleList->setDeleteable(false); $this->roleList->setEditable(false); $this->roleList->setWidth("100%"); $this->roleList->setHeight("120px"); $this->roleList->setColspecs(array('20px','*','*')); $this->roleList->setHeader(array(_("Used"),_("Name"),_("Description"))); $this->roleList->setDefaultSortColumn(1); $this->roleList->setAcl('rwcdm'); // All ACLs, we filter on our own here. $this->aclMemberList = new sortableListing(array(), array(), false); $this->aclMemberList->setEditable(false); $this->aclMemberList->setDeleteable(true); $this->aclMemberList->setInstantDelete(false); $this->aclMemberList->sortingEnabled(true); $this->aclMemberList->setWidth("100%"); $this->aclMemberList->setHeight("150px"); $this->aclMemberList->setColspecs(array('20px','*','*')); $this->aclMemberList->setHeader(array(_("~"),_("Name"),_("Description"))); $this->aclMemberList->setDefaultSortColumn(1); $this->aclMemberList->setAcl('rwcdm'); // All ACLs, we filter on our own here. } function updateList() { if(!$this->list){ $this->list = new sortableListing($this->gosaAclEntry,array(),TRUE); $this->list->setDeleteable(true); $this->list->setEditable(true); $this->list->setColspecs(array('*')); $this->list->setWidth("100%"); $this->list->setHeight("400px"); $this->list->setAcl("rwcdm"); $this->list->setHeader(array(_("Member"),_("Permissions"),_("Type"))); } // Add ACL entries to the listing $lData = array(); foreach($this->gosaAclEntry as $id => $entry){ $lData[] = $this->convertForListing($entry); } $this->list->setListData($this->gosaAclEntry, $lData); } function convertForListing($entry) { $member = implode($entry['members'],", "); if(isset($entry['acl']) && is_array($entry['acl'])){ $acl = implode(array_keys($entry['acl']),", "); }else{ $acl=""; } return(array('data' => array($member, $acl, $this->aclTypes[$entry['type']]))); } function execute() { /* Call parent execute */ plugin::execute(); $tmp= session::global_get('plist'); $plist= $tmp->info; /* Handle posts */ if (isset($_POST['new_acl'])){ $this->dialogState= 'create'; $this->dialog= TRUE; $this->currentIndex= count($this->gosaAclEntry); $this->loadAclEntry(TRUE); $this->aclMemberList->setListData(array()); $this->aclMemberList->update(); } $new_acl= array(); $aclDialog= FALSE; $firstedit= FALSE; // Get listing actions. Delete or Edit. $this->list->save_object(); $lAction = $this->list->getAction(); $this->gosaAclEntry = array_values($this->list->getMaintainedData()); /* Act on HTML post and gets here. */ if($lAction['action'] == "edit"){ $this->currentIndex = $this->list->getKey($lAction['targets'][0]); $this->dialogState= 'create'; $firstedit= TRUE; $this->dialog= TRUE; $this->loadAclEntry(); } foreach($_POST as $name => $post){ $post =get_post($name); /* Actions... */ if (preg_match('/^acl_edit_[0-9]*$/', $name)){ $this->dialogState= 'create'; $firstedit= TRUE; $this->dialog= TRUE; $this->currentIndex= preg_replace('/^acl_edit_([0-9]*)$/', '\1', $name); $this->loadAclEntry(); continue; } if (preg_match('/^cat_edit_.*$/', $name)){ $this->aclObject= preg_replace('/^cat_edit_(.*)$/', '\1', $name); $this->dialogState= 'edit'; foreach ($this->ocMapping[$this->aclObject] as $oc){ if (isset($this->aclContents[$oc])){ $this->savedAclContents[$oc]= $this->aclContents[$oc]; } } continue; } /* Only handle posts, if we allowed to modify ACLs */ if(!$this->acl_is_writeable("")){ continue; } if (preg_match('/^acl_del_[0-9]*$/', $name)){ unset($this->gosaAclEntry[preg_replace('/^acl_del_([0-9]*)$/', '\1', $name)]); continue; } if (preg_match('/^cat_del_.*$/', $name)){ $idx= preg_replace('/^cat_del_(.*)$/', '\1', $name); foreach ($this->ocMapping[$idx] as $key){ if(isset($this->aclContents[$idx])) unset($this->aclContents[$idx]); if(isset($this->aclContents["$idx/$key"])) unset($this->aclContents["$idx/$key"]); } continue; } /* ACL saving... */ if (preg_match('/^acl_.*_[^xy]$/', $name)){ list($dummy, $object, $attribute, $value)= explode('_', $name); /* Skip for detection entry */ if ($object == 'dummy') { continue; } /* Ordinary ACLs */ if (!isset($new_acl[$object])){ $new_acl[$object]= array(); } if (isset($new_acl[$object][$attribute])){ $new_acl[$object][$attribute].= $value; } else { $new_acl[$object][$attribute]= $value; } } // Remember the selected ACL role. if(isset($_POST['selected_role']) && $_POST['aclType'] == 'role'){ $this->aclContents = ""; $this->aclContents = base64_decode(get_post('selected_role')); }else{ if(is_string($this->aclContents)) $this->aclContents = array(); } } if(isset($_POST['acl_dummy_0_0_0'])){ $aclDialog= TRUE; } if($this->acl_is_writeable("")){ /* Only be interested in new acl's, if we're in the right _POST place */ if ($aclDialog && $this->aclObject != "" && is_array($this->ocMapping[$this->aclObject])){ foreach ($this->ocMapping[$this->aclObject] as $oc){ if(isset($this->aclContents[$oc]) && is_array($this->aclContents)){ unset($this->aclContents[$oc]); }elseif(isset($this->aclContents[$this->aclObject.'/'.$oc]) && is_array($this->aclContents)){ unset($this->aclContents[$this->aclObject.'/'.$oc]); }else{ # trigger_error("Huhm?"); } if (isset($new_acl[$oc]) && is_array($new_acl)){ $this->aclContents[$oc]= $new_acl[$oc]; } if (isset($new_acl[$this->aclObject.'/'.$oc]) && is_array($new_acl)){ $this->aclContents[$this->aclObject.'/'.$oc]= $new_acl[$this->aclObject.'/'.$oc]; } } } /* Save new acl in case of base edit mode */ if ($this->aclType == 'base' && !$firstedit){ $this->aclContents= $new_acl; } } /* Cancel new acl? */ if (isset($_POST['cancel_new_acl'])){ $this->dialogState= 'head'; $this->dialog= FALSE; if ($this->wasNewEntry){ unset ($this->gosaAclEntry[$this->currentIndex]); } } /* Save common values */ if($this->acl_is_writeable("")){ foreach (array("aclType","aclFilter", "aclObject", "target") as $key){ if (isset($_POST[$key])){ $this->$key= get_post($key); } } } /* Store ACL in main object? */ if (isset($_POST['submit_new_acl'])){ $this->gosaAclEntry[$this->currentIndex]['type']= $this->aclType; $this->gosaAclEntry[$this->currentIndex]['members']= $this->recipients; $this->gosaAclEntry[$this->currentIndex]['acl']= $this->aclContents; $this->gosaAclEntry[$this->currentIndex]['filter']= $this->aclFilter; $this->dialogState= 'head'; $this->dialog= FALSE; } /* Cancel edit acl? */ if (isset($_POST['cancel_edit_acl'])){ $this->dialogState= 'create'; foreach ($this->ocMapping[$this->aclObject] as $oc){ if (isset($this->savedAclContents[$oc])){ $this->aclContents[$oc]= $this->savedAclContents[$oc]; } } } /* Save edit acl? */ if (isset($_POST['submit_edit_acl'])){ $this->dialogState= 'create'; } /* Add acl? */ if (isset($_POST['add_acl']) && $_POST['aclObject'] != ""){ $this->dialogState= 'edit'; $this->savedAclContents= array(); foreach ($this->ocMapping[$this->aclObject] as $oc){ if (isset($this->aclContents[$oc])){ $this->savedAclContents[$oc]= $this->aclContents[$oc]; } } } /* Add to list? */ if (isset($_POST['add']) && isset($_POST['source'])){ foreach ($_POST['source'] as $key){ if ($this->target == 'user'){ $this->recipients[$key]= $this->users[$key]; } if ($this->target == 'group'){ $this->recipients[$key]= $this->groups[$key]; } } ksort($this->recipients); } /* Remove from list? */ if (isset($_POST['del']) && isset($_POST['recipient'])) { foreach ($_POST['recipient'] as $key) { unset($this->recipients[$key]); } } $this->aclMemberList->save_object(); $actionL = $this->aclMemberList->getAction(); if($actionL['action'] == "delete") { $key = $this->aclMemberList->getData($actionL['targets'][0]); unset($this->recipients[$key]); $this->aclMemberList->deleteEntry($actionL['targets'][0]); } /* Adds the 'all-users' peudo-group to the acl */ if(isset($_POST['add_all_users'])) { if(!isset($this->recipients['G:*'])) { $this->recipients['G:*'] = _("All users"); $key = "G:*"; $vData = array("data" => array(image("plugins/groups/images/select_group.png"), _("All users"), _("Pseudo-group for all users."))); $this->aclMemberList->addEntry($key, $vData, $key); } } /* Show User/Group-Add-Dialog */ if(isset($_POST['add_user_or_group'])) { $this->dialog = new userGroupSelect($this->config, get_userinfo()); } /* If dialog is confirmed */ if(isset($_POST['userGroupSelect_save']) && $this->dialog instanceof userGroupSelect) { $groupIcon = image("plugins/groups/images/select_group.png"); $userIcon = image("plugins/users/images/select_user.png"); if($this->acl_is_writeable("")) { foreach($this->dialog->save() as $entry) { if(in_array_strict("posixGroup", $entry['objectClass'])) { $key = "G:" . $entry['dn']; $vData = array("data" => array($groupIcon, $entry['cn'][0], $entry['description'][0])); $this->recipients[$key] = $entry['cn'][0]; } else if(isset($entry['uid'])) { $key = "U:" . $entry['dn']; $vData = array("data" => array($userIcon, $entry['uid'][0], $entry['cn'][0])); $lData = array($key => $key); $this->recipients["U:" . $entry['dn']] = $entry['uid'][0]; } else { // Error break; } $this->aclMemberList->addEntry($key, $vData, $key); } } unset($this->dialog); $this->dialog = true; } /* If dialog is canceled */ if(isset($_POST['userGroupSelect_cancel']) && $this->dialog instanceof userGroupSelect) { unset($this->dialog); $this->dialog = true; } if($this->dialog instanceof userGroupSelect) { // filter current members out $used = array(); foreach(array_keys($this->recipients) as $key) { $used['dn'][] = substr($key, 2); } session::set('filterBlacklist', $used); return $this->dialog->execute(); } /* Create templating instance */ $smarty= get_smarty(); $smarty->assign("acl_readable",$this->acl_is_readable("")); if(!$this->acl_is_readable("")){ return ($smarty->fetch (get_template_path('acl.tpl'))); } if ($this->dialogState == 'head'){ $this->updateList(); $smarty->assign("aclList", $this->list->render()); } if ($this->dialogState == 'create'){ if($this->aclType != 'role'){ // Create a map of all used sections, this allows us to simply hide the remove button // if no acl is configured for the given section // e.g. ';all;department/country;users/user; $usedList = ";".implode(array_keys($this->aclContents),';').";"; /* Add settings for all categories to the (permanent) list */ $data = $lData = array(); foreach ($this->aclObjects as $section => $dsc){ $summary= ""; foreach($this->ocMapping[$section] as $oc){ if (isset($this->aclContents[$oc]) && count($this->aclContents[$oc]) && isset($this->aclContents[$oc][0]) && $this->aclContents[$oc][0] != ""){ $summary.= "$oc, "; continue; } if (isset($this->aclContents["$section/$oc"]) && count($this->aclContents["$section/$oc"])){ $summary.= "$oc, "; continue; } if (isset($this->aclContents[$oc]) && !isset($this->aclContents[$oc][0]) && count($this->aclContents[$oc])){ $summary.= "$oc, "; } } /* Set summary... */ if ($summary == ""){ $summary= ''._("No ACL settings for this category!").''; } else { $summary= trim($summary,", "); $summary= " ".sprintf(_("ACLs for: %s"), $summary); } $actions =""; if($this->acl_is_readable("")){ $actions.= image('images/lists/edit.png','cat_edit_'.$section, msgPool::editButton(_("category ACL"))); } if($this->acl_is_removeable() && preg_match("/;".$section."(;|\/)/", $usedList)){ $actions.= image('images/lists/trash.png','cat_del_'.$section, msgPool::delButton(_("category ACL"))); } $data[] = $section; $lData[] = array('data'=>array($dsc, $summary, $actions)); } $this->sectionList->setListData($data,$lData); $this->sectionList->update(); $smarty->assign("aclList", $this->sectionList->render()); } $smarty->assign("aclType", set_post($this->aclType)); $smarty->assign("aclFilter", set_post($this->aclFilter)); $smarty->assign("aclTypes", set_post($this->aclTypes)); $smarty->assign("target", set_post($this->target)); $smarty->assign("targets", set_post($this->targets)); /* Assign possible target types */ $smarty->assign("targets", $this->targets); foreach ($this->attributes as $attr){ $smarty->assign($attr, set_post($this->$attr)); } /* Generate list */ $tmp= array(); if ($this->target == "group" && !isset($this->recipients["G:*"])){ $tmp["G:*"]= _("All users"); } foreach (array("user" => "users", "group" => "groups") as $field => $arr){ if ($this->target == $field){ foreach ($this->$arr as $key => $value){ if (!isset($this->recipients[$key])){ $tmp[$key]= $value; } } } } $smarty->assign('sources', set_post($tmp)); $smarty->assign('recipients', set_post($this->recipients)); /* Generate ACL member list */ if($this->acl_is_writeable("")) { $this->aclMemberList->setDeleteable(true); } else { $this->aclMemberList->setDeleteable(false); } $this->aclMemberList->update(); $smarty->assign("aclMemberList", $this->aclMemberList->render()); /* Acl selector if scope is base */ if ($this->aclType == 'base'){ $smarty->assign('aclSelector', $this->buildAclSelector($this->myAclObjects)); } /* Role selector if scope is base */ if ($this->aclType == 'role'){ $smarty->assign('roleSelector', $this->buildRoleSelector($this->roles)); } } if ($this->dialogState == 'edit'){ $smarty->assign('headline', sprintf(_("Edit ACL for '%s' with scope '%s'"), $this->aclObjects[$this->aclObject], $this->aclTypes[$this->aclType])); /* Collect objects for selected category */ foreach ($this->ocMapping[$this->aclObject] as $idx => $class){ if ($idx == 0){ continue; } $aclObjects[$this->aclObject.'/'.$class]= $plist[$class]['plDescription']; } /* Role selector if scope is base */ if ($this->aclType == 'role'){ $smarty->assign('roleSelector', $this->buildRoleSelector($this->roles)); } else { $smarty->assign('aclSelector', $this->buildAclSelector($aclObjects)); } } /* Show main page */ $smarty->assign("dialogState", $this->dialogState); /* Assign acls */ $smarty->assign("acl_createable",$this->acl_is_createable()); $smarty->assign("acl_writeable" ,$this->acl_is_writeable("")); $smarty->assign("acl_readable" ,$this->acl_is_readable("")); $smarty->assign("acl_removeable",$this->acl_is_removeable()); return ($smarty->fetch (get_template_path('acl.tpl'))); } function sort_by_priority($list) { $tmp= session::global_get('plist'); $plist= $tmp->info; asort($plist); $newSort = array(); foreach($list as $name => $translation){ $na = preg_replace("/^.*\//","",$name); $prio = 0; if(isset($plist[$na]['plPriority'])){ $prio= $plist[$na]['plPriority'] ; } $newSort[$name] = $prio; } asort($newSort); $ret = array(); foreach($newSort as $name => $prio){ $ret[$name] = $list[$name]; } return($ret); } function buildRoleSelector($list) { $selected = $this->aclContents; if(!is_string($this->aclContents) || !isset($list[$this->aclContents])){ $selected = key($list); } $data = $lData = array(); foreach($list as $dn => $values){ if($dn == $selected){ $option = ""; }else{ $option = ""; } $data[] = postEncode($dn); $lData[] = array('data'=>array($option, $values['cn'], $values['description'])); } $this->roleList->setListData($data,$lData); $this->roleList->update(); return($this->roleList->render()); } function buildAclSelector($list) { $display= ""; $cols= 3; $tmp= session::global_get('plist'); $plist= $tmp->info; asort($plist); /* Add select all/none buttons */ $style = "style='width:100px;'"; if($this->acl_is_writeable("")){ $display .= ""; $display .= ""; $display .= " - "; $display .= ""; $display .= " - "; $display .= ""; $display .= ""; $display .= "
    "; $style = "style='width:50px;'"; $display .= ""; $display .= ""; $display .= ""; $display .= ""; $display .= ""; $display .= " - "; $display .= ""; $display .= ""; $display .= ""; $display .= " - "; $display .= ""; $display .= ""; $display .= ""; $display .= ""; } /* Build general objects */ $list =$this->sort_by_priority($list); foreach ($list as $key => $name){ /* Create sub acl if it does not exist */ if (!isset($this->aclContents[$key])){ $this->aclContents[$key]= array(); } if(!isset($this->aclContents[$key][0])){ $this->aclContents[$key][0]= ''; } $currentAcl= $this->aclContents[$key]; /* Get the overall plugin acls */ $overall_acl =""; if(isset($currentAcl[0])){ $overall_acl = $currentAcl[0]; } // Detect configured plugins $expand = count($currentAcl) > 1 || $currentAcl[0] != ""; /* Object header */ $tname= preg_replace("/[^a-z0-9]/i","_",$name); if($expand){ $back_color = "#C8C8FF"; }else{ $back_color = "#C8C8C8"; } if(isset($_SERVER['HTTP_USER_AGENT']) && (preg_match("/gecko/i",$_SERVER['HTTP_USER_AGENT'])) || (preg_match("/presto/i",$_SERVER['HTTP_USER_AGENT']))) { $display.= "\n". "\n ". "\n ". "\n ". "\n "; } else if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match("/ie/i",$_SERVER['HTTP_USER_AGENT'])) { $display.= "\n
    "._("Object").": $name". "\n
    ". "\n ". "\n ". "\n ". "\n "; } else { $display.= "\n
    "._("Object").": $name". "\n
    ". "\n ". "\n ". "\n "; } /* Generate options */ $spc= "  "; $options= $this->mkchkbx($key."_0_c", _("Create objects"), preg_match('/c/', $overall_acl)).$spc; $options.= $this->mkchkbx($key."_0_m", _("Move objects"), preg_match('/m/', $overall_acl)).$spc; $options.= $this->mkchkbx($key."_0_d", _("Remove objects"), preg_match('/d/', $overall_acl)).$spc; if ($plist[preg_replace('%^.*/%', '', $key)]['plSelfModify']){ $options.= $this->mkchkbx($key."_0_s", _("Restrict changes to user's own object"), preg_match('/s/', $overall_acl)).$spc; } /* Global options */ $more_options= $this->mkchkbx($key."_0_r", _("read"), preg_match('/r/', $overall_acl)).$spc; $more_options.= $this->mkchkbx($key."_0_w", _("write"), preg_match('/w/', $overall_acl)); $display.= "\n ". "\n ". "\n ". "\n "; /* Walk through the list of attributes */ $cnt= 1; $splist= array(); if(isset($plist[preg_replace('%^.*/%', '', $key)]['plProvidedAcls'])){ $splist= $plist[preg_replace('%^.*/%', '', $key)]['plProvidedAcls']; } if(session::global_get('js')) { if(isset($_SERVER['HTTP_USER_AGENT']) && (preg_match("/gecko/i",$_SERVER['HTTP_USER_AGENT'])) || (preg_match("/presto/i",$_SERVER['HTTP_USER_AGENT']))) { $display.= "\n ". "\n ' + '' + '
    "._("Object").": $name
    $options "._("Complete object").": $more_options
    ". "\n
    StatusTestMessage
    '; this.logsummary = $('logsummary'); this.loglines = $('loglines'); }, _toHTML: function(txt) { return txt.escapeHTML().replace(/\n/g,"
    "); }, addLinksToResults: function(){ $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log td.title = "Run only this test"; Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;}); }); $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log td.title = "Run all tests"; Event.observe(td, 'click', function(){ window.location.search = "";}); }); } }; Test.Unit.Runner = Class.create(); Test.Unit.Runner.prototype = { initialize: function(testcases) { this.options = Object.extend({ testLog: 'testlog' }, arguments[1] || {}); this.options.resultsURL = this.parseResultsURLQueryParameter(); this.options.tests = this.parseTestsQueryParameter(); if (this.options.testLog) { this.options.testLog = $(this.options.testLog) || null; } if(this.options.tests) { this.tests = []; for(var i = 0; i < this.options.tests.length; i++) { if(/^test/.test(this.options.tests[i])) { this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"])); } } } else { if (this.options.test) { this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])]; } else { this.tests = []; for(var testcase in testcases) { if(/^test/.test(testcase)) { this.tests.push( new Test.Unit.Testcase( this.options.context ? ' -> ' + this.options.titles[testcase] : testcase, testcases[testcase], testcases["setup"], testcases["teardown"] )); } } } } this.currentTest = 0; this.logger = new Test.Unit.Logger(this.options.testLog); setTimeout(this.runTests.bind(this), 1000); }, parseResultsURLQueryParameter: function() { return window.location.search.parseQuery()["resultsURL"]; }, parseTestsQueryParameter: function(){ if (window.location.search.parseQuery()["tests"]){ return window.location.search.parseQuery()["tests"].split(','); }; }, // Returns: // "ERROR" if there was an error, // "FAILURE" if there was a failure, or // "SUCCESS" if there was neither getResult: function() { var hasFailure = false; for(var i=0;i 0) { return "ERROR"; } if (this.tests[i].failures > 0) { hasFailure = true; } } if (hasFailure) { return "FAILURE"; } else { return "SUCCESS"; } }, postResults: function() { if (this.options.resultsURL) { new Ajax.Request(this.options.resultsURL, { method: 'get', parameters: 'result=' + this.getResult(), asynchronous: false }); } }, runTests: function() { var test = this.tests[this.currentTest]; if (!test) { // finished! this.postResults(); this.logger.summary(this.summary()); return; } if(!test.isWaiting) { this.logger.start(test.name); } test.run(); if(test.isWaiting) { this.logger.message("Waiting for " + test.timeToWait + "ms"); setTimeout(this.runTests.bind(this), test.timeToWait || 1000); } else { this.logger.finish(test.status(), test.summary()); this.currentTest++; // tail recursive, hopefully the browser will skip the stackframe this.runTests(); } }, summary: function() { var assertions = 0; var failures = 0; var errors = 0; var messages = []; for(var i=0;i 0) return 'failed'; if (this.errors > 0) return 'error'; return 'passed'; }, assert: function(expression) { var message = arguments[1] || 'assert: got "' + Test.Unit.inspect(expression) + '"'; try { expression ? this.pass() : this.fail(message); } catch(e) { this.error(e); } }, assertEqual: function(expected, actual) { var message = arguments[2] || "assertEqual"; try { (expected == actual) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) + '", actual "' + Test.Unit.inspect(actual) + '"'); } catch(e) { this.error(e); } }, assertInspect: function(expected, actual) { var message = arguments[2] || "assertInspect"; try { (expected == actual.inspect()) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) + '", actual "' + Test.Unit.inspect(actual) + '"'); } catch(e) { this.error(e); } }, assertEnumEqual: function(expected, actual) { var message = arguments[2] || "assertEnumEqual"; try { $A(expected).length == $A(actual).length && expected.zip(actual).all(function(pair) { return pair[0] == pair[1] }) ? this.pass() : this.fail(message + ': expected ' + Test.Unit.inspect(expected) + ', actual ' + Test.Unit.inspect(actual)); } catch(e) { this.error(e); } }, assertNotEqual: function(expected, actual) { var message = arguments[2] || "assertNotEqual"; try { (expected != actual) ? this.pass() : this.fail(message + ': got "' + Test.Unit.inspect(actual) + '"'); } catch(e) { this.error(e); } }, assertIdentical: function(expected, actual) { var message = arguments[2] || "assertIdentical"; try { (expected === actual) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) + '", actual "' + Test.Unit.inspect(actual) + '"'); } catch(e) { this.error(e); } }, assertNotIdentical: function(expected, actual) { var message = arguments[2] || "assertNotIdentical"; try { !(expected === actual) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) + '", actual "' + Test.Unit.inspect(actual) + '"'); } catch(e) { this.error(e); } }, assertNull: function(obj) { var message = arguments[1] || 'assertNull'; try { (obj==null) ? this.pass() : this.fail(message + ': got "' + Test.Unit.inspect(obj) + '"'); } catch(e) { this.error(e); } }, assertMatch: function(expected, actual) { var message = arguments[2] || 'assertMatch'; var regex = new RegExp(expected); try { (regex.exec(actual)) ? this.pass() : this.fail(message + ' : regex: "' + Test.Unit.inspect(expected) + ' did not match: ' + Test.Unit.inspect(actual) + '"'); } catch(e) { this.error(e); } }, assertHidden: function(element) { var message = arguments[1] || 'assertHidden'; this.assertEqual("none", element.style.display, message); }, assertNotNull: function(object) { var message = arguments[1] || 'assertNotNull'; this.assert(object != null, message); }, assertType: function(expected, actual) { var message = arguments[2] || 'assertType'; try { (actual.constructor == expected) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) + '", actual "' + (actual.constructor) + '"'); } catch(e) { this.error(e); } }, assertNotOfType: function(expected, actual) { var message = arguments[2] || 'assertNotOfType'; try { (actual.constructor != expected) ? this.pass() : this.fail(message + ': expected "' + Test.Unit.inspect(expected) + '", actual "' + (actual.constructor) + '"'); } catch(e) { this.error(e); } }, assertInstanceOf: function(expected, actual) { var message = arguments[2] || 'assertInstanceOf'; try { (actual instanceof expected) ? this.pass() : this.fail(message + ": object was not an instance of the expected type"); } catch(e) { this.error(e); } }, assertNotInstanceOf: function(expected, actual) { var message = arguments[2] || 'assertNotInstanceOf'; try { !(actual instanceof expected) ? this.pass() : this.fail(message + ": object was an instance of the not expected type"); } catch(e) { this.error(e); } }, assertRespondsTo: function(method, obj) { var message = arguments[2] || 'assertRespondsTo'; try { (obj[method] && typeof obj[method] == 'function') ? this.pass() : this.fail(message + ": object doesn't respond to [" + method + "]"); } catch(e) { this.error(e); } }, assertReturnsTrue: function(method, obj) { var message = arguments[2] || 'assertReturnsTrue'; try { var m = obj[method]; if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)]; m() ? this.pass() : this.fail(message + ": method returned false"); } catch(e) { this.error(e); } }, assertReturnsFalse: function(method, obj) { var message = arguments[2] || 'assertReturnsFalse'; try { var m = obj[method]; if(!m) m = obj['is'+method.charAt(0).toUpperCase()+method.slice(1)]; !m() ? this.pass() : this.fail(message + ": method returned true"); } catch(e) { this.error(e); } }, assertRaise: function(exceptionName, method) { var message = arguments[2] || 'assertRaise'; try { method(); this.fail(message + ": exception expected but none was raised"); } catch(e) { ((exceptionName == null) || (e.name==exceptionName)) ? this.pass() : this.error(e); } }, assertElementsMatch: function() { var expressions = $A(arguments), elements = $A(expressions.shift()); if (elements.length != expressions.length) { this.fail('assertElementsMatch: size mismatch: ' + elements.length + ' elements, ' + expressions.length + ' expressions'); return false; } elements.zip(expressions).all(function(pair, index) { var element = $(pair.first()), expression = pair.last(); if (element.match(expression)) return true; this.fail('assertElementsMatch: (in index ' + index + ') expected ' + expression.inspect() + ' but got ' + element.inspect()); }.bind(this)) && this.pass(); }, assertElementMatches: function(element, expression) { this.assertElementsMatch([element], expression); }, benchmark: function(operation, iterations) { var startAt = new Date(); (iterations || 1).times(operation); var timeTaken = ((new Date())-startAt); this.info((arguments[2] || 'Operation') + ' finished ' + iterations + ' iterations in ' + (timeTaken/1000)+'s' ); return timeTaken; }, _isVisible: function(element) { element = $(element); if(!element.parentNode) return true; this.assertNotNull(element); if(element.style && Element.getStyle(element, 'display') == 'none') return false; return this._isVisible(element.parentNode); }, assertNotVisible: function(element) { this.assert(!this._isVisible(element), Test.Unit.inspect(element) + " was not hidden and didn't have a hidden parent either. " + ("" || arguments[1])); }, assertVisible: function(element) { this.assert(this._isVisible(element), Test.Unit.inspect(element) + " was not visible. " + ("" || arguments[1])); }, benchmark: function(operation, iterations) { var startAt = new Date(); (iterations || 1).times(operation); var timeTaken = ((new Date())-startAt); this.info((arguments[2] || 'Operation') + ' finished ' + iterations + ' iterations in ' + (timeTaken/1000)+'s' ); return timeTaken; } }; Test.Unit.Testcase = Class.create(); Object.extend(Object.extend(Test.Unit.Testcase.prototype, Test.Unit.Assertions.prototype), { initialize: function(name, test, setup, teardown) { Test.Unit.Assertions.prototype.initialize.bind(this)(); this.name = name; if(typeof test == 'string') { test = test.gsub(/(\.should[^\(]+\()/,'#{0}this,'); test = test.gsub(/(\.should[^\(]+)\(this,\)/,'#{1}(this)'); this.test = function() { eval('with(this){'+test+'}'); } } else { this.test = test || function() {}; } this.setup = setup || function() {}; this.teardown = teardown || function() {}; this.isWaiting = false; this.timeToWait = 1000; }, wait: function(time, nextPart) { this.isWaiting = true; this.test = nextPart; this.timeToWait = time; }, run: function() { try { try { if (!this.isWaiting) this.setup.bind(this)(); this.isWaiting = false; this.test.bind(this)(); } finally { if(!this.isWaiting) { this.teardown.bind(this)(); } } } catch(e) { this.error(e); } } }); // *EXPERIMENTAL* BDD-style testing to please non-technical folk // This draws many ideas from RSpec http://rspec.rubyforge.org/ Test.setupBDDExtensionMethods = function(){ var METHODMAP = { shouldEqual: 'assertEqual', shouldNotEqual: 'assertNotEqual', shouldEqualEnum: 'assertEnumEqual', shouldBeA: 'assertType', shouldNotBeA: 'assertNotOfType', shouldBeAn: 'assertType', shouldNotBeAn: 'assertNotOfType', shouldBeNull: 'assertNull', shouldNotBeNull: 'assertNotNull', shouldBe: 'assertReturnsTrue', shouldNotBe: 'assertReturnsFalse', shouldRespondTo: 'assertRespondsTo' }; var makeAssertion = function(assertion, args, object) { this[assertion].apply(this,(args || []).concat([object])); }; Test.BDDMethods = {}; $H(METHODMAP).each(function(pair) { Test.BDDMethods[pair.key] = function() { var args = $A(arguments); var scope = args.shift(); makeAssertion.apply(scope, [pair.value, args, this]); }; }); [Array.prototype, String.prototype, Number.prototype, Boolean.prototype].each( function(p){ Object.extend(p, Test.BDDMethods) } ); }; Test.context = function(name, spec, log){ Test.setupBDDExtensionMethods(); var compiledSpec = {}; var titles = {}; for(specName in spec) { switch(specName){ case "setup": case "teardown": compiledSpec[specName] = spec[specName]; break; default: var testName = 'test'+specName.gsub(/\s+/,'-').camelize(); var body = spec[specName].toString().split('\n').slice(1); if(/^\{/.test(body[0])) body = body.slice(1); body.pop(); body = body.map(function(statement){ return statement.strip() }); compiledSpec[testName] = body.join('\n'); titles[testName] = specName; } } new Test.Unit.Runner(compiledSpec, { titles: titles, testLog: log || 'testlog', context: name }); };gosa-core-2.7.4/html/include/effects.js0000644000175000017500000011310711325266624016755 0ustar cajuscajus// script.aculo.us effects.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // Contributors: // Justin Palmer (http://encytemedia.com/) // Mark Pilgrim (http://diveintomark.org/) // Martin Bialasinki // // script.aculo.us is freely distributable under the terms of an MIT-style license. // For details, see the script.aculo.us web site: http://script.aculo.us/ // converts rgb() and #xxx to #xxxxxx format, // returns self (or first argument) if not convertable String.prototype.parseColor = function() { var color = '#'; if (this.slice(0,4) == 'rgb(') { var cols = this.slice(4,this.length-1).split(','); var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); } else { if (this.slice(0,1) == '#') { if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); if (this.length==7) color = this.toLowerCase(); } } return (color.length==7 ? color : (arguments[0] || this)); }; /*--------------------------------------------------------------------------*/ Element.collectTextNodes = function(element) { return $A($(element).childNodes).collect( function(node) { return (node.nodeType==3 ? node.nodeValue : (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); }).flatten().join(''); }; Element.collectTextNodesIgnoreClass = function(element, className) { return $A($(element).childNodes).collect( function(node) { return (node.nodeType==3 ? node.nodeValue : ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? Element.collectTextNodesIgnoreClass(node, className) : '')); }).flatten().join(''); }; Element.setContentZoom = function(element, percent) { element = $(element); element.setStyle({fontSize: (percent/100) + 'em'}); if (Prototype.Browser.WebKit) window.scrollBy(0,0); return element; }; Element.getInlineOpacity = function(element){ return $(element).style.opacity || ''; }; Element.forceRerendering = function(element) { try { element = $(element); var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch(e) { } }; /*--------------------------------------------------------------------------*/ var Effect = { _elementDoesNotExistError: { name: 'ElementDoesNotExistError', message: 'The specified DOM element does not exist, but is required for this effect to operate' }, Transitions: { linear: Prototype.K, sinoidal: function(pos) { return (-Math.cos(pos*Math.PI)/2) + .5; }, reverse: function(pos) { return 1-pos; }, flicker: function(pos) { var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4; return pos > 1 ? 1 : pos; }, wobble: function(pos) { return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5; }, pulse: function(pos, pulses) { return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; }, spring: function(pos) { return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); }, none: function(pos) { return 0; }, full: function(pos) { return 1; } }, DefaultOptions: { duration: 1.0, // seconds fps: 100, // 100= assume 66fps max. sync: false, // true for combining from: 0.0, to: 1.0, delay: 0.0, queue: 'parallel' }, tagifyText: function(element) { var tagifyStyle = 'position:relative'; if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; element = $(element); $A(element.childNodes).each( function(child) { if (child.nodeType==3) { child.nodeValue.toArray().each( function(character) { element.insertBefore( new Element('span', {style: tagifyStyle}).update( character == ' ' ? String.fromCharCode(160) : character), child); }); Element.remove(child); } }); }, multiple: function(element, effect) { var elements; if (((typeof element == 'object') || Object.isFunction(element)) && (element.length)) elements = element; else elements = $(element).childNodes; var options = Object.extend({ speed: 0.1, delay: 0.0 }, arguments[2] || { }); var masterDelay = options.delay; $A(elements).each( function(element, index) { new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); }); }, PAIRS: { 'slide': ['SlideDown','SlideUp'], 'blind': ['BlindDown','BlindUp'], 'appear': ['Appear','Fade'] }, toggle: function(element, effect, options) { element = $(element); effect = (effect || 'appear').toLowerCase(); return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({ queue: { position:'end', scope:(element.id || 'global'), limit: 1 } }, options || {})); } }; Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; /* ------------- core effects ------------- */ Effect.ScopedQueue = Class.create(Enumerable, { initialize: function() { this.effects = []; this.interval = null; }, _each: function(iterator) { this.effects._each(iterator); }, add: function(effect) { var timestamp = new Date().getTime(); var position = Object.isString(effect.options.queue) ? effect.options.queue : effect.options.queue.position; switch(position) { case 'front': // move unstarted effects after this effect this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { e.startOn += effect.finishOn; e.finishOn += effect.finishOn; }); break; case 'with-last': timestamp = this.effects.pluck('startOn').max() || timestamp; break; case 'end': // start effect after last queued effect has finished timestamp = this.effects.pluck('finishOn').max() || timestamp; break; } effect.startOn += timestamp; effect.finishOn += timestamp; if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) this.effects.push(effect); if (!this.interval) this.interval = setInterval(this.loop.bind(this), 15); }, remove: function(effect) { this.effects = this.effects.reject(function(e) { return e==effect }); if (this.effects.length == 0) { clearInterval(this.interval); this.interval = null; } }, loop: function() { var timePos = new Date().getTime(); for(var i=0, len=this.effects.length;i= this.startOn) { if (timePos >= this.finishOn) { this.render(1.0); this.cancel(); this.event('beforeFinish'); if (this.finish) this.finish(); this.event('afterFinish'); return; } var pos = (timePos - this.startOn) / this.totalTime, frame = (pos * this.totalFrames).round(); if (frame > this.currentFrame) { this.render(pos); this.currentFrame = frame; } } }, cancel: function() { if (!this.options.sync) Effect.Queues.get(Object.isString(this.options.queue) ? 'global' : this.options.queue.scope).remove(this); this.state = 'finished'; }, event: function(eventName) { if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); if (this.options[eventName]) this.options[eventName](this); }, inspect: function() { var data = $H(); for(property in this) if (!Object.isFunction(this[property])) data.set(property, this[property]); return '#'; } }); Effect.Parallel = Class.create(Effect.Base, { initialize: function(effects) { this.effects = effects || []; this.start(arguments[1]); }, update: function(position) { this.effects.invoke('render', position); }, finish: function(position) { this.effects.each( function(effect) { effect.render(1.0); effect.cancel(); effect.event('beforeFinish'); if (effect.finish) effect.finish(position); effect.event('afterFinish'); }); } }); Effect.Tween = Class.create(Effect.Base, { initialize: function(object, from, to) { object = Object.isString(object) ? $(object) : object; var args = $A(arguments), method = args.last(), options = args.length == 5 ? args[3] : null; this.method = Object.isFunction(method) ? method.bind(object) : Object.isFunction(object[method]) ? object[method].bind(object) : function(value) { object[method] = value }; this.start(Object.extend({ from: from, to: to }, options || { })); }, update: function(position) { this.method(position); } }); Effect.Event = Class.create(Effect.Base, { initialize: function() { this.start(Object.extend({ duration: 0 }, arguments[0] || { })); }, update: Prototype.emptyFunction }); Effect.Opacity = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); // make this work on IE on elements without 'layout' if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) this.element.setStyle({zoom: 1}); var options = Object.extend({ from: this.element.getOpacity() || 0.0, to: 1.0 }, arguments[1] || { }); this.start(options); }, update: function(position) { this.element.setOpacity(position); } }); Effect.Move = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ x: 0, y: 0, mode: 'relative' }, arguments[1] || { }); this.start(options); }, setup: function() { this.element.makePositioned(); this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); this.originalTop = parseFloat(this.element.getStyle('top') || '0'); if (this.options.mode == 'absolute') { this.options.x = this.options.x - this.originalLeft; this.options.y = this.options.y - this.originalTop; } }, update: function(position) { this.element.setStyle({ left: (this.options.x * position + this.originalLeft).round() + 'px', top: (this.options.y * position + this.originalTop).round() + 'px' }); } }); // for backwards compatibility Effect.MoveBy = function(element, toTop, toLeft) { return new Effect.Move(element, Object.extend({ x: toLeft, y: toTop }, arguments[3] || { })); }; Effect.Scale = Class.create(Effect.Base, { initialize: function(element, percent) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ scaleX: true, scaleY: true, scaleContent: true, scaleFromCenter: false, scaleMode: 'box', // 'box' or 'contents' or { } with provided values scaleFrom: 100.0, scaleTo: percent }, arguments[2] || { }); this.start(options); }, setup: function() { this.restoreAfterFinish = this.options.restoreAfterFinish || false; this.elementPositioning = this.element.getStyle('position'); this.originalStyle = { }; ['top','left','width','height','fontSize'].each( function(k) { this.originalStyle[k] = this.element.style[k]; }.bind(this)); this.originalTop = this.element.offsetTop; this.originalLeft = this.element.offsetLeft; var fontSize = this.element.getStyle('font-size') || '100%'; ['em','px','%','pt'].each( function(fontSizeType) { if (fontSize.indexOf(fontSizeType)>0) { this.fontSize = parseFloat(fontSize); this.fontSizeType = fontSizeType; } }.bind(this)); this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; this.dims = null; if (this.options.scaleMode=='box') this.dims = [this.element.offsetHeight, this.element.offsetWidth]; if (/^content/.test(this.options.scaleMode)) this.dims = [this.element.scrollHeight, this.element.scrollWidth]; if (!this.dims) this.dims = [this.options.scaleMode.originalHeight, this.options.scaleMode.originalWidth]; }, update: function(position) { var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); if (this.options.scaleContent && this.fontSize) this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); }, finish: function(position) { if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); }, setDimensions: function(height, width) { var d = { }; if (this.options.scaleX) d.width = width.round() + 'px'; if (this.options.scaleY) d.height = height.round() + 'px'; if (this.options.scaleFromCenter) { var topd = (height - this.dims[0])/2; var leftd = (width - this.dims[1])/2; if (this.elementPositioning == 'absolute') { if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; } else { if (this.options.scaleY) d.top = -topd + 'px'; if (this.options.scaleX) d.left = -leftd + 'px'; } } this.element.setStyle(d); } }); Effect.Highlight = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); this.start(options); }, setup: function() { // Prevent executing on elements not in the layout flow if (this.element.getStyle('display')=='none') { this.cancel(); return; } // Disable background image during the effect this.oldStyle = { }; if (!this.options.keepBackgroundImage) { this.oldStyle.backgroundImage = this.element.getStyle('background-image'); this.element.setStyle({backgroundImage: 'none'}); } if (!this.options.endcolor) this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); if (!this.options.restorecolor) this.options.restorecolor = this.element.getStyle('background-color'); // init color calculations this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); }, update: function(position) { this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); }, finish: function() { this.element.setStyle(Object.extend(this.oldStyle, { backgroundColor: this.options.restorecolor })); } }); Effect.ScrollTo = function(element) { var options = arguments[1] || { }, scrollOffsets = document.viewport.getScrollOffsets(), elementOffsets = $(element).cumulativeOffset(); if (options.offset) elementOffsets[1] += options.offset; return new Effect.Tween(null, scrollOffsets.top, elementOffsets[1], options, function(p){ scrollTo(scrollOffsets.left, p.round()); } ); }; /* ------------- combination effects ------------- */ Effect.Fade = function(element) { element = $(element); var oldOpacity = element.getInlineOpacity(); var options = Object.extend({ from: element.getOpacity() || 1.0, to: 0.0, afterFinishInternal: function(effect) { if (effect.options.to!=0) return; effect.element.hide().setStyle({opacity: oldOpacity}); } }, arguments[1] || { }); return new Effect.Opacity(element,options); }; Effect.Appear = function(element) { element = $(element); var options = Object.extend({ from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), to: 1.0, // force Safari to render floated elements properly afterFinishInternal: function(effect) { effect.element.forceRerendering(); }, beforeSetup: function(effect) { effect.element.setOpacity(effect.options.from).show(); }}, arguments[1] || { }); return new Effect.Opacity(element,options); }; Effect.Puff = function(element) { element = $(element); var oldStyle = { opacity: element.getInlineOpacity(), position: element.getStyle('position'), top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; return new Effect.Parallel( [ new Effect.Scale(element, 200, { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], Object.extend({ duration: 1.0, beforeSetupInternal: function(effect) { Position.absolutize(effect.effects[0].element); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().setStyle(oldStyle); } }, arguments[1] || { }) ); }; Effect.BlindUp = function(element) { element = $(element); element.makeClipping(); return new Effect.Scale(element, 0, Object.extend({ scaleContent: false, scaleX: false, restoreAfterFinish: true, afterFinishInternal: function(effect) { effect.element.hide().undoClipping(); } }, arguments[1] || { }) ); }; Effect.BlindDown = function(element) { element = $(element); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: 0, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makeClipping().setStyle({height: '0px'}).show(); }, afterFinishInternal: function(effect) { effect.element.undoClipping(); } }, arguments[1] || { })); }; Effect.SwitchOff = function(element) { element = $(element); var oldOpacity = element.getInlineOpacity(); return new Effect.Appear(element, Object.extend({ duration: 0.4, from: 0, transition: Effect.Transitions.flicker, afterFinishInternal: function(effect) { new Effect.Scale(effect.element, 1, { duration: 0.3, scaleFromCenter: true, scaleX: false, scaleContent: false, restoreAfterFinish: true, beforeSetup: function(effect) { effect.element.makePositioned().makeClipping(); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); } }); } }, arguments[1] || { })); }; Effect.DropOut = function(element) { element = $(element); var oldStyle = { top: element.getStyle('top'), left: element.getStyle('left'), opacity: element.getInlineOpacity() }; return new Effect.Parallel( [ new Effect.Move(element, {x: 0, y: 100, sync: true }), new Effect.Opacity(element, { sync: true, to: 0.0 }) ], Object.extend( { duration: 0.5, beforeSetup: function(effect) { effect.effects[0].element.makePositioned(); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); } }, arguments[1] || { })); }; Effect.Shake = function(element) { element = $(element); var options = Object.extend({ distance: 20, duration: 0.5 }, arguments[1] || {}); var distance = parseFloat(options.distance); var split = parseFloat(options.duration) / 10.0; var oldStyle = { top: element.getStyle('top'), left: element.getStyle('left') }; return new Effect.Move(element, { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { new Effect.Move(effect.element, { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { effect.element.undoPositioned().setStyle(oldStyle); }}); }}); }}); }}); }}); }}); }; Effect.SlideDown = function(element) { element = $(element).cleanWhitespace(); // SlideDown need to have the content of the element wrapped in a container element with fixed height! var oldInnerBottom = element.down().getStyle('bottom'); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, 100, Object.extend({ scaleContent: false, scaleX: false, scaleFrom: window.opera ? 0 : 1, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makePositioned(); effect.element.down().makePositioned(); if (window.opera) effect.element.setStyle({top: ''}); effect.element.makeClipping().setStyle({height: '0px'}).show(); }, afterUpdateInternal: function(effect) { effect.element.down().setStyle({bottom: (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, afterFinishInternal: function(effect) { effect.element.undoClipping().undoPositioned(); effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } }, arguments[1] || { }) ); }; Effect.SlideUp = function(element) { element = $(element).cleanWhitespace(); var oldInnerBottom = element.down().getStyle('bottom'); var elementDimensions = element.getDimensions(); return new Effect.Scale(element, window.opera ? 0 : 1, Object.extend({ scaleContent: false, scaleX: false, scaleMode: 'box', scaleFrom: 100, scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, restoreAfterFinish: true, afterSetup: function(effect) { effect.element.makePositioned(); effect.element.down().makePositioned(); if (window.opera) effect.element.setStyle({top: ''}); effect.element.makeClipping().show(); }, afterUpdateInternal: function(effect) { effect.element.down().setStyle({bottom: (effect.dims[0] - effect.element.clientHeight) + 'px' }); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().undoPositioned(); effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } }, arguments[1] || { }) ); }; // Bug in opera makes the TD containing this element expand for a instance after finish Effect.Squish = function(element) { return new Effect.Scale(element, window.opera ? 1 : 0, { restoreAfterFinish: true, beforeSetup: function(effect) { effect.element.makeClipping(); }, afterFinishInternal: function(effect) { effect.element.hide().undoClipping(); } }); }; Effect.Grow = function(element) { element = $(element); var options = Object.extend({ direction: 'center', moveTransition: Effect.Transitions.sinoidal, scaleTransition: Effect.Transitions.sinoidal, opacityTransition: Effect.Transitions.full }, arguments[1] || { }); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getInlineOpacity() }; var dims = element.getDimensions(); var initialMoveX, initialMoveY; var moveX, moveY; switch (options.direction) { case 'top-left': initialMoveX = initialMoveY = moveX = moveY = 0; break; case 'top-right': initialMoveX = dims.width; initialMoveY = moveY = 0; moveX = -dims.width; break; case 'bottom-left': initialMoveX = moveX = 0; initialMoveY = dims.height; moveY = -dims.height; break; case 'bottom-right': initialMoveX = dims.width; initialMoveY = dims.height; moveX = -dims.width; moveY = -dims.height; break; case 'center': initialMoveX = dims.width / 2; initialMoveY = dims.height / 2; moveX = -dims.width / 2; moveY = -dims.height / 2; break; } return new Effect.Move(element, { x: initialMoveX, y: initialMoveY, duration: 0.01, beforeSetup: function(effect) { effect.element.hide().makeClipping().makePositioned(); }, afterFinishInternal: function(effect) { new Effect.Parallel( [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), new Effect.Scale(effect.element, 100, { scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) ], Object.extend({ beforeSetup: function(effect) { effect.effects[0].element.setStyle({height: '0px'}).show(); }, afterFinishInternal: function(effect) { effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); } }, options) ); } }); }; Effect.Shrink = function(element) { element = $(element); var options = Object.extend({ direction: 'center', moveTransition: Effect.Transitions.sinoidal, scaleTransition: Effect.Transitions.sinoidal, opacityTransition: Effect.Transitions.none }, arguments[1] || { }); var oldStyle = { top: element.style.top, left: element.style.left, height: element.style.height, width: element.style.width, opacity: element.getInlineOpacity() }; var dims = element.getDimensions(); var moveX, moveY; switch (options.direction) { case 'top-left': moveX = moveY = 0; break; case 'top-right': moveX = dims.width; moveY = 0; break; case 'bottom-left': moveX = 0; moveY = dims.height; break; case 'bottom-right': moveX = dims.width; moveY = dims.height; break; case 'center': moveX = dims.width / 2; moveY = dims.height / 2; break; } return new Effect.Parallel( [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) ], Object.extend({ beforeStartInternal: function(effect) { effect.effects[0].element.makePositioned().makeClipping(); }, afterFinishInternal: function(effect) { effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } }, options) ); }; Effect.Pulsate = function(element) { element = $(element); var options = arguments[1] || { }, oldOpacity = element.getInlineOpacity(), transition = options.transition || Effect.Transitions.linear, reverser = function(pos){ return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); }; return new Effect.Opacity(element, Object.extend(Object.extend({ duration: 2.0, from: 0, afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } }, options), {transition: reverser})); }; Effect.Fold = function(element) { element = $(element); var oldStyle = { top: element.style.top, left: element.style.left, width: element.style.width, height: element.style.height }; element.makeClipping(); return new Effect.Scale(element, 5, Object.extend({ scaleContent: false, scaleX: false, afterFinishInternal: function(effect) { new Effect.Scale(element, 1, { scaleContent: false, scaleY: false, afterFinishInternal: function(effect) { effect.element.hide().undoClipping().setStyle(oldStyle); } }); }}, arguments[1] || { })); }; Effect.Morph = Class.create(Effect.Base, { initialize: function(element) { this.element = $(element); if (!this.element) throw(Effect._elementDoesNotExistError); var options = Object.extend({ style: { } }, arguments[1] || { }); if (!Object.isString(options.style)) this.style = $H(options.style); else { if (options.style.include(':')) this.style = options.style.parseStyle(); else { this.element.addClassName(options.style); this.style = $H(this.element.getStyles()); this.element.removeClassName(options.style); var css = this.element.getStyles(); this.style = this.style.reject(function(style) { return style.value == css[style.key]; }); options.afterFinishInternal = function(effect) { effect.element.addClassName(effect.options.style); effect.transforms.each(function(transform) { effect.element.style[transform.style] = ''; }); }; } } this.start(options); }, setup: function(){ function parseColor(color){ if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; color = color.parseColor(); return $R(0,2).map(function(i){ return parseInt( color.slice(i*2+1,i*2+3), 16 ); }); } this.transforms = this.style.map(function(pair){ var property = pair[0], value = pair[1], unit = null; if (value.parseColor('#zzzzzz') != '#zzzzzz') { value = value.parseColor(); unit = 'color'; } else if (property == 'opacity') { value = parseFloat(value); if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) this.element.setStyle({zoom: 1}); } else if (Element.CSS_LENGTH.test(value)) { var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); value = parseFloat(components[1]); unit = (components.length == 3) ? components[2] : null; } var originalValue = this.element.getStyle(property); return { style: property.camelize(), originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), targetValue: unit=='color' ? parseColor(value) : value, unit: unit }; }.bind(this)).reject(function(transform){ return ( (transform.originalValue == transform.targetValue) || ( transform.unit != 'color' && (isNaN(transform.originalValue) || isNaN(transform.targetValue)) ) ); }); }, update: function(position) { var style = { }, transform, i = this.transforms.length; while(i--) style[(transform = this.transforms[i]).style] = transform.unit=='color' ? '#'+ (Math.round(transform.originalValue[0]+ (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + (Math.round(transform.originalValue[1]+ (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + (Math.round(transform.originalValue[2]+ (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : (transform.originalValue + (transform.targetValue - transform.originalValue) * position).toFixed(3) + (transform.unit === null ? '' : transform.unit); this.element.setStyle(style, true); } }); Effect.Transform = Class.create({ initialize: function(tracks){ this.tracks = []; this.options = arguments[1] || { }; this.addTracks(tracks); }, addTracks: function(tracks){ tracks.each(function(track){ track = $H(track); var data = track.values().first(); this.tracks.push($H({ ids: track.keys().first(), effect: Effect.Morph, options: { style: data } })); }.bind(this)); return this; }, play: function(){ return new Effect.Parallel( this.tracks.map(function(track){ var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); var elements = [$(ids) || $$(ids)].flatten(); return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); }).flatten(), this.options ); } }); Element.CSS_PROPERTIES = $w( 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + 'fontSize fontWeight height left letterSpacing lineHeight ' + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + 'right textIndent top width wordSpacing zIndex'); Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; String.__parseStyleElement = document.createElement('div'); String.prototype.parseStyle = function(){ var style, styleRules = $H(); if (Prototype.Browser.WebKit) style = new Element('div',{style:this}).style; else { String.__parseStyleElement.innerHTML = '
    '; style = String.__parseStyleElement.childNodes[0].style; } Element.CSS_PROPERTIES.each(function(property){ if (style[property]) styleRules.set(property, style[property]); }); if (Prototype.Browser.IE && this.include('opacity')) styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); return styleRules; }; if (document.defaultView && document.defaultView.getComputedStyle) { Element.getStyles = function(element) { var css = document.defaultView.getComputedStyle($(element), null); return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { styles[property] = css[property]; return styles; }); }; } else { Element.getStyles = function(element) { element = $(element); var css = element.currentStyle, styles; styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { results[property] = css[property]; return results; }); if (!styles.opacity) styles.opacity = element.getOpacity(); return styles; }; } Effect.Methods = { morph: function(element, style) { element = $(element); new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); return element; }, visualEffect: function(element, effect, options) { element = $(element); var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); new Effect[klass](element, options); return element; }, highlight: function(element, options) { element = $(element); new Effect.Highlight(element, options); return element; } }; $w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ 'pulsate shake puff squish switchOff dropOut').each( function(effect) { Effect.Methods[effect] = function(element, options){ element = $(element); Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); return element; }; } ); $w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( function(f) { Effect.Methods[f] = Element[f]; } ); Element.addMethods(Effect.Methods);gosa-core-2.7.4/html/include/gosa.js0000644000175000017500000004227711557560321016276 0ustar cajuscajus/* * This code is part of GOsa (http://www.gosa-project.org) * Copyright (C) 2003-2010 GONICUS GmbH * * ID: $$Id: index.php 15301 2010-01-26 09:40:08Z cajus $$ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* Install event handlers */ Event.observe(window, 'resize', resizeHandler); Event.observe(window, 'load', resizeHandler); Event.observe(window, 'load', initProgressPie); Event.observe(window, 'keypress', keyHandler); /* Ask before switching a plugin with this function */ function question(text, url) { if(document.mainform.ignore || $('pluginModified') == null || $('pluginModified').value == 0){ location.href= url; return true; } if(confirm(text)){ location.href= url; return true; } return false; } /* Toggle checkbox that matches regex */ function chk_set_all(regex,value) { for (var i = 0; i < document.mainform.elements.length; i++) { var _id=document.mainform.elements[i].id; if(_id.match(regex)) { document.getElementById(_id).checked= value; } } } function toggle_all_(regex,state_object) { state = document.getElementById(state_object).checked; chk_set_all(regex, state); } /* Scroll down the body frame */ function scrollDown2() { document.body.scrollTop = document.body.scrollHeight - document.body.clientHeight; } /* Toggle checkbox that matches regex */ function acl_set_all(regex,value) { for (var i = 0; i < document.mainform.elements.length; i++) { var _id=document.mainform.elements[i].id; if(_id.match(regex)) { document.getElementById(_id).checked= value; } } } /* Toggle checkbox that matches regex */ function acl_toggle_all(regex) { for (var i = 0; i < document.mainform.elements.length; i++) { var _id=document.mainform.elements[i].id; if(_id.match(regex)) { if (document.getElementById(_id).checked == true){ document.getElementById(_id).checked= false; } else { document.getElementById(_id).checked= true; } } } } /* Global key handler to estimate which element gets the next focus if enter is pressed */ function keyHandler(DnEvents) { var element = Event.element(DnEvents); // determines whether Netscape or Internet Explorer k = (Prototype.Browser.Gecko) ? DnEvents.keyCode : window.event.keyCode; if (k == 13 && element.type!='textarea') { // enter key pressed // Stop 'Enter' key-press from beeing processed internally Event.stop(DnEvents); // No nextfield explicitly specified var next_element = null; if(typeof(nextfield)!='undefined') { next_element = $(nextfield); } // nextfield not given or invalid if(!next_element || typeof(nextfield)=='undefined'){ next_element = getNextInputElement(element); } if(element != null && element.type == 'submit'){ // If the current element is of type submit, then submit the button else set focus element.click(); return(false); }else if(next_element!=null && next_element.type == 'submit'){ // If next element is of type submit, then submit the button else set focus next_element.click(); return(false); }else if(next_element){ next_element.focus(); return; } } else if (k==9 && element.type=='textarea') { Event.stop(DnEvents); element.value += "\t"; return false; } } function getNextInputElement(element) { var found = false; for (var e=0;e< document.forms.length; e++){ for (var i = 0; i < document.forms[e].elements.length; i++) { var el = document.forms[e].elements[i] if(found && !el.disabled && el.type!='hidden' && !el.name.match(/^submit_tree_base/) && !el.name.match(/^bs_rebase/)){ return(el); } if((el.id != "" && el.id==element.id) || (el.name != "" && el.name==element.name)){ found =true; } } } } function changeState() { for (var i = 0; i < arguments.length; i++) { var element = $(arguments[i]); if (element.hasAttribute('disabled')) { element.removeAttribute('disabled'); } else { element.setAttribute('disabled', 'disabled'); } } } function changeSelectState(triggerField, myField) { if (document.getElementById(triggerField).value != 2){ document.getElementById(myField).disabled= true; } else { document.getElementById(myField).disabled= false; } } function changeSubselectState(triggerField, myField) { if (document.getElementById(triggerField).checked == true){ document.getElementById(myField).disabled= false; } else { document.getElementById(myField).disabled= true; } } function changeTripleSelectState(firstTriggerField, secondTriggerField, myField) { if ( document.getElementById(firstTriggerField).checked == true && document.getElementById(secondTriggerField).checked == true){ document.getElementById(myField).disabled= false; } else { document.getElementById(myField).disabled= true; } } function changeTripleSelectState_2nd_neg(firstTriggerField, secondTriggerField, myField) { if ( document.getElementById(firstTriggerField).checked == true && document.getElementById(secondTriggerField).checked == false){ document.getElementById(myField).disabled= false; } else { document.getElementById(myField).disabled= true; } } function popup(target, name) { var mypopup= window.open( target, name, "width=600,height=700,location=no,toolbar=no,directories=no,menubar=no,status=no,scrollbars=yes" ); mypopup.focus(); return false; } function js_check(form) { form.javascript.value = 'true'; } function divGOsa_toggle(element) { var cell; var cellname="tr_"+(element); if (Prototype.Browser.Gecko) { document.poppedLayer = document.getElementById(element); cell= document.getElementById(cellname); if (document.poppedLayer.style.visibility == "visible") { $(element).hide(); cell.style.height="0px"; document.poppedLayer.style.height="0px"; } else { $(element).show(); document.poppedLayer.style.height=""; if(document.defaultView) { cell.style.height=document.defaultView.getComputedStyle(document.poppedLayer,"").getPropertyValue('height'); } } } else if (Prototype.Browser.IE) { document.poppedLayer = document.getElementById(element); cell= document.getElementById(cellname); if (document.poppedLayer.style.visibility == "visible") { $(element).hide(); cell.style.height="0px"; document.poppedLayer.style.height="0px"; document.poppedLayer.style.position="absolute"; } else { $(element).show(); cell.style.height=""; document.poppedLayer.style.height=""; document.poppedLayer.style.position="relative"; } } } function resizeHandler (e) { if (!e) e= window.event; // This works with FF / IE9. If Apples resolves a bug in webkit, // it works with Safari/Chrome, too. if ($("d_scrollbody") && $("t_nscrollbody")) { var contentHeight= document.viewport.getHeight() - 216; if ($$('div.plugin-actions').length != 0) { var height= 0; $$('div.plugin-actions').each(function(s) { height+= s.getHeight(); }); contentHeight-= height + 25; } if (Prototype.Browser.IE) { document.getElementById('d_scrollbody').style.height = contentHeight+23+'px'; document.getElementById('t_nscrollbody').style.height = contentHeight+'px'; } else { document.getElementById('d_scrollbody').style.minHeight = contentHeight+23+'px'; document.getElementById('t_nscrollbody').style.minHeight = contentHeight+'px'; } } return true; } function absTop(e) { return (e.offsetParent)?e.offsetTop+absTop(e.offsetParent) : e.offsetTop; } /* Set focus to first valid input field avoid IExplorer warning about hidding or disabled fields */ function focus_field() { var i = 0; var e = 0; var found = false; var element_name = ""; var element =null; while(focus_field.arguments[i] && !found){ var tmp = document.getElementsByName(focus_field.arguments[i]); for(e = 0 ; e < tmp.length ; e ++ ){ if(isVisible(tmp[e])){ found = true; element = tmp[e]; break; } } i++; } if(element && found){ element.blur(); element.focus(); } } /* This function pops up messages from message queue All messages are hidden in html output (style='display:none;'). This function makes single messages visible till there are no more dialogs queued. hidden inputs: current_msg_dialogs - Currently visible dialog closed_msg_dialogs - IDs of already closed dialogs pending_msg_dialogs - Queued dialog IDs. */ function next_msg_dialog() { var s_pending = ""; var a_pending = new Array(); var i_id = 0; var i = 0; var tmp = ""; var ele = null; var ele2 = null; var cur_id = ""; if(document.getElementById('current_msg_dialogs')){ cur_id = document.getElementById('current_msg_dialogs').value; if(cur_id != ""){ ele = document.getElementById('e_layer' + cur_id); ele.onmousemove = ""; $('e_layer' + cur_id).hide(); document.getElementById('closed_msg_dialogs').value += "," + cur_id; document.getElementById('current_msg_dialogs').value= ""; } } if(document.getElementById('pending_msg_dialogs')){ s_pending = document.getElementById('pending_msg_dialogs').value; a_pending = s_pending.split(","); if(a_pending.length){ i_id = a_pending.pop(); for (i = 0 ; i < a_pending.length; ++i){ tmp = tmp + a_pending[i] + ','; } tmp = tmp.replace(/,$/g,""); if(i_id != ""){ ele = document.getElementById('e_layer' + i_id); ele3 = document.getElementById('e_layerTitle' + i_id); ele.style.display= 'block' ; document.getElementById('pending_msg_dialogs').value= tmp; document.getElementById('current_msg_dialogs').value= i_id; ele2 = document.getElementById('e_layer2') ; ele3.onmousedown = start_move_div_by_cursor; ele2.onmouseup = stop_move_div_by_cursor; ele2.onmousemove = move_div_by_cursor; }else{ ele2 = document.getElementById('e_layer2') ; ele2.style.display ="none"; } } } } /* Drag & drop for message dialogs */ var enable_move_div_by_cursor = false; // Indicates wheter the div movement is enabled or not var mouse_x_on_div = 0; // var mouse_y_on_div = 0; var div_offset_x = 0; var div_offset_y = 0; /* Activates msg_dialog drag & drop * This function is called when clicking on a displayed msg_dialog */ function start_move_div_by_cursor(e) { var x = 0; var y = 0; var cur_id = 0; var dialog = null; var event = null; /* Get current msg_dialog position */ cur_id = document.getElementById('current_msg_dialogs').value; if(cur_id != ""){ dialog = document.getElementById('e_layer' + cur_id); x = dialog.style.left; y = dialog.style.top; x = x.replace(/[^0-9]/g,""); y = y.replace(/[^0-9]/g,""); if(!y) y = 1; if(!x) x = 1; } /* Get mouse position within msg_dialog */ if(window.event){ event = window.event; if(event.offsetX){ div_offset_x = event.clientX -x; div_offset_y = event.clientY -y; enable_move_div_by_cursor = true; } }else if(e){ event = e; if(event.layerX){ div_offset_x = event.screenX -x; div_offset_y = event.screenY -y; enable_move_div_by_cursor = true; } } } /* Deactivate msg_dialog movement */ function stop_move_div_by_cursor() { mouse_x_on_div = 0; mouse_y_on_div = 0; div_offset_x = 0; div_offset_y = 0; enable_move_div_by_cursor = false; } /* Move msg_dialog with cursor */ function move_div_by_cursor(e) { var event = false; var mouse_pos_x = 0; var mouse_pos_y = 0; var cur_div_x = 0; var cur_div_y = 0; var cur_id = 0; var dialog = null; if(undefined !== enable_move_div_by_cursor && enable_move_div_by_cursor == true){ if(document.getElementById('current_msg_dialogs')){ /* Get mouse position on screen */ if(window.event){ event = window.event; mouse_pos_x =event.clientX; mouse_pos_y =event.clientY; }else if (e){ event = e; mouse_pos_x =event.screenX; mouse_pos_y =event.screenY; }else{ return; } /* Get id of current msg_dialog */ cur_id = document.getElementById('current_msg_dialogs').value; if(cur_id != ""){ dialog = document.getElementById('e_layer' + cur_id); /* Calculate new position */ cur_div_x = mouse_pos_x - div_offset_x; cur_div_y = mouse_pos_y - div_offset_y; /* Ensure that dialog can't be moved out of screen */ if(cur_div_x < 0 ) cur_div_x = 0 if(cur_div_y < 0 ) cur_div_y = 0 /* Assign new values */ dialog.style.left = (cur_div_x ) + "px"; dialog.style.top = (cur_div_y ) + "px"; } } } } function isVisible(obj) { if (obj == document) return true if (!obj) return false if (!obj.parentNode) return false if (obj.style) { if (obj.style.display == 'none') return false if (obj.style.visibility == 'hidden') return false } //Try the computed style in a standard way if (window.getComputedStyle) { var style = window.getComputedStyle(obj, "") if (style.display == 'none') return false if (style.visibility == 'hidden') return false } //Or get the computed style using IE's silly proprietary way var style = obj.currentStyle if (style) { if (style['display'] == 'none') return false if (style['visibility'] == 'hidden') return false } return isVisible(obj.parentNode) } /* Check if capslock is enabled */ function capslock(e) { e = (e) ? e : window.event; var charCode = false; if (e.which) { charCode = e.which; } else if (e.keyCode) { charCode = e.keyCode; } var shifton = false; if (e.shiftKey) { shifton = e.shiftKey; } else if (e.modifiers) { shifton = !!(e.modifiers & 4); } if (charCode >= 97 && charCode <= 122 && shifton) { return true; } if (charCode >= 65 && charCode <= 90 && !shifton) { return true; } return false; } function setProgressPie(context, percent) { context.clearRect(0, 0, 22, 22); var r = "FF"; var g = "FF"; var b = "FF"; // Fade yellow if (percent > 50) { d = 255 - parseInt((percent-50) * 255 / 50) b = d.toString(16); } // Fade red if (percent > 75) { d = 255 - parseInt((percent-75) * 255 / 25) g = d.toString(16); } context.strokeStyle = "#" + r + g + b context.fillStyle = context.strokeStyle; context.beginPath(); context.moveTo(11,11) context.arc(11,11,8,-Math.PI/2,-Math.PI/2 + Math.PI*percent/50,true); context.closePath(); context.fill(); context.moveTo(11,11) context.beginPath(); context.arc(11,11,8,0,Math.PI*2,false); context.closePath(); context.stroke(); } function initProgressPie(){ var canvas = $('sTimeout'); // Check the element is in the DOM and the browser supports canvas if(canvas && canvas.getContext) { var percent = 0.01; var context = canvas.getContext('2d'); setProgressPie(context, percent); // Extract timeout and title string out out canvas.title var data = canvas.title; var timeout = data.replace(/\|.*$/,''); var title = data.replace(/^.*\|/,''); var interval = 1; var time = 0; setInterval(function() { // Calculate percentage percent+= (interval / timeout) * 100; // Increase current time by interval time += interval; // Generate title var minutes = parseInt((timeout-time) / 60 ); var seconds = '' + parseInt((timeout-time) % 60); if(seconds.length == 1) seconds = '0' + seconds ; minutes = minutes + ':' + seconds; // Set new canval title canvas.title= title.replace(/%d/ ,minutes); setProgressPie(context, percent); if (percent>99) percent= 99; }, (interval * 1000)); } } /* Scroll down the body frame */ function scrollDown2() { document.body.scrollTop = document.body.scrollHeight - document.body.clientHeight; } // Global storage for baseSelector timer var rtimer; // vim:ts=2:syntax gosa-core-2.7.4/html/include/prototype.js0000644000175000017500000042111611325266624017405 0ustar cajuscajus/* Prototype JavaScript framework, version 1.6.1 * (c) 2005-2009 Sam Stephenson * * Prototype is freely distributable under the terms of an MIT-style license. * For details, see the Prototype web site: http://www.prototypejs.org/ * *--------------------------------------------------------------------------*/ var Prototype = { Version: '1.6.1', Browser: (function(){ var ua = navigator.userAgent; var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; return { IE: !!window.attachEvent && !isOpera, Opera: isOpera, WebKit: ua.indexOf('AppleWebKit/') > -1, Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, MobileSafari: /Apple.*Mobile.*Safari/.test(ua) } })(), BrowserFeatures: { XPath: !!document.evaluate, SelectorsAPI: !!document.querySelector, ElementExtensions: (function() { var constructor = window.Element || window.HTMLElement; return !!(constructor && constructor.prototype); })(), SpecificElementExtensions: (function() { if (typeof window.HTMLDivElement !== 'undefined') return true; var div = document.createElement('div'); var form = document.createElement('form'); var isSupported = false; if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { isSupported = true; } div = form = null; return isSupported; })() }, ScriptFragment: ']*>([\\S\\s]*?)<\/script>', JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, emptyFunction: function() { }, K: function(x) { return x } }; if (Prototype.Browser.MobileSafari) Prototype.BrowserFeatures.SpecificElementExtensions = false; var Abstract = { }; var Try = { these: function() { var returnValue; for (var i = 0, length = arguments.length; i < length; i++) { var lambda = arguments[i]; try { returnValue = lambda(); break; } catch (e) { } } return returnValue; } }; /* Based on Alex Arnell's inheritance implementation. */ var Class = (function() { function subclass() {}; function create() { var parent = null, properties = $A(arguments); if (Object.isFunction(properties[0])) parent = properties.shift(); function klass() { this.initialize.apply(this, arguments); } Object.extend(klass, Class.Methods); klass.superclass = parent; klass.subclasses = []; if (parent) { subclass.prototype = parent.prototype; klass.prototype = new subclass; parent.subclasses.push(klass); } for (var i = 0; i < properties.length; i++) klass.addMethods(properties[i]); if (!klass.prototype.initialize) klass.prototype.initialize = Prototype.emptyFunction; klass.prototype.constructor = klass; return klass; } function addMethods(source) { var ancestor = this.superclass && this.superclass.prototype; var properties = Object.keys(source); if (!Object.keys({ toString: true }).length) { if (source.toString != Object.prototype.toString) properties.push("toString"); if (source.valueOf != Object.prototype.valueOf) properties.push("valueOf"); } for (var i = 0, length = properties.length; i < length; i++) { var property = properties[i], value = source[property]; if (ancestor && Object.isFunction(value) && value.argumentNames().first() == "$super") { var method = value; value = (function(m) { return function() { return ancestor[m].apply(this, arguments); }; })(property).wrap(method); value.valueOf = method.valueOf.bind(method); value.toString = method.toString.bind(method); } this.prototype[property] = value; } return this; } return { create: create, Methods: { addMethods: addMethods } }; })(); (function() { var _toString = Object.prototype.toString; function extend(destination, source) { for (var property in source) destination[property] = source[property]; return destination; } function inspect(object) { try { if (isUndefined(object)) return 'undefined'; if (object === null) return 'null'; return object.inspect ? object.inspect() : String(object); } catch (e) { if (e instanceof RangeError) return '...'; throw e; } } function toJSON(object) { var type = typeof object; switch (type) { case 'undefined': case 'function': case 'unknown': return; case 'boolean': return object.toString(); } if (object === null) return 'null'; if (object.toJSON) return object.toJSON(); if (isElement(object)) return; var results = []; for (var property in object) { var value = toJSON(object[property]); if (!isUndefined(value)) results.push(property.toJSON() + ': ' + value); } return '{' + results.join(', ') + '}'; } function toQueryString(object) { return $H(object).toQueryString(); } function toHTML(object) { return object && object.toHTML ? object.toHTML() : String.interpret(object); } function keys(object) { var results = []; for (var property in object) results.push(property); return results; } function values(object) { var results = []; for (var property in object) results.push(object[property]); return results; } function clone(object) { return extend({ }, object); } function isElement(object) { return !!(object && object.nodeType == 1); } function isArray(object) { return _toString.call(object) == "[object Array]"; } function isHash(object) { return object instanceof Hash; } function isFunction(object) { return typeof object === "function"; } function isString(object) { return _toString.call(object) == "[object String]"; } function isNumber(object) { return _toString.call(object) == "[object Number]"; } function isUndefined(object) { return typeof object === "undefined"; } extend(Object, { extend: extend, inspect: inspect, toJSON: toJSON, toQueryString: toQueryString, toHTML: toHTML, keys: keys, values: values, clone: clone, isElement: isElement, isArray: isArray, isHash: isHash, isFunction: isFunction, isString: isString, isNumber: isNumber, isUndefined: isUndefined }); })(); Object.extend(Function.prototype, (function() { var slice = Array.prototype.slice; function update(array, args) { var arrayLength = array.length, length = args.length; while (length--) array[arrayLength + length] = args[length]; return array; } function merge(array, args) { array = slice.call(array, 0); return update(array, args); } function argumentNames() { var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') .replace(/\s+/g, '').split(','); return names.length == 1 && !names[0] ? [] : names; } function bind(context) { if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; var __method = this, args = slice.call(arguments, 1); return function() { var a = merge(args, arguments); return __method.apply(context, a); } } function bindAsEventListener(context) { var __method = this, args = slice.call(arguments, 1); return function(event) { var a = update([event || window.event], args); return __method.apply(context, a); } } function curry() { if (!arguments.length) return this; var __method = this, args = slice.call(arguments, 0); return function() { var a = merge(args, arguments); return __method.apply(this, a); } } function delay(timeout) { var __method = this, args = slice.call(arguments, 1); timeout = timeout * 1000 return window.setTimeout(function() { return __method.apply(__method, args); }, timeout); } function defer() { var args = update([0.01], arguments); return this.delay.apply(this, args); } function wrap(wrapper) { var __method = this; return function() { var a = update([__method.bind(this)], arguments); return wrapper.apply(this, a); } } function methodize() { if (this._methodized) return this._methodized; var __method = this; return this._methodized = function() { var a = update([this], arguments); return __method.apply(null, a); }; } return { argumentNames: argumentNames, bind: bind, bindAsEventListener: bindAsEventListener, curry: curry, delay: delay, defer: defer, wrap: wrap, methodize: methodize } })()); Date.prototype.toJSON = function() { return '"' + this.getUTCFullYear() + '-' + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + this.getUTCDate().toPaddedString(2) + 'T' + this.getUTCHours().toPaddedString(2) + ':' + this.getUTCMinutes().toPaddedString(2) + ':' + this.getUTCSeconds().toPaddedString(2) + 'Z"'; }; RegExp.prototype.match = RegExp.prototype.test; RegExp.escape = function(str) { return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); }; var PeriodicalExecuter = Class.create({ initialize: function(callback, frequency) { this.callback = callback; this.frequency = frequency; this.currentlyExecuting = false; this.registerCallback(); }, registerCallback: function() { this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); }, execute: function() { this.callback(this); }, stop: function() { if (!this.timer) return; clearInterval(this.timer); this.timer = null; }, onTimerEvent: function() { if (!this.currentlyExecuting) { try { this.currentlyExecuting = true; this.execute(); this.currentlyExecuting = false; } catch(e) { this.currentlyExecuting = false; throw e; } } } }); Object.extend(String, { interpret: function(value) { return value == null ? '' : String(value); }, specialChar: { '\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '\\': '\\\\' } }); Object.extend(String.prototype, (function() { function prepareReplacement(replacement) { if (Object.isFunction(replacement)) return replacement; var template = new Template(replacement); return function(match) { return template.evaluate(match) }; } function gsub(pattern, replacement) { var result = '', source = this, match; replacement = prepareReplacement(replacement); if (Object.isString(pattern)) pattern = RegExp.escape(pattern); if (!(pattern.length || pattern.source)) { replacement = replacement(''); return replacement + source.split('').join(replacement) + replacement; } while (source.length > 0) { if (match = source.match(pattern)) { result += source.slice(0, match.index); result += String.interpret(replacement(match)); source = source.slice(match.index + match[0].length); } else { result += source, source = ''; } } return result; } function sub(pattern, replacement, count) { replacement = prepareReplacement(replacement); count = Object.isUndefined(count) ? 1 : count; return this.gsub(pattern, function(match) { if (--count < 0) return match[0]; return replacement(match); }); } function scan(pattern, iterator) { this.gsub(pattern, iterator); return String(this); } function truncate(length, truncation) { length = length || 30; truncation = Object.isUndefined(truncation) ? '...' : truncation; return this.length > length ? this.slice(0, length - truncation.length) + truncation : String(this); } function strip() { return this.replace(/^\s+/, '').replace(/\s+$/, ''); } function stripTags() { return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); } function stripScripts() { return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); } function extractScripts() { var matchAll = new RegExp(Prototype.ScriptFragment, 'img'); var matchOne = new RegExp(Prototype.ScriptFragment, 'im'); return (this.match(matchAll) || []).map(function(scriptTag) { return (scriptTag.match(matchOne) || ['', ''])[1]; }); } function evalScripts() { return this.extractScripts().map(function(script) { return eval(script) }); } function escapeHTML() { return this.replace(/&/g,'&').replace(//g,'>'); } function unescapeHTML() { return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); } function toQueryParams(separator) { var match = this.strip().match(/([^?#]*)(#.*)?$/); if (!match) return { }; return match[1].split(separator || '&').inject({ }, function(hash, pair) { if ((pair = pair.split('='))[0]) { var key = decodeURIComponent(pair.shift()); var value = pair.length > 1 ? pair.join('=') : pair[0]; if (value != undefined) value = decodeURIComponent(value); if (key in hash) { if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; hash[key].push(value); } else hash[key] = value; } return hash; }); } function toArray() { return this.split(''); } function succ() { return this.slice(0, this.length - 1) + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); } function times(count) { return count < 1 ? '' : new Array(count + 1).join(this); } function camelize() { var parts = this.split('-'), len = parts.length; if (len == 1) return parts[0]; var camelized = this.charAt(0) == '-' ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1) : parts[0]; for (var i = 1; i < len; i++) camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1); return camelized; } function capitalize() { return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); } function underscore() { return this.replace(/::/g, '/') .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') .replace(/([a-z\d])([A-Z])/g, '$1_$2') .replace(/-/g, '_') .toLowerCase(); } function dasherize() { return this.replace(/_/g, '-'); } function inspect(useDoubleQuotes) { var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { if (character in String.specialChar) { return String.specialChar[character]; } return '\\u00' + character.charCodeAt().toPaddedString(2, 16); }); if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; return "'" + escapedString.replace(/'/g, '\\\'') + "'"; } function toJSON() { return this.inspect(true); } function unfilterJSON(filter) { return this.replace(filter || Prototype.JSONFilter, '$1'); } function isJSON() { var str = this; if (str.blank()) return false; str = this.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, ''); return (/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(str); } function evalJSON(sanitize) { var json = this.unfilterJSON(); try { if (!sanitize || json.isJSON()) return eval('(' + json + ')'); } catch (e) { } throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); } function include(pattern) { return this.indexOf(pattern) > -1; } function startsWith(pattern) { return this.indexOf(pattern) === 0; } function endsWith(pattern) { var d = this.length - pattern.length; return d >= 0 && this.lastIndexOf(pattern) === d; } function empty() { return this == ''; } function blank() { return /^\s*$/.test(this); } function interpolate(object, pattern) { return new Template(this, pattern).evaluate(object); } return { gsub: gsub, sub: sub, scan: scan, truncate: truncate, strip: String.prototype.trim ? String.prototype.trim : strip, stripTags: stripTags, stripScripts: stripScripts, extractScripts: extractScripts, evalScripts: evalScripts, escapeHTML: escapeHTML, unescapeHTML: unescapeHTML, toQueryParams: toQueryParams, parseQuery: toQueryParams, toArray: toArray, succ: succ, times: times, camelize: camelize, capitalize: capitalize, underscore: underscore, dasherize: dasherize, inspect: inspect, toJSON: toJSON, unfilterJSON: unfilterJSON, isJSON: isJSON, evalJSON: evalJSON, include: include, startsWith: startsWith, endsWith: endsWith, empty: empty, blank: blank, interpolate: interpolate }; })()); var Template = Class.create({ initialize: function(template, pattern) { this.template = template.toString(); this.pattern = pattern || Template.Pattern; }, evaluate: function(object) { if (object && Object.isFunction(object.toTemplateReplacements)) object = object.toTemplateReplacements(); return this.template.gsub(this.pattern, function(match) { if (object == null) return (match[1] + ''); var before = match[1] || ''; if (before == '\\') return match[2]; var ctx = object, expr = match[3]; var pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; match = pattern.exec(expr); if (match == null) return before; while (match != null) { var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; ctx = ctx[comp]; if (null == ctx || '' == match[3]) break; expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); match = pattern.exec(expr); } return before + String.interpret(ctx); }); } }); Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; var $break = { }; var Enumerable = (function() { function each(iterator, context) { var index = 0; try { this._each(function(value) { iterator.call(context, value, index++); }); } catch (e) { if (e != $break) throw e; } return this; } function eachSlice(number, iterator, context) { var index = -number, slices = [], array = this.toArray(); if (number < 1) return array; while ((index += number) < array.length) slices.push(array.slice(index, index+number)); return slices.collect(iterator, context); } function all(iterator, context) { iterator = iterator || Prototype.K; var result = true; this.each(function(value, index) { result = result && !!iterator.call(context, value, index); if (!result) throw $break; }); return result; } function any(iterator, context) { iterator = iterator || Prototype.K; var result = false; this.each(function(value, index) { if (result = !!iterator.call(context, value, index)) throw $break; }); return result; } function collect(iterator, context) { iterator = iterator || Prototype.K; var results = []; this.each(function(value, index) { results.push(iterator.call(context, value, index)); }); return results; } function detect(iterator, context) { var result; this.each(function(value, index) { if (iterator.call(context, value, index)) { result = value; throw $break; } }); return result; } function findAll(iterator, context) { var results = []; this.each(function(value, index) { if (iterator.call(context, value, index)) results.push(value); }); return results; } function grep(filter, iterator, context) { iterator = iterator || Prototype.K; var results = []; if (Object.isString(filter)) filter = new RegExp(RegExp.escape(filter)); this.each(function(value, index) { if (filter.match(value)) results.push(iterator.call(context, value, index)); }); return results; } function include(object) { if (Object.isFunction(this.indexOf)) if (this.indexOf(object) != -1) return true; var found = false; this.each(function(value) { if (value == object) { found = true; throw $break; } }); return found; } function inGroupsOf(number, fillWith) { fillWith = Object.isUndefined(fillWith) ? null : fillWith; return this.eachSlice(number, function(slice) { while(slice.length < number) slice.push(fillWith); return slice; }); } function inject(memo, iterator, context) { this.each(function(value, index) { memo = iterator.call(context, memo, value, index); }); return memo; } function invoke(method) { var args = $A(arguments).slice(1); return this.map(function(value) { return value[method].apply(value, args); }); } function max(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value >= result) result = value; }); return result; } function min(iterator, context) { iterator = iterator || Prototype.K; var result; this.each(function(value, index) { value = iterator.call(context, value, index); if (result == null || value < result) result = value; }); return result; } function partition(iterator, context) { iterator = iterator || Prototype.K; var trues = [], falses = []; this.each(function(value, index) { (iterator.call(context, value, index) ? trues : falses).push(value); }); return [trues, falses]; } function pluck(property) { var results = []; this.each(function(value) { results.push(value[property]); }); return results; } function reject(iterator, context) { var results = []; this.each(function(value, index) { if (!iterator.call(context, value, index)) results.push(value); }); return results; } function sortBy(iterator, context) { return this.map(function(value, index) { return { value: value, criteria: iterator.call(context, value, index) }; }).sort(function(left, right) { var a = left.criteria, b = right.criteria; return a < b ? -1 : a > b ? 1 : 0; }).pluck('value'); } function toArray() { return this.map(); } function zip() { var iterator = Prototype.K, args = $A(arguments); if (Object.isFunction(args.last())) iterator = args.pop(); var collections = [this].concat(args).map($A); return this.map(function(value, index) { return iterator(collections.pluck(index)); }); } function size() { return this.toArray().length; } function inspect() { return '#'; } return { each: each, eachSlice: eachSlice, all: all, every: all, any: any, some: any, collect: collect, map: collect, detect: detect, findAll: findAll, select: findAll, filter: findAll, grep: grep, include: include, member: include, inGroupsOf: inGroupsOf, inject: inject, invoke: invoke, max: max, min: min, partition: partition, pluck: pluck, reject: reject, sortBy: sortBy, toArray: toArray, entries: toArray, zip: zip, size: size, inspect: inspect, find: detect }; })(); function $A(iterable) { if (!iterable) return []; if ('toArray' in Object(iterable)) return iterable.toArray(); var length = iterable.length || 0, results = new Array(length); while (length--) results[length] = iterable[length]; return results; } function $w(string) { if (!Object.isString(string)) return []; string = string.strip(); return string ? string.split(/\s+/) : []; } Array.from = $A; (function() { var arrayProto = Array.prototype, slice = arrayProto.slice, _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available function each(iterator) { for (var i = 0, length = this.length; i < length; i++) iterator(this[i]); } if (!_each) _each = each; function clear() { this.length = 0; return this; } function first() { return this[0]; } function last() { return this[this.length - 1]; } function compact() { return this.select(function(value) { return value != null; }); } function flatten() { return this.inject([], function(array, value) { if (Object.isArray(value)) return array.concat(value.flatten()); array.push(value); return array; }); } function without() { var values = slice.call(arguments, 0); return this.select(function(value) { return !values.include(value); }); } function reverse(inline) { return (inline !== false ? this : this.toArray())._reverse(); } function uniq(sorted) { return this.inject([], function(array, value, index) { if (0 == index || (sorted ? array.last() != value : !array.include(value))) array.push(value); return array; }); } function intersect(array) { return this.uniq().findAll(function(item) { return array.detect(function(value) { return item === value }); }); } function clone() { return slice.call(this, 0); } function size() { return this.length; } function inspect() { return '[' + this.map(Object.inspect).join(', ') + ']'; } function toJSON() { var results = []; this.each(function(object) { var value = Object.toJSON(object); if (!Object.isUndefined(value)) results.push(value); }); return '[' + results.join(', ') + ']'; } function indexOf(item, i) { i || (i = 0); var length = this.length; if (i < 0) i = length + i; for (; i < length; i++) if (this[i] === item) return i; return -1; } function lastIndexOf(item, i) { i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; var n = this.slice(0, i).reverse().indexOf(item); return (n < 0) ? n : i - n - 1; } function concat() { var array = slice.call(this, 0), item; for (var i = 0, length = arguments.length; i < length; i++) { item = arguments[i]; if (Object.isArray(item) && !('callee' in item)) { for (var j = 0, arrayLength = item.length; j < arrayLength; j++) array.push(item[j]); } else { array.push(item); } } return array; } Object.extend(arrayProto, Enumerable); if (!arrayProto._reverse) arrayProto._reverse = arrayProto.reverse; Object.extend(arrayProto, { _each: _each, clear: clear, first: first, last: last, compact: compact, flatten: flatten, without: without, reverse: reverse, uniq: uniq, intersect: intersect, clone: clone, toArray: clone, size: size, inspect: inspect, toJSON: toJSON }); var CONCAT_ARGUMENTS_BUGGY = (function() { return [].concat(arguments)[0][0] !== 1; })(1,2) if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; })(); function $H(object) { return new Hash(object); }; var Hash = Class.create(Enumerable, (function() { function initialize(object) { this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); } function _each(iterator) { for (var key in this._object) { var value = this._object[key], pair = [key, value]; pair.key = key; pair.value = value; iterator(pair); } } function set(key, value) { return this._object[key] = value; } function get(key) { if (this._object[key] !== Object.prototype[key]) return this._object[key]; } function unset(key) { var value = this._object[key]; delete this._object[key]; return value; } function toObject() { return Object.clone(this._object); } function keys() { return this.pluck('key'); } function values() { return this.pluck('value'); } function index(value) { var match = this.detect(function(pair) { return pair.value === value; }); return match && match.key; } function merge(object) { return this.clone().update(object); } function update(object) { return new Hash(object).inject(this, function(result, pair) { result.set(pair.key, pair.value); return result; }); } function toQueryPair(key, value) { if (Object.isUndefined(value)) return key; return key + '=' + encodeURIComponent(String.interpret(value)); } function toQueryString() { return this.inject([], function(results, pair) { var key = encodeURIComponent(pair.key), values = pair.value; if (values && typeof values == 'object') { if (Object.isArray(values)) return results.concat(values.map(toQueryPair.curry(key))); } else results.push(toQueryPair(key, values)); return results; }).join('&'); } function inspect() { return '#'; } function toJSON() { return Object.toJSON(this.toObject()); } function clone() { return new Hash(this); } return { initialize: initialize, _each: _each, set: set, get: get, unset: unset, toObject: toObject, toTemplateReplacements: toObject, keys: keys, values: values, index: index, merge: merge, update: update, toQueryString: toQueryString, inspect: inspect, toJSON: toJSON, clone: clone }; })()); Hash.from = $H; Object.extend(Number.prototype, (function() { function toColorPart() { return this.toPaddedString(2, 16); } function succ() { return this + 1; } function times(iterator, context) { $R(0, this, true).each(iterator, context); return this; } function toPaddedString(length, radix) { var string = this.toString(radix || 10); return '0'.times(length - string.length) + string; } function toJSON() { return isFinite(this) ? this.toString() : 'null'; } function abs() { return Math.abs(this); } function round() { return Math.round(this); } function ceil() { return Math.ceil(this); } function floor() { return Math.floor(this); } return { toColorPart: toColorPart, succ: succ, times: times, toPaddedString: toPaddedString, toJSON: toJSON, abs: abs, round: round, ceil: ceil, floor: floor }; })()); function $R(start, end, exclusive) { return new ObjectRange(start, end, exclusive); } var ObjectRange = Class.create(Enumerable, (function() { function initialize(start, end, exclusive) { this.start = start; this.end = end; this.exclusive = exclusive; } function _each(iterator) { var value = this.start; while (this.include(value)) { iterator(value); value = value.succ(); } } function include(value) { if (value < this.start) return false; if (this.exclusive) return value < this.end; return value <= this.end; } return { initialize: initialize, _each: _each, include: include }; })()); var Ajax = { getTransport: function() { return Try.these( function() {return new XMLHttpRequest()}, function() {return new ActiveXObject('Msxml2.XMLHTTP')}, function() {return new ActiveXObject('Microsoft.XMLHTTP')} ) || false; }, activeRequestCount: 0 }; Ajax.Responders = { responders: [], _each: function(iterator) { this.responders._each(iterator); }, register: function(responder) { if (!this.include(responder)) this.responders.push(responder); }, unregister: function(responder) { this.responders = this.responders.without(responder); }, dispatch: function(callback, request, transport, json) { this.each(function(responder) { if (Object.isFunction(responder[callback])) { try { responder[callback].apply(responder, [request, transport, json]); } catch (e) { } } }); } }; Object.extend(Ajax.Responders, Enumerable); Ajax.Responders.register({ onCreate: function() { Ajax.activeRequestCount++ }, onComplete: function() { Ajax.activeRequestCount-- } }); Ajax.Base = Class.create({ initialize: function(options) { this.options = { method: 'post', asynchronous: true, contentType: 'application/x-www-form-urlencoded', encoding: 'UTF-8', parameters: '', evalJSON: true, evalJS: true }; Object.extend(this.options, options || { }); this.options.method = this.options.method.toLowerCase(); if (Object.isString(this.options.parameters)) this.options.parameters = this.options.parameters.toQueryParams(); else if (Object.isHash(this.options.parameters)) this.options.parameters = this.options.parameters.toObject(); } }); Ajax.Request = Class.create(Ajax.Base, { _complete: false, initialize: function($super, url, options) { $super(options); this.transport = Ajax.getTransport(); this.request(url); }, request: function(url) { this.url = url; this.method = this.options.method; var params = Object.clone(this.options.parameters); if (!['get', 'post'].include(this.method)) { params['_method'] = this.method; this.method = 'post'; } this.parameters = params; if (params = Object.toQueryString(params)) { if (this.method == 'get') this.url += (this.url.include('?') ? '&' : '?') + params; else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='; } try { var response = new Ajax.Response(this); if (this.options.onCreate) this.options.onCreate(response); Ajax.Responders.dispatch('onCreate', this, response); this.transport.open(this.method.toUpperCase(), this.url, this.options.asynchronous); if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); this.transport.onreadystatechange = this.onStateChange.bind(this); this.setRequestHeaders(); this.body = this.method == 'post' ? (this.options.postBody || params) : null; this.transport.send(this.body); /* Force Firefox to handle ready state 4 for synchronous requests */ if (!this.options.asynchronous && this.transport.overrideMimeType) this.onStateChange(); } catch (e) { this.dispatchException(e); } }, onStateChange: function() { var readyState = this.transport.readyState; if (readyState > 1 && !((readyState == 4) && this._complete)) this.respondToReadyState(this.transport.readyState); }, setRequestHeaders: function() { var headers = { 'X-Requested-With': 'XMLHttpRequest', 'X-Prototype-Version': Prototype.Version, 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' }; if (this.method == 'post') { headers['Content-type'] = this.options.contentType + (this.options.encoding ? '; charset=' + this.options.encoding : ''); /* Force "Connection: close" for older Mozilla browsers to work * around a bug where XMLHttpRequest sends an incorrect * Content-length header. See Mozilla Bugzilla #246651. */ if (this.transport.overrideMimeType && (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) headers['Connection'] = 'close'; } if (typeof this.options.requestHeaders == 'object') { var extras = this.options.requestHeaders; if (Object.isFunction(extras.push)) for (var i = 0, length = extras.length; i < length; i += 2) headers[extras[i]] = extras[i+1]; else $H(extras).each(function(pair) { headers[pair.key] = pair.value }); } for (var name in headers) this.transport.setRequestHeader(name, headers[name]); }, success: function() { var status = this.getStatus(); return !status || (status >= 200 && status < 300); }, getStatus: function() { try { return this.transport.status || 0; } catch (e) { return 0 } }, respondToReadyState: function(readyState) { var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); if (state == 'Complete') { try { this._complete = true; (this.options['on' + response.status] || this.options['on' + (this.success() ? 'Success' : 'Failure')] || Prototype.emptyFunction)(response, response.headerJSON); } catch (e) { this.dispatchException(e); } var contentType = response.getHeader('Content-type'); if (this.options.evalJS == 'force' || (this.options.evalJS && this.isSameOrigin() && contentType && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) this.evalResponse(); } try { (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); } catch (e) { this.dispatchException(e); } if (state == 'Complete') { this.transport.onreadystatechange = Prototype.emptyFunction; } }, isSameOrigin: function() { var m = this.url.match(/^\s*https?:\/\/[^\/]*/); return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ protocol: location.protocol, domain: document.domain, port: location.port ? ':' + location.port : '' })); }, getHeader: function(name) { try { return this.transport.getResponseHeader(name) || null; } catch (e) { return null; } }, evalResponse: function() { try { return eval((this.transport.responseText || '').unfilterJSON()); } catch (e) { this.dispatchException(e); } }, dispatchException: function(exception) { (this.options.onException || Prototype.emptyFunction)(this, exception); Ajax.Responders.dispatch('onException', this, exception); } }); Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; Ajax.Response = Class.create({ initialize: function(request){ this.request = request; var transport = this.transport = request.transport, readyState = this.readyState = transport.readyState; if((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { this.status = this.getStatus(); this.statusText = this.getStatusText(); this.responseText = String.interpret(transport.responseText); this.headerJSON = this._getHeaderJSON(); } if(readyState == 4) { var xml = transport.responseXML; this.responseXML = Object.isUndefined(xml) ? null : xml; this.responseJSON = this._getResponseJSON(); } }, status: 0, statusText: '', getStatus: Ajax.Request.prototype.getStatus, getStatusText: function() { try { return this.transport.statusText || ''; } catch (e) { return '' } }, getHeader: Ajax.Request.prototype.getHeader, getAllHeaders: function() { try { return this.getAllResponseHeaders(); } catch (e) { return null } }, getResponseHeader: function(name) { return this.transport.getResponseHeader(name); }, getAllResponseHeaders: function() { return this.transport.getAllResponseHeaders(); }, _getHeaderJSON: function() { var json = this.getHeader('X-JSON'); if (!json) return null; json = decodeURIComponent(escape(json)); try { return json.evalJSON(this.request.options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } }, _getResponseJSON: function() { var options = this.request.options; if (!options.evalJSON || (options.evalJSON != 'force' && !(this.getHeader('Content-type') || '').include('application/json')) || this.responseText.blank()) return null; try { return this.responseText.evalJSON(options.sanitizeJSON || !this.request.isSameOrigin()); } catch (e) { this.request.dispatchException(e); } } }); Ajax.Updater = Class.create(Ajax.Request, { initialize: function($super, container, url, options) { this.container = { success: (container.success || container), failure: (container.failure || (container.success ? null : container)) }; options = Object.clone(options); var onComplete = options.onComplete; options.onComplete = (function(response, json) { this.updateContent(response.responseText); if (Object.isFunction(onComplete)) onComplete(response, json); }).bind(this); $super(url, options); }, updateContent: function(responseText) { var receiver = this.container[this.success() ? 'success' : 'failure'], options = this.options; if (!options.evalScripts) responseText = responseText.stripScripts(); if (receiver = $(receiver)) { if (options.insertion) { if (Object.isString(options.insertion)) { var insertion = { }; insertion[options.insertion] = responseText; receiver.insert(insertion); } else options.insertion(receiver, responseText); } else receiver.update(responseText); } } }); Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { initialize: function($super, container, url, options) { $super(options); this.onComplete = this.options.onComplete; this.frequency = (this.options.frequency || 2); this.decay = (this.options.decay || 1); this.updater = { }; this.container = container; this.url = url; this.start(); }, start: function() { this.options.onComplete = this.updateComplete.bind(this); this.onTimerEvent(); }, stop: function() { this.updater.options.onComplete = undefined; clearTimeout(this.timer); (this.onComplete || Prototype.emptyFunction).apply(this, arguments); }, updateComplete: function(response) { if (this.options.decay) { this.decay = (response.responseText == this.lastText ? this.decay * this.options.decay : 1); this.lastText = response.responseText; } this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); }, onTimerEvent: function() { this.updater = new Ajax.Updater(this.container, this.url, this.options); } }); function $(element) { if (arguments.length > 1) { for (var i = 0, elements = [], length = arguments.length; i < length; i++) elements.push($(arguments[i])); return elements; } if (Object.isString(element)) element = document.getElementById(element); return Element.extend(element); } if (Prototype.BrowserFeatures.XPath) { document._getElementsByXPath = function(expression, parentElement) { var results = []; var query = document.evaluate(expression, $(parentElement) || document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); for (var i = 0, length = query.snapshotLength; i < length; i++) results.push(Element.extend(query.snapshotItem(i))); return results; }; } /*--------------------------------------------------------------------------*/ if (!window.Node) var Node = { }; if (!Node.ELEMENT_NODE) { Object.extend(Node, { ELEMENT_NODE: 1, ATTRIBUTE_NODE: 2, TEXT_NODE: 3, CDATA_SECTION_NODE: 4, ENTITY_REFERENCE_NODE: 5, ENTITY_NODE: 6, PROCESSING_INSTRUCTION_NODE: 7, COMMENT_NODE: 8, DOCUMENT_NODE: 9, DOCUMENT_TYPE_NODE: 10, DOCUMENT_FRAGMENT_NODE: 11, NOTATION_NODE: 12 }); } (function(global) { var SETATTRIBUTE_IGNORES_NAME = (function(){ var elForm = document.createElement("form"); var elInput = document.createElement("input"); var root = document.documentElement; elInput.setAttribute("name", "test"); elForm.appendChild(elInput); root.appendChild(elForm); var isBuggy = elForm.elements ? (typeof elForm.elements.test == "undefined") : null; root.removeChild(elForm); elForm = elInput = null; return isBuggy; })(); var element = global.Element; global.Element = function(tagName, attributes) { attributes = attributes || { }; tagName = tagName.toLowerCase(); var cache = Element.cache; if (SETATTRIBUTE_IGNORES_NAME && attributes.name) { tagName = '<' + tagName + ' name="' + attributes.name + '">'; delete attributes.name; return Element.writeAttribute(document.createElement(tagName), attributes); } if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); }; Object.extend(global.Element, element || { }); if (element) global.Element.prototype = element.prototype; })(this); Element.cache = { }; Element.idCounter = 1; Element.Methods = { visible: function(element) { return $(element).style.display != 'none'; }, toggle: function(element) { element = $(element); Element[Element.visible(element) ? 'hide' : 'show'](element); return element; }, hide: function(element) { element = $(element); element.style.display = 'none'; return element; }, show: function(element) { element = $(element); element.style.display = ''; return element; }, remove: function(element) { element = $(element); element.parentNode.removeChild(element); return element; }, update: (function(){ var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ var el = document.createElement("select"), isBuggy = true; el.innerHTML = ""; if (el.options && el.options[0]) { isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; } el = null; return isBuggy; })(); var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ try { var el = document.createElement("table"); if (el && el.tBodies) { el.innerHTML = "test"; var isBuggy = typeof el.tBodies[0] == "undefined"; el = null; return isBuggy; } } catch (e) { return true; } })(); var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { var s = document.createElement("script"), isBuggy = false; try { s.appendChild(document.createTextNode("")); isBuggy = !s.firstChild || s.firstChild && s.firstChild.nodeType !== 3; } catch (e) { isBuggy = true; } s = null; return isBuggy; })(); function update(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) return element.update().insert(content); content = Object.toHTML(content); var tagName = element.tagName.toUpperCase(); if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { element.text = content; return element; } if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { if (tagName in Element._insertionTranslations.tags) { while (element.firstChild) { element.removeChild(element.firstChild); } Element._getContentFromAnonymousElement(tagName, content.stripScripts()) .each(function(node) { element.appendChild(node) }); } else { element.innerHTML = content.stripScripts(); } } else { element.innerHTML = content.stripScripts(); } content.evalScripts.bind(content).defer(); return element; } return update; })(), replace: function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); else if (!Object.isElement(content)) { content = Object.toHTML(content); var range = element.ownerDocument.createRange(); range.selectNode(element); content.evalScripts.bind(content).defer(); content = range.createContextualFragment(content.stripScripts()); } element.parentNode.replaceChild(content, element); return element; }, insert: function(element, insertions) { element = $(element); if (Object.isString(insertions) || Object.isNumber(insertions) || Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) insertions = {bottom:insertions}; var content, insert, tagName, childNodes; for (var position in insertions) { content = insertions[position]; position = position.toLowerCase(); insert = Element._insertionTranslations[position]; if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { insert(element, content); continue; } content = Object.toHTML(content); tagName = ((position == 'before' || position == 'after') ? element.parentNode : element).tagName.toUpperCase(); childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); if (position == 'top' || position == 'after') childNodes.reverse(); childNodes.each(insert.curry(element)); content.evalScripts.bind(content).defer(); } return element; }, wrap: function(element, wrapper, attributes) { element = $(element); if (Object.isElement(wrapper)) $(wrapper).writeAttribute(attributes || { }); else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); else wrapper = new Element('div', wrapper); if (element.parentNode) element.parentNode.replaceChild(wrapper, element); wrapper.appendChild(element); return wrapper; }, inspect: function(element) { element = $(element); var result = '<' + element.tagName.toLowerCase(); $H({'id': 'id', 'className': 'class'}).each(function(pair) { var property = pair.first(), attribute = pair.last(); var value = (element[property] || '').toString(); if (value) result += ' ' + attribute + '=' + value.inspect(true); }); return result + '>'; }, recursivelyCollect: function(element, property) { element = $(element); var elements = []; while (element = element[property]) if (element.nodeType == 1) elements.push(Element.extend(element)); return elements; }, ancestors: function(element) { return Element.recursivelyCollect(element, 'parentNode'); }, descendants: function(element) { return Element.select(element, "*"); }, firstDescendant: function(element) { element = $(element).firstChild; while (element && element.nodeType != 1) element = element.nextSibling; return $(element); }, immediateDescendants: function(element) { if (!(element = $(element).firstChild)) return []; while (element && element.nodeType != 1) element = element.nextSibling; if (element) return [element].concat($(element).nextSiblings()); return []; }, previousSiblings: function(element) { return Element.recursivelyCollect(element, 'previousSibling'); }, nextSiblings: function(element) { return Element.recursivelyCollect(element, 'nextSibling'); }, siblings: function(element) { element = $(element); return Element.previousSiblings(element).reverse() .concat(Element.nextSiblings(element)); }, match: function(element, selector) { if (Object.isString(selector)) selector = new Selector(selector); return selector.match($(element)); }, up: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(element.parentNode); var ancestors = Element.ancestors(element); return Object.isNumber(expression) ? ancestors[expression] : Selector.findElement(ancestors, expression, index); }, down: function(element, expression, index) { element = $(element); if (arguments.length == 1) return Element.firstDescendant(element); return Object.isNumber(expression) ? Element.descendants(element)[expression] : Element.select(element, expression)[index || 0]; }, previous: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); var previousSiblings = Element.previousSiblings(element); return Object.isNumber(expression) ? previousSiblings[expression] : Selector.findElement(previousSiblings, expression, index); }, next: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); var nextSiblings = Element.nextSiblings(element); return Object.isNumber(expression) ? nextSiblings[expression] : Selector.findElement(nextSiblings, expression, index); }, select: function(element) { var args = Array.prototype.slice.call(arguments, 1); return Selector.findChildElements(element, args); }, adjacent: function(element) { var args = Array.prototype.slice.call(arguments, 1); return Selector.findChildElements(element.parentNode, args).without(element); }, identify: function(element) { element = $(element); var id = Element.readAttribute(element, 'id'); if (id) return id; do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); Element.writeAttribute(element, 'id', id); return id; }, readAttribute: function(element, name) { element = $(element); if (Prototype.Browser.IE) { var t = Element._attributeTranslations.read; if (t.values[name]) return t.values[name](element, name); if (t.names[name]) name = t.names[name]; if (name.include(':')) { return (!element.attributes || !element.attributes[name]) ? null : element.attributes[name].value; } } return element.getAttribute(name); }, writeAttribute: function(element, name, value) { element = $(element); var attributes = { }, t = Element._attributeTranslations.write; if (typeof name == 'object') attributes = name; else attributes[name] = Object.isUndefined(value) ? true : value; for (var attr in attributes) { name = t.names[attr] || attr; value = attributes[attr]; if (t.values[attr]) name = t.values[attr](element, value); if (value === false || value === null) element.removeAttribute(name); else if (value === true) element.setAttribute(name, name); else element.setAttribute(name, value); } return element; }, getHeight: function(element) { return Element.getDimensions(element).height; }, getWidth: function(element) { return Element.getDimensions(element).width; }, classNames: function(element) { return new Element.ClassNames(element); }, hasClassName: function(element, className) { if (!(element = $(element))) return; var elementClassName = element.className; return (elementClassName.length > 0 && (elementClassName == className || new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); }, addClassName: function(element, className) { if (!(element = $(element))) return; if (!Element.hasClassName(element, className)) element.className += (element.className ? ' ' : '') + className; return element; }, removeClassName: function(element, className) { if (!(element = $(element))) return; element.className = element.className.replace( new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); return element; }, toggleClassName: function(element, className) { if (!(element = $(element))) return; return Element[Element.hasClassName(element, className) ? 'removeClassName' : 'addClassName'](element, className); }, cleanWhitespace: function(element) { element = $(element); var node = element.firstChild; while (node) { var nextNode = node.nextSibling; if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) element.removeChild(node); node = nextNode; } return element; }, empty: function(element) { return $(element).innerHTML.blank(); }, descendantOf: function(element, ancestor) { element = $(element), ancestor = $(ancestor); if (element.compareDocumentPosition) return (element.compareDocumentPosition(ancestor) & 8) === 8; if (ancestor.contains) return ancestor.contains(element) && ancestor !== element; while (element = element.parentNode) if (element == ancestor) return true; return false; }, scrollTo: function(element) { element = $(element); var pos = Element.cumulativeOffset(element); window.scrollTo(pos[0], pos[1]); return element; }, getStyle: function(element, style) { element = $(element); style = style == 'float' ? 'cssFloat' : style.camelize(); var value = element.style[style]; if (!value || value == 'auto') { var css = document.defaultView.getComputedStyle(element, null); value = css ? css[style] : null; } if (style == 'opacity') return value ? parseFloat(value) : 1.0; return value == 'auto' ? null : value; }, getOpacity: function(element) { return $(element).getStyle('opacity'); }, setStyle: function(element, styles) { element = $(element); var elementStyle = element.style, match; if (Object.isString(styles)) { element.style.cssText += ';' + styles; return styles.include('opacity') ? element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; } for (var property in styles) if (property == 'opacity') element.setOpacity(styles[property]); else elementStyle[(property == 'float' || property == 'cssFloat') ? (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : property] = styles[property]; return element; }, setOpacity: function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }, getDimensions: function(element) { element = $(element); var display = Element.getStyle(element, 'display'); if (display != 'none' && display != null) // Safari bug return {width: element.offsetWidth, height: element.offsetHeight}; var els = element.style; var originalVisibility = els.visibility; var originalPosition = els.position; var originalDisplay = els.display; els.visibility = 'hidden'; if (originalPosition != 'fixed') // Switching fixed to absolute causes issues in Safari els.position = 'absolute'; els.display = 'block'; var originalWidth = element.clientWidth; var originalHeight = element.clientHeight; els.display = originalDisplay; els.position = originalPosition; els.visibility = originalVisibility; return {width: originalWidth, height: originalHeight}; }, makePositioned: function(element) { element = $(element); var pos = Element.getStyle(element, 'position'); if (pos == 'static' || !pos) { element._madePositioned = true; element.style.position = 'relative'; if (Prototype.Browser.Opera) { element.style.top = 0; element.style.left = 0; } } return element; }, undoPositioned: function(element) { element = $(element); if (element._madePositioned) { element._madePositioned = undefined; element.style.position = element.style.top = element.style.left = element.style.bottom = element.style.right = ''; } return element; }, makeClipping: function(element) { element = $(element); if (element._overflow) return element; element._overflow = Element.getStyle(element, 'overflow') || 'auto'; if (element._overflow !== 'hidden') element.style.overflow = 'hidden'; return element; }, undoClipping: function(element) { element = $(element); if (!element._overflow) return element; element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; element._overflow = null; return element; }, cumulativeOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }, positionedOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; element = element.offsetParent; if (element) { if (element.tagName.toUpperCase() == 'BODY') break; var p = Element.getStyle(element, 'position'); if (p !== 'static') break; } } while (element); return Element._returnOffset(valueL, valueT); }, absolutize: function(element) { element = $(element); if (Element.getStyle(element, 'position') == 'absolute') return element; var offsets = Element.positionedOffset(element); var top = offsets[1]; var left = offsets[0]; var width = element.clientWidth; var height = element.clientHeight; element._originalLeft = left - parseFloat(element.style.left || 0); element._originalTop = top - parseFloat(element.style.top || 0); element._originalWidth = element.style.width; element._originalHeight = element.style.height; element.style.position = 'absolute'; element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.width = width + 'px'; element.style.height = height + 'px'; return element; }, relativize: function(element) { element = $(element); if (Element.getStyle(element, 'position') == 'relative') return element; element.style.position = 'relative'; var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); element.style.top = top + 'px'; element.style.left = left + 'px'; element.style.height = element._originalHeight; element.style.width = element._originalWidth; return element; }, cumulativeScrollOffset: function(element) { var valueT = 0, valueL = 0; do { valueT += element.scrollTop || 0; valueL += element.scrollLeft || 0; element = element.parentNode; } while (element); return Element._returnOffset(valueL, valueT); }, getOffsetParent: function(element) { if (element.offsetParent) return $(element.offsetParent); if (element == document.body) return $(element); while ((element = element.parentNode) && element != document.body) if (Element.getStyle(element, 'position') != 'static') return $(element); return $(document.body); }, viewportOffset: function(forElement) { var valueT = 0, valueL = 0; var element = forElement; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body && Element.getStyle(element, 'position') == 'absolute') break; } while (element = element.offsetParent); element = forElement; do { if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { valueT -= element.scrollTop || 0; valueL -= element.scrollLeft || 0; } } while (element = element.parentNode); return Element._returnOffset(valueL, valueT); }, clonePosition: function(element, source) { var options = Object.extend({ setLeft: true, setTop: true, setWidth: true, setHeight: true, offsetTop: 0, offsetLeft: 0 }, arguments[2] || { }); source = $(source); var p = Element.viewportOffset(source); element = $(element); var delta = [0, 0]; var parent = null; if (Element.getStyle(element, 'position') == 'absolute') { parent = Element.getOffsetParent(element); delta = Element.viewportOffset(parent); } if (parent == document.body) { delta[0] -= document.body.offsetLeft; delta[1] -= document.body.offsetTop; } if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; if (options.setWidth) element.style.width = source.offsetWidth + 'px'; if (options.setHeight) element.style.height = source.offsetHeight + 'px'; return element; } }; Object.extend(Element.Methods, { getElementsBySelector: Element.Methods.select, childElements: Element.Methods.immediateDescendants }); Element._attributeTranslations = { write: { names: { className: 'class', htmlFor: 'for' }, values: { } } }; if (Prototype.Browser.Opera) { Element.Methods.getStyle = Element.Methods.getStyle.wrap( function(proceed, element, style) { switch (style) { case 'left': case 'top': case 'right': case 'bottom': if (proceed(element, 'position') === 'static') return null; case 'height': case 'width': if (!Element.visible(element)) return null; var dim = parseInt(proceed(element, style), 10); if (dim !== element['offset' + style.capitalize()]) return dim + 'px'; var properties; if (style === 'height') { properties = ['border-top-width', 'padding-top', 'padding-bottom', 'border-bottom-width']; } else { properties = ['border-left-width', 'padding-left', 'padding-right', 'border-right-width']; } return properties.inject(dim, function(memo, property) { var val = proceed(element, property); return val === null ? memo : memo - parseInt(val, 10); }) + 'px'; default: return proceed(element, style); } } ); Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( function(proceed, element, attribute) { if (attribute === 'title') return element.title; return proceed(element, attribute); } ); } else if (Prototype.Browser.IE) { Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( function(proceed, element) { element = $(element); try { element.offsetParent } catch(e) { return $(document.body) } var position = element.getStyle('position'); if (position !== 'static') return proceed(element); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); $w('positionedOffset viewportOffset').each(function(method) { Element.Methods[method] = Element.Methods[method].wrap( function(proceed, element) { element = $(element); try { element.offsetParent } catch(e) { return Element._returnOffset(0,0) } var position = element.getStyle('position'); if (position !== 'static') return proceed(element); var offsetParent = element.getOffsetParent(); if (offsetParent && offsetParent.getStyle('position') === 'fixed') offsetParent.setStyle({ zoom: 1 }); element.setStyle({ position: 'relative' }); var value = proceed(element); element.setStyle({ position: position }); return value; } ); }); Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( function(proceed, element) { try { element.offsetParent } catch(e) { return Element._returnOffset(0,0) } return proceed(element); } ); Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); var value = element.style[style]; if (!value && element.currentStyle) value = element.currentStyle[style]; if (style == 'opacity') { if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) if (value[1]) return parseFloat(value[1]) / 100; return 1.0; } if (value == 'auto') { if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) return element['offset' + style.capitalize()] + 'px'; return null; } return value; }; Element.Methods.setOpacity = function(element, value) { function stripAlpha(filter){ return filter.replace(/alpha\([^\)]*\)/gi,''); } element = $(element); var currentStyle = element.currentStyle; if ((currentStyle && !currentStyle.hasLayout) || (!currentStyle && element.style.zoom == 'normal')) element.style.zoom = 1; var filter = element.getStyle('filter'), style = element.style; if (value == 1 || value === '') { (filter = stripAlpha(filter)) ? style.filter = filter : style.removeAttribute('filter'); return element; } else if (value < 0.00001) value = 0; style.filter = stripAlpha(filter) + 'alpha(opacity=' + (value * 100) + ')'; return element; }; Element._attributeTranslations = (function(){ var classProp = 'className'; var forProp = 'for'; var el = document.createElement('div'); el.setAttribute(classProp, 'x'); if (el.className !== 'x') { el.setAttribute('class', 'x'); if (el.className === 'x') { classProp = 'class'; } } el = null; el = document.createElement('label'); el.setAttribute(forProp, 'x'); if (el.htmlFor !== 'x') { el.setAttribute('htmlFor', 'x'); if (el.htmlFor === 'x') { forProp = 'htmlFor'; } } el = null; return { read: { names: { 'class': classProp, 'className': classProp, 'for': forProp, 'htmlFor': forProp }, values: { _getAttr: function(element, attribute) { return element.getAttribute(attribute); }, _getAttr2: function(element, attribute) { return element.getAttribute(attribute, 2); }, _getAttrNode: function(element, attribute) { var node = element.getAttributeNode(attribute); return node ? node.value : ""; }, _getEv: (function(){ var el = document.createElement('div'); el.onclick = Prototype.emptyFunction; var value = el.getAttribute('onclick'); var f; if (String(value).indexOf('{') > -1) { f = function(element, attribute) { attribute = element.getAttribute(attribute); if (!attribute) return null; attribute = attribute.toString(); attribute = attribute.split('{')[1]; attribute = attribute.split('}')[0]; return attribute.strip(); }; } else if (value === '') { f = function(element, attribute) { attribute = element.getAttribute(attribute); if (!attribute) return null; return attribute.strip(); }; } el = null; return f; })(), _flag: function(element, attribute) { return $(element).hasAttribute(attribute) ? attribute : null; }, style: function(element) { return element.style.cssText.toLowerCase(); }, title: function(element) { return element.title; } } } } })(); Element._attributeTranslations.write = { names: Object.extend({ cellpadding: 'cellPadding', cellspacing: 'cellSpacing' }, Element._attributeTranslations.read.names), values: { checked: function(element, value) { element.checked = !!value; }, style: function(element, value) { element.style.cssText = value ? value : ''; } } }; Element._attributeTranslations.has = {}; $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; Element._attributeTranslations.has[attr.toLowerCase()] = attr; }); (function(v) { Object.extend(v, { href: v._getAttr2, src: v._getAttr2, type: v._getAttr, action: v._getAttrNode, disabled: v._flag, checked: v._flag, readonly: v._flag, multiple: v._flag, onload: v._getEv, onunload: v._getEv, onclick: v._getEv, ondblclick: v._getEv, onmousedown: v._getEv, onmouseup: v._getEv, onmouseover: v._getEv, onmousemove: v._getEv, onmouseout: v._getEv, onfocus: v._getEv, onblur: v._getEv, onkeypress: v._getEv, onkeydown: v._getEv, onkeyup: v._getEv, onsubmit: v._getEv, onreset: v._getEv, onselect: v._getEv, onchange: v._getEv }); })(Element._attributeTranslations.read.values); if (Prototype.BrowserFeatures.ElementExtensions) { (function() { function _descendants(element) { var nodes = element.getElementsByTagName('*'), results = []; for (var i = 0, node; node = nodes[i]; i++) if (node.tagName !== "!") // Filter out comment nodes. results.push(node); return results; } Element.Methods.down = function(element, expression, index) { element = $(element); if (arguments.length == 1) return element.firstDescendant(); return Object.isNumber(expression) ? _descendants(element)[expression] : Element.select(element, expression)[index || 0]; } })(); } } else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1) ? 0.999999 : (value === '') ? '' : (value < 0.00001) ? 0 : value; return element; }; } else if (Prototype.Browser.WebKit) { Element.Methods.setOpacity = function(element, value) { element = $(element); element.style.opacity = (value == 1 || value === '') ? '' : (value < 0.00001) ? 0 : value; if (value == 1) if(element.tagName.toUpperCase() == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); element.appendChild(n); element.removeChild(n); } catch (e) { } return element; }; Element.Methods.cumulativeOffset = function(element) { var valueT = 0, valueL = 0; do { valueT += element.offsetTop || 0; valueL += element.offsetLeft || 0; if (element.offsetParent == document.body) if (Element.getStyle(element, 'position') == 'absolute') break; element = element.offsetParent; } while (element); return Element._returnOffset(valueL, valueT); }; } if ('outerHTML' in document.documentElement) { Element.Methods.replace = function(element, content) { element = $(element); if (content && content.toElement) content = content.toElement(); if (Object.isElement(content)) { element.parentNode.replaceChild(content, element); return element; } content = Object.toHTML(content); var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); if (Element._insertionTranslations.tags[tagName]) { var nextSibling = element.next(); var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); parent.removeChild(element); if (nextSibling) fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); else fragments.each(function(node) { parent.appendChild(node) }); } else element.outerHTML = content.stripScripts(); content.evalScripts.bind(content).defer(); return element; }; } Element._returnOffset = function(l, t) { var result = [l, t]; result.left = l; result.top = t; return result; }; Element._getContentFromAnonymousElement = function(tagName, html) { var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; if (t) { div.innerHTML = t[0] + html + t[1]; t[2].times(function() { div = div.firstChild }); } else div.innerHTML = html; return $A(div.childNodes); }; Element._insertionTranslations = { before: function(element, node) { element.parentNode.insertBefore(node, element); }, top: function(element, node) { element.insertBefore(node, element.firstChild); }, bottom: function(element, node) { element.appendChild(node); }, after: function(element, node) { element.parentNode.insertBefore(node, element.nextSibling); }, tags: { TABLE: ['', '
    ', 1], TBODY: ['', '
    ', 2], TR: ['', '
    ', 3], TD: ['
    ', '
    ', 4], SELECT: ['', 1] } }; (function() { var tags = Element._insertionTranslations.tags; Object.extend(tags, { THEAD: tags.TBODY, TFOOT: tags.TBODY, TH: tags.TD }); })(); Element.Methods.Simulated = { hasAttribute: function(element, attribute) { attribute = Element._attributeTranslations.has[attribute] || attribute; var node = $(element).getAttributeNode(attribute); return !!(node && node.specified); } }; Element.Methods.ByTag = { }; Object.extend(Element, Element.Methods); (function(div) { if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { window.HTMLElement = { }; window.HTMLElement.prototype = div['__proto__']; Prototype.BrowserFeatures.ElementExtensions = true; } div = null; })(document.createElement('div')) Element.extend = (function() { function checkDeficiency(tagName) { if (typeof window.Element != 'undefined') { var proto = window.Element.prototype; if (proto) { var id = '_' + (Math.random()+'').slice(2); var el = document.createElement(tagName); proto[id] = 'x'; var isBuggy = (el[id] !== 'x'); delete proto[id]; el = null; return isBuggy; } } return false; } function extendElementWith(element, methods) { for (var property in methods) { var value = methods[property]; if (Object.isFunction(value) && !(property in element)) element[property] = value.methodize(); } } var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); if (Prototype.BrowserFeatures.SpecificElementExtensions) { if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { return function(element) { if (element && typeof element._extendedByPrototype == 'undefined') { var t = element.tagName; if (t && (/^(?:object|applet|embed)$/i.test(t))) { extendElementWith(element, Element.Methods); extendElementWith(element, Element.Methods.Simulated); extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); } } return element; } } return Prototype.K; } var Methods = { }, ByTag = Element.Methods.ByTag; var extend = Object.extend(function(element) { if (!element || typeof element._extendedByPrototype != 'undefined' || element.nodeType != 1 || element == window) return element; var methods = Object.clone(Methods), tagName = element.tagName.toUpperCase(); if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); extendElementWith(element, methods); element._extendedByPrototype = Prototype.emptyFunction; return element; }, { refresh: function() { if (!Prototype.BrowserFeatures.ElementExtensions) { Object.extend(Methods, Element.Methods); Object.extend(Methods, Element.Methods.Simulated); } } }); extend.refresh(); return extend; })(); Element.hasAttribute = function(element, attribute) { if (element.hasAttribute) return element.hasAttribute(attribute); return Element.Methods.Simulated.hasAttribute(element, attribute); }; Element.addMethods = function(methods) { var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; if (!methods) { Object.extend(Form, Form.Methods); Object.extend(Form.Element, Form.Element.Methods); Object.extend(Element.Methods.ByTag, { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), "TEXTAREA": Object.clone(Form.Element.Methods) }); } if (arguments.length == 2) { var tagName = methods; methods = arguments[1]; } if (!tagName) Object.extend(Element.Methods, methods || { }); else { if (Object.isArray(tagName)) tagName.each(extend); else extend(tagName); } function extend(tagName) { tagName = tagName.toUpperCase(); if (!Element.Methods.ByTag[tagName]) Element.Methods.ByTag[tagName] = { }; Object.extend(Element.Methods.ByTag[tagName], methods); } function copy(methods, destination, onlyIfAbsent) { onlyIfAbsent = onlyIfAbsent || false; for (var property in methods) { var value = methods[property]; if (!Object.isFunction(value)) continue; if (!onlyIfAbsent || !(property in destination)) destination[property] = value.methodize(); } } function findDOMClass(tagName) { var klass; var trans = { "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": "FrameSet", "IFRAME": "IFrame" }; if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName + 'Element'; if (window[klass]) return window[klass]; klass = 'HTML' + tagName.capitalize() + 'Element'; if (window[klass]) return window[klass]; var element = document.createElement(tagName); var proto = element['__proto__'] || element.constructor.prototype; element = null; return proto; } var elementPrototype = window.HTMLElement ? HTMLElement.prototype : Element.prototype; if (F.ElementExtensions) { copy(Element.Methods, elementPrototype); copy(Element.Methods.Simulated, elementPrototype, true); } if (F.SpecificElementExtensions) { for (var tag in Element.Methods.ByTag) { var klass = findDOMClass(tag); if (Object.isUndefined(klass)) continue; copy(T[tag], klass.prototype); } } Object.extend(Element, Element.Methods); delete Element.ByTag; if (Element.extend.refresh) Element.extend.refresh(); Element.cache = { }; }; document.viewport = { getDimensions: function() { return { width: this.getWidth(), height: this.getHeight() }; }, getScrollOffsets: function() { return Element._returnOffset( window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; (function(viewport) { var B = Prototype.Browser, doc = document, element, property = {}; function getRootElement() { if (B.WebKit && !doc.evaluate) return document; if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) return document.body; return document.documentElement; } function define(D) { if (!element) element = getRootElement(); property[D] = 'client' + D; viewport['get' + D] = function() { return element[property[D]] }; return viewport['get' + D](); } viewport.getWidth = define.curry('Width'); viewport.getHeight = define.curry('Height'); })(document.viewport); Element.Storage = { UID: 1 }; Element.addMethods({ getStorage: function(element) { if (!(element = $(element))) return; var uid; if (element === window) { uid = 0; } else { if (typeof element._prototypeUID === "undefined") element._prototypeUID = [Element.Storage.UID++]; uid = element._prototypeUID[0]; } if (!Element.Storage[uid]) Element.Storage[uid] = $H(); return Element.Storage[uid]; }, store: function(element, key, value) { if (!(element = $(element))) return; if (arguments.length === 2) { Element.getStorage(element).update(key); } else { Element.getStorage(element).set(key, value); } return element; }, retrieve: function(element, key, defaultValue) { if (!(element = $(element))) return; var hash = Element.getStorage(element), value = hash.get(key); if (Object.isUndefined(value)) { hash.set(key, defaultValue); value = defaultValue; } return value; }, clone: function(element, deep) { if (!(element = $(element))) return; var clone = element.cloneNode(deep); clone._prototypeUID = void 0; if (deep) { var descendants = Element.select(clone, '*'), i = descendants.length; while (i--) { descendants[i]._prototypeUID = void 0; } } return Element.extend(clone); } }); /* Portions of the Selector class are derived from Jack Slocum's DomQuery, * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style * license. Please see http://www.yui-ext.com/ for more information. */ var Selector = Class.create({ initialize: function(expression) { this.expression = expression.strip(); if (this.shouldUseSelectorsAPI()) { this.mode = 'selectorsAPI'; } else if (this.shouldUseXPath()) { this.mode = 'xpath'; this.compileXPathMatcher(); } else { this.mode = "normal"; this.compileMatcher(); } }, shouldUseXPath: (function() { var IS_DESCENDANT_SELECTOR_BUGGY = (function(){ var isBuggy = false; if (document.evaluate && window.XPathResult) { var el = document.createElement('div'); el.innerHTML = '
    '; var xpath = ".//*[local-name()='ul' or local-name()='UL']" + "//*[local-name()='li' or local-name()='LI']"; var result = document.evaluate(xpath, el, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); isBuggy = (result.snapshotLength !== 2); el = null; } return isBuggy; })(); return function() { if (!Prototype.BrowserFeatures.XPath) return false; var e = this.expression; if (Prototype.Browser.WebKit && (e.include("-of-type") || e.include(":empty"))) return false; if ((/(\[[\w-]*?:|:checked)/).test(e)) return false; if (IS_DESCENDANT_SELECTOR_BUGGY) return false; return true; } })(), shouldUseSelectorsAPI: function() { if (!Prototype.BrowserFeatures.SelectorsAPI) return false; if (Selector.CASE_INSENSITIVE_CLASS_NAMES) return false; if (!Selector._div) Selector._div = new Element('div'); try { Selector._div.querySelector(this.expression); } catch(e) { return false; } return true; }, compileMatcher: function() { var e = this.expression, ps = Selector.patterns, h = Selector.handlers, c = Selector.criteria, le, p, m, len = ps.length, name; if (Selector._cache[e]) { this.matcher = Selector._cache[e]; return; } this.matcher = ["this.matcher = function(root) {", "var r = root, h = Selector.handlers, c = false, n;"]; while (e && le != e && (/\S/).test(e)) { le = e; for (var i = 0; i"; } }); if (Prototype.BrowserFeatures.SelectorsAPI && document.compatMode === 'BackCompat') { Selector.CASE_INSENSITIVE_CLASS_NAMES = (function(){ var div = document.createElement('div'), span = document.createElement('span'); div.id = "prototype_test_id"; span.className = 'Test'; div.appendChild(span); var isIgnored = (div.querySelector('#prototype_test_id .test') !== null); div = span = null; return isIgnored; })(); } Object.extend(Selector, { _cache: { }, xpath: { descendant: "//*", child: "/*", adjacent: "/following-sibling::*[1]", laterSibling: '/following-sibling::*', tagName: function(m) { if (m[1] == '*') return ''; return "[local-name()='" + m[1].toLowerCase() + "' or local-name()='" + m[1].toUpperCase() + "']"; }, className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", id: "[@id='#{1}']", attrPresence: function(m) { m[1] = m[1].toLowerCase(); return new Template("[@#{1}]").evaluate(m); }, attr: function(m) { m[1] = m[1].toLowerCase(); m[3] = m[5] || m[6]; return new Template(Selector.xpath.operators[m[2]]).evaluate(m); }, pseudo: function(m) { var h = Selector.xpath.pseudos[m[1]]; if (!h) return ''; if (Object.isFunction(h)) return h(m); return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); }, operators: { '=': "[@#{1}='#{3}']", '!=': "[@#{1}!='#{3}']", '^=': "[starts-with(@#{1}, '#{3}')]", '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", '*=': "[contains(@#{1}, '#{3}')]", '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" }, pseudos: { 'first-child': '[not(preceding-sibling::*)]', 'last-child': '[not(following-sibling::*)]', 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', 'empty': "[count(*) = 0 and (count(text()) = 0)]", 'checked': "[@checked]", 'disabled': "[(@disabled) and (@type!='hidden')]", 'enabled': "[not(@disabled) and (@type!='hidden')]", 'not': function(m) { var e = m[6], p = Selector.patterns, x = Selector.xpath, le, v, len = p.length, name; var exclusion = []; while (e && le != e && (/\S/).test(e)) { le = e; for (var i = 0; i= 0)]"; return new Template(predicate).evaluate({ fragment: fragment, a: a, b: b }); } } } }, criteria: { tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', className: 'n = h.className(n, r, "#{1}", c); c = false;', id: 'n = h.id(n, r, "#{1}", c); c = false;', attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', attr: function(m) { m[3] = (m[5] || m[6]); return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); }, pseudo: function(m) { if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); }, descendant: 'c = "descendant";', child: 'c = "child";', adjacent: 'c = "adjacent";', laterSibling: 'c = "laterSibling";' }, patterns: [ { name: 'laterSibling', re: /^\s*~\s*/ }, { name: 'child', re: /^\s*>\s*/ }, { name: 'adjacent', re: /^\s*\+\s*/ }, { name: 'descendant', re: /^\s/ }, { name: 'tagName', re: /^\s*(\*|[\w\-]+)(\b|$)?/ }, { name: 'id', re: /^#([\w\-\*]+)(\b|$)/ }, { name: 'className', re: /^\.([\w\-\*]+)(\b|$)/ }, { name: 'pseudo', re: /^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/ }, { name: 'attrPresence', re: /^\[((?:[\w-]+:)?[\w-]+)\]/ }, { name: 'attr', re: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ } ], assertions: { tagName: function(element, matches) { return matches[1].toUpperCase() == element.tagName.toUpperCase(); }, className: function(element, matches) { return Element.hasClassName(element, matches[1]); }, id: function(element, matches) { return element.id === matches[1]; }, attrPresence: function(element, matches) { return Element.hasAttribute(element, matches[1]); }, attr: function(element, matches) { var nodeValue = Element.readAttribute(element, matches[1]); return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); } }, handlers: { concat: function(a, b) { for (var i = 0, node; node = b[i]; i++) a.push(node); return a; }, mark: function(nodes) { var _true = Prototype.emptyFunction; for (var i = 0, node; node = nodes[i]; i++) node._countedByPrototype = _true; return nodes; }, unmark: (function(){ var PROPERTIES_ATTRIBUTES_MAP = (function(){ var el = document.createElement('div'), isBuggy = false, propName = '_countedByPrototype', value = 'x' el[propName] = value; isBuggy = (el.getAttribute(propName) === value); el = null; return isBuggy; })(); return PROPERTIES_ATTRIBUTES_MAP ? function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node.removeAttribute('_countedByPrototype'); return nodes; } : function(nodes) { for (var i = 0, node; node = nodes[i]; i++) node._countedByPrototype = void 0; return nodes; } })(), index: function(parentNode, reverse, ofType) { parentNode._countedByPrototype = Prototype.emptyFunction; if (reverse) { for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { var node = nodes[i]; if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; } } else { for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; } }, unique: function(nodes) { if (nodes.length == 0) return nodes; var results = [], n; for (var i = 0, l = nodes.length; i < l; i++) if (typeof (n = nodes[i])._countedByPrototype == 'undefined') { n._countedByPrototype = Prototype.emptyFunction; results.push(Element.extend(n)); } return Selector.handlers.unmark(results); }, descendant: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) h.concat(results, node.getElementsByTagName('*')); return results; }, child: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) { for (var j = 0, child; child = node.childNodes[j]; j++) if (child.nodeType == 1 && child.tagName != '!') results.push(child); } return results; }, adjacent: function(nodes) { for (var i = 0, results = [], node; node = nodes[i]; i++) { var next = this.nextElementSibling(node); if (next) results.push(next); } return results; }, laterSibling: function(nodes) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) h.concat(results, Element.nextSiblings(node)); return results; }, nextElementSibling: function(node) { while (node = node.nextSibling) if (node.nodeType == 1) return node; return null; }, previousElementSibling: function(node) { while (node = node.previousSibling) if (node.nodeType == 1) return node; return null; }, tagName: function(nodes, root, tagName, combinator) { var uTagName = tagName.toUpperCase(); var results = [], h = Selector.handlers; if (nodes) { if (combinator) { if (combinator == "descendant") { for (var i = 0, node; node = nodes[i]; i++) h.concat(results, node.getElementsByTagName(tagName)); return results; } else nodes = this[combinator](nodes); if (tagName == "*") return nodes; } for (var i = 0, node; node = nodes[i]; i++) if (node.tagName.toUpperCase() === uTagName) results.push(node); return results; } else return root.getElementsByTagName(tagName); }, id: function(nodes, root, id, combinator) { var targetNode = $(id), h = Selector.handlers; if (root == document) { if (!targetNode) return []; if (!nodes) return [targetNode]; } else { if (!root.sourceIndex || root.sourceIndex < 1) { var nodes = root.getElementsByTagName('*'); for (var j = 0, node; node = nodes[j]; j++) { if (node.id === id) return [node]; } } } if (nodes) { if (combinator) { if (combinator == 'child') { for (var i = 0, node; node = nodes[i]; i++) if (targetNode.parentNode == node) return [targetNode]; } else if (combinator == 'descendant') { for (var i = 0, node; node = nodes[i]; i++) if (Element.descendantOf(targetNode, node)) return [targetNode]; } else if (combinator == 'adjacent') { for (var i = 0, node; node = nodes[i]; i++) if (Selector.handlers.previousElementSibling(targetNode) == node) return [targetNode]; } else nodes = h[combinator](nodes); } for (var i = 0, node; node = nodes[i]; i++) if (node == targetNode) return [targetNode]; return []; } return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; }, className: function(nodes, root, className, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); return Selector.handlers.byClassName(nodes, root, className); }, byClassName: function(nodes, root, className) { if (!nodes) nodes = Selector.handlers.descendant([root]); var needle = ' ' + className + ' '; for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { nodeClassName = node.className; if (nodeClassName.length == 0) continue; if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) results.push(node); } return results; }, attrPresence: function(nodes, root, attr, combinator) { if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); var results = []; for (var i = 0, node; node = nodes[i]; i++) if (Element.hasAttribute(node, attr)) results.push(node); return results; }, attr: function(nodes, root, attr, value, operator, combinator) { if (!nodes) nodes = root.getElementsByTagName("*"); if (nodes && combinator) nodes = this[combinator](nodes); var handler = Selector.operators[operator], results = []; for (var i = 0, node; node = nodes[i]; i++) { var nodeValue = Element.readAttribute(node, attr); if (nodeValue === null) continue; if (handler(nodeValue, value)) results.push(node); } return results; }, pseudo: function(nodes, name, value, root, combinator) { if (nodes && combinator) nodes = this[combinator](nodes); if (!nodes) nodes = root.getElementsByTagName("*"); return Selector.pseudos[name](nodes, value, root); } }, pseudos: { 'first-child': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.previousElementSibling(node)) continue; results.push(node); } return results; }, 'last-child': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (Selector.handlers.nextElementSibling(node)) continue; results.push(node); } return results; }, 'only-child': function(nodes, value, root) { var h = Selector.handlers; for (var i = 0, results = [], node; node = nodes[i]; i++) if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) results.push(node); return results; }, 'nth-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root); }, 'nth-last-child': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true); }, 'nth-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, false, true); }, 'nth-last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, formula, root, true, true); }, 'first-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, false, true); }, 'last-of-type': function(nodes, formula, root) { return Selector.pseudos.nth(nodes, "1", root, true, true); }, 'only-of-type': function(nodes, formula, root) { var p = Selector.pseudos; return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); }, getIndices: function(a, b, total) { if (a == 0) return b > 0 ? [b] : []; return $R(1, total).inject([], function(memo, i) { if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); return memo; }); }, nth: function(nodes, formula, root, reverse, ofType) { if (nodes.length == 0) return []; if (formula == 'even') formula = '2n+0'; if (formula == 'odd') formula = '2n+1'; var h = Selector.handlers, results = [], indexed = [], m; h.mark(nodes); for (var i = 0, node; node = nodes[i]; i++) { if (!node.parentNode._countedByPrototype) { h.index(node.parentNode, reverse, ofType); indexed.push(node.parentNode); } } if (formula.match(/^\d+$/)) { // just a number formula = Number(formula); for (var i = 0, node; node = nodes[i]; i++) if (node.nodeIndex == formula) results.push(node); } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b if (m[1] == "-") m[1] = -1; var a = m[1] ? Number(m[1]) : 1; var b = m[2] ? Number(m[2]) : 0; var indices = Selector.pseudos.getIndices(a, b, nodes.length); for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { for (var j = 0; j < l; j++) if (node.nodeIndex == indices[j]) results.push(node); } } h.unmark(nodes); h.unmark(indexed); return results; }, 'empty': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) { if (node.tagName == '!' || node.firstChild) continue; results.push(node); } return results; }, 'not': function(nodes, selector, root) { var h = Selector.handlers, selectorType, m; var exclusions = new Selector(selector).findElements(root); h.mark(exclusions); for (var i = 0, results = [], node; node = nodes[i]; i++) if (!node._countedByPrototype) results.push(node); h.unmark(exclusions); return results; }, 'enabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (!node.disabled && (!node.type || node.type !== 'hidden')) results.push(node); return results; }, 'disabled': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (node.disabled) results.push(node); return results; }, 'checked': function(nodes, value, root) { for (var i = 0, results = [], node; node = nodes[i]; i++) if (node.checked) results.push(node); return results; } }, operators: { '=': function(nv, v) { return nv == v; }, '!=': function(nv, v) { return nv != v; }, '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + '-').include('-' + (v || "").toUpperCase() + '-'); } }, split: function(expression) { var expressions = []; expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { expressions.push(m[1].strip()); }); return expressions; }, matchElements: function(elements, expression) { var matches = $$(expression), h = Selector.handlers; h.mark(matches); for (var i = 0, results = [], element; element = elements[i]; i++) if (element._countedByPrototype) results.push(element); h.unmark(matches); return results; }, findElement: function(elements, expression, index) { if (Object.isNumber(expression)) { index = expression; expression = false; } return Selector.matchElements(elements, expression || '*')[index || 0]; }, findChildElements: function(element, expressions) { expressions = Selector.split(expressions.join(',')); var results = [], h = Selector.handlers; for (var i = 0, l = expressions.length, selector; i < l; i++) { selector = new Selector(expressions[i].strip()); h.concat(results, selector.findElements(element)); } return (l > 1) ? h.unique(results) : results; } }); if (Prototype.Browser.IE) { Object.extend(Selector.handlers, { concat: function(a, b) { for (var i = 0, node; node = b[i]; i++) if (node.tagName !== "!") a.push(node); return a; } }); } function $$() { return Selector.findChildElements(document, $A(arguments)); } var Form = { reset: function(form) { form = $(form); form.reset(); return form; }, serializeElements: function(elements, options) { if (typeof options != 'object') options = { hash: !!options }; else if (Object.isUndefined(options.hash)) options.hash = true; var key, value, submitted = false, submit = options.submit; var data = elements.inject({ }, function(result, element) { if (!element.disabled && element.name) { key = element.name; value = $(element).getValue(); if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true)))) { if (key in result) { if (!Object.isArray(result[key])) result[key] = [result[key]]; result[key].push(value); } else result[key] = value; } } return result; }); return options.hash ? data : Object.toQueryString(data); } }; Form.Methods = { serialize: function(form, options) { return Form.serializeElements(Form.getElements(form), options); }, getElements: function(form) { var elements = $(form).getElementsByTagName('*'), element, arr = [ ], serializers = Form.Element.Serializers; for (var i = 0; element = elements[i]; i++) { arr.push(element); } return arr.inject([], function(elements, child) { if (serializers[child.tagName.toLowerCase()]) elements.push(Element.extend(child)); return elements; }) }, getInputs: function(form, typeName, name) { form = $(form); var inputs = form.getElementsByTagName('input'); if (!typeName && !name) return $A(inputs).map(Element.extend); for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { var input = inputs[i]; if ((typeName && input.type != typeName) || (name && input.name != name)) continue; matchingInputs.push(Element.extend(input)); } return matchingInputs; }, disable: function(form) { form = $(form); Form.getElements(form).invoke('disable'); return form; }, enable: function(form) { form = $(form); Form.getElements(form).invoke('enable'); return form; }, findFirstElement: function(form) { var elements = $(form).getElements().findAll(function(element) { return 'hidden' != element.type && !element.disabled; }); var firstByIndex = elements.findAll(function(element) { return element.hasAttribute('tabIndex') && element.tabIndex >= 0; }).sortBy(function(element) { return element.tabIndex }).first(); return firstByIndex ? firstByIndex : elements.find(function(element) { return /^(?:input|select|textarea)$/i.test(element.tagName); }); }, focusFirstElement: function(form) { form = $(form); form.findFirstElement().activate(); return form; }, request: function(form, options) { form = $(form), options = Object.clone(options || { }); var params = options.parameters, action = form.readAttribute('action') || ''; if (action.blank()) action = window.location.href; options.parameters = form.serialize(true); if (params) { if (Object.isString(params)) params = params.toQueryParams(); Object.extend(options.parameters, params); } if (form.hasAttribute('method') && !options.method) options.method = form.method; return new Ajax.Request(action, options); } }; /*--------------------------------------------------------------------------*/ Form.Element = { focus: function(element) { $(element).focus(); return element; }, select: function(element) { $(element).select(); return element; } }; Form.Element.Methods = { serialize: function(element) { element = $(element); if (!element.disabled && element.name) { var value = element.getValue(); if (value != undefined) { var pair = { }; pair[element.name] = value; return Object.toQueryString(pair); } } return ''; }, getValue: function(element) { element = $(element); var method = element.tagName.toLowerCase(); return Form.Element.Serializers[method](element); }, setValue: function(element, value) { element = $(element); var method = element.tagName.toLowerCase(); Form.Element.Serializers[method](element, value); return element; }, clear: function(element) { $(element).value = ''; return element; }, present: function(element) { return $(element).value != ''; }, activate: function(element) { element = $(element); try { element.focus(); if (element.select && (element.tagName.toLowerCase() != 'input' || !(/^(?:button|reset|submit)$/i.test(element.type)))) element.select(); } catch (e) { } return element; }, disable: function(element) { element = $(element); element.disabled = true; return element; }, enable: function(element) { element = $(element); element.disabled = false; return element; } }; /*--------------------------------------------------------------------------*/ var Field = Form.Element; var $F = Form.Element.Methods.getValue; /*--------------------------------------------------------------------------*/ Form.Element.Serializers = { input: function(element, value) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': return Form.Element.Serializers.inputSelector(element, value); default: return Form.Element.Serializers.textarea(element, value); } }, inputSelector: function(element, value) { if (Object.isUndefined(value)) return element.checked ? element.value : null; else element.checked = !!value; }, textarea: function(element, value) { if (Object.isUndefined(value)) return element.value; else element.value = value; }, select: function(element, value) { if (Object.isUndefined(value)) return this[element.type == 'select-one' ? 'selectOne' : 'selectMany'](element); else { var opt, currentValue, single = !Object.isArray(value); for (var i = 0, length = element.length; i < length; i++) { opt = element.options[i]; currentValue = this.optionValue(opt); if (single) { if (currentValue == value) { opt.selected = true; return; } } else opt.selected = value.include(currentValue); } } }, selectOne: function(element) { var index = element.selectedIndex; return index >= 0 ? this.optionValue(element.options[index]) : null; }, selectMany: function(element) { var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; if (opt.selected) values.push(this.optionValue(opt)); } return values; }, optionValue: function(opt) { return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } }; /*--------------------------------------------------------------------------*/ Abstract.TimedObserver = Class.create(PeriodicalExecuter, { initialize: function($super, element, frequency, callback) { $super(callback, frequency); this.element = $(element); this.lastValue = this.getValue(); }, execute: function() { var value = this.getValue(); if (Object.isString(this.lastValue) && Object.isString(value) ? this.lastValue != value : String(this.lastValue) != String(value)) { this.callback(this.element, value); this.lastValue = value; } } }); Form.Element.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.Observer = Class.create(Abstract.TimedObserver, { getValue: function() { return Form.serialize(this.element); } }); /*--------------------------------------------------------------------------*/ Abstract.EventObserver = Class.create({ initialize: function(element, callback) { this.element = $(element); this.callback = callback; this.lastValue = this.getValue(); if (this.element.tagName.toLowerCase() == 'form') this.registerFormCallbacks(); else this.registerCallback(this.element); }, onElementEvent: function() { var value = this.getValue(); if (this.lastValue != value) { this.callback(this.element, value); this.lastValue = value; } }, registerFormCallbacks: function() { Form.getElements(this.element).each(this.registerCallback, this); }, registerCallback: function(element) { if (element.type) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': Event.observe(element, 'click', this.onElementEvent.bind(this)); break; default: Event.observe(element, 'change', this.onElementEvent.bind(this)); break; } } } }); Form.Element.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.Element.getValue(this.element); } }); Form.EventObserver = Class.create(Abstract.EventObserver, { getValue: function() { return Form.serialize(this.element); } }); (function() { var Event = { KEY_BACKSPACE: 8, KEY_TAB: 9, KEY_RETURN: 13, KEY_ESC: 27, KEY_LEFT: 37, KEY_UP: 38, KEY_RIGHT: 39, KEY_DOWN: 40, KEY_DELETE: 46, KEY_HOME: 36, KEY_END: 35, KEY_PAGEUP: 33, KEY_PAGEDOWN: 34, KEY_INSERT: 45, cache: {} }; var docEl = document.documentElement; var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl && 'onmouseleave' in docEl; var _isButton; if (Prototype.Browser.IE) { var buttonMap = { 0: 1, 1: 4, 2: 2 }; _isButton = function(event, code) { return event.button === buttonMap[code]; }; } else if (Prototype.Browser.WebKit) { _isButton = function(event, code) { switch (code) { case 0: return event.which == 1 && !event.metaKey; case 1: return event.which == 1 && event.metaKey; default: return false; } }; } else { _isButton = function(event, code) { return event.which ? (event.which === code + 1) : (event.button === code); }; } function isLeftClick(event) { return _isButton(event, 0) } function isMiddleClick(event) { return _isButton(event, 1) } function isRightClick(event) { return _isButton(event, 2) } function element(event) { event = Event.extend(event); var node = event.target, type = event.type, currentTarget = event.currentTarget; if (currentTarget && currentTarget.tagName) { if (type === 'load' || type === 'error' || (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' && currentTarget.type === 'radio')) node = currentTarget; } if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; return Element.extend(node); } function findElement(event, expression) { var element = Event.element(event); if (!expression) return element; var elements = [element].concat(element.ancestors()); return Selector.findElement(elements, expression, 0); } function pointer(event) { return { x: pointerX(event), y: pointerY(event) }; } function pointerX(event) { var docElement = document.documentElement, body = document.body || { scrollLeft: 0 }; return event.pageX || (event.clientX + (docElement.scrollLeft || body.scrollLeft) - (docElement.clientLeft || 0)); } function pointerY(event) { var docElement = document.documentElement, body = document.body || { scrollTop: 0 }; return event.pageY || (event.clientY + (docElement.scrollTop || body.scrollTop) - (docElement.clientTop || 0)); } function stop(event) { Event.extend(event); event.preventDefault(); event.stopPropagation(); event.stopped = true; } Event.Methods = { isLeftClick: isLeftClick, isMiddleClick: isMiddleClick, isRightClick: isRightClick, element: element, findElement: findElement, pointer: pointer, pointerX: pointerX, pointerY: pointerY, stop: stop }; var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { m[name] = Event.Methods[name].methodize(); return m; }); if (Prototype.Browser.IE) { function _relatedTarget(event) { var element; switch (event.type) { case 'mouseover': element = event.fromElement; break; case 'mouseout': element = event.toElement; break; default: return null; } return Element.extend(element); } Object.extend(methods, { stopPropagation: function() { this.cancelBubble = true }, preventDefault: function() { this.returnValue = false }, inspect: function() { return '[object Event]' } }); Event.extend = function(event, element) { if (!event) return false; if (event._extendedByPrototype) return event; event._extendedByPrototype = Prototype.emptyFunction; var pointer = Event.pointer(event); Object.extend(event, { target: event.srcElement || element, relatedTarget: _relatedTarget(event), pageX: pointer.x, pageY: pointer.y }); return Object.extend(event, methods); }; } else { Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; Object.extend(Event.prototype, methods); Event.extend = Prototype.K; } function _createResponder(element, eventName, handler) { var registry = Element.retrieve(element, 'prototype_event_registry'); if (Object.isUndefined(registry)) { CACHE.push(element); registry = Element.retrieve(element, 'prototype_event_registry', $H()); } var respondersForEvent = registry.get(eventName); if (Object.isUndefined(respondersForEvent)) { respondersForEvent = []; registry.set(eventName, respondersForEvent); } if (respondersForEvent.pluck('handler').include(handler)) return false; var responder; if (eventName.include(":")) { responder = function(event) { if (Object.isUndefined(event.eventName)) return false; if (event.eventName !== eventName) return false; Event.extend(event, element); handler.call(element, event); }; } else { if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && (eventName === "mouseenter" || eventName === "mouseleave")) { if (eventName === "mouseenter" || eventName === "mouseleave") { responder = function(event) { Event.extend(event, element); var parent = event.relatedTarget; while (parent && parent !== element) { try { parent = parent.parentNode; } catch(e) { parent = element; } } if (parent === element) return; handler.call(element, event); }; } } else { responder = function(event) { Event.extend(event, element); handler.call(element, event); }; } } responder.handler = handler; respondersForEvent.push(responder); return responder; } function _destroyCache() { for (var i = 0, length = CACHE.length; i < length; i++) { Event.stopObserving(CACHE[i]); CACHE[i] = null; } } var CACHE = []; if (Prototype.Browser.IE) window.attachEvent('onunload', _destroyCache); if (Prototype.Browser.WebKit) window.addEventListener('unload', Prototype.emptyFunction, false); var _getDOMEventName = Prototype.K; if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { _getDOMEventName = function(eventName) { var translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; return eventName in translations ? translations[eventName] : eventName; }; } function observe(element, eventName, handler) { element = $(element); var responder = _createResponder(element, eventName, handler); if (!responder) return element; if (eventName.include(':')) { if (element.addEventListener) element.addEventListener("dataavailable", responder, false); else { element.attachEvent("ondataavailable", responder); element.attachEvent("onfilterchange", responder); } } else { var actualEventName = _getDOMEventName(eventName); if (element.addEventListener) element.addEventListener(actualEventName, responder, false); else element.attachEvent("on" + actualEventName, responder); } return element; } function stopObserving(element, eventName, handler) { element = $(element); var registry = Element.retrieve(element, 'prototype_event_registry'); if (Object.isUndefined(registry)) return element; if (eventName && !handler) { var responders = registry.get(eventName); if (Object.isUndefined(responders)) return element; responders.each( function(r) { Element.stopObserving(element, eventName, r.handler); }); return element; } else if (!eventName) { registry.each( function(pair) { var eventName = pair.key, responders = pair.value; responders.each( function(r) { Element.stopObserving(element, eventName, r.handler); }); }); return element; } var responders = registry.get(eventName); if (!responders) return; var responder = responders.find( function(r) { return r.handler === handler; }); if (!responder) return element; var actualEventName = _getDOMEventName(eventName); if (eventName.include(':')) { if (element.removeEventListener) element.removeEventListener("dataavailable", responder, false); else { element.detachEvent("ondataavailable", responder); element.detachEvent("onfilterchange", responder); } } else { if (element.removeEventListener) element.removeEventListener(actualEventName, responder, false); else element.detachEvent('on' + actualEventName, responder); } registry.set(eventName, responders.without(responder)); return element; } function fire(element, eventName, memo, bubble) { element = $(element); if (Object.isUndefined(bubble)) bubble = true; if (element == document && document.createEvent && !element.dispatchEvent) element = document.documentElement; var event; if (document.createEvent) { event = document.createEvent('HTMLEvents'); event.initEvent('dataavailable', true, true); } else { event = document.createEventObject(); event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; } event.eventName = eventName; event.memo = memo || { }; if (document.createEvent) element.dispatchEvent(event); else element.fireEvent(event.eventType, event); return Event.extend(event); } Object.extend(Event, Event.Methods); Object.extend(Event, { fire: fire, observe: observe, stopObserving: stopObserving }); Element.addMethods({ fire: fire, observe: observe, stopObserving: stopObserving }); Object.extend(document, { fire: fire.methodize(), observe: observe.methodize(), stopObserving: stopObserving.methodize(), loaded: false }); if (window.Event) Object.extend(window.Event, Event); else window.Event = Event; })(); (function() { /* Support for the DOMContentLoaded event is based on work by Dan Webb, Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ var timer; function fireContentLoadedEvent() { if (document.loaded) return; if (timer) window.clearTimeout(timer); document.loaded = true; document.fire('dom:loaded'); } function checkReadyState() { if (document.readyState === 'complete') { document.stopObserving('readystatechange', checkReadyState); fireContentLoadedEvent(); } } function pollDoScroll() { try { document.documentElement.doScroll('left'); } catch(e) { timer = pollDoScroll.defer(); return; } fireContentLoadedEvent(); } if (document.addEventListener) { document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); } else { document.observe('readystatechange', checkReadyState); if (window == top) timer = pollDoScroll.defer(); } Event.observe(window, 'load', fireContentLoadedEvent); })(); Element.addMethods(); /*------------------------------- DEPRECATED -------------------------------*/ Hash.toQueryString = Object.toQueryString; var Toggle = { display: Element.toggle }; Element.Methods.childOf = Element.Methods.descendantOf; var Insertion = { Before: function(element, content) { return Element.insert(element, {before:content}); }, Top: function(element, content) { return Element.insert(element, {top:content}); }, Bottom: function(element, content) { return Element.insert(element, {bottom:content}); }, After: function(element, content) { return Element.insert(element, {after:content}); } }; var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); var Position = { includeScrollOffsets: false, prepare: function() { this.deltaX = window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0; this.deltaY = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; }, within: function(element, x, y) { if (this.includeScrollOffsets) return this.withinIncludingScrolloffsets(element, x, y); this.xcomp = x; this.ycomp = y; this.offset = Element.cumulativeOffset(element); return (y >= this.offset[1] && y < this.offset[1] + element.offsetHeight && x >= this.offset[0] && x < this.offset[0] + element.offsetWidth); }, withinIncludingScrolloffsets: function(element, x, y) { var offsetcache = Element.cumulativeScrollOffset(element); this.xcomp = x + offsetcache[0] - this.deltaX; this.ycomp = y + offsetcache[1] - this.deltaY; this.offset = Element.cumulativeOffset(element); return (this.ycomp >= this.offset[1] && this.ycomp < this.offset[1] + element.offsetHeight && this.xcomp >= this.offset[0] && this.xcomp < this.offset[0] + element.offsetWidth); }, overlap: function(mode, element) { if (!mode) return 0; if (mode == 'vertical') return ((this.offset[1] + element.offsetHeight) - this.ycomp) / element.offsetHeight; if (mode == 'horizontal') return ((this.offset[0] + element.offsetWidth) - this.xcomp) / element.offsetWidth; }, cumulativeOffset: Element.Methods.cumulativeOffset, positionedOffset: Element.Methods.positionedOffset, absolutize: function(element) { Position.prepare(); return Element.absolutize(element); }, relativize: function(element) { Position.prepare(); return Element.relativize(element); }, realOffset: Element.Methods.cumulativeScrollOffset, offsetParent: Element.Methods.getOffsetParent, page: Element.Methods.viewportOffset, clone: function(source, target, options) { options = options || { }; return Element.clonePosition(target, source, options); } }; /*--------------------------------------------------------------------------*/ if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ function iter(name) { return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; } instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? function(element, className) { className = className.toString().strip(); var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); return cond ? document._getElementsByXPath('.//*' + cond, element) : []; } : function(element, className) { className = className.toString().strip(); var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); if (!classNames && !className) return elements; var nodes = $(element).getElementsByTagName('*'); className = ' ' + className + ' '; for (var i = 0, child, cn; child = nodes[i]; i++) { if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || (classNames && classNames.all(function(name) { return !name.toString().blank() && cn.include(' ' + name + ' '); })))) elements.push(Element.extend(child)); } return elements; }; return function(className, parentElement) { return $(parentElement || document.body).getElementsByClassName(className); }; }(Element.Methods); /*--------------------------------------------------------------------------*/ Element.ClassNames = Class.create(); Element.ClassNames.prototype = { initialize: function(element) { this.element = $(element); }, _each: function(iterator) { this.element.className.split(/\s+/).select(function(name) { return name.length > 0; })._each(iterator); }, set: function(className) { this.element.className = className; }, add: function(classNameToAdd) { if (this.include(classNameToAdd)) return; this.set($A(this).concat(classNameToAdd).join(' ')); }, remove: function(classNameToRemove) { if (!this.include(classNameToRemove)) return; this.set($A(this).without(classNameToRemove).join(' ')); }, toString: function() { return $A(this).join(' '); } }; Object.extend(Element.ClassNames.prototype, Enumerable); /*--------------------------------------------------------------------------*/ gosa-core-2.7.4/html/include/pulldown.js0000644000175000017500000001554211320625460017176 0ustar cajuscajus/** * dropDownMenu v0.5 sw edition * An easy to implement dropDown Menu for Websites, that may be based on styled list tags * * Works for IE 5.5+ PC, Mozilla 1+ all Plattforms, Opera 7+ * * Copyright (c) 2004 Knallgrau New Medias Solutions GmbH, Vienna - Austria * * Original written by Matthias Platzer at http://knallgrau.at * * Modified by Sven Wappler http://www.wappler.eu * * Use it as you need it * It is distributed under a BSD style license */ /** * Container Class (Prototype) for the dropDownMenu * * @param idOrElement String|HTMLElement root Node of the menu (ul) * @param name String name of the variable that stores the result * of this constructor function * @param customConfigFunction Function optional config function to override the default settings * for an example see Menu.prototype.config */ var Menu = Class.create(); Menu.prototype = { initialize: function(idOrElement, name, customConfigFunction) { this.name = name; this.type = "menu"; this.closeDelayTimer = null; this.closingMenuItem = null; this.config(); if (typeof customConfigFunction == "function") { this.customConfig = customConfigFunction; this.customConfig(); } this.rootContainer = new MenuContainer(idOrElement, this); }, config: function() { this.collapseBorders = true; this.quickCollapse = true; this.closeDelayTime = 500; } } var MenuContainer = Class.create(); MenuContainer.prototype = { initialize: function(idOrElement, parent) { this.type = "menuContainer"; this.menuItems = []; this.init(idOrElement, parent); }, init: function(idOrElement, parent) { this.element = $(idOrElement); if (!this.element) return; this.parent = parent; this.parentMenu = (this.type == "menuContainer") ? ((parent) ? parent.parent : null) : parent; this.root = parent instanceof Menu ? parent : parent.root; this.id = this.element.id; if (this.type == "menuContainer") { if (this.element.hasClassName("level1")) this.menuType = "horizontal"; else if (this.element.hasClassName("level2")) this.menuType = "dropdown"; else this.menuType = "flyout"; if (this.menuType == "flyout" || this.menuType == "dropdown") { this.isOpen = false; Element.setStyle(this.element,{ position: "absolute", top: "0px", left: "0px", visibility: "hidden"}); } else { this.isOpen = true; } } else { this.isOpen = this.parentMenu.isOpen; } var childNodes = this.element.childNodes; if (childNodes == null) return; for (var i = 0; i < childNodes.length; i++) { var node = childNodes[i]; if (node.nodeType == 1) { if (this.type == "menuContainer") { if (node.tagName.toLowerCase() == "li") { this.menuItems.push(new MenuItem(node, this)); } } else { if (node.tagName.toLowerCase() == "ul") { this.subMenu = new MenuContainer(node, this); } } } } }, getBorders: function(element) { var ltrb = ["Left","Top","Right","Bottom"]; var result = {}; for (var i = 0; i < ltrb.length; ++i) { if (this.element.currentStyle) var value = parseInt(this.element.currentStyle["border"+ltrb[i]+"Width"]); else if (window.getComputedStyle) var value = parseInt(window.getComputedStyle(this.element, "").getPropertyValue("border-"+ltrb[i].toLowerCase()+"-width")); else var value = parseInt(this.element.style["border"+ltrb[i]]); result[ltrb[i].toLowerCase()] = isNaN(value) ? 0 : value; } return result; }, open: function() { if (this.root.closeDelayTimer) window.clearTimeout(this.root.closeDelayTimer); this.parentMenu.closeAll(this); this.isOpen = true; if (this.menuType == "dropdown") { Element.setStyle(this.element,{ left: (Position.positionedOffset(this.parent.element)[0]) + "px", top: (Position.positionedOffset(this.parent.element)[1] + Element.getHeight(this.parent.element)) + "px" }); } else if (this.menuType == "flyout") { var parentMenuBorders = this.parentMenu ? this.parentMenu.getBorders() : new Object(); var thisBorders = this.getBorders(); if ( (Position.positionedOffset(this.parentMenu.element)[0] + this.parentMenu.element.offsetWidth + this.element.offsetWidth + 20) > (window.innerWidth ? window.innerWidth : document.body.offsetWidth) ) { Element.setStyle(this.element,{ left: (- this.element.offsetWidth - (this.root.collapseBorders ? 0 : parentMenuBorders["left"])) + "px" }); } else { Element.setStyle(this.element,{ left: (this.parentMenu.element.offsetWidth - parentMenuBorders["left"] - (this.root.collapseBorders ? Math.min(parentMenuBorders["right"], thisBorders["left"]) : 0)) + "px" }); } Element.setStyle(this.element,{ top: (this.parent.element.offsetTop - parentMenuBorders["top"] - this.menuItems[0].element.offsetTop) + "px" }); } Element.setStyle(this.element,{visibility: "visible"}); }, close: function() { Element.setStyle(this.element,{visibility: "hidden"}); this.isOpen = false; this.closeAll(); }, closeAll: function(trigger) { for (var i = 0; i < this.menuItems.length; ++i) { this.menuItems[i].closeItem(trigger); } } } var MenuItem = Class.create(); Object.extend(Object.extend(MenuItem.prototype, MenuContainer.prototype), { initialize: function(idOrElement, parent) { var menuItem = this; this.type = "menuItem"; this.subMenu; this.init(idOrElement, parent); if (this.subMenu) { this.element.onmouseover = function() { menuItem.subMenu.open(); } } else { if (this.root.quickCollapse) { this.element.onmouseover = function() { menuItem.parentMenu.closeAll(); } } } var linkTag = this.element.getElementsByTagName("A")[0]; if (linkTag) { linkTag.onfocus = this.element.onmouseover; this.link = linkTag; this.text = linkTag.text; } if (this.subMenu) { this.element.onmouseout = function() { if (menuItem.root.openDelayTimer) window.clearTimeout(menuItem.root.openDelayTimer); if (menuItem.root.closeDelayTimer) window.clearTimeout(menuItem.root.closeDelayTimer); eval(menuItem.root.name + ".closingMenuItem = menuItem"); menuItem.root.closeDelayTimer = window.setTimeout(menuItem.root.name + ".closingMenuItem.subMenu.close()", menuItem.root.closeDelayTime); } } }, openItem: function() { this.isOpen = true; if (this.subMenu) { this.subMenu.open(); } }, closeItem: function(trigger) { this.isOpen = false; if (this.subMenu) { if (this.subMenu != trigger) this.subMenu.close(); } } }); var menu; function configMenu() { this.closeDelayTime = 300; } function initMenu() { menu = new Menu('root', 'menu', configMenu); } Event.observe(window, 'load', initMenu, false); gosa-core-2.7.4/html/include/builder.js0000644000175000017500000001121011325266624016754 0ustar cajuscajus// script.aculo.us builder.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // // script.aculo.us is freely distributable under the terms of an MIT-style license. // For details, see the script.aculo.us web site: http://script.aculo.us/ var Builder = { NODEMAP: { AREA: 'map', CAPTION: 'table', COL: 'table', COLGROUP: 'table', LEGEND: 'fieldset', OPTGROUP: 'select', OPTION: 'select', PARAM: 'object', TBODY: 'table', TD: 'table', TFOOT: 'table', TH: 'table', THEAD: 'table', TR: 'table' }, // note: For Firefox < 1.5, OPTION and OPTGROUP tags are currently broken, // due to a Firefox bug node: function(elementName) { elementName = elementName.toUpperCase(); // try innerHTML approach var parentTag = this.NODEMAP[elementName] || 'div'; var parentElement = document.createElement(parentTag); try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 parentElement.innerHTML = "<" + elementName + ">"; } catch(e) {} var element = parentElement.firstChild || null; // see if browser added wrapping tags if(element && (element.tagName.toUpperCase() != elementName)) element = element.getElementsByTagName(elementName)[0]; // fallback to createElement approach if(!element) element = document.createElement(elementName); // abort if nothing could be created if(!element) return; // attributes (or text) if(arguments[1]) if(this._isStringOrNumber(arguments[1]) || (arguments[1] instanceof Array) || arguments[1].tagName) { this._children(element, arguments[1]); } else { var attrs = this._attributes(arguments[1]); if(attrs.length) { try { // prevent IE "feature": http://dev.rubyonrails.org/ticket/2707 parentElement.innerHTML = "<" +elementName + " " + attrs + ">"; } catch(e) {} element = parentElement.firstChild || null; // workaround firefox 1.0.X bug if(!element) { element = document.createElement(elementName); for(attr in arguments[1]) element[attr == 'class' ? 'className' : attr] = arguments[1][attr]; } if(element.tagName.toUpperCase() != elementName) element = parentElement.getElementsByTagName(elementName)[0]; } } // text, or array of children if(arguments[2]) this._children(element, arguments[2]); return $(element); }, _text: function(text) { return document.createTextNode(text); }, ATTR_MAP: { 'className': 'class', 'htmlFor': 'for' }, _attributes: function(attributes) { var attrs = []; for(attribute in attributes) attrs.push((attribute in this.ATTR_MAP ? this.ATTR_MAP[attribute] : attribute) + '="' + attributes[attribute].toString().escapeHTML().gsub(/"/,'"') + '"'); return attrs.join(" "); }, _children: function(element, children) { if(children.tagName) { element.appendChild(children); return; } if(typeof children=='object') { // array can hold nodes and text children.flatten().each( function(e) { if(typeof e=='object') element.appendChild(e); else if(Builder._isStringOrNumber(e)) element.appendChild(Builder._text(e)); }); } else if(Builder._isStringOrNumber(children)) element.appendChild(Builder._text(children)); }, _isStringOrNumber: function(param) { return(typeof param=='string' || typeof param=='number'); }, build: function(html) { var element = this.node('div'); $(element).update(html.strip()); return element.down(); }, dump: function(scope) { if(typeof scope != 'object' && typeof scope != 'function') scope = window; //global scope var tags = ("A ABBR ACRONYM ADDRESS APPLET AREA B BASE BASEFONT BDO BIG BLOCKQUOTE BODY " + "BR BUTTON CAPTION CENTER CITE CODE COL COLGROUP DD DEL DFN DIR DIV DL DT EM FIELDSET " + "FONT FORM FRAME FRAMESET H1 H2 H3 H4 H5 H6 HEAD HR HTML I IFRAME IMG INPUT INS ISINDEX "+ "KBD LABEL LEGEND LI LINK MAP MENU META NOFRAMES NOSCRIPT OBJECT OL OPTGROUP OPTION P "+ "PARAM PRE Q S SAMP SCRIPT SELECT SMALL SPAN STRIKE STRONG STYLE SUB SUP TABLE TBODY TD "+ "TEXTAREA TFOOT TH THEAD TITLE TR TT U UL VAR").split(/\s+/); tags.each( function(tag){ scope[tag] = function() { return Builder.node.apply(Builder, [tag].concat($A(arguments))); }; }); } };gosa-core-2.7.4/html/include/tooltip.js0000644000175000017500000001603711370303656017031 0ustar cajuscajus/* * Copyright (c) 2006 Jonathan Weiss * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ /* tooltip-0.2.js - Small tooltip library on top of Prototype * by Jonathan Weiss distributed under the BSD license. * * This tooltip library works in two modes. If it gets a valid DOM element * or DOM id as an argument it uses this element as the tooltip. This * element will be placed (and shown) near the mouse pointer when a trigger- * element is moused-over. * If it gets only a text as an argument instead of a DOM id or DOM element * it will create a div with the classname 'tooltip' that holds the given text. * This newly created div will be used as the tooltip. This is usefull if you * want to use tooltip.js to create popups out of title attributes. * * * Usage: * * * * * Now whenever you trigger a mouseOver on the `trigger` element, the tooltip element will * be shown. On o mouseOut the tooltip disappears. * * Example: * * * * * * * *
    * This is product 1 *
    * * * * You can use my_tooltip.destroy() to remove the event observers and thereby the tooltip. */ var Tooltip = Class.create(); Tooltip.prototype = { initialize: function(element, tool_tip) { var options = Object.extend({ default_css: false, margin: "0px", padding: "5px", backgroundColor: "#d6d6fc", min_distance_x: 5, min_distance_y: 5, delta_x: 0, delta_y: 0, zindex: 1000 }, arguments[2] || {}); this.element = $(element); this.options = options; // use the supplied tooltip element or create our own div if($(tool_tip)) { this.tool_tip = $(tool_tip); } else { this.tool_tip = $(document.createElement("div")); document.body.appendChild(this.tool_tip); this.tool_tip.addClassName("tooltip"); this.tool_tip.appendChild(document.createTextNode(tool_tip)); } // hide the tool-tip by default this.tool_tip.hide(); this.eventMouseOver = this.showTooltip.bindAsEventListener(this); this.eventMouseOut = this.hideTooltip.bindAsEventListener(this); this.eventMouseMove = this.moveTooltip.bindAsEventListener(this); this.registerEvents(); }, destroy: function() { Event.stopObserving(this.element, "mouseover", this.eventMouseOver); Event.stopObserving(this.element, "mouseout", this.eventMouseOut); Event.stopObserving(this.element, "mousemove", this.eventMouseMove); }, registerEvents: function() { Event.observe(this.element, "mouseover", this.eventMouseOver); Event.observe(this.element, "mouseout", this.eventMouseOut); Event.observe(this.element, "mousemove", this.eventMouseMove); }, moveTooltip: function(event){ Event.stop(event); // get Mouse position var mouse_x = Event.pointerX(event); var mouse_y = Event.pointerY(event); // decide if wee need to switch sides for the tooltip var dimensions = Element.getDimensions( this.tool_tip ); var element_width = dimensions.width; var element_height = dimensions.height; if ( (element_width + mouse_x) >= ( this.getWindowWidth() - this.options.min_distance_x) ){ // too big for X mouse_x = mouse_x - element_width; // apply min_distance to make sure that the mouse is not on the tool-tip mouse_x = mouse_x - this.options.min_distance_x; } else { mouse_x = mouse_x + this.options.min_distance_x; } if ( (element_height + mouse_y) >= ( this.getWindowHeight() - this.options.min_distance_y) ){ // too big for Y mouse_y = mouse_y - element_height; // apply min_distance to make sure that the mouse is not on the tool-tip mouse_y = mouse_y - this.options.min_distance_y; } else { mouse_y = mouse_y + this.options.min_distance_y; } // now set the right styles this.setStyles(mouse_x, mouse_y); }, showTooltip: function(event) { Event.stop(event); this.moveTooltip(event); new Element.show(this.tool_tip); }, setStyles: function(x, y){ // set the right styles to position the tool tip Element.setStyle(this.tool_tip, { position:'absolute', top:y + this.options.delta_y + "px", left:x + this.options.delta_x + "px", zindex:this.options.zindex }); // apply default theme if wanted if (this.options.default_css){ Element.setStyle(this.tool_tip, { margin:this.options.margin, padding:this.options.padding, backgroundColor:this.options.backgroundColor, zindex:this.options.zindex }); } }, hideTooltip: function(event){ new Element.hide(this.tool_tip); }, getWindowHeight: function(){ var innerHeight; if (navigator.appVersion.indexOf('MSIE')>0) { innerHeight = document.body.clientHeight; } else { innerHeight = window.innerHeight; } return innerHeight; }, getWindowWidth: function(){ var innerWidth; if (navigator.appVersion.indexOf('MSIE')>0) { innerWidth = document.body.clientWidth; } else { innerWidth = window.innerWidth; } return innerWidth; } } gosa-core-2.7.4/html/include/controls.js0000644000175000017500000010374311325266624017206 0ustar cajuscajus// script.aculo.us controls.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // (c) 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan) // (c) 2005-2009 Jon Tirsen (http://www.tirsen.com) // Contributors: // Richard Livsey // Rahul Bhargava // Rob Wills // // script.aculo.us is freely distributable under the terms of an MIT-style license. // For details, see the script.aculo.us web site: http://script.aculo.us/ // Autocompleter.Base handles all the autocompletion functionality // that's independent of the data source for autocompletion. This // includes drawing the autocompletion menu, observing keyboard // and mouse events, and similar. // // Specific autocompleters need to provide, at the very least, // a getUpdatedChoices function that will be invoked every time // the text inside the monitored textbox changes. This method // should get the text for which to provide autocompletion by // invoking this.getToken(), NOT by directly accessing // this.element.value. This is to allow incremental tokenized // autocompletion. Specific auto-completion logic (AJAX, etc) // belongs in getUpdatedChoices. // // Tokenized incremental autocompletion is enabled automatically // when an autocompleter is instantiated with the 'tokens' option // in the options parameter, e.g.: // new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); // will incrementally autocomplete with a comma as the token. // Additionally, ',' in the above example can be replaced with // a token array, e.g. { tokens: [',', '\n'] } which // enables autocompletion on multiple tokens. This is most // useful when one of the tokens is \n (a newline), as it // allows smart autocompletion after linebreaks. if(typeof Effect == 'undefined') throw("controls.js requires including script.aculo.us' effects.js library"); var Autocompleter = { }; Autocompleter.Base = Class.create({ baseInitialize: function(element, update, options) { element = $(element); this.element = element; this.update = $(update); this.hasFocus = false; this.changed = false; this.active = false; this.index = 0; this.entryCount = 0; this.oldElementValue = this.element.value; if(this.setOptions) this.setOptions(options); else this.options = options || { }; this.options.paramName = this.options.paramName || this.element.name; this.options.tokens = this.options.tokens || []; this.options.frequency = this.options.frequency || 0.4; this.options.minChars = this.options.minChars || 1; this.options.onShow = this.options.onShow || function(element, update){ if(!update.style.position || update.style.position=='absolute') { update.style.position = 'absolute'; Position.clone(element, update, { setHeight: false, offsetTop: element.offsetHeight }); } Effect.Appear(update,{duration:0.15}); }; this.options.onHide = this.options.onHide || function(element, update){ new Effect.Fade(update,{duration:0.15}) }; if(typeof(this.options.tokens) == 'string') this.options.tokens = new Array(this.options.tokens); // Force carriage returns as token delimiters anyway if (!this.options.tokens.include('\n')) this.options.tokens.push('\n'); this.observer = null; this.element.setAttribute('autocomplete','off'); Element.hide(this.update); Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); }, show: function() { if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); if(!this.iefix && (Prototype.Browser.IE) && (Element.getStyle(this.update, 'position')=='absolute')) { new Insertion.After(this.update, ''); this.iefix = $(this.update.id+'_iefix'); } if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); }, fixIEOverlapping: function() { Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); this.iefix.style.zIndex = 1; this.update.style.zIndex = 2; Element.show(this.iefix); }, hide: function() { this.stopIndicator(); if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); if(this.iefix) Element.hide(this.iefix); }, startIndicator: function() { if(this.options.indicator) Element.show(this.options.indicator); }, stopIndicator: function() { if(this.options.indicator) Element.hide(this.options.indicator); }, onKeyPress: function(event) { if(this.active) switch(event.keyCode) { case Event.KEY_TAB: case Event.KEY_RETURN: this.selectEntry(); Event.stop(event); case Event.KEY_ESC: this.hide(); this.active = false; Event.stop(event); return; case Event.KEY_LEFT: case Event.KEY_RIGHT: return; case Event.KEY_UP: this.markPrevious(); this.render(); Event.stop(event); return; case Event.KEY_DOWN: this.markNext(); this.render(); Event.stop(event); return; } else if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; this.changed = true; this.hasFocus = true; if(this.observer) clearTimeout(this.observer); this.observer = setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); }, activate: function() { this.changed = false; this.hasFocus = true; this.getUpdatedChoices(); }, onHover: function(event) { var element = Event.findElement(event, 'LI'); if(this.index != element.autocompleteIndex) { this.index = element.autocompleteIndex; this.render(); } Event.stop(event); }, onClick: function(event) { var element = Event.findElement(event, 'LI'); this.index = element.autocompleteIndex; this.selectEntry(); this.hide(); }, onBlur: function(event) { // needed to make click events working setTimeout(this.hide.bind(this), 250); this.hasFocus = false; this.active = false; }, render: function() { if(this.entryCount > 0) { for (var i = 0; i < this.entryCount; i++) this.index==i ? Element.addClassName(this.getEntry(i),"selected") : Element.removeClassName(this.getEntry(i),"selected"); if(this.hasFocus) { this.show(); this.active = true; } } else { this.active = false; this.hide(); } }, markPrevious: function() { if(this.index > 0) this.index--; else this.index = this.entryCount-1; this.getEntry(this.index).scrollIntoView(true); }, markNext: function() { if(this.index < this.entryCount-1) this.index++; else this.index = 0; this.getEntry(this.index).scrollIntoView(false); }, getEntry: function(index) { return this.update.firstChild.childNodes[index]; }, getCurrentEntry: function() { return this.getEntry(this.index); }, selectEntry: function() { this.active = false; this.updateElement(this.getCurrentEntry()); }, updateElement: function(selectedElement) { if (this.options.updateElement) { this.options.updateElement(selectedElement); return; } var value = ''; if (this.options.select) { var nodes = $(selectedElement).select('.' + this.options.select) || []; if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); } else value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); var bounds = this.getTokenBounds(); if (bounds[0] != -1) { var newValue = this.element.value.substr(0, bounds[0]); var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); if (whitespace) newValue += whitespace[0]; this.element.value = newValue + value + this.element.value.substr(bounds[1]); } else { this.element.value = value; } this.oldElementValue = this.element.value; this.element.focus(); if (this.options.afterUpdateElement) this.options.afterUpdateElement(this.element, selectedElement); }, updateChoices: function(choices) { if(!this.changed && this.hasFocus) { this.update.innerHTML = choices; Element.cleanWhitespace(this.update); Element.cleanWhitespace(this.update.down()); if(this.update.firstChild && this.update.down().childNodes) { this.entryCount = this.update.down().childNodes.length; for (var i = 0; i < this.entryCount; i++) { var entry = this.getEntry(i); entry.autocompleteIndex = i; this.addObservers(entry); } } else { this.entryCount = 0; } this.stopIndicator(); this.index = 0; if(this.entryCount==1 && this.options.autoSelect) { this.selectEntry(); this.hide(); } else { this.render(); } } }, addObservers: function(element) { Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); Event.observe(element, "click", this.onClick.bindAsEventListener(this)); }, onObserverEvent: function() { this.changed = false; this.tokenBounds = null; if(this.getToken().length>=this.options.minChars) { this.getUpdatedChoices(); } else { this.active = false; this.hide(); } this.oldElementValue = this.element.value; }, getToken: function() { var bounds = this.getTokenBounds(); return this.element.value.substring(bounds[0], bounds[1]).strip(); }, getTokenBounds: function() { if (null != this.tokenBounds) return this.tokenBounds; var value = this.element.value; if (value.strip().empty()) return [-1, 0]; var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); var offset = (diff == this.oldElementValue.length ? 1 : 0); var prevTokenPos = -1, nextTokenPos = value.length; var tp; for (var index = 0, l = this.options.tokens.length; index < l; ++index) { tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); if (tp > prevTokenPos) prevTokenPos = tp; tp = value.indexOf(this.options.tokens[index], diff + offset); if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; } return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); } }); Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { var boundary = Math.min(newS.length, oldS.length); for (var index = 0; index < boundary; ++index) if (newS[index] != oldS[index]) return index; return boundary; }; Ajax.Autocompleter = Class.create(Autocompleter.Base, { initialize: function(element, update, url, options) { this.baseInitialize(element, update, options); this.options.asynchronous = true; this.options.onComplete = this.onComplete.bind(this); this.options.defaultParams = this.options.parameters || null; this.url = url; }, getUpdatedChoices: function() { this.startIndicator(); var entry = encodeURIComponent(this.options.paramName) + '=' + encodeURIComponent(this.getToken()); this.options.parameters = this.options.callback ? this.options.callback(this.element, entry) : entry; if(this.options.defaultParams) this.options.parameters += '&' + this.options.defaultParams; new Ajax.Request(this.url, this.options); }, onComplete: function(request) { this.updateChoices(request.responseText); } }); // The local array autocompleter. Used when you'd prefer to // inject an array of autocompletion options into the page, rather // than sending out Ajax queries, which can be quite slow sometimes. // // The constructor takes four parameters. The first two are, as usual, // the id of the monitored textbox, and id of the autocompletion menu. // The third is the array you want to autocomplete from, and the fourth // is the options block. // // Extra local autocompletion options: // - choices - How many autocompletion choices to offer // // - partialSearch - If false, the autocompleter will match entered // text only at the beginning of strings in the // autocomplete array. Defaults to true, which will // match text at the beginning of any *word* in the // strings in the autocomplete array. If you want to // search anywhere in the string, additionally set // the option fullSearch to true (default: off). // // - fullSsearch - Search anywhere in autocomplete array strings. // // - partialChars - How many characters to enter before triggering // a partial match (unlike minChars, which defines // how many characters are required to do any match // at all). Defaults to 2. // // - ignoreCase - Whether to ignore case when autocompleting. // Defaults to true. // // It's possible to pass in a custom function as the 'selector' // option, if you prefer to write your own autocompletion logic. // In that case, the other options above will not apply unless // you support them. Autocompleter.Local = Class.create(Autocompleter.Base, { initialize: function(element, update, array, options) { this.baseInitialize(element, update, options); this.options.array = array; }, getUpdatedChoices: function() { this.updateChoices(this.options.selector(this)); }, setOptions: function(options) { this.options = Object.extend({ choices: 10, partialSearch: true, partialChars: 2, ignoreCase: true, fullSearch: false, selector: function(instance) { var ret = []; // Beginning matches var partial = []; // Inside matches var entry = instance.getToken(); var count = 0; for (var i = 0; i < instance.options.array.length && ret.length < instance.options.choices ; i++) { var elem = instance.options.array[i]; var foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase()) : elem.indexOf(entry); while (foundPos != -1) { if (foundPos == 0 && elem.length != entry.length) { ret.push("
  • " + elem.substr(0, entry.length) + "" + elem.substr(entry.length) + "
  • "); break; } else if (entry.length >= instance.options.partialChars && instance.options.partialSearch && foundPos != -1) { if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { partial.push("
  • " + elem.substr(0, foundPos) + "" + elem.substr(foundPos, entry.length) + "" + elem.substr( foundPos + entry.length) + "
  • "); break; } } foundPos = instance.options.ignoreCase ? elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : elem.indexOf(entry, foundPos + 1); } } if (partial.length) ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); return "
      " + ret.join('') + "
    "; } }, options || { }); } }); // AJAX in-place editor and collection editor // Full rewrite by Christophe Porteneuve (April 2007). // Use this if you notice weird scrolling problems on some browsers, // the DOM might be a bit confused when this gets called so do this // waits 1 ms (with setTimeout) until it does the activation Field.scrollFreeActivate = function(field) { setTimeout(function() { Field.activate(field); }, 1); }; Ajax.InPlaceEditor = Class.create({ initialize: function(element, url, options) { this.url = url; this.element = element = $(element); this.prepareOptions(); this._controls = { }; arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! Object.extend(this.options, options || { }); if (!this.options.formId && this.element.id) { this.options.formId = this.element.id + '-inplaceeditor'; if ($(this.options.formId)) this.options.formId = ''; } if (this.options.externalControl) this.options.externalControl = $(this.options.externalControl); if (!this.options.externalControl) this.options.externalControlOnly = false; this._originalBackground = this.element.getStyle('background-color') || 'transparent'; this.element.title = this.options.clickToEditText; this._boundCancelHandler = this.handleFormCancellation.bind(this); this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); this._boundFailureHandler = this.handleAJAXFailure.bind(this); this._boundSubmitHandler = this.handleFormSubmission.bind(this); this._boundWrapperHandler = this.wrapUp.bind(this); this.registerListeners(); }, checkForEscapeOrReturn: function(e) { if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; if (Event.KEY_ESC == e.keyCode) this.handleFormCancellation(e); else if (Event.KEY_RETURN == e.keyCode) this.handleFormSubmission(e); }, createControl: function(mode, handler, extraClasses) { var control = this.options[mode + 'Control']; var text = this.options[mode + 'Text']; if ('button' == control) { var btn = document.createElement('input'); btn.type = 'submit'; btn.value = text; btn.className = 'editor_' + mode + '_button'; if ('cancel' == mode) btn.onclick = this._boundCancelHandler; this._form.appendChild(btn); this._controls[mode] = btn; } else if ('link' == control) { var link = document.createElement('a'); link.href = '#'; link.appendChild(document.createTextNode(text)); link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; link.className = 'editor_' + mode + '_link'; if (extraClasses) link.className += ' ' + extraClasses; this._form.appendChild(link); this._controls[mode] = link; } }, createEditField: function() { var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); var fld; if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { fld = document.createElement('input'); fld.type = 'text'; var size = this.options.size || this.options.cols || 0; if (0 < size) fld.size = size; } else { fld = document.createElement('textarea'); fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); fld.cols = this.options.cols || 40; } fld.name = this.options.paramName; fld.value = text; // No HTML breaks conversion anymore fld.className = 'editor_field'; if (this.options.submitOnBlur) fld.onblur = this._boundSubmitHandler; this._controls.editor = fld; if (this.options.loadTextURL) this.loadExternalText(); this._form.appendChild(this._controls.editor); }, createForm: function() { var ipe = this; function addText(mode, condition) { var text = ipe.options['text' + mode + 'Controls']; if (!text || condition === false) return; ipe._form.appendChild(document.createTextNode(text)); }; this._form = $(document.createElement('form')); this._form.id = this.options.formId; this._form.addClassName(this.options.formClassName); this._form.onsubmit = this._boundSubmitHandler; this.createEditField(); if ('textarea' == this._controls.editor.tagName.toLowerCase()) this._form.appendChild(document.createElement('br')); if (this.options.onFormCustomization) this.options.onFormCustomization(this, this._form); addText('Before', this.options.okControl || this.options.cancelControl); this.createControl('ok', this._boundSubmitHandler); addText('Between', this.options.okControl && this.options.cancelControl); this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); addText('After', this.options.okControl || this.options.cancelControl); }, destroy: function() { if (this._oldInnerHTML) this.element.innerHTML = this._oldInnerHTML; this.leaveEditMode(); this.unregisterListeners(); }, enterEditMode: function(e) { if (this._saving || this._editing) return; this._editing = true; this.triggerCallback('onEnterEditMode'); if (this.options.externalControl) this.options.externalControl.hide(); this.element.hide(); this.createForm(); this.element.parentNode.insertBefore(this._form, this.element); if (!this.options.loadTextURL) this.postProcessEditField(); if (e) Event.stop(e); }, enterHover: function(e) { if (this.options.hoverClassName) this.element.addClassName(this.options.hoverClassName); if (this._saving) return; this.triggerCallback('onEnterHover'); }, getText: function() { return this.element.innerHTML.unescapeHTML(); }, handleAJAXFailure: function(transport) { this.triggerCallback('onFailure', transport); if (this._oldInnerHTML) { this.element.innerHTML = this._oldInnerHTML; this._oldInnerHTML = null; } }, handleFormCancellation: function(e) { this.wrapUp(); if (e) Event.stop(e); }, handleFormSubmission: function(e) { var form = this._form; var value = $F(this._controls.editor); this.prepareSubmission(); var params = this.options.callback(form, value) || ''; if (Object.isString(params)) params = params.toQueryParams(); params.editorId = this.element.id; if (this.options.htmlResponse) { var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); Object.extend(options, { parameters: params, onComplete: this._boundWrapperHandler, onFailure: this._boundFailureHandler }); new Ajax.Updater({ success: this.element }, this.url, options); } else { var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: params, onComplete: this._boundWrapperHandler, onFailure: this._boundFailureHandler }); new Ajax.Request(this.url, options); } if (e) Event.stop(e); }, leaveEditMode: function() { this.element.removeClassName(this.options.savingClassName); this.removeForm(); this.leaveHover(); this.element.style.backgroundColor = this._originalBackground; this.element.show(); if (this.options.externalControl) this.options.externalControl.show(); this._saving = false; this._editing = false; this._oldInnerHTML = null; this.triggerCallback('onLeaveEditMode'); }, leaveHover: function(e) { if (this.options.hoverClassName) this.element.removeClassName(this.options.hoverClassName); if (this._saving) return; this.triggerCallback('onLeaveHover'); }, loadExternalText: function() { this._form.addClassName(this.options.loadingClassName); this._controls.editor.disabled = true; var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport) { this._form.removeClassName(this.options.loadingClassName); var text = transport.responseText; if (this.options.stripLoadedTextTags) text = text.stripTags(); this._controls.editor.value = text; this._controls.editor.disabled = false; this.postProcessEditField(); }.bind(this), onFailure: this._boundFailureHandler }); new Ajax.Request(this.options.loadTextURL, options); }, postProcessEditField: function() { var fpc = this.options.fieldPostCreation; if (fpc) $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); }, prepareOptions: function() { this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); [this._extraDefaultOptions].flatten().compact().each(function(defs) { Object.extend(this.options, defs); }.bind(this)); }, prepareSubmission: function() { this._saving = true; this.removeForm(); this.leaveHover(); this.showSaving(); }, registerListeners: function() { this._listeners = { }; var listener; $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { listener = this[pair.value].bind(this); this._listeners[pair.key] = listener; if (!this.options.externalControlOnly) this.element.observe(pair.key, listener); if (this.options.externalControl) this.options.externalControl.observe(pair.key, listener); }.bind(this)); }, removeForm: function() { if (!this._form) return; this._form.remove(); this._form = null; this._controls = { }; }, showSaving: function() { this._oldInnerHTML = this.element.innerHTML; this.element.innerHTML = this.options.savingText; this.element.addClassName(this.options.savingClassName); this.element.style.backgroundColor = this._originalBackground; this.element.show(); }, triggerCallback: function(cbName, arg) { if ('function' == typeof this.options[cbName]) { this.options[cbName](this, arg); } }, unregisterListeners: function() { $H(this._listeners).each(function(pair) { if (!this.options.externalControlOnly) this.element.stopObserving(pair.key, pair.value); if (this.options.externalControl) this.options.externalControl.stopObserving(pair.key, pair.value); }.bind(this)); }, wrapUp: function(transport) { this.leaveEditMode(); // Can't use triggerCallback due to backward compatibility: requires // binding + direct element this._boundComplete(transport, this.element); } }); Object.extend(Ajax.InPlaceEditor.prototype, { dispose: Ajax.InPlaceEditor.prototype.destroy }); Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { initialize: function($super, element, url, options) { this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; $super(element, url, options); }, createEditField: function() { var list = document.createElement('select'); list.name = this.options.paramName; list.size = 1; this._controls.editor = list; this._collection = this.options.collection || []; if (this.options.loadCollectionURL) this.loadCollection(); else this.checkForExternalText(); this._form.appendChild(this._controls.editor); }, loadCollection: function() { this._form.addClassName(this.options.loadingClassName); this.showLoadingText(this.options.loadingCollectionText); var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport) { var js = transport.responseText.strip(); if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check throw('Server returned an invalid collection representation.'); this._collection = eval(js); this.checkForExternalText(); }.bind(this), onFailure: this.onFailure }); new Ajax.Request(this.options.loadCollectionURL, options); }, showLoadingText: function(text) { this._controls.editor.disabled = true; var tempOption = this._controls.editor.firstChild; if (!tempOption) { tempOption = document.createElement('option'); tempOption.value = ''; this._controls.editor.appendChild(tempOption); tempOption.selected = true; } tempOption.update((text || '').stripScripts().stripTags()); }, checkForExternalText: function() { this._text = this.getText(); if (this.options.loadTextURL) this.loadExternalText(); else this.buildOptionList(); }, loadExternalText: function() { this.showLoadingText(this.options.loadingText); var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); Object.extend(options, { parameters: 'editorId=' + encodeURIComponent(this.element.id), onComplete: Prototype.emptyFunction, onSuccess: function(transport) { this._text = transport.responseText.strip(); this.buildOptionList(); }.bind(this), onFailure: this.onFailure }); new Ajax.Request(this.options.loadTextURL, options); }, buildOptionList: function() { this._form.removeClassName(this.options.loadingClassName); this._collection = this._collection.map(function(entry) { return 2 === entry.length ? entry : [entry, entry].flatten(); }); var marker = ('value' in this.options) ? this.options.value : this._text; var textFound = this._collection.any(function(entry) { return entry[0] == marker; }.bind(this)); this._controls.editor.update(''); var option; this._collection.each(function(entry, index) { option = document.createElement('option'); option.value = entry[0]; option.selected = textFound ? entry[0] == marker : 0 == index; option.appendChild(document.createTextNode(entry[1])); this._controls.editor.appendChild(option); }.bind(this)); this._controls.editor.disabled = false; Field.scrollFreeActivate(this._controls.editor); } }); //**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** //**** This only exists for a while, in order to let **** //**** users adapt to the new API. Read up on the new **** //**** API and convert your code to it ASAP! **** Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { if (!options) return; function fallback(name, expr) { if (name in options || expr === undefined) return; options[name] = expr; }; fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : options.cancelLink == options.cancelButton == false ? false : undefined))); fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : options.okLink == options.okButton == false ? false : undefined))); fallback('highlightColor', options.highlightcolor); fallback('highlightEndColor', options.highlightendcolor); }; Object.extend(Ajax.InPlaceEditor, { DefaultOptions: { ajaxOptions: { }, autoRows: 3, // Use when multi-line w/ rows == 1 cancelControl: 'link', // 'link'|'button'|false cancelText: 'cancel', clickToEditText: 'Click to edit', externalControl: null, // id|elt externalControlOnly: false, fieldPostCreation: 'activate', // 'activate'|'focus'|false formClassName: 'inplaceeditor-form', formId: null, // id|elt highlightColor: '#ffff99', highlightEndColor: '#ffffff', hoverClassName: '', htmlResponse: true, loadingClassName: 'inplaceeditor-loading', loadingText: 'Loading...', okControl: 'button', // 'link'|'button'|false okText: 'ok', paramName: 'value', rows: 1, // If 1 and multi-line, uses autoRows savingClassName: 'inplaceeditor-saving', savingText: 'Saving...', size: 0, stripLoadedTextTags: false, submitOnBlur: false, textAfterControls: '', textBeforeControls: '', textBetweenControls: '' }, DefaultCallbacks: { callback: function(form) { return Form.serialize(form); }, onComplete: function(transport, element) { // For backward compatibility, this one is bound to the IPE, and passes // the element directly. It was too often customized, so we don't break it. new Effect.Highlight(element, { startcolor: this.options.highlightColor, keepBackgroundImage: true }); }, onEnterEditMode: null, onEnterHover: function(ipe) { ipe.element.style.backgroundColor = ipe.options.highlightColor; if (ipe._effect) ipe._effect.cancel(); }, onFailure: function(transport, ipe) { alert('Error communication with the server: ' + transport.responseText.stripTags()); }, onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. onLeaveEditMode: null, onLeaveHover: function(ipe) { ipe._effect = new Effect.Highlight(ipe.element, { startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, restorecolor: ipe._originalBackground, keepBackgroundImage: true }); } }, Listeners: { click: 'enterEditMode', keydown: 'checkForEscapeOrReturn', mouseover: 'enterHover', mouseout: 'leaveHover' } }); Ajax.InPlaceCollectionEditor.DefaultOptions = { loadingCollectionText: 'Loading options...' }; // Delayed observer, like Form.Element.Observer, // but waits for delay after last key input // Ideal for live-search fields Form.Element.DelayedObserver = Class.create({ initialize: function(element, delay, callback) { this.delay = delay || 0.5; this.element = $(element); this.callback = callback; this.timer = null; this.lastValue = $F(this.element); Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); }, delayedListener: function(event) { if(this.lastValue == $F(this.element)) return; if(this.timer) clearTimeout(this.timer); this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); this.lastValue = $F(this.element); }, onTimerEvent: function() { this.timer = null; this.callback(this.element, $F(this.element)); } });gosa-core-2.7.4/html/include/sound.js0000644000175000017500000000463011325266624016466 0ustar cajuscajus// script.aculo.us sound.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // // Based on code created by Jules Gravinese (http://www.webveteran.com/) // // script.aculo.us is freely distributable under the terms of an MIT-style license. // For details, see the script.aculo.us web site: http://script.aculo.us/ Sound = { tracks: {}, _enabled: true, template: new Template(''), enable: function(){ Sound._enabled = true; }, disable: function(){ Sound._enabled = false; }, play: function(url){ if(!Sound._enabled) return; var options = Object.extend({ track: 'global', url: url, replace: false }, arguments[1] || {}); if(options.replace && this.tracks[options.track]) { $R(0, this.tracks[options.track].id).each(function(id){ var sound = $('sound_'+options.track+'_'+id); sound.Stop && sound.Stop(); sound.remove(); }); this.tracks[options.track] = null; } if(!this.tracks[options.track]) this.tracks[options.track] = { id: 0 }; else this.tracks[options.track].id++; options.id = this.tracks[options.track].id; $$('body')[0].insert( Prototype.Browser.IE ? new Element('bgsound',{ id: 'sound_'+options.track+'_'+options.id, src: options.url, loop: 1, autostart: true }) : Sound.template.evaluate(options)); } }; if(Prototype.Browser.Gecko && navigator.userAgent.indexOf("Win") > 0){ if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('QuickTime') != -1 })) Sound.template = new Template(''); else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('Windows Media') != -1 })) Sound.template = new Template(''); else if(navigator.plugins && $A(navigator.plugins).detect(function(p){ return p.name.indexOf('RealPlayer') != -1 })) Sound.template = new Template(''); else Sound.play = function(){}; } gosa-core-2.7.4/html/include/datepicker.js0000644000175000017500000006646111340757577017474 0ustar cajuscajus/** * DatePicker widget using Prototype and Scriptaculous. * (c) 2007 Mathieu Jondet * Eulerian Technologies * * DatePicker is freely distributable under the same terms as Prototype. * * Modified 10.06.2008 * by Manu * */ /** * DatePickerFormatter class for matching and stringifying dates. * * By Arturas Slajus . */ var DatePickerFormatter = Class.create(); DatePickerFormatter.prototype = { /** * Create a DatePickerFormatter. * * format: specify a format by passing 3 value array consisting of * "yyyy", "mm", "dd". Default: ["yyyy", "mm", "dd"]. * * separator: string for splitting the values. Default: "-". * * Use it like this: * var df = new DatePickerFormatter(["dd", "mm", "yyyy"], "/"); * df.current_date(); * df.match("7/7/2007"); */ initialize: function(format, separator) { if (Object.isUndefined(format)) format = ["yyyy", "mm", "dd"]; if (Object.isUndefined(separator)) separator = "-"; this._format = format; this.separator = separator; this._format_year_index = format.indexOf("yyyy"); this._format_month_index= format.indexOf("mm"); this._format_day_index = format.indexOf("dd"); this._year_regexp = /^\d{4}$/; this._month_regexp = /^0\d|1[012]|\d$/; this._day_regexp = /^0\d|[12]\d|3[01]|\d$/; }, /** * Match a string against date format. * Returns: [year, month, day] */ match: function(str) { var d = str.split(this.separator); if (d.length < 3) { return false; } var year = d[this._format_year_index].match(this._year_regexp); if (year) { year = year[0] } else { return false } var month = d[this._format_month_index].match(this._month_regexp); if (month) { month = month[0] } else { return false } var day = d[this._format_day_index].match(this._day_regexp); if (day) { day = day[0] } else { return false } return [year, month, day]; }, /** * Return current date according to format. */ current_date: function() { var d = new Date; return this.date_to_string ( d.getFullYear(), d.getMonth() + 1, d.getDate() ); }, /** * Return a stringified date accordint to format. */ date_to_string: function(year, month, day, separator) { if (Object.isUndefined(separator)) separator = this.separator; var a = [0, 0, 0]; a[this._format_year_index] = year; a[this._format_month_index]= month.toPaddedString(2); a[this._format_day_index] = day.toPaddedString(2); return a.join(separator); } }; /** * DatePicker */ var datepickers = $H(); var DatePicker = Class.create(); DatePicker.prototype = { Version : '0.9.4', _relative : null, _div : null, _zindex : 1, _keepFieldEmpty : false, _daysInMonth : [31,28,31,30,31,30,31,31,30,31,30,31], _dateFormat : [ ["dd", "mm", "yyyy"], "." ], /* language */ _language : 'de', _language_month : $H({ 'fr' : [ 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Aout', 'Septembre', 'Octobre', 'Novembre', 'Décembre' ], 'en' : [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ], 'es' : [ 'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre' ], 'it' : [ 'Gennaio', 'Febbraio', 'Marzo', 'Aprile', 'Maggio', 'Giugno', 'Luglio', 'Agosto', 'Settembre', 'Ottobre', 'Novembre', 'Dicembre' ], 'de' : [ 'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember' ], 'pt' : [ 'Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro' ], 'hu' : [ 'Január', 'Február', 'Március', 'Április', 'Május', 'Június', 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December' ], 'lt' : [ 'Sausis', 'Vasaris', 'Kovas', 'Balandis', 'Gegužė', 'Birželis', 'Liepa', 'Rugjūtis', 'Rusėjis', 'Spalis', 'Lapkritis', 'Gruodis' ], 'nl' : [ 'januari', 'februari', 'maart', 'april', 'mei', 'juni', 'juli', 'augustus', 'september', 'oktober', 'november', 'december' ], 'dk' : [ 'Januar', 'Februar', 'Marts', 'April', 'Maj', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'December' ], 'no' : [ 'Januar', 'Februar', 'Mars', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Desember' ], 'lv' : [ 'Janvāris', 'Februāris', 'Marts', 'Aprīlis', 'Maijs', 'Jūnijs', 'Jūlijs', 'Augusts', 'Septembris', 'Oktobris', 'Novembris', 'Decemberis' ], 'ja' : [ '1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月' ], 'fi' : [ 'Tammikuu', 'Helmikuu', 'Maaliskuu', 'Huhtikuu', 'Toukokuu', 'Kesäkuu', 'Heinäkuu', 'Elokuu', 'Syyskuu', 'Lokakuu', 'Marraskuu', 'Joulukuu' ], 'ro' : [ 'Ianuarie', 'Februarie', 'Martie', 'Aprilie', 'Mai', 'Junie', 'Julie', 'August', 'Septembrie', 'Octombrie', 'Noiembrie', 'Decembrie' ], 'zh' : [ '1 月', '2 月', '3 月', '4 月', '5 月', '6 月', '7 月', '8 月', '9 月', '10月', '11月', '12月'], 'sv' : [ 'Januari', 'Februari', 'Mars', 'April', 'Maj', 'Juni', 'Juli', 'Augusti', 'September', 'Oktober', 'November', 'December' ] }), _language_day : $H({ 'fr' : [ 'Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim' ], 'en' : [ 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun' ], 'es' : [ 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sàb', 'Dom' ], 'it' : [ 'Lun', 'Mar', 'Mer', 'Gio', 'Ven', 'Sab', 'Dom' ], 'de' : [ 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So' ], 'pt' : [ 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sá', 'Dom' ], 'hu' : [ 'Hé', 'Ke', 'Sze', 'Csü', 'Pé', 'Szo', 'Vas' ], 'lt' : [ 'Pir', 'Ant', 'Tre', 'Ket', 'Pen', 'Šeš', 'Sek' ], 'nl' : [ 'ma', 'di', 'wo', 'do', 'vr', 'za', 'zo' ], 'dk' : [ 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør', 'Søn' ], 'no' : [ 'Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør', 'Sun' ], 'lv' : [ 'P', 'O', 'T', 'C', 'Pk', 'S', 'Sv' ], 'ja' : [ '月', '火', '水', '木', '金', '土', '日' ], 'fi' : [ 'Ma', 'Ti', 'Ke', 'To', 'Pe', 'La', 'Su' ], 'ro' : [ 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sam', 'Dum' ], 'zh' : [ '周一', '周二', '周三', '周四', '周五', '周六', '周日' ], 'sv' : [ 'Mån', 'Tis', 'Ons', 'Tor', 'Fre', 'Lör', 'Sön' ] }), _language_close : $H({ 'fr' : 'fermer', 'en' : 'close', 'es' : 'cierre', 'it' : 'fine', 'de' : 'schliessen', 'pt' : 'fim', 'hu' : 'bezár', 'lt' : 'udaryti', 'nl' : 'sluiten', 'dk' : 'luk', 'no' : 'lukk', 'lv' : 'aizvērt', 'ja' : '閉じる', 'fi' : 'sulje', 'ro' : 'inchide', 'zh' : '关 闭', 'sv' : 'stäng' }), /* date manipulation */ _todayDate : new Date(), _current_date : null, _clickCallback : Prototype.emptyFunction, _cellCallback : Prototype.emptyFunction, _id_datepicker : null, _disablePastDate : false, _disableFutureDate : false, _oneDayInMs : 24 * 3600 * 1000, /* positionning */ _topOffset : 20, _leftOffset : 0, _isPositionned : false, _relativePosition : true, _setPositionTop : 0, _setPositionLeft : 0, _bodyAppend : false, /* Effects Adjustment */ _showEffect : "appear", _showDuration : 1, _enableShowEffect : true, _closeEffect : "fade", _closeEffectDuration : 0.3, _enableCloseEffect : true, _closeTimer : null, _enableCloseOnBlur : false, /* afterClose : called when the close function is executed */ _afterClose : Prototype.emptyFunction, /* return the name of current month in appropriate language */ getMonthLocale : function ( month ) { return this._language_month.get(this._language)[month]; }, getLocaleClose : function () { return this._language_close.get(this._language); }, _initCurrentDate : function () { /* Create the DateFormatter */ this._df = new DatePickerFormatter(this._dateFormat[0], this._dateFormat[1]); /* check if value in field is proper, if not set to today */ this._current_date = $F(this._relative); if (! this._df.match(this._current_date)) { this._current_date = this._df.current_date(); /* set the field value ? */ if (!this._keepFieldEmpty) $(this._relative).value = this._current_date; } var a_date = this._df.match(this._current_date); this._current_year = Number(a_date[0]); this._current_mon = Number(a_date[1]) - 1; this._current_day = Number(a_date[2]); }, /* init */ initialize : function ( h_p ) { /* arguments */ this._relative= h_p["relative"]; if (h_p["language"]) this._language = h_p["language"]; this._zindex = ( h_p["zindex"] ) ? parseInt(Number(h_p["zindex"])) : 999; if (!Object.isUndefined(h_p["keepFieldEmpty"])) this._keepFieldEmpty = h_p["keepFieldEmpty"]; if (Object.isFunction(h_p["clickCallback"])) this._clickCallback = h_p["clickCallback"]; if (!Object.isUndefined(h_p["leftOffset"])) this._leftOffset = parseInt(h_p["leftOffset"]); if (!Object.isUndefined(h_p["topOffset"])) this._topOffset = parseInt(h_p["topOffset"]); if (!Object.isUndefined(h_p["relativePosition"])) this._relativePosition = h_p["relativePosition"]; if (!Object.isUndefined(h_p["showEffect"])) this._showEffect = h_p["showEffect"]; if (!Object.isUndefined(h_p["enableShowEffect"])) this._enableShowEffect = h_p["enableShowEffect"]; if (!Object.isUndefined(h_p["showDuration"])) this._showDuration = h_p["showDuration"]; if (!Object.isUndefined(h_p["closeEffect"])) this._closeEffect = h_p["closeEffect"]; if (!Object.isUndefined(h_p["enableCloseEffect"])) this._enableCloseEffect = h_p["enableCloseEffect"]; if (!Object.isUndefined(h_p["closeEffectDuration"])) this._closeEffectDuration = h_p["closeEffectDuration"]; if (Object.isFunction(h_p["afterClose"])) this._afterClose = h_p["afterClose"]; if (!Object.isUndefined(h_p["externalControl"])) this._externalControl = h_p["externalControl"]; if (!Object.isUndefined(h_p["dateFormat"])) this._dateFormat = h_p["dateFormat"]; if (Object.isFunction(h_p["cellCallback"])) this._cellCallback = h_p["cellCallback"]; this._setPositionTop = ( h_p["setPositionTop"] ) ? parseInt(Number(h_p["setPositionTop"])) : 0; this._setPositionLeft = ( h_p["setPositionLeft"] ) ? parseInt(Number(h_p["setPositionLeft"])) : 0; if (!Object.isUndefined(h_p["enableCloseOnBlur"]) && h_p["enableCloseOnBlur"]) this._enableCloseOnBlur = true; if (!Object.isUndefined(h_p["disablePastDate"]) && h_p["disablePastDate"]) this._disablePastDate = true; if (!Object.isUndefined(h_p["disableFutureDate"]) && !h_p["disableFutureDate"]) this._disableFutureDate = false; this._id_datepicker = 'datepicker-'+ this._relative; this._id_datepicker_prev = this._id_datepicker +'-prev'; this._id_datepicker_prev_year = this._id_datepicker +'-prev-year'; this._id_datepicker_next = this._id_datepicker +'-next'; this._id_datepicker_next_year = this._id_datepicker +'-next-year'; this._id_datepicker_hdr = this._id_datepicker +'-header'; this._id_datepicker_ftr = this._id_datepicker +'-footer'; /* build up calendar skel */ this._div = new Element('div', { id : this._id_datepicker, className : 'datepicker', style : 'display: none; z-index:'+ this._zindex }); // this._div.innerHTML = '
     <<  >> 
    '; this._div.innerHTML = '
    << < > >>
    '; /* Build the datepicker icon */ var datepickeropener = Builder.node('table',{className : "datepicker-opener-table", id: this._id_datepicker + '_image'}); var con = Builder.node('tr',{},[ Builder.node('td',{className : "datepicker-opener", id : "datepicker-opener-"+ this._relative}) ]); // insert into TBODY if (datepickeropener.childNodes[0] != undefined) { datepickeropener.childNodes[0].appendChild(con); } else { datepickeropener.appendChild(con); } Event.observe(datepickeropener,'click', this.click.bindAsEventListener(this), false); this.insertAfter($(this._relative).parentNode,datepickeropener,$(this._relative)); /* End Build the datepicker icon */ /* finally declare the event listener on input field */ //Event.observe(this._relative, 'click', this.click.bindAsEventListener(this), false); /* need to append on body when doc is loaded for IE */ document.observe('dom:loaded', this.load.bindAsEventListener(this), false); /* automatically close when blur event is triggered */ if ( this._enableCloseOnBlur ) { Event.observe(this._relative, 'blur', function (e) { this._closeTimer = this.close.bind(this).delay(1); }.bindAsEventListener(this)); Event.observe(this._div, 'click', function (e) { if (this._closeTimer) { window.clearTimeout(this._closeTimer); this._closeTimer = null; } }); } }, /** * load : called when document is fully-loaded to append datepicker * to main object. */ load : function () { /* if externalControl defined set the observer on it */ if (this._externalControl) Event.observe(this._externalControl, 'click', this.click.bindAsEventListener(this), false); /* append to page */ if (this._relativeAppend) { /* append to parent node */ if ($(this._relative).parentNode) { this._div.innerHTML = this._wrap_in_iframe(this._div.innerHTML); $(this._relative).parentNode.appendChild( this._div ); } } else { /* append to body */ var body = document.getElementsByTagName("body").item(0); if (body) { this._div.innerHTML = this._wrap_in_iframe(this._div.innerHTML); body.appendChild(this._div); } if ( this._relativePosition ) { var a_pos = Element.cumulativeOffset($(this._relative)); this.setPosition(a_pos[1], a_pos[0]); } else { if (this._setPositionTop || this._setPositionLeft) this.setPosition(this._setPositionTop, this._setPositionLeft); } } /* init the date in field if needed */ this._initCurrentDate(); /* set the close locale content */ $(this._id_datepicker_ftr).innerHTML = this.getLocaleClose(); /* declare the observers for UI control */ Event.observe($(this._id_datepicker_prev), 'click', this.prevMonth.bindAsEventListener(this), false); Event.observe($(this._id_datepicker_prev_year), 'click', this.prevYear.bindAsEventListener(this), false); Event.observe($(this._id_datepicker_next), 'click', this.nextMonth.bindAsEventListener(this), false); Event.observe($(this._id_datepicker_next_year), 'click', this.nextYear.bindAsEventListener(this), false); Event.observe($(this._id_datepicker_ftr), 'click', this.close.bindAsEventListener(this), false); }, insertAfter : function(parent, node, referenceNode) { parent.insertBefore(node, referenceNode.nextSibling); }, /* hack for buggy form elements layering in IE */ _wrap_in_iframe : function ( content ) { return ( Prototype.Browser.IE && msieversion() < 8 ) ? "
    " + content + "
    " : content; }, /** * visible : return the visibility status of the datepicker. */ visible : function () { return $(this._id_datepicker).visible(); }, /** * click : called when input element is clicked */ click : function () { /* init the datepicker if it doesn't exists */ if ( $(this._id_datepicker) == null ) this.load(); var a_pos = Element.cumulativeOffset($(this._relative)); this.setPosition(a_pos[1], a_pos[0]); if (!this._isPositionned && this._relativePosition) { /* position the datepicker relatively to element */ var a_lt = Element.positionedOffset($(this._relative)); $(this._id_datepicker).setStyle({ 'left' : Number(a_lt[0]+this._leftOffset)+'px', 'top' : Number(a_lt[1]+this._topOffset)+'px' }); this._isPositionned = true; } if (!this.visible()) { this._initCurrentDate(); this._redrawCalendar(); } /* eval the clickCallback function */ eval(this._clickCallback()); /* Effect toggle to fade-in / fade-out the datepicker */ if ( this._enableShowEffect ) { new Effect.toggle(this._id_datepicker, this._showEffect, { duration: this._showDuration }); } else { $(this._id_datepicker).show(); } }, /** * close : called when the datepicker is closed */ close : function () { if ( this._enableCloseEffect ) { switch(this._closeEffect) { case 'puff': new Effect.Puff(this._id_datepicker, { duration : this._closeEffectDuration }); break; case 'blindUp': new Effect.BlindUp(this._id_datepicker, { duration : this._closeEffectDuration }); break; case 'dropOut': new Effect.DropOut(this._id_datepicker, { duration : this._closeEffectDuration }); break; case 'switchOff': new Effect.SwitchOff(this._id_datepicker, { duration : this._closeEffectDuration }); break; case 'squish': new Effect.Squish(this._id_datepicker, { duration : this._closeEffectDuration }); break; case 'fold': new Effect.Fold(this._id_datepicker, { duration : this._closeEffectDuration }); break; case 'shrink': new Effect.Shrink(this._id_datepicker, { duration : this._closeEffectDuration }); break; default: new Effect.Fade(this._id_datepicker, { duration : this._closeEffectDuration }); break; }; } else { $(this._id_datepicker).hide(); } eval(this._afterClose()); }, /** * setDateFormat */ setDateFormat : function ( format, separator ) { if (Object.isUndefined(format)) format = this._dateFormat[0]; if (Object.isUndefined(separator)) separator = this._dateFormat[1]; this._dateFormat = [ format, separator ]; }, /** * setPosition : set the position of the datepicker. * param : t=top | l=left */ setPosition : function ( t, l ) { var h_pos = { 'top' : '0px', 'left' : '0px' }; if (!Object.isUndefined(t)) h_pos['top'] = Number(t) + this._topOffset +'px'; if (!Object.isUndefined(l)) h_pos['left']= Number(l) + this._leftOffset +'px'; $(this._id_datepicker).setStyle(h_pos); this._isPositionned = true; }, /** * _getMonthDays : given the year and month find the number of days. */ _getMonthDays : function ( year, month ) { if (((0 == (year%4)) && ((0 != (year%100)) || (0 == (year%400)))) && (month == 1)) return 29; return this._daysInMonth[month]; }, /** * _buildCalendar : draw the days array for current date */ _buildCalendar : function () { var _self = this; var tbody = $(this._id_datepicker +'-tbody'); try { while ( tbody.hasChildNodes() ) tbody.removeChild(tbody.childNodes[0]); } catch ( e ) {}; /* generate day headers */ var trDay = new Element('tr'); this._language_day.get(this._language).each( function ( item ) { var td = new Element('td'); td.innerHTML = item; td.className = 'wday'; trDay.appendChild( td ); }); tbody.appendChild( trDay ); /* generate the content of days */ /* build-up days matrix */ var a_d = [ [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0 ] ]; /* set date at beginning of month to display */ var d = new Date(this._current_year, this._current_mon, 1, 12); /* start the day list on monday */ var startIndex = ( !d.getDay() ) ? 6 : d.getDay() - 1; var nbDaysInMonth = this._getMonthDays( this._current_year, this._current_mon); var daysIndex = 1; for ( var j = startIndex; j < 7; j++ ) { a_d[0][j] = { d : daysIndex, m : this._current_mon, y : this._current_year }; daysIndex++; } var a_prevMY = this._prevMonthYear(); var nbDaysInMonthPrev = this._getMonthDays(a_prevMY[1], a_prevMY[0]); for ( var j = 0; j < startIndex; j++ ) { a_d[0][j] = { d : Number(nbDaysInMonthPrev - startIndex + j + 1), m : Number(a_prevMY[0]), y : a_prevMY[1], c : 'outbound' }; } var switchNextMonth = false; var currentMonth = this._current_mon; var currentYear = this._current_year; for ( var i = 1; i < 6; i++ ) { for ( var j = 0; j < 7; j++ ) { a_d[i][j] = { d : daysIndex, m : currentMonth, y : currentYear, c : ( switchNextMonth ) ? 'outbound' : (((daysIndex == this._todayDate.getDate()) && (this._current_mon == this._todayDate.getMonth()) && (this._current_year == this._todayDate.getFullYear())) ? 'today' : null) }; daysIndex++; /* if at the end of the month : reset counter */ if (daysIndex > nbDaysInMonth ) { daysIndex = 1; switchNextMonth = true; if (this._current_mon + 1 > 11 ) { currentMonth = 0; currentYear += 1; } else { currentMonth += 1; } } } } /* generate days for current date */ for ( var i = 0; i < 6; i++ ) { var tr = new Element('tr'); for ( var j = 0; j < 7; j++ ) { var h_ij = a_d[i][j]; var td = new Element('td'); /* id is : datepicker-day-mon-year or depending on language other way */ /* don't forget to add 1 on month for proper formmatting */ var id = $A([ this._relative, this._df.date_to_string(h_ij["y"], h_ij["m"]+1, h_ij["d"], '-') ]).join('-'); /* set id and classname for cell if exists */ td.setAttribute('id', id); if (h_ij["c"]) td.className = h_ij["c"]; /* on onclick : rebuild date value from id of current cell */ var _curDate = new Date(); _curDate.setFullYear(h_ij["y"], h_ij["m"], h_ij["d"]); if ( this._disablePastDate || this._disableFutureDate ) { if ( this._disablePastDate ) { var _res = ( _curDate >= this._todayDate ) ? true : false; this._bindCellOnClick( td, true, _res, h_ij["c"] ); } if ( this._disableFutureDate ) { var _res = ( this._todayDate.getTime() + this._oneDayInMs > _curDate.getTime() ) ? true : false; this._bindCellOnClick( td, true, _res, h_ij["c"] ); } } else { this._bindCellOnClick( td, false ); } td.innerHTML= h_ij["d"]; tr.appendChild( td ); } tbody.appendChild( tr ); } return tbody; }, /** * _bindCellOnClick : bind the cell onclick depending on status. */ _bindCellOnClick : function ( td, wcompare, compareresult, h_ij_c ) { var doBind = false; if ( wcompare ) { if ( compareresult ) { doBind = true; } else { td.className= ( h_ij_c ) ? 'nclick_outbound' : 'nclick'; } } else { doBind = true; } if ( doBind ) { var _self = this; td.onclick = function () { $(_self._relative).value = String($(this).readAttribute('id')).replace(_self._relative+'-','').replace(/-/g, _self._df.separator); /* if we have a cellCallback defined call it and pass it the cell */ if (_self._cellCallback) _self._cellCallback(this); _self.close(); }; } }, /** * nextMonth : redraw the calendar content for next month. */ _nextMonthYear : function () { var c_mon = this._current_mon; var c_year = this._current_year; if (c_mon + 1 > 11) { c_mon = 0; c_year += 1; } else { c_mon += 1; } return [ c_mon, c_year ]; }, nextMonth : function () { var a_next = this._nextMonthYear(); var _nextMon = a_next[0]; var _nextYear = a_next[1]; var _curDate = new Date(); _curDate.setFullYear(_nextYear, _nextMon, 1); var _res = ( this._todayDate.getTime() + this._oneDayInMs > _curDate.getTime() ) ? true : false; if ( this._disableFutureDate && !_res ) return; this._current_mon = _nextMon; this._current_year = _nextYear; this._redrawCalendar(); }, _nextYear : function () { var c_mon = this._current_mon; var c_year = this._current_year; c_year += 1; return [ c_mon, c_year ]; }, nextYear : function () { var a_next = this._nextYear(); this._current_mon = a_next[0]; this._current_year = a_next[1]; this._redrawCalendar(); }, /** * prevMonth : redraw the calendar content for previous month. */ _prevMonthYear : function () { var c_mon = this._current_mon; var c_year = this._current_year; if (c_mon - 1 < 0) { c_mon = 11; c_year -= 1; } else { c_mon -= 1; } return [ c_mon, c_year ]; }, prevMonth : function () { var a_prev = this._prevMonthYear(); var _prevMon = a_prev[0]; var _prevYear = a_prev[1]; var _curDate = new Date(); _curDate.setFullYear(_prevYear, _prevMon, 1); var _res = ( _curDate >= this._todayDate ) ? true : false; if ( this._disablePastDate && !_res ) return; this._current_mon = _prevMon; this._current_year = _prevYear; this._redrawCalendar(); }, _prevYear : function () { var c_mon = this._current_mon; var c_year = this._current_year; c_year -= 1; return [ c_mon, c_year ]; }, prevYear : function () { var a_prev = this._prevYear(); this._current_mon = a_prev[0]; this._current_year = a_prev[1]; this._redrawCalendar(); }, _redrawCalendar : function () { this._setLocaleHdr(); this._buildCalendar(); }, _setLocaleHdr : function () { /* prev year link */ var a_prevy = this._prevYear(); $(this._id_datepicker_prev_year).setAttribute('title', this.getMonthLocale(a_prevy[0]) +' '+ a_prevy[1]); /* prev link */ var a_prev = this._prevMonthYear(); $(this._id_datepicker_prev).setAttribute('title', this.getMonthLocale(a_prev[0]) +' '+ a_prev[1]); /* next link */ var a_next = this._nextMonthYear(); $(this._id_datepicker_next).setAttribute('title', this.getMonthLocale(a_next[0]) +' '+ a_next[1]); /* next year link */ var a_nexty = this._nextYear(); $(this._id_datepicker_next_year).setAttribute('title', this.getMonthLocale(a_nexty[0]) +' '+ a_nexty[1]); /* header */ $(this._id_datepicker_hdr).update('   '+ this.getMonthLocale(this._current_mon) +' '+ this._current_year +'   '); } }; function msieversion() { var ua = window.navigator.userAgent var msie = ua.indexOf ( "MSIE " ) if ( msie > 0 ) // If Internet Explorer, return version number return parseInt (ua.substring (msie+5, ua.indexOf (".", msie ))) else // If another browser, return 0 return 0 } gosa-core-2.7.4/html/include/scriptaculous.js0000644000175000017500000000557011325266624020242 0ustar cajuscajus// script.aculo.us scriptaculous.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 // Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // For details, see the script.aculo.us web site: http://script.aculo.us/ var Scriptaculous = { Version: '1.8.3', require: function(libraryName) { try{ // inserting via DOM fails in Safari 2.0, so brute force approach document.write(''; } $focus= ''; $smarty->assign("focus", $focus); /* Set channel if needed */ #TODO: * move all global session calls to global_ # * create a new channel where needed (mostly management dialogues) # * remove regulary created channels when not needed anymore # * take a look at external php calls (i.e. get fax, ldif, etc.) # * handle aborted sessions (by pressing anachors i.e. Main, Menu, etc.) # * check lock removals, is "dn" global or not in this case? # * last page request -> global or not? # * check that filters are still global # * maxC global? if (isset($_POST['_channel_'])){ echo "DEBUG - current channel: ".$_POST['_channel_']; $smarty->assign("channel", $_POST['_channel_']); } else { $smarty->assign("channel", ""); } $display= "".$smarty->fetch(get_template_path('headers.tpl')). $smarty->fetch(get_template_path('framework.tpl')); /* Save dialog filters and selected base in a cookie. So we may be able to restore the filter an base settings on reload. */ $cookie = array(); if(isset($_COOKIE['GOsa_Filter_Settings'])){ $cookie = unserialize(base64_decode($_COOKIE['GOsa_Filter_Settings'])); }elseif(isset($HTTP_COOKIE_VARS['GOsa_Filter_Settings'])){ $cookie = unserialize(base64_decode($HTTP_COOKIE_VARS['GOsa_Filter_Settings'])); } /* Save filters? */ if($config->get_cfg_value("core","storeFilterSettings") == "true"){ $cookie_vars = array("MultiDialogFilters","CurrentMainBase"); foreach($cookie_vars as $var){ if(session::global_is_set($var)){ $cookie[$ui->dn][$var] = session::global_get($var); } } if(isset($_GET['plug'])){ $cookie[$ui->dn]['plug'] = $_GET['plug']; } @setcookie("GOsa_Filter_Settings",base64_encode(serialize($cookie)),time() + (60*60*24)); } /* Show page... */ echo $display; /* Save plist and config */ session::global_set('plist',$plist); session::global_set('config',$config); session::set('errorsAlreadyPosted',array()); // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/html/plugins/0000755000175000017500000000000011752422547015035 5ustar cajuscajusgosa-core-2.7.4/html/plugins/generic/0000755000175000017500000000000011752422547016451 5ustar cajuscajusgosa-core-2.7.4/html/plugins/generic/images/0000755000175000017500000000000011752422547017716 5ustar cajuscajusgosa-core-2.7.4/html/plugins/generic/images/plugin.png0000644000175000017500000000663211010656213021713 0ustar cajuscajus‰PNG  IHDR00Wù‡gAMAÖØÔOX2tEXtSoftwareAdobe ImageReadyqÉe< ,IDATxÚíZYlWþf¿ûµ¯¯÷Äi¼$%iÒ4-Ð"„ Pª h+â—¾ð„<Þ*$¤VB-!JÄ.!*±¨)[ %¤&´YÝ$Ž/±¯¯ï>wîÌðå¿3w<4 ^@ʉŽÏÌñ93ÿòýßÿŸqß÷ñÿÜTö» ÜUà®w¸«ÀÜv“}/ûþ|.—àŒ?Zðßg >Î%x]l~¡”%®¯T*Õ€7Ø/겇úÔ‰“'ŸÉå Ißwe¡"R ጲe gÃßGoŽ >ÂóÇõ#1|–¡@U•ÐP½w¶;×wg-]•¹–ãñZ¦iX\\l>ýôÓÏÍÎÎ~Uà>ùÔSìݳ'‰ÿÁÖbï¸À 8àµ졬Ÿ8zì*àê`k¶ìŽŒ¶-aáy~hÅmÜÚ¿‡ ƒ¦ŠåF×õØîíΦ¡‚† öùÝ=ˆî›mBûÈ¥tüírYæïOã·o–0=’ƽ;2hµZ"³(๮ ¶„©ãòr ³×ªÈXÚ"@Ù6*ªÍØÇÌXZ P¯×E Çi£í8(oÖaú°QÚ€â{Èæó°L³g]éìoܨ‚ŠÉ|ÝvqúÒ&v“Ø1`û»2ë¡uñã¸hÒ!šTUnãU•ÑãË] ¹µl´]ZÙ›àºZ«âê[oáÀÁƒ¼n Óq êV—o±›"\:“éY]ÆàGÂÔ`h*ßá d®ßja gÒ#jM™¤Ao+[iT ýÇ Q ‹£® eéГYÔ} +UŽ >„óZo]ÒÔzõØm*´¶^b@‚ SØlétµê&tb>ßG‘ð~dÄß*Ke‡'³b°‡¦òXÛ´ñÙo¼‰…R HAˆÄ؆›¤+캦£­¤Pž?ÿÜ dn¼„åËgpqaSA£Wd¸»‹ñ¦ãÃS4ì?ø¡S!œjX]YÆ ­?±s'Tîk6›¯ÀÒŒ™„Ú†® |þt©„G÷fD¹^í!"€P çÏ/b¨?…}‡ß…ŽºŽŸ]>‹9í0öŒåÑ!î 1Û& …Á<˰ìgt`Y&ú32™4&#²Þãåö*à‡&óøã… |óWóé30”Óq’‚?<•Ň „Y$R '¾*tÍ@½V†uów˜¹ÊN7«î!§M+Wðúâ&Gûé%Ÿžpׇ«ŠJ wäN×M(š)qåy3 !“×Ý{€cد6Ú¸¸XÅFãRMâ¡ÑKÅÄ@"7:âPBšNJóØ]Ìà¡<†vË åZHePó+Øœ_bàÞG& !r”"Âq”ÑôŠp§ ²<" Q |Ù(žZ-7ñ®™¦†“øö©%‘ë3ïÅbÉF¹ÞÆ¢÷@ „&èº6iø„_kBK¤ÑWÌ {÷Îàååª0VŽ÷š&{C«pò6ÂX®+,Dx’‘:\Ï¡UUUG2©À¥¡®,7ðØýñè••Z>®@îh@ÃZ” I©.f&wÒª;„†WÊu´´ ÍoÑÒiˆ™á @(ÀÓt™ k ²‹•n ­X,A5,ød¢‘‚Ž…›71?ß@6›cÏz›d:ù,(;œ6™ >¡‘™$ù…1qg”¬…Úì%ŒŸx»óªåÖ¹YQ7$ 5b×¥ˉ$-ׯ^âw—{ _ŸÕp}߆óI¤’:¡ó Ðt:%¹`£Þ!Ì\Aù@¨#Ÿ2 ¸  Ü á”H$$GTÈLïyäݨ±Š½~,¦ëB·‡?È5á¹kšœ1þ| ù•ldö¢>w>©L#S¨†ÑëŠÉNÜÖË÷`×;`jþn,­ãá;…ó‡GFà]Öª’¬åo-ÏK16>jµ0V*¥eìÜ9Œ­¿¾±Ù«tƒ^KøØßl’VVVE×s·g!™p€Ìü%IÅj?뜩4g_‡’΀n€ñÙÕ./‹EÍÂn¬ÁQÉš<á‘}†Yyî@½åB/·ÃàN˜¦ÅƒÍ $¦¾Û¢–¹B#£c€!»Á^Ô4±<•Ü%ùÄ Pî €TŽ£ŒÄâW¾ TÂCj™z²k±³˜Q¡7*t‰dŠÅ_SHÁqlØm‹m9¤ó±Âû¾ç ½r'|! MìWËÌø*Ò¦*‡}êÇíÈ* ήIlµÚ:Ñ‚¸r†“Ç>oË—ý¶"Á}L QÚ–Ñn¯±í€|p½êð…®°š¬¥¼è ”Î6ç8#µW•Þª4o¯&¯q€x…BËy9?ÊúvÈC%ÀÚmð"°r4•±rþNF7œ ε6­ºÙèȵ­ 3*­é‹€ù¤BÁæ ”&–—ý½µ@$ $¡mĬáÃ¥b%%´eèŠØÝF-,¡AYƒ^ j g«»>» ¤,ýi KF\é´0×H]«;zòø®'¬ bŽ)ÀXªBibýhô£ûÐêÑ(Óq±‹å³&…#“¬ÕœðŒ ØîKi´¼Ì0È=n’ [A©,—B*æ}=W¤AF!Ìu%R€üË´ /½ô &ž 7Ä- ÄÊÙ횬ŠÎ׫v¿[º" ˆgL Áa½Þvƒò<Œ»È86 ¼©Á@3ÌHÛ¶IqE|ðȇ$â{Ö˜©¿¿_xz»¶ÁÂmmm®…q3… ½"˜nÙH#CEÜ©­7€ s7˜ÐJ¤\=Œ7Q:kù‘\( Bʆ& L+É¢«+«•o}óÅ_ÕêuJ Që¤RIóèÑO¾wrrwŽÙ46F[¡ <>–Íò™+µgŸ}öT½ÞpèQäÁµ’i÷È?’™¸'·Y®NÝgj.0SåcOx[‹9Á-cGP‘σ(÷Ä?~æÌ_ÿ€mÚ‹/¼ð¹sãk4øÉïm Å`Òõß÷øcGžyóü…ï`›öÓ|ïÈO~óÚ/76jðäÄÊâåfTÊÆÆA’ ïu7Ðrzzú-­P(àŸ[2•X‘=žÛïuç8FxWÞá± í›C¬ÅŸ=>:v•ë‚õ>:u-:81Ck=ðH'#q¾%`zÉB=qâä_=ö}žW_ûÒ—¾x¢T*5‹rüøñ'§¦§ýèG?öiÓ4äÄ•Éd#E'¨-Lâ‚vįsêÇ$ï^8þôñã_þ!Ž>c Ï?ÿü'x†~ç£xâ“ü 'V ¹¶ÕMw5à)®wšàâó'ù÷b²ÓqclÃ-œD¡/Ï‚jå ~»œL&}çÏ_<·k×ÄŽÍJMζšâɇ-b2)·i¬† ¸zíÚÂþ}ûÐ8eEŸŸuttôÁ‹W—ä‹žÕ bé4³|7jÛ­æ±cGŸ;{öìWã¡Éçѧ8ÃQæZµZ}ÀZ0—e —ÍN²Æ‘/žÙîô9>>IC°Ò¬ž8Ë^ æ‹ù|îý–¡gøLoëè)¿ÖK¥Þ_hîþWƒ» ÜUàÿ¼ýÕû¡V>:AIEND®B`‚gosa-core-2.7.4/html/plugins/generic/images/head.png0000644000175000017500000000136111001315337021307 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7Šé¨IDATxœ}’ÝKSqÆŸßù×¹M7]›šn6'bhŽÈPª #£º Ò@z£«¨‹®ºŠ ª‹0‚¼1 ‚¢"*owÑ‹`“Ä–šæÜ\¾íUwÎί+E§ö½{àù<|ù>_`犮¾‹7ûÆ&Ÿ£ÉþáhòêÃá1[}G×.Þã>yýÖ‹‘,›^6X8®±p\cS+Œõ.3KÃÙîB?ݦÄjÿ¹kwŸô”HSñ,æ:"«:þ,å ©Xâ«›ô?ôäÂm奚¦V±ØeeIˆe DÓæ’yŒGÒ0»¼n¹²¡u+³=@A¢HäuB qtÊa  A‘ð’\´•á·ŠÄܧ% §½„3‰‘‚1†ôšÅD±¸°¨§¢á‰=7ÀßÐà×·}¯^§‚ªRUeÃI™¡Ct‘-{°¾bžâä7ì ì«aôÕ—d…7îØd­¦ÇGeüÅcy=Ð/Ÿ&Æ$²œP($sssþ¾,@@¿ø¼Ždr…—W’ž|Kl;Nó™ñx!¶0Ÿ±Î8²ƒ¶mc¥ÓD£q +øŠ@×!è°‰Å$“I,Ë"‹e-1EM+F½›tXJA“GÚ²t]GDÒ³Qþeþ9AWW—$ÛÑ^\&ä/*#­a&Ä~?4šAWæ~5ÃÎ/èÄ4«5IEND®B`‚gosa-core-2.7.4/html/plugins/propertyEditor/0000755000175000017500000000000011752422547020070 5ustar cajuscajusgosa-core-2.7.4/html/plugins/propertyEditor/images/0000755000175000017500000000000011752422547021335 5ustar cajuscajusgosa-core-2.7.4/html/plugins/propertyEditor/images/plugin.png0000644000175000017500000001014711370005614023330 0ustar cajuscajus‰PNG  IHDR00Wù‡sRGB®Îé pHYsÃÃpMBtIMEÙ 3ØÔÁbKGDÿÿÿ ½§“çIDATxÚíYTUWºFÇÍLŒšÄ™(šXN¢£NÆgbwˆŽQÔØ;R, "‚ÒP, bÁŠE¤#Š"`¥ÜK,`Åc»ßûþ½r|aL|Ç·œYköZÿ:÷îsÏ>ß÷·ýÿûýgüg¼Á1lØ0#___£Å‹·Ñét!çÏŸß“›››DI9{öl¯y¿¥Æ¿, ‹ZAAA[ îÞ½‹{÷Ïßÿ=âããÏÌž=ûwoTËÕ?WóçϯãïïÿìÙ3<|ø?üðÃsyúô)ÂÂÂÊfΜÙðhܸ±Q=jñŵ以¥¥šß½{·º:::þvÕªUàxôèQ5«DEE]·¶¶6þéš+V¬PWÎ×466~{ë֭껯ßÂ× ~ß¾}5FŽùçììlÝ‘#G¢GŒñáOï?¾Vÿþý;òwWžˆKˆ6ÏÓL üÝY³fMJII9uéÒ%ÃãÇqÿþýäÁƒ*nݺþVçåå5oàÀ Ÿ†¹®Ü7ܺu~‹| Åbü~¥¥%¸s§NR&#l÷ö'Æ i÷«Àoܸ±Æ”)SÌ‹ŠŠž1  ªªJ9~üxerrr )€¼;wî¼L´à6`f§ëG-àg¹g¸}û6|}}@%ðû]7wªî ¢òª!/?!ëWÃ̬߃:ujï'´ö”—g´àà`#ºÍ—gΜ¹ÇÅ 7nÜÀÍ›7•ù]$„äû Ây‘Ÿ½ÿ£" ò¼ZšÞ»o/bb¢Q~©\~#D¨˜ûضm+ê¼]ç{BÚC1—p¤üååcܸq‡çÈ *++•\¿~BD#£ú©hà5­ó³vO~/Ïj"ë)¹víÜ=ÜpîüY”——©{šÛ­xH8_S$ÿú}ÄÉÉ©‹‹KBii)`¸|ù2***~–E¬¡î¥§§#55IIIHJNDJZ"ÒÒ“PR^$ä4ÀJ!š”–”bÄÈáü}‚P÷ïÜ»£â' `ù ÂiDùdž­­m ¦·¿,Y²D/À¤"ÕHhš•ùÄÄDüâÅ‹Q޲²2ùÒ‹e”RœÈ8†Ø”¸ ;ÍçopJ\½zU­Çì†é3¦ÂÓk>®V\•yQ ߢ"Ÿ(·y•áææöºÒ7k×®½NJÀÉ „€rÓ§Oãĉê^II Š‹‹•0ð•>ÿ\\T‚¬³HH‹bpVÒªW”u™‰°débLŸnƒ¬ìL!!VPŠªºS…¹óœÕ†a?Ë®¾ñFÿ~±¿_¿—’`jZBÍŠFE¬2}FFòóó°€ùEÐëõÐé(|&6%W ¾¬¬\Üû£"àíã-™ˆàŵ*”u._¹lHLJ€¯ŸwêW=º7L޳L"÷G„'%'á󎟇pê­ŸÏÚ¥ÆôéÓ­XŒi€ Pš¿páB5à¥Å¥¸XJ*» ½®ùyy()Òå$QDð:(ÉËG^~ROÆ¡° þK#!16®Ç˜±£™‰.‘°$QƘ¸t¹Ë—/5øúy=[´Ø/%#ã¤XÊ Â\J©ý³ÞY¿~}&‹ö4w2ÊmrrrdþG ”R."lß*lÚ늇\ã‚-‘ó°v›+²²2P¨'‰|D!¹9¹È:} qÉ1Y·ÇÒâH\ l¦ME§/¿D3SHPóªÇ¡C¸È> ^‡ß|L˜ýUvš7oÞsàmÛ¶5êÛ·oÁƒwfù„n"š°Š@ff&¸3‹ 犑G`Ë×ÙàXÎ\(Û’‡QV]E$Ε†aS„"m£Æ‹øLž<«¬¸zm0RR“º%]{ôÄŽ;àåã‹–Ÿ´ƒ«»®\¥5 ôœeK´2ˆ›àÑ#±¢ý-Àµš¦9}};5MÀ©Ü-Ë ZÌ£;ˆP¾Ï{BBÝ+ÐböžH<¿'‹p¡rŠîî@é½pèn…âô¥UH/„ûš.¬kO²Ü e7ÇÒeKQXTÀùd|lÒV©¸[ÏÞhÛ¾‰ž§ât|×YÖCàççkÈÎÎBݺu¯²¥¦ïááQsåÊ•þ&îa`ñE³g PMÓB@ˆˆæ4üž»×ÁmˈËuBJ‘3N\ö@æ5odÝðAF…'ÒÊ\‘¤wÂöŒ^pôíI÷Ñ++†nÞŒS™L½¥(§ŸÛÚÙ£Y«ÖÛµ žÞ aB+®¤ëêqîÂ9è òÑ«WOÔ«_ï&!OS››6æÎ[‹Ó Ë $?+M;wNÓ¶ˆ“yEBŸ_ˆY^½˜Úág† Z? ±%S_førkÄ]´Bl¡çMFðñæ°[YOí;wîä:™\û,*™unܼ¡Õ´…  ŒqÆcÚ´i,¿GiY)û‰˜å`ÿ¤MkS8 ¥^µ€å®[ÛÛÛûµ/&T$HF«ù¼XAÍkVÈ£6-Ü?BÐQc,KkЧ»b_Þ ìÓA$%B?[Ï÷FÀ‰Và}÷°ºððtâóÙ¬<ýðégŸ¢IÓ&B„$®#õh*2³N=:ué„Aƒ¾E‡À¸¬’¶ƒÒ…R‡R}Ì™3çmOOÏCâ—iii ÍV,¡ùäÉ“ÿKì\.Æ;7ÄŠÔ¦ðOiŸ´æXp¬7…WzxkOŠßÑæðOn‡•Íq2=Ö6Öèúß]%“ˆ[°hÛÆr¤ {Â÷`Ô¨QèÖ­¦NÊô¹¬É Ŭ ~yGž1cÆ[´ÂN–¸Rh$l5 b5¯Íåå`”m ,Oj ¿ÄfðLn÷”V˜—ÒÎÉ­1/ÙT}÷LúÎëÛ!5)ýÌþŠöÚ£{îè? ?&O±À3<…³³Ø{Hû –ê*È5….]ºôñ½÷‹ؘüÆÕÕ5˜ ‡*Äx}ÝF6¬js99y˜î8n;>€_B3Ìk ç8S8i û#mÔun\s8¬éŒøØTÿZ´l!ÄŠ žuÈIY[+ ‡ánÆÒæ_$À.©Æ„ Ì׬Y£§TlذáûÝG\H´ ‹Šï‹Ö%i$Hê ¶ïØ†AVõáÝ b[`ÎáV˜q° l¢Úbú¡–˜Ø ÷Ç Í'ŸàÃFâãf£Ýۡß: ûL¶¤FŠŸZ1(ï“®ï)1Ü ¹ÆZ¬”=‡‰æå}€2›ó´Fž t577ŸsèСgÇŽÀ ±‚ÒŠ''©5ûÙVjû.æï5†GL ØG™Â2²%¦ú÷Æ®{Eë ¼qc46n cnØî0¬ ^ WW®„ïR–u˘¯íìì:“©hŸG7ډȋ£{÷î/Ì‘DSž4è%.(¢y‰VisBJšn88NÃ߯´Äعõ`³¼.ì<ûaúÍhaÒRndÜH]ë×oÀ,ãƒ-[CÁzK\U”#WYÓÀ¸Ç*øÏ|ÏßÝýCÃÝÝý-‚­Ts¥BÖ)é'ŽË é§©Ê_÷ìÙ¿Å a;Óã'Žæ¶ŒvíÚ¡m»¶0mmª\çýÞ‡…¥vï ƒí [ñqYOYS{Ç‚ Óê¿–ƒ,øœ>xUÖDÅűãÈÊKCt|$b¢cXl\ÃúÝ ‹—ø¡K§ÎèÚµ+:w鬂֤•‰J›‘ûÃÁs%¤Ok*7ÔööønsÆã?w É8Ð3èèó’dUÂ"qqñˆ:¾ÑGà |8›gF~Äðj$èƒoñ°Ö‡5¿€5H€iA¬íÐZ”•Ͷ‡‹«F +k+L¶˜¬4=Œ€¿ùÛ¬]· #F ¥Qu×+HzÖR¨Ú壣£ÑÍê¾²˜ÂÒ§ ¸ \ àj…žhlŽÓl8Ï›C¿¶‚ãG8ÌrŸ‡wØá#F°Ž÷Çø ce3ÐÕ€³Æ ÈZ²®Ì^²¤øô• °6ª=|øpGúþc)¯ ¾ZmDa#’†dÐç¥našë)ZÂìæÀ~ }=a3Õ´¨€àZD¬'",ëÉÚòÌù!ܸ¼øŽ;j%ö{ÌÇÔº¶°Ö#Уž9ƒ5$@wQ }||°hÑ"°·}n.ʵX„ÉóxƒDFFþÀCÝt%!` x±®Aˆ±.‹âþÐLbqÒ¤I¯ÄAÔ,ј¹†f}JðÊì›7o¾Ïã§;Ãv†Ó¯¹[2€Àîð˜ïç¹Î˜ëæÌŒ4W‚Y\PZR X)ÔªX°EÓ=ÆŽ3fO¤uB‚kHD,y˜ð´¤Ñkät¢!Å8p ŠUáµQûŸnß±Õ`ffæk0ÕÂn¦f;(ÿwdLxû, $)W|^2Øã>}úñ·½hÙ†t±ܰjÑ:Ýi±“ÌliíÍo²lÙ²×÷W”öG땺ƒ ²[½&ع×0yò$|7ü;ÐÌ Ðñ˜b9–V–°³·…ÿr?ü•U&ÝL´®dïÞ½W Öäï×wvv®IÐmhñ$ö{4zí#åhœÑÀAÚø.ò~¶aCÝeνÐÐMn² ôòö‚ùsЕؤX!`ÅR˜¼´Œxq‘]»v²¶jô’£|£ÿÏQƒ.¡Ÿïåö”ŸC)Ã)Ó,,&çÉnÊ¿ž`=Õ[·oâæ50hZÆÿô(ƒã#žé¨c‘u!w¤3eÑŠ¾Ü’Aú)ëøöÌbò½ ëùß2ó¨˜z£ålGûŠÕ!+Y*ŒzÞ8Dîß·‘' ,©SJÆ¥Ôû?ŽìÞÔx§Á{ –. ôçÆŒàÕA)‘áe9¹ó@Z ýû_{´áqÞÎÉïûùû‰§L¥Åœwøw¯2‘øÿÌÀÆúŸáÅ«Ï@ù@³ÿãþ?Ãëw?89X$E9dxTÔ%œ¾ÿ” ¦@üûù›áÇÇ/·¾û·çÓV†GO>3 r2<}ú‰äÀ_@W¼}ÿAAŠ}ùÃ).ÂéÇõó+  3#ƒ'Çï$„¹„†>†Ïýo8…ù®Ýý, @Ì,j à$ ò®¾üòOGN„Mƒñû^>v``22|ùö‹‹“á骂 §/¿dxñå×ÿœ Wo¿g FÿCˆ„ tï÷ßTt´…÷Ä›²Éó±üf—ax ço¾1¼ýÅÊpçÅo†[~ܺvêî¶ÿï?- F&ëMÈùáß/`Êùó?ÄËC~E˜'3ãï ï~±3ì9ó‘áâ™ç—Ÿ¼úº˜ª6ýw”Lˆ‘Á`%Jg’¿XØ™ûT4EsE…¸®ž¼æÝ“÷m Ÿ¾ždâ}ÅL; À¨åK€KïŒ|U‚òjIEND®B`‚gosa-core-2.7.4/html/plugins/propertyEditor/images/ldap.png0000644000175000017500000000147311370027602022755 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<ÍIDATxÚbdÈüÉÀðóÑÜ@<…á÷(†Ÿßã€ì• ¿€â¿@òß¡ê@ô78 €˜@ˆ—202úé} ÿ302d3Ä¡þ‹300®g`d2àÁðŸá8Ãÿý ÿþO² Zp@L ÿÿ«5ïj–g`b²aøûûPs#³Ð€j†ôi6l ÐF f†ß@ v@…w~ÿ‰_ºÊh0/Øöÿÿ+r"@vG6 €€aðÿ–Ò@ƒ88A^:Ïðï_P£ Ðo %u@¶е@I!dhc$P¢ƒáßß9@Eu@Å Ì  a<4Ȉٜx 80þ]Űˆåa( ¼€6³q5Ãÿ¿@üèo&FfVü ¨ÿß *:È–`øÏ¸(§ R@LИ(JÊá èš, ¢Å@1Nff 0ãS¨óOÅ@.œ 4ì¿È7 €œ ¢x Û(™ÃðÿO Ð5ë| ¡@C˜>å#€x%P¾èÚ5@ú!¯ XBÎ?o &O  !@ é@I]`@î*–b`+ûÊðïO:Ãß›˜XYZrrJÜt‰ PP ÈÎZ[dó˜*™4ÀI÷û×? ÿ| JÀ<À𠀘ÐÒÅi &g Íœ@EM@—Ñÿ/@×mº¬( Äü x††#@±`I\7ò.@C6Ù˜XŠ~| ÃÀÎù‘áÏ ¡{€ü¿ ƒˆG ´òÿæ]2è÷R†_?gùl`Ûÿýý d›Ù¬Ä‚'£ãž! èçI ¬ìøï0üøÎÎÊ¿ÿþ8Ðÿ $ÓÎ¥D§§IEND®B`‚gosa-core-2.7.4/html/plugins/references/0000755000175000017500000000000011752422547017156 5ustar cajuscajusgosa-core-2.7.4/html/plugins/acl/0000755000175000017500000000000011752422547015574 5ustar cajuscajusgosa-core-2.7.4/html/plugins/acl/images/0000755000175000017500000000000011752422547017041 5ustar cajuscajusgosa-core-2.7.4/html/plugins/acl/images/plugin.png0000644000175000017500000000345311362006411021033 0ustar cajuscajus‰PNG  IHDR00Wù‡sBIT|dˆ pHYs11·í(RtEXtSoftwarewww.inkscape.org›î<¨IDATxÚÕYKlUEþgÎ}õýÀ‚± Ý4FÑ BLH1´hR¸1®Lì’…©‹nŒ²`©!î\ÛøX¹¡m`aB´àA Ѷ”6\û¦½÷žsÆïûs™sãÅ@Óž[™äãŸ33gÎÿý¯™rsNžæ–‘Ú7rׯ_±T*½º¹¹É¡+³³³×FGG˲ÃmÇ<0>>¾¿R©|¥_Éf³/777ç;::ÄZ++++²¼¼\ºÿþ5Ìÿ´gÏž³CCCýoLLL|†áhkkkOww·är9á¾KKK*÷îÝ+PZÇäÒ¥KE=uêÔç»J`rr²Š‰î]]]È­[·dqqQokkc = cPZ<(ÇŽ“©©))‹ãíííï=zt¶áÆÆÆr°öèöÁòr÷î]†‰tvvJEDZ€œÊ $“É( 2==-ÃÃÃ:óæÍ™ÞÞÞ8Pn$†Í7x÷­|>/·oßÄ<­N‹ÿ ¥?¦@dêÁƒ$p¨\.‚F^t“àÕ«WeppPð>=÷íáÇßn .Gr~‹fiQH*A_mll¼úôéEyD;þ|¬þ<6T(äòåË222B/„ >ß§NàâÅ‹(9Ëí£ÒóóójyäÀÈÀÀÀ§òíܹsõôô|¼¾¾®‰Ýßß/sssókkk}GŽ e Ín‘0ãü$>ºÉ933£ñ2¿Bù³ò„íÌ™3Ÿ ±ijjÒÜAi¥÷aê$ i`âõ³šÐêTžUKKË›˜ÚŠ+”<ǃŠùÓŸ6ZŠÉ(HJ’áGWOœ8qG¶Öè…;x{Ý»wOè äÕ¡´ °,ö¬í$ÁþÝOn}¯kô"7–b´Þ´ ÐJ ŸÕÕUàa5é'·¾× A¤Ú:Ó&À ða†­Ï¡•mXæ,¨@ Ò#Pÿq=„Øvb_ÎEÉÇÄÛ.mï‘ÙBÛm<‘}k°üÇSÚ#}Œßm6îñÔ`0 ÓÿƒæÇ¯ßq/½æ¤8Ý-‹ÅfÜ]"ž•%öë αܼ.@á¼äò9U<‹>% AšrÒÝ×%Ùgœ\™øYŽ¿7fv,‰m&”g÷ÿ&ÝÊÆR(ëëM¸eecÃV66EJ‘M뤤ˆ% €”4’'ò„•—/ [œ4€ö²tôd¥é¹×Å´=/ŹbzUÈeŠ’3ëRÎIJ‰ÖL ­eDCXà°X†ÞÌìCâ•X—k‰VlÅsKŸ.Ä› ­tP©("q„39Æ2‰‚J`Ü¢¯t„αD’Á#±å×ÖÆ€ÃÞáF®é°–Ös0%>Š„´–èL•> 8k4t8ƒDˆá€ÖÕW#Ç2@B h¨¼ÙÖ¦äߜĀ‹aµÀÑ`e¤WÃÇ.CˆÄTZŒìc\/:ÂqM2 h˜Ô<àèêÈ xD@ˆ¹X’&c_ŸÄ¨S¬_k¢ˆQ@¶F!ÃÄDLh@<²Æ5t×ðñI\Íí[c(˜Þ!OÍ) &]øÐ–ØQQB•¨ÂèXTUÀéº,=¢J‡!ÃÉá<ˆ¡°Ógt}uчt=`L-Œ¢6?ødù¯JZ?äpÕÞ+UŒFB¶1·Qc4y!¤©‹qmì1×êœ&œ ¼€¹y¯Ùô¯Ó¬ÑUèy`|Q¹„„æŠ÷TÆ[Ù+ÕxBGðžn&Xs€ ‡ Ä€Ñ@ª;Áù.Ç•„ÊHȉ!LcB(I\«2ñQ*Ưçi› œ_†Vr.ÙG Ñi k"®¹JÔ ¡Ä ÉZ-£”€ø¼¨®ÚµŸ˜¿€Ô‚%“ãþ¤$ˆ”Hÿ 9QØÆˆcZ+z¥Ù¢ˆ·!«§­ˆÁ³UëK(cu£½^5¢ ÑÊ ­>øl ‘ .Ѓâ<}5yk®šÐ<8¯0œHŸSÁªá㟠¸8¢òèø<ÔkƒõWŠ&1C ð!‡~ ¸Ýü™Õ×%a«Ê °/É‘$}Bd·8GÄ*«Ö¢vmYÀí.)Uj=‰ÚÒ[‡Tÿ[%ýöHá—z_Î2@ðX//‰ú檈½L=”AHk Pé ªt–r‡a«Š…;ˆ Pfÿ¿<`ë‘Xý1°‰â ©³´‡ë=PïÂýKáØnÆÝ]Ö IEND®B`‚gosa-core-2.7.4/html/plugins/acl/images/acl.png0000644000175000017500000000135611001115416020270 0ustar cajuscajus‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ÒÝ~ütIMEÓ $84Fe{IDATxÚ}’MHTQÇÎ÷èè8ø1©ÉI‚R*CPµw)DëZ¸j„p¶™n‚ (ÂE«\XÐÊÖ"4ð;”!Mg†qÞ8Ï÷î¼ïÓŒS’guî=ÿÿï\ιuüÓÓo#mmᇭ­Íššê¯ȲšÊf¥™\®øzròT«wצ¦^µ„áD<Þÿlh¨7‹µÓÕÕBww{s à»NçÝñøýÕÅÅyqH̸êëc##7¦z{»vw÷ååµÂÖVJUUÅÝÓsÙïóy®§RéÃãkKKO ëFC4Å¢áÍÍ=maáËUÕžÊÊJÝSI*<è G£ÍãùüÉ@pUBh¿ßwÅïw³¾¾—Éd¤—ÉäÄÏdrâXˆRr{ûà@×>ŸçŠZµq (*†¡#„ “ÉŸ˜¦¹Z©ÍÎ&²²¬hšVB×uE­Î­Jºyi3„èô i¯™õLÎuNöW…s¿$¯ušÆUÊxïv¼  `5Ù7ê Ö'¬ÈÕ‘Pc(p"D$ ¯×nèX„ú›šÃAõT)y {ˆP_ <ÙøìÈJÜ‹ÝmêÈÇ€„àP- †äÁqÅŽ;_ßï~Ê€£œ¥î@1Ç…á’ÀÚ8Ê…Îfp˜s0 *ø´ ÌKpp‚!9æœ3@¾è`5ðŠ¿ •®– ŠÇ*VÉE¾Xp@5À¯«lL»l4mÐ-(`Ø`X »«üê1ì2Iÿ#2l0­²Ù´Ï̦:çÿp‚g¢* V¹7m„pŸì̒寿Û)¿ÄÿåŠî’€ßݹ[è¯ÿ”IEND®B`‚gosa-core-2.7.4/html/plugins/acl/images/role.png0000644000175000017500000000154411001115416020471 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéIDATxœ…“_h[uÅ?÷_þ4ÉMSÓ´5Ýfi»v´q¸neê:-¨µsÙVн¨ æ‹AÅ_öªhŸ”¹‚Œ‰Œ¹uâh·Zuk“.íÚ%MzóÇ&7ɽ÷çC· "ì<|ßÎá|9çH<ácá#G޾ÙÓë6òFá»±3ßN}}ý`íA\<}òËýò¡˜ÈLŠ+éIq%sUŒ§ÇEÿhßY@åþùïÉ<óp€åi›ÙÓ•à~jIZä››Ÿd#hŠÏ€÷ g8Æ-¾Ø¨ë>¸ëè‰ïÄZöá<ï\š¸v¶îÞ ©Ïiòê¸Tã@Á„¤ÇÓÊ.sSÀ¿mÇñѾýÐcQɱ@’Ø{éÙ†KÛ8_~_K ¿ªÔJðPM&³Lbó…èþWÞˆ´÷F'ç  k»‰'éiú˜FÝE¹"_µY+_®þå|µ)nnÝš5-,ÇÁã’A€YsÈZ‚ì!d @ ¯å!mX¤ç~ø È(ÞHçž}CÃ{u¨×5ü>M•±k*¶zƒ@}‘âß!L3Lз…Zg¾?9µò‡“áw 7?5ÓØ±ó¹§žè‰tDT"ºŠŠÆõôynºFY“§Y±gY©Í,ÍPt’–ºs?‰/ï¥PÎÞJ¬eŒ”‰¿ QΩ$SKÔÚâ¯@•ÀqÀ¬‚eBýN9èbPØú»Ÿ?ur¤Åï)ZÊ6nÍA—ûXÍÚ4·ÿL8~( Þ ;¡,«Ôoôé‘×^µ…EŸÏÕ&MUEêcµRÑt*l¹,O«uÀ²,3 ‹ÅÂÄ(u=Kª9H—e Bk¿> Ï¡”ÒˆYèúª šQ@5ì ( (Ð"bF€†€RþvÊ@ë8ÏÀ%ÄT­ 8V}€Àd1P[±@mAÇ!¦e¥aBÀÓd,ð¡Ñ°IÈQìae‡ÝE}Àw’ðçpÑëA·Û…¯õZX HÞia¾ ‡Ã»ê½ö] §hW®ëî3ÆÚÚFgÖ}U³Åq|Á¥öÓ4≠h‹’ÂÉA'ÇGŸ¸Ðw}>›Ínúýþퟯ0cJ©‡Ûw¥”ç¾ï··+u:×årù¬}<«â?$´)mƒêç÷}y/üO¨ïÐÞÝ{÷Óì7ßMN:öøZ¯*þ%u©®ÛÚ„¿¯µ)p|ß5Âß›¯K™z"¥”ÒN>ζíò°â95·-`Xíè<ø¾7TS_Ò$Ñ…5Ú+g«WÃä4Œ<‚ñ rïõ’Õx9ÿÁßU¡ÜÈYî ' kž [Ó–£ýz ±ým€û÷}ˆ¿½•Pj"Ú~¦hÚ'@ç_U•þ/Pæ}Â÷)KàìÚ²~=¨*³/·a}…Åׯ4®Zm¼›H€ãìö‹ÑÆÈ«›WS)›EuA–TÅ0§ê‘ýQ®^¥dÛïÜeú-x[ÛÙzãKm›s >„VQ;z{Ñþô—Š©Á=2‚8÷NòÔžôX |>r‰;½'i(9ÔaÑ.% ì”LˆMMÕââ%Ü©gŽ`uu!޾†;‘@íëƒLws 'N“;~”üÏqr@ƒ„x."Ë—…K'ŽsD>'þ#ž={) 3=ka;6>$ók›É¼¡¢¶ˆ}2C²˜R¾"xù­%©¬„t–ÌL–±tGš¬V 5º˜¿*€ïž…¹¡œúeYH37iûXn'™9û ùÂ#ãúO†1ܲnvmwµÝUã÷QµÆO°yjeG”2°Šà ¢¯,J«Ìz.â8âpṞ¥œ_Óã@à›Áš®¢XOÛ¦f¢xKºûYÞJ‹¹×ôhxQ¸\Pf€a06jæ?ÿâ÷ÁþoGû¿Íþâr¡ÄZÔ®BŽ´2w hP×ý’º9öÖ;º!“­±C™Á”É çÄÿÑÿÏü §Ë2d\à IEND®B`‚gosa-core-2.7.4/html/plugins/departments/images/plugin.png0000644000175000017500000000215411362006411022617 0ustar cajuscajus‰PNG  IHDR00Wù‡sRGB®ÎébKGDÿÿÿ ½§“ pHYs a aüÌJ%tIMEÙ9/.ËpìIDATxÚí–O¨UÀgîÜûþj/Ñô½Ò ±rÒ_\ ¹qñ0Eá"ÝA‹jÕ®E»pº¨V>´À( "ZÔBMÊ÷Ôç{÷Þ™9sþ}Í›ûçå¾.ä,îïÞï~çÂÌðýÎ9óÍ0`À€wÅ*œûóƒ½íìÆÉ㿾[ç)‰n?Á{xvûAóàú'÷íÞúÚW•8õÛ·cËæhlø^”GBˆ'”ã"ÑJçŦ[ÔÎû§w˜U8vöÚ{/åÊâE¤,Z^|Gb9õºz÷ËW)©’€·0ŸÎ‘èVY(²T|¸U¸,ÿoÄ5pTO Ï ÖU’<í:³K tr=ŽÉM´k‹sd…€G@e.E¤È­ì:‹Ù,ÆÄ€«Þ ÌÎÿ¶–€Ã¸k5¹ÏÉLmS"µX’R½°6æü…óø ,)¨ò³ô]þ¡ FÊñÑ"]NŠ8Ä ¾øevo3ÉO;{)ÖÆÝÖ^|f³ytjbú…'6éo é@ž× Åí+©Eµ½ZÑGtÑjg3LNF¯¼4…¾:ãÈ™úäHrP} ´ 4«áÂ\ ZÙª ]¼óÙµ=ö“f良¾ó² µºzÿô™þ·ÐŽÓo³C—®^SQ¤èEÂC“ëeãø&ó1gïèA…œ…fN®MY¼].Þ{ÊízC[êØþ&Æ×>×jß3ó×ܺõnO̳níš}ô&YÞFBãœçfË`rÓ™õ åJ$y ™yŒÄLè¬O_ÿþ4Ðà?ø‘ïøÆŠ8È \Ö<üÇÕ6ÁtlÂJˆè qÀæº?þYý0yF²˜‚·¬$¬8EçiV!Opå ½¾8æN‰øŸyxÛ”nÜg$Œ€ŒvÅ mÔ²ë©GLeW`tÍðô®æ¥Sßüü{ÝZËJœvïÜfG×Mì¥"|HTb  R]èÊç£{¬MO ŒÓ¥HjÑý[žO¿®¤@ë¦>±ýÀ‘±xl= ]ï|‚K¯^øä­`¸’ºÆk#×péå²`‘P$¸"[âáºÒImUPt¡› .'˜ …CÄ–²(Ä_,$«sH÷ë´h|¾ˆÁ#åìaç ©ËPo¡ÛQeÑEóftØ-ü„M ,Ù¸…Îb©5 ySªÛ…tá.àu¯n.@'Èš‚ä ŸzIÀdQuLâíž­7.*è.T°j«äís¶²*¨ýÇßüvfíÔ†!ézˆ)Z³çl£!Ó 0`À€¨>ÿ¿YW‹Åu¾°IEND®B`‚gosa-core-2.7.4/html/plugins/departments/images/locality.png0000644000175000017500000000071111362006411023136 0ustar cajuscajus‰PNG  IHDR(-SsBITÛáOà pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<¢PLTEÿÿÿA‡ÛIŒÜBˆÛD‰Û†³çBˆÛA‡ÛA‡ÛB‡ÛD‰ÛFŠÜHŒÝJÝLŽÞOßQ‘ßS“àU”ài ço¤èu©ê‚±í‹¶íŽºð™¾ï™¿ïšÀï›ÂóœÁð Æó¦Éõ§Êö®Î÷¯Ëî¯Íó°Ìî¶ÕùÁØñÃÙòÄÙõÄÚòäîûõùþúüþûüþûýÿüýÿ}L tRNS "=@Ëúûûüþ ÿÇIDATÁÁJBaÀùŽç†¡”´Ô÷)W.3QÄìþÎÈjÂãÿ »…ùP+€Îsfà˜5 ³çÎx [?oéTQ_åû4SéT|,Cmï•NÊõr-I'MüúÔ$ Ñ¢I:›ÉÍ„tN é Æœ$ãìd“VµÂIEND®B`‚gosa-core-2.7.4/html/plugins/departments/images/department.png0000644000175000017500000000060211362006411023460 0ustar cajuscajus‰PNG  IHDR(-SsBITÛáOà pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<xPLTEÿÿÿfî¤ÐþÊúy°÷{¯óo¦íbœç”»ìV“áI‰ÚgŸí7zÍ>€Òh í2wÊ3wËfŸíp§ñuªóz®ô€³õºú„¶õ…¶õ…¿ú¼ö½÷•»è–Äø™Åø¤Åë¥Îù¯Óü¯Ôü²Îõ´Ðõ1¯›WtRNS<|†©²ËÖàèíïõõöùùù»R^IDATxÚ…ÈG@@À‘Y™•óJÿÿ!ª¦ÊA_òéJ)?•¯'&rGœg$‘'9„EIŠAU“*€hÒ xãBFî¼’Ù…Óô¤q`íÙmh†I ¿. 0Ó×ÈìIEND®B`‚gosa-core-2.7.4/html/plugins/departments/images/department_referal.png0000644000175000017500000000161011024414256025165 0ustar cajuscajus‰PNG  IHDRóÿasBIT|dˆtEXtSoftwarewww.inkscape.org›î<IDATxœ…’Oh#UÇ¿oÞ{yïM33iš’H´uÙ Dª‡]h‹.²J/"è¹{¼º½¬ ç=¯+‚Êêi= 6Ô®….¬´Å†mí6“¦é¤“m2“I2yÜ®ü^¿ü>ü¾¿ïà™*•ŠJ¥^Ïd2oض=G)†‘ã¸?Oâ8~|~~¾Y¯×X]]ݹ˜#•J…–J¥¯‹Åâ’mÛ"´Z- ‡C€”Œ1†¥úý¾ö}¿éyÞG+++wY>Ÿÿ|~~þ½µµ5ŒF£ 0¤”PJR !¤”BÀq"„˜fŒ­...~ÇlÛ¾aš&(¥ÿ†J)(¥`Œ!‘H@!¢(B*•RJ©ËL¡8çX^^F£Ñ@«ÕÂ`0@§ÓA`ŒA)¥â8F·ÛE6›E¯×ç<Á|ß÷LÓœ±m–eÁó<B0== Ó4ñ¨ý§{1fÓ/céòÂ0„Öq‡lbbÂÙÞÞ†išàœÃqBžGYo®ãæ[7áv\Üúö”EZkA ¥” Æ£…Bíva¢Z­‚R Çq`Yº½.¢Q„º_G?ŠL&1155e0Æ(ó}¿­µžUJAJ‰…… ‡ÃçkrÁP;«a³µ nþyLBŽŽŽ´ÖºÏÒétîàà®ë"™L"ŽcÜ>¼ÂdÁ(@ߊP k¸rž<Å;?½ ­50yɘ™aQõfgg1 ÎÎÎÏæñþ«àIðûçû¸çÞƒ+]@COÏ:)¶»»ûE¡Pø¬\.˲à8~ÇÃ;p#{Á"égÿA dDWŒ+¨zU—nmm­†5›ÍÒññ±¨×ë”…œð#†b§ˆq¨Ñ(6x¡VÐ×_X5{÷áÎWç?w¿ù«/ ‘Íf3ssså\.· ¥|‘sžûå•—ü7;%N8°¡ýíýNÄðwÀêÚ÷W?½úÚµ9áð¶NÞ}÷ËyÑ…Ïþ0Mîô„?ÔP£ãQãßþÒ¸K‹‰C9±IEND®B`‚gosa-core-2.7.4/html/plugins/departments/images/domain.png0000644000175000017500000000717311261120743022601 0ustar cajuscajus‰PNG  IHDRóÿa pHYs  šœ OiCCPPhotoshop ICC profilexÚSgTSé=÷ÞôBKˆ€”KoR RB‹€‘&*! Jˆ!¡ÙQÁEEÈ ˆŽŽ€ŒQ, Š Øä!¢Žƒ£ˆŠÊûá{£kÖ¼÷æÍþµ×>ç¬ó³ÏÀ –H3Q5€ ©BàƒÇÄÆáä.@ $p³d!sý#ø~<<+"À¾xÓ ÀM›À0‡ÿêB™\€„Àt‘8K€@zŽB¦@F€˜&S `ËcbãP-`'æÓ€ø™{[”! ‘ eˆDh;¬ÏVŠEX0fKÄ9Ø-0IWfH°·ÀÎ ² 0Qˆ…){`È##x„™FòW<ñ+®ç*x™²<¹$9E[-qWW.(ÎI+6aaš@.Ây™24àóÌ ‘àƒóýxήÎÎ6޶_-ê¿ÿ"bbãþåÏ«p@át~Ñþ,/³€;€mþ¢%îh^  u÷‹f²@µ éÚWópø~<ß5°j>{‘-¨]cöK'XtÀâ÷ò»oÁÔ(€hƒáÏwÿï?ýG %€fI’q^D$.Tʳ?ÇD *°AôÁ,ÀÁÜÁ ü`6„B$ÄÂBB d€r`)¬‚B(†Í°*`/Ô@4ÀQh†“p.ÂU¸=púažÁ(¼ AÈa!ÚˆbŠX#Ž™…ø!ÁH‹$ ɈQ"K‘5H1RŠT UHò=r9‡\Fº‘;È2‚ü†¼G1”²Q=Ô µC¹¨7„F¢ Ðdt1š ›Ðr´=Œ6¡çЫhÚ>CÇ0Àè3Äl0.ÆÃB±8, “c˱"¬ «Æ°V¬»‰õcϱwEÀ 6wB aAHXLXNØH¨ $4Ú 7 „QÂ'"“¨K´&ºùÄb21‡XH,#Ö/{ˆCÄ7$‰C2'¹I±¤TÒÒFÒnR#é,©›4H#“ÉÚdk²9”, +È…ääÃä3ää!ò[ b@q¤øSâ(RÊjJåå4åe˜2AU£šRݨ¡T5ZB­¡¶R¯Q‡¨4uš9̓IK¥­¢•Óhh÷i¯ètºÝ•N—ÐWÒËéGè—èôw †ƒÇˆg(›gw¯˜L¦Ó‹ÇT071ë˜ç™™oUX*¶*|‘Ê •J•&•*/T©ª¦ªÞª UóUËT©^S}®FU3Sã© Ô–«UªPëSSg©;¨‡ªg¨oT?¤~Yý‰YÃLÃOC¤Q ±_ã¼Æ c³x,!k «†u5Ä&±ÍÙ|v*»˜ý»‹=ª©¡9C3J3W³Ró”f?ã˜qøœtN ç(§—ó~ŠÞï)â)¦4L¹1e\kª–—–X«H«Q«Gë½6®í§¦½E»YûAÇJ'\'GgÎçSÙSݧ §M=:õ®.ªk¥¡»Dw¿n§î˜ž¾^€žLo§Þy½çú}/ýTýmú§õG X³ $Û Î<Å5qo</ÇÛñQC]Ã@C¥a•a—á„‘¹Ñ<£ÕFFŒiÆ\ã$ãmÆmÆ£&&!&KMêMîšRM¹¦)¦;L;LÇÍÌÍ¢ÍÖ™5›=1×2ç›ç›×›ß·`ZxZ,¶¨¶¸eI²äZ¦Yî¶¼n…Z9Y¥XUZ]³F­­%Ö»­»§§¹N“N«žÖgðñ¶É¶©·°åØÛ®¶m¶}agbg·Å®Ã“}º}ý= ‡Ù«Z~s´r:V:ޚΜî?}Åô–é/gXÏÏØ3ã¶Ë)ÄiS›ÓGgg¹sƒóˆ‹‰K‚Ë.—>.›ÆÝȽäJtõq]ázÒõ›³›Âí¨Û¯î6îiî‡ÜŸÌ4Ÿ)žY3sÐÃÈCàQåÑ? Ÿ•0k߬~OCOgµç#/c/‘W­×°·¥wª÷aï>ö>rŸã>ã<7Þ2ÞY_Ì7À·È·ËOÃož_…ßC#ÿdÿzÿѧ€%g‰A[ûøz|!¿Ž?:Ûeö²ÙíAŒ ¹AA‚­‚åÁ­!hÈì­!÷ç˜Î‘Îi…P~èÖÐaæa‹Ã~ '…‡…W†?ŽpˆXÑ1—5wÑÜCsßDúD–DÞ›g1O9¯-J5*>ª.j<Ú7º4º?Æ.fYÌÕXXIlK9.*®6nl¾ßüíó‡ââ ã{˜/È]py¡ÎÂô…§©.,:–@LˆN8”ðA*¨Œ%òw%Ž yÂÂg"/Ñ6шØC\*NòH*Mz’쑼5y$Å3¥,幄'©¼L LÝ›:žšv m2=:½1ƒ’‘qBª!M“¶gêgæfvˬe…²þÅn‹·/•Ék³¬Y- ¶B¦èTZ(×*²geWf¿Í‰Ê9–«ž+Íí̳ÊÛ7œïŸÿíÂá’¶¥†KW-X潬j9²‰Š®Û—Ø(Üxå‡oÊ¿™Ü”´©«Ä¹dÏfÒféæÞ-ž[–ª—æ—n ÙÚ´ ßV´íõöEÛ/—Í(Û»ƒ¶C¹£¿<¸¼e§ÉÎÍ;?T¤TôTúT6îÒݵa×ønÑî{¼ö4ìÕÛ[¼÷ý>ɾÛUUMÕfÕeûIû³÷?®‰ªéø–ûm]­NmqíÇÒý#¶×¹ÔÕÒ=TRÖ+ëGǾþïw- 6 UœÆâ#pDyäé÷ ß÷ :ÚvŒ{¬áÓvg/jBšòšF›Sšû[b[ºOÌ>ÑÖêÞzüGÛœ499â?rýéü§CÏdÏ&žþ¢þË®/~øÕë×Îјѡ—ò—“¿m|¥ýêÀë¯ÛÆÂƾÉx31^ôVûíÁwÜwï£ßOä| (ÿhù±õSЧû“““ÿ˜óüc3-ÛgAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF–IDATxÚDÓoLeÇñßsÏóܵ½ëµ½Ò?ü+Ì€ ¦  u“³Wš˜8£¾sÆË^™é £ÆÄø†¸i¢¾÷…3Ñø 3ÑM% ËAʲRZ ”^{¥´GïÎ{±ÏëïÛ/™ZÒ!2×þÚÆkŸü ‰#.Kd¤+æ?ÑÚà9ÀYß©¬­¤K“;Åêá«—ÎâÉþ0̺ æ8 Dòêƒ=Úùç‹u¶„dd@¡l>4Ÿ4ÎŒO§“ÿ/ø”àÆ(@ YHÞíŠ)oŒ 5‘á¾(ò†‰[Y¢ àsáôP#bAwW¶8ÿñòz1òÔ‘wˆÍ fW ÏñãÚ…îVÙ«Úøj*ƒ•\zÙAF7Á@°‘¯â檎·_ì%Qxsî?ýLÐç3ªV೫ÉWlFiÅ–7+(–ëè«ÙxëÙØ_7ðåoXÝ,#Þä†(2,§ :·R<{ogpœªƒgOŽO¥.|-›<Çñ¸'ºƒ  ïWñáX íaFî‹â½Ï˜YÚA¾d6†ԟص…R“eÛ¼·MÅ#½öë ñfï¿8§Bx´?Œ£M .^I”âXÜDÊ&æK!Áïw[m‚C`:×y|3“CKHAsHF‹&aô¥.,föà š y½Õ#Âã•mv$®% ™-ãFbÛ›­Xh¨P½""~ >ÓË%EÄöÎL³ŽžŽˆ>Щ­ ÷´úæŽõ·_W½nÅ,ÛB[؆Ã8Òªba³†‰¥ÚÃ2LIJÐÝîÇàñÎ_:½³ân®BìhOGdXsÁ×׿AT£øèJ9¸à€ÚžÒJïb×¥"èõLòÖhÖß¾O žh3¿ÿô3œ;wêåérârªˆXTEKÈBqðDŸŠÉ•=dõzmâ»ÉKsc—_ÇÁm‡Bl”Æh6©³?Ó‡»Šy>ªAÓÈŠ „s¤ u¤3…ÔØå«ß.ü¾ø3DkÕ­} 1 HA®-mçJ†^ÌpNuˆRÅåâ†àXùÝœ¾6{313öõ¯ãk «7 Ѹ¼OÌfwVB D˜•yÓ²ìD&³3ã(AEvËfÝNÝÞ*g7r9ÀÙ¤ŠgÃ:¨o‚ ÆÀp— MM‹9§"c”ÚŽι%IÜdŒšwspü?þ—}µIå±IEND®B`‚gosa-core-2.7.4/html/plugins/departments/images/organization.png0000644000175000017500000000155711030207164024033 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% €X–.½Èð÷ï?0þýDÿgøóçÿüeðn|ýúí£‡÷ï%20°}üùóÇoþýcg8wn@± šÒüd˜“ˆ¨`­’š¬ƒ¨”óg?ýú'òøÁ£hÆÇÈ:ˆ‰‰ Âøóçÿ·áÙnc¯¹ÇÅSÇAQU€™™AX”ÁÎÝÖVJ^aûïß¿uAÁ@±5þ×HP»ZCKÜ_NA™‘‰‘áÛw†Ÿ?ÁŽbøó›››™ÁÙÛV›™™eÇÙ§¢ÿº† €XxyÙgijÊ%++ 01332ü*þþ $?AílìŒ VRLÌ[N=“üïß¿UÄ"//¬¦&ÈUÌ@PÃ/ a “X€üÿ@¯üò´½§/ß²óçü ¦×_Þ0\ýu¬‘(üïÒ ffˆ!,@Í<œ ÚÊ ¾>ŠÌ@  @Lþ­xQɰàæ*†ßELP÷ƒ4³2A4³³30ˆ 30(H•¨äâÿ ÿˆéÕ›S_72|úø“áå'†Wï 6³±B » ¨šƒ ‚AÀƒ‡Ÿ~ýúý €X®Þ¼˜öêÀ“9…yßÿ20|òá ƒÐ–wþþ1Œèt6 ×®|gXµbד5«§ÎyýúÜZ€bùõëÛ¯KWç¯]£óÊÐL§YCOñÍ{†Ï_!ÈË }†G~1lÞ°÷ÅÊ哿=x°PöÈÄñ+3Ã÷ïßZwlÚýüÍk«éÚ¦Úl 9÷õ‹ ;6ïzµaÝ´÷îîYüïß«HÆ@ð¤ÌÊÊÌðûÏÏy»¶m~úåëïe&úBv~·qí¤%7nl›Ôx ¨ìzf ”¼LeÀdܹeýBß™SÎ{?}zyËÏŸïObÓÄHiv0Ú'3Ýù/rIEND®B`‚gosa-core-2.7.4/html/plugins/departments/images/department_alias.png0000644000175000017500000000071711024414256024645 0ustar cajuscajus‰PNG  IHDR&”N:sBIT|dˆtEXtSoftwarewww.inkscape.org›î<aIDAT(‘mÓÏ‹ÎQðÏù6Þ%!)cçG1KÊÂXÙ(ÿƒ,d%¥”XÈ¡ÉÂN¦˜ì¬l(;+KV6lÄø£†Ñc1÷Íõ¾óÔÓ÷Ö=çÜsŸs¿ªÊVq£Éý•d'i7‚)\S“ãvb³í»†xZU`˜ú€ulk=j½p3ÉhŠXUßñ«©ïE\‡!ɾ$“J2TÕîá]/ãMçâl’…à"vµûÜi§j–.aŸpgÚŸ ØÞ©­w¶UÕRU}¬Í >ïpG‡6±Q;ñØäØ»zÙ ìÈ€/ÒÉlÖÞ$×Z¦ãÚÑÄGØàJ³<‡·x…Ëm}«ª~$™ÁéF\MUIr§±~ïqµª>÷¾Ç9>ÄkÓÁ°€ûI槈UõKx„¯i,4ã=ñ¿· I<Á›ñ¬`¹ª¾õ¸©¿Ã¿<ïâqUýÜã/¾9…À~(‹}IEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/0000755000175000017500000000000011752422547016533 5ustar cajuscajusgosa-core-2.7.4/html/plugins/ogroups/images/0000755000175000017500000000000011752422547020000 5ustar cajuscajusgosa-core-2.7.4/html/plugins/ogroups/images/application.png0000644000175000017500000000167711002130510022772 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<QIDATxÚb,Ùú÷" 3ƒÄ«¯ ÿÞ}g`á?¾þf`ø÷ þC13+Ûó¥9³¿ŸšÚäþÉ‹ï?in6á¿@Å_~20üúÃÀðöÄF&`dbbø4ü÷ïf@®8?‰‹®ø¿ßf2@ãþ%†üÒ†ýcxôä Ãÿ¿ÿþÿÿäÿbàæeh<òçÏ c` 7; 7H#¼þð—áÛ×? êÂì <\, ï?32¼|óáׇo <Ìœ| Á  †#÷ÿ>ÚðÿÛïÿÿ¿üýÿÿÁë?ÿ¯ÞûõÿÛ÷ÿ¿ÿüÿÿÃ×ÿÿ¯=üÿÿüÝÿÿŸ¾ýÿÿè‰'¿u }Z ® †ÃP¾ xýíßÿ‹w~ƒ5ÍúÿHúöÿÿí'ÿÿßzüÿÿçoÿÁ`ëΛßyù¤B@úˆ Ê ÿðé?;;Ã'``ýøÅÀÀÆ Ä, Üœ b‚ l@oº¹¨q88‡¤µˆ0|ÀšAø×oF†˜>cáÆÊ›·?^½zËÀÌø‡á'0jß}Š}a`Ð3²ÒjÑ &PÀýòD3B4mÿTü¥G/ÞgغÿË×?Þ5¾ú4ä3¿ ˜0,eˆ…‘‘‘‘âf`°H 10ò@œ â«ÊK1ˆòó0ñ³$q1å~~ÿ4þ?+@±übdäú´k ?Αù•C D%.ÆÏ ªÀ &Fhx-»zñäk ó @±ÔäçLaüùј^þ12°2µÕ6ظXËqƒ¼ñâ=Äk<À@ü 4œ¨Q˜`.\ýÀ°{çªK@îÈ"}r@¬Ä’Ž)eÏñýe'oÿÿåÑÿÿo>ýÿÿ…oßÿûïãŸy¨6ˆˆ `rðH­Þ´ÿÉ—S÷þÿ¿ÿ˜ÈþÓïÿÿO_|ùßÝ'íPM5«€Ô# $¢èobá-!!$ËÊÌÈòòåÛ?§N¸÷êÅ­ý@é½@ü”ú§PÀJ,Po2@³ð[ þ M Ô€i‰–ºoIEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/list_ogroup.png0000644000175000017500000000133011042050271023030 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéIDATxœµ’KHTqGÏÜÇÌèè䌖éd¦˜©™RJHÄH*¤ˆÂè-,£UÔ®‚ ¢"jSô+¨-Š4‚^Ô¦DË(­ 4j¾ftræ^ïçþ[DPQA¿ý9|ðøŸSkžn¸¸]}áE#xgü=9¿&½à\ðÄž·z¨nBˆ3Q!*/¶¼&!3ï¯ø)ÛNYÔ+Äò!*Û…Xñ^ˆeÝBdnïÄþ³Dú $„í• Mxôžö€¦AÖêülÉ=³ø·‚gd‡ÊÎ5lÉ¿’†9]‡‰Dðy!ÇJ´}¨ëÜk€¸ïœÜX†÷pUæî¬µç«vTÌ)Í+–LGÑ}{‰dY`WaЀÎ0hC6jWˆy‘ÅïŠGnë‚;k7Õ*îÔD†ü é,ú%£m€×·kµ¨ý‚|­™…¹]Ì^âËíÏ ,}2òX±ÅK™ø›Àc ‡"q<¹•á#¡›Û] j‹2Í{´¼žEb6Ò«|KÂ}᳊2E‚XzûÀ›…K!^%¥îà-3Vï¶ím[?§Ýv„"˜•æ£H.àSRwº¢ê¦ƒáq@ö\°{`ð3Œõ1¡›aËóFcÂ"ž$=i*n‡ê¡}ð#}Iåvk°yWIR6–r Æý`³ÐuKžì•öa'b,LÄa Ð5Ô‹á2‘ É)ßó„Yî•çÙô(ŒFè48ð<ôðú€yÒhÓî:®\É—o‹(èá(QÓBzÓEƒvõû;í;³g?V&‹£ÊËi›Ç½Ä¹ªS.¥^.Îc3„´ÊU“ò_”=2+”?®Ä—º÷I©ÒÆ?üOû n! '¢±6IEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/generic.png0000644000175000017500000000141211042060420022074 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéÁIDATxœm’Ïk\uÅ?÷½ï{óœ¯N[užÑĉ‡´!E&DLDîE!‹.\„ü.ºªÝT܈;AZ³0DFÐ ƒ”I´¥MfœIæ53ïû¾_i)sv÷rÏáœ{¯ÌÌÌÌÍÎÎ~èû¾JÓ”‡Q(°Ö""h­íÂÂÂùùù÷®lllÜ+ ÑÖÖ¥R cÌ £ZDh4DQ„çy”Ëåó­VëW•ËåìÚÚ‹‹‹ ÑÏ€ã8looS­V™œœ4Žãd”µÖæóy:›››}ÉGˆãÏóh·Û°êAƒõõu¢(ÂZ{L‘ãZDØÝÝe||œJ¥r<£\× ^¯Ól6Éçó(¥´Öh­I’„â8>$*uMDp]Çq0Æ µÆƒµc Æ’$¡Óé`­ÅZ{bOÊq”R„aH±X$›Íâû>Žã`­EkÍ^·K’ ˆ{=Ò4=q)%"ˆJ)|ß'‚ @)…1†û©fì ÇóÝ}Ö”(‹¢”ê ¨R©ÄÔÔa:ÈdP®‹¶»ó—n/óäëg¹ûÌ{4_:ÇÍßö^™˜8ÿØéÓOÈÊÊÊ­jµZ9²›¦)q’ Ó#‚ýôQc‰{cÔμIðËçôj¤xé²¾þÍ×?ÉàààÅéééwD$0‡áô°µ/Zð~KÓß?º]{{äÕJ±5jheòä2{oñÝõïïÎÌͽ&ýæ x÷ÂeøøòH}xìܳŒ?  Ü:¥m:×®þ3õåjYõP ÏÁãËàÆqóW ²Ã`ùêÖ·”°FçÆ`À>51˜”2ÎŒ¼~ýƧkkkß8Ëï¾ó^7)ùßþ¸Ãød¯ìà•ŠŠÖ¢(# Súý„“nŸÏ®¾Ê›o\\W‰ÃNÌßcž?Œ}Îc¤’S(JŒ1DaÎñ“”öQHØ‹ùøð„œ=<>œ=˜ŠÿPîZÀÎ4¿ÉÐ&‹zRÑËÓJë^-•"çë¬}I*9骴r²dæF–ÊräVªËS³ÊŸßw™çRº™ÆÔZß»†\:7{YDb.w-öNq QÄ+5A³¨…P‚ê•C%1T:ÐÚá­ç²\>ˆüÁ³ø8á³îh(9­Å„{3·®h)…—-àW~ôÂçøåßö®¸™€(f""A$imU jÕWÂlžÚ–³mq³I”5ÅúФ‚yê‚Q(f^¬¸•¢VŠº½¼ý¢:ðþ_ø¼”/ÁŠš¹ºÅL=›â‚ u$>½Oœ$Bqt·!ŒBt!P:¥”๨—¢^rôRÄK–»øíÏ˲ßùÍïÄ­|)ˆ›‰X77+ªžuD–Oí¯MѾ$ Ñ•˜…`æ\ÔJV_@¼·Åñe øÝ_þ¦—®Ä¿÷;ß‹{i¸‘WÌ48ôÔùônáêy?$ €§*ŽdCKÎâ%᥈•,V KòK1™/‡³ïy/gßóÞ¡;íÿìÇøÀ/=úâX$œIÎI¼¤~Uòs»]zv?1ÒU¨Mè9hqbr*7¢ç"ÖË9¥œs¶œ²å‚—ŒåòeñÐÏÿà—γ?yÿwáfwÂÜÌ­”ÄQdíÚA>~m\΋~¢l%z©Š#P„<÷kËëQíD%r¢_w³ÚKÎV ^²}©•øç~⋸Ýu3÷Áßz7"a­zï ^u|%>´;/'¯ì¦•¡zU‰á¹¸[v_”c28–“cÅÄJ¬ÈƒA`}}ϯâ…Aî *ÇqçÅð¶ŸýÕ/âôkÿuþåu£ùÇ?‚U=¬ê­³¾^Ýíò“·š\I)ÑsöœÜ™§ìbf”€{6“ܹåÎ%wÙr.mו¦éòdž´ér¿˜­"G¸çG€wþÌï½$§—ÝNø¯œáô xNÜ·öŸ›sk Þ8>7¡¨¢ý±ß§ŠìPZèAúL„Y)z8™ûxÜøáጦéŠåì–³Y2Žpö‡ß÷eùÜM3·œîÞ¼ê]ÛŸxëGìaæ·§ñµƒ>¬mX韡 V°=I ç,–%+e6gfCƒUz½‘…A‡îmÓîc%ªXÂ:q/âoúÉ_dë.È}¡Y½8¼Aßþö¯²ÑhëjC¨¼¤´k:úgxð²ÒS‚—P¦»äÃ2N+m¨Êœ¨–7|2ëÈÅp€ÅèAûT'¤>£BšJsý™n݈ë|€7ýŒ½»ìGc¼ðy­Äû†>ú^ÌzrüxJ‘ÖÌK)"nhÉ©—g9ì݇\åéÁ*½á:«ªŒÀ£#XG,®£T¤šE¾pEvŸ3ðb¢ÚIѨ–]òlOl|ƒ•ê&÷^¸rþ«ÞÔ½î¼ÀbVx’ż0yIÝç7sç§—.õãÁA  Cˆ~üxœ¾êU2v ³~Å®­ú;æ·í[&òÏÜ¢üõ=ßž>uÁ/‡ Íý“~r:áÔÎ-Â|.]—iš{˜JÑÍ @î2í¼Ñ<ß¡Ÿ¯²:ºÉWí8>7 6„5è­ä‘ûƒ“B;kÂ|«c¾ \f1/\n@lîPzëë"!Ä4J¯ëtåúu9uñb%„ãý°ÿðCr}í”l|ÏûäW?éßÿÌŸfþñ 6¯vþÁ³ß!yà­üû¹7ÈÌŽqÏiåòîìàúXéOnÂÆ`—Ñ»÷knù¹ c‹ÇÜ¥xêFqÜöH9™1–«a%¬É”Óuî¿>Îß~cr¥lï_þ}àb¹S€µHªÚÔuÑ(˜{*mÒËÏÉFóXœ¼åõë+Ÿù‡>ðÏàÞ9öÓÿˆŸâõ¿ïùûû×>®üÆÉöFúOqöÑë~âÌu»½ó“íª¯ï_`²³*ÝžS¢‰UÎ*'õÞ‘SUC¶ë›áSþŸ~{z£\Ÿ_³ýé´ÐR4S‡ÂÊgCè ÆÉ ¨‚fiE‚‚†¨q°~\9¼Ë“j7oÒüÍ¿HQ¨Ø  Ñw•ºÀý›7ä»Oû¯n~Hž˜œãß8áÖ±ìY>ã-O¯t2ظäÕƒDy[ûnÿºú[ù þ69ñW½nÂv“ifäÐངõ[¨¥ ž>7rÆ/(3h¦ Ô fUÉ««!N«ê“UE":VãÚfØ©U'U`jöz\Y?AW Š1grû4ʌڪºà½VdU˜ŸÞ÷?¯]öãþâö¤4G3d¥Ã×:ÐVp-¸gðõÄgÃFß¹¹I·Ìˆ( ¶ð‚g¬ê>†Ô4Ò|ü?TM¨·¹u´Ð©y‹ù ÷™à«§2 åOíkÕ¥Á=¹hgôÓµÉ:WnJÆ»{ìÏ·ŽÅ‰ëé9õj"V OMϨ§H HËJüžÍMŽÇ€fqÞ3xVõ2X2ËÓÇ/­{nAŽœÔàû˜5R|êâ3ïÜ}.n`¥(¥± ääd7ÉVj¾Rz~qü¸ßœr,¯‹ ô2®‰È¡$Têâ‹£z‡ZB,¥; ÙÑ‹ùâ|R­z=)îñà±Çê¡{¯@H@ `ʞ b#Z…„{+ –˼5³b±dÁ‹»´© %TýŠ!}züq¹Vn2€fE]Ðì♊Dñ„Ó-WýsGB‰†ˆyÀœÁa¹ºff-n §O8 ÚéG $ƒê‰ñŒÔµH¯ÇîG?ê¡m}T×¹u'˜17$E„mñÒX¦xå3ŸKYzÀè<»fÜ;qCÐì>¨þÜΓ<;»ÄÊjÔØ™{‹·Ý¢m.h,:ô"O6/…¹go¬£ó†DÁ%s Íb÷‘¸Qfî½’’g÷îÖã‹4c”™»‘¤çî•bÙî³ì7ÍyÁ³ïxðÆÜâѼ̻d¥±ä.Ùço>%—¦OËhÐC[5§ "]4LЄYBÐR k“¡&®TeZ¬Ì‹»àù(âåˆüwÉÌo\¼HÛ4¶Ô¥è9îÎH•Ê””8cæç¬ØëÛCvìП×Êž¨jßah×(4Ip*ê Ÿ¹}‰K{O”Ѱ¢_#š’ V “ ˆ{¦x‚’,{'K‘Œ«+ÁÂÈ% Ö¨€>rÎqzåŠU‡‡¼¸OU"D3É"LÝ=¹‹C_lŸÁAÁNC¹¯$ÿ¦’¬cÚýSÿ´]Xëëš\½õi. ®tÑk®H*SQ©ÅÍKÉæ$ÀqËâ–Ì<™—.On%SȈ$ðBu”»G!T±ÛÝÕ5_ a¨jØ1Y$¾ƒøòÆkeÆ8/úï P*ã oÎý±½­gõÒËÖ{˜‡T>ÐPúæ:·àX†ù~'©É°©2D p7 EÉɸgÜ eÈ¢Ø~ÖÂCu}ñR¯wâ±Éä|pl¸‡‘ûB®ˆËB¶;°îÎl!ÊãòœÎ„ð §z"¨=yûšÝ.›yðFiõ´(#QÄ¡y×Áœ’!÷2Þ9Ý.0<,V†.õ)‹øuj#œ%‰„ªºñ–ÕÕ uÝŸt݉)=¸Ý¶ç³ûÀÜctG!8”Ófˆ¸¸Ët|Rû'•çOìúmÙü9O%=Q›I´‰‰Q–w+Ü!gèFŠ'§ì %â²p¬;«fA3n‡`УÆéâ’|ÃbtÝÏ"ëkª““ýþøÞº¾Æp8èºîØõÃÃáÌ–êÆà›¿9^{akç™ÅÂt ¶O 7Þ"<;ŠlwÊìÒPì[æké¹çÒ«÷iïm¢mhEˆˆº $H¯÷¹³ìUi‘ÒB^3·¹c7«©@à3Ûà9ïq͆\Ñšu’ÏãdBh4a¯«ª ©ªÊº®nööªÊ¬îA]Vî7ã3Ï:nOåYzPöyÝj×ßx×k¾¯ÿïü×Ù é f¾ÂÕ2à9¯Ø"°Ñª‘éhVŒñ¢ëY„-rkTçU¥ª*žR5ßÚ uÎÕ`±SE_Ä¿ ý¾6Mn¡tg¦'ŽMŸÒ†0(‚C¥xˆ«;˜uUÚfƒg}ƒK’Ž}$|ø5“× 4p9þÃ'‰SH4­8­,Èw8ó£:¼™Ï«J‚Ó7´×u:\*Ë^\Ä#ØÊìÐÉ`ǧMЇ© A%jTÕü[ÏË<¡Æé9TIÊÖM¿ùéª_2‘‚«“—¡ÝÉ"::YêÄ(⌗QcGÛ¨RBhw›½ðq>—c ½ÅN&}jy¿¬ArFÀVÁkð¸6Z‡y†RBÀ£F\¦Í.ÓtC$ˆ8¡ PUƒšª:ˆ,o¥.ÊZÈKo˜Y †1_†¾y@O]×Nž>ŸL8±(H —ŽöÚ嵨*¶ø¬;€û?Sð}Op)‹Z©do¼Í¸ÞC{ˆ P¨(Áeáaw_ÌŽË"¬³8&NÁ(b¸L2¾h´¡$ÀévwóIÈ,Yæe•=šß0X¾oÝ}~‡û–‰ä¨Ã¹Ö»(›»{lÛv (ˆÇEEÇ˨š1\ÌA–|D0Ã1ýKÁCZz)àøBwðxEOü^®5Írª;Ê'мÈeG K¿zéçÆ_é“úWj~ÇQîxÿb×|Iû¿p§}Eÿ÷ù_flÙmIEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/printer.png0000644000175000017500000000124611002130510022142 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7Šé]IDATxœ•RMOQ=oúÊ aâB3MÁ)©mb” V ¬ØtÁ¿¶nKâš Y!aÔ 4bº °h C­ie>Þ›yÏSJ‰&Þäæ}äžsÏ;ïÜŒ;›››{ù|þ¡”Ð××!<ÏÃìììÛ¶KÚE@,Ë2‡††úã Î98ç „ ‘H¤ºêo@)þYáû>|ßçžç"»ëµ®³ ”ªÎÎq !†¡ø§‚\.÷Àu]Öh4Ðl6áû>‚ ç®ë"NglÛf‚“è$XYYù`Fîòò’4 ÔëõvÖj5Œ=BÇÇÇo(X|µ8:’)NOO?M¥®}Š¢BˆN#i2™|­iš³µµõþêꪆɉɗ;ßw¼ýú¾úŸX__/¸GgŠ3séLZ?ùq‚(Œ Õ-£„kã(ÅÔÔTn||üÎ?¶¸˰ÐüÕ¹Q‡Rª½—R"™L¢P(<¡=´çîYõ ”RPJ¡i¹M¢”‚”J)AÆt]ï§Õjõ§iš÷ŽŽà8\×ýë4Mƒ®ëÈf³Èd2p§E> …‘µµ5ìîî¢X,‚1Ö–,¥lw¾¸¸Àöö6–––`š&ÊåòbYÖÄÂÂÂ[ÆØ£Äüü<¡”¶Áã|~~Ž †á~*•Js±ÂÔàààóJ¥âuW†ªÕj)Çq”ã8jyyÙîííÐÓ$­ÓÓÓ½ÕÕÕwŒ1=–RER‚B*•Ê7×u¿ÆÞy̧kA‡IEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/winstation.png0000644000175000017500000000124311002130510022653 0ustar cajuscajus‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  d_‘tIMEÔ &(2*­0IDATxœÅÒ=LqÆñï]¯×+M TzmTÄbRÔ`ÆÄ(!!²029828˜8Ó8°šHÜd1ÆÜŒ«F‚˜à  ba)ÐÇËQ®½»þÿN ¥†ÄÉgü%Ï'ù%üï(GÅG²Ò-ç*s „Ú…Ôö˳‰‘»c´£n&©8¸»†áKœâ+1%“›¹è6¯ (*š¢£+úâPzd²°ß¾Ì8ï_ôyß§ G}¤dÛÒX,‰LÁ‹=\ØÑð…J‹a’2Rï€Z!nÏuæª_?¡†(z+bÁØãËÞ4ò°[ëÉO Ô¿ íoâuJ]ý¸q¨:ò1…e½Â– |'ô™hw=ðÜ`Ëvù)‰#¹šÞÂ2¿á4La—ÂT\A2eõ ?Tõñ:àÙVJžÂúA€¦°ŠÊ*]ñCñ8M;¸¾Cº±˜Þ¸Øvh¶xòºœUάlH´f ¿Âvwi‹æ¹”Þ!»Áw!atÖNsŸ7µ/Aîb«:¼Vô ê’H@!ݼÌIsÓüŒQÀOdëw`í ¦äZ ,³±íÐÖ¼D‹Q[¾„p3xZg= $cj€§!]’LÈøí~÷¦ªñØ”UðM4wyÌÕnLöê¦ 0?·FÆÔhˆùŒ&VP|Ï6Ü_ªt&”ÞùßLJ)®[9Y.ôÉÊ:Šô¶{Éó7­ã:ÿœ?=eßÞ àaOIEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/mail.png0000644000175000017500000000117311002130510021400 0ustar cajuscajus‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ’ù¥tIMEÕ 8õð…(IDAT8ËÅ“AKTQÇ×¹Ïy“ŽÃXf-f¶¬ËšSF#J ÄŒV­ƒ>F»ð[´rS)$”a%fYÒ€ÕÐ8Õ€ÙˆN>ÇÞ›yçÍkñ&ÜÔË…s/¿óçÎÿêÖkþß4ÀñqÄq%hD Jìà— ù]ÕÙàæí»@œ­‰öÚ«ìá]'H)A£)ëàyQò™,¸–_¾E¿^e`¸‹ª™@‰€´%ˆh´_å8ÌܟƲ~ "Ô Ž?azbŠ­õ¯ ¥=“DÐx.éùçLÜ›$Žp¾/I(d 0„Îs¼ ½aya%Ûô2 ÊösSÙÚ°h9ÜBÇ©ã˜õ:T*"”8y¦“lz›Õ•]žL> õÈ1ª;2éO|/¹ÞCì@Ó4ñ¤ˆRªf¢ë@CŒ•¥y¾­Y¤®Ž°[Ú`aî)ÅÂ&ÉîvŒx¯fÑvÔáDW?‹>Zר;>[kÏXÏåI^F×—‰57Ñ?t϶AkB†"u9Å‹™Çìk4Ù0JX‡ó¹%²óô^£1ª78Ú$6Z{44Çé$“þ@î}3\(ØÞ´8ÝÝGµºJ¥¾ :€ ÔaW-|?†á[(ªœ½ÐÃâì žç£üùKöÆØ.{(  HÖnõÏ·ñM¾ÕÓOa’—IEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/asterisk.png0000644000175000017500000000142011002130510022276 0ustar cajuscajus‰PNG  IHDRóÿa pHYs  ÒÝ~ügAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF†IDATxÚbüÿÿ?###!2÷¯@¤ S? #CÂëo ÷_30‡à†'ø¾}ÿ3 €ˆ2 mþ‡•Kº tµ5¾0ˆ3\½õœáãßo ¿~~g ¢ øöù=#‡ÃÝç¿Þ½ÃÀ.fÀð—ñÃÿ¿ˆ‰>½~ $£ÃðëÏ?i G1®_ Ÿ_?c`†@e€¨¤ÓÿŸ ß>}d`ÿû–“‹‹áí³» Ìlì ˆ b&¾U`bø•ÏÌ!Ì ªcÄ +ÂÆpìø9n>fVö…DМ¬ ó¿ÿ)ðç÷f¦ ¿dxrç:ƒ ¤â†Z¯… ?Ïgø÷Ëáû·ï ÿþüdøÏÀÌpbß1E­ìÜ|‰ 5Ä‚#ÚD¹ÿôÿüþ5áã§o ÛÙ¹øNí[ÃÀ+"Å *¯¸­ÃäH-@¡³â¿‚ª8ƒÃÿß õŸ?ÿUxúþ+ÃÏŸ?¸ùEÎïZÌÀÌÌÆ ¨oŸ¸µÝèL@1‚’òäƒ /o\®ÿúùƒÃ±=;¬‚³¾þá`øô×@E—ö,g`åàbP4°KÜÔ¬·ÙR€‡ÁŸ¿ ûy8fö÷2üâVd¸}ÿÃo6†¯3œÛ±AXVõƒª¹»!ºf ° rW2Üÿû‡AáÏo†¯ß0¼}|›áÙí <¢ÀÓÞŒ²Ä•e2°…@Ã@ùÇ'Ÿq$°ðð0üþþ•ƒGàƒ¡[ô6Nž‰s’™à‹)€b¹ (¨û=ƒO ÀR×í_Ô8IEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/select_terminal.png0000644000175000017500000000141211042035364023643 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéÁIDATxœm’Ïk\uÅ?÷½ï{óœ¯N[užÑĉ‡´!E&DLDîE!‹.\„ü.ºªÝT܈;AZ³0DFÐ ƒ”I´¥MfœIæ53ïû¾_i)sv÷rÏáœ{¯ÌÌÌÌÍÎÎ~èû¾JÓ”‡Q(°Ö""h­íÂÂÂùùù÷®lllÜ+ ÑÖÖ¥R cÌ £ZDh4DQ„çy”Ëåó­VëW•ËåìÚÚ‹‹‹ ÑÏ€ã8looS­V™œœ4Žãd”µÖæóy:›››}ÉGˆãÏóh·Û°êAƒõõu¢(ÂZ{L‘ãZDØÝÝe||œJ¥r<£\× ^¯Ól6Éçó(¥´Öh­I’„â8>$*uMDp]Çq0Æ µÆƒµc Æ’$¡Óé`­ÅZ{bOÊq”R„aH±X$›Íâû>Žã`­EkÍ^·K’ ˆ{=Ò4=q)%"ˆJ)|ß'‚ @)…1†û©fì ÇóÝ}Ö”(‹¢”ê ¨R©ÄÔÔa:ÈdP®‹¶»ó—n/óäëg¹ûÌ{4_:ÇÍßö^™˜8ÿØéÓOÈÊÊÊ­jµZ9²›¦)q’ Ó#‚ýôQc‰{cÔμIðËçôj¤xé²¾þÍ×?ÉàààÅéééwD$0‡áô°µ/Zð~KÓß?º]{{äÕJ±5jheòä2{oñÝõïïÎÌͽ&ýæ x÷ÂeøøòH}xìܳŒ?  Ü:¥m:×®þ3õåjYõP ÏÁãËàÆqóW ²Ã`½IÝþÚºøï1@´ûÛŒî=¿vØO[OxCÝ3šÓ¯´ÚQt×oZèœNs`MŠþCñþÇÚX‹=<{ð´ƒ;{.Ä7ô­'ý^ŽÃLоâãO©õ¢2|¹Î–þ[„:ÓhÕñM-½©`¦Ûþ½pC—’­0ùÒYHO[ƒhœÝ«B¸©oø~{³ÉÇ|ÕÔUWIìïÚ匕&õªíB®ªáfDaéJa‰ý'–šå¯J™†|˜bþ5Á ºã,Ó?f4ô°Y/˜e—¼¶Á0T\M‚S¤VsáU©+ñÚçÐkGêø<ƒ‘É‹%Ñî¾(M|à‹V_m¥*ü—ƒY'[áÒX1ug…W?– Sæ “fÓµP“µQ-ç2qå¹ýG¡m^P"^¶ÌÕq;»7iþm¢²ÏKVn…áÏÅÐ1«P.;HEAqòÞµò¹wƒA÷ÑD`hk£vøäóŒè½Ñ£GÎ÷ˆz$:«¬ó󽂾yÐX·º¾¯á:½sí7á3.àhýIEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/select_ogroup.png0000644000175000017500000000143211042032110023327 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéÑIDATxœ}“OhSÇ?ïOóÒ$vM“Ô¦´SÛF;‹"Øê<(°Q"x˜cˆTØeÈ`“yðàA=ˆ‡Íƒó¢ ˆÂÚÎ)£JT´¤ë´1µËÚ$¾ô%/y¾äý<ÒIë÷øåóû~/ß,¤ëÆŠ'ïþ5ûÄèØ¸yAn)‘2;v]Ë=øÉ¹,"ûnÏä}]Ûæƒµ÷è‘Á3›¾Zujqg}|ªÿÀh Ôû×nßùò^*íeŸ<ú`}ÃÉáÁ–ŒHô¶HxH¤iH$:,²î™ÈÊŸŸf€Ö¹¼ú~@µL-8àX HÄ`iòºj€a,p¼…XSµsó`¹k‡XdUœ†Óó@©Í½Ñƺ0býÍ_6nÝóßh]öísðBPP¡ä+o«‚>½IÝþÚºøï1@´ûÛŒî=¿vØO[OxCÝ3šÓ¯´ÚQt×oZèœNs`MŠþCñþÇÚX‹=<{ð´ƒ;{.Ä7ô­'ý^ŽÃLоâãO©õ¢2|¹Î–þ[„:ÓhÕñM-½©`¦Ûþ½pC—’­0ùÒYHO[ƒhœÝ«B¸©oø~{³ÉÇ|ÕÔUWIìïÚ匕&õªíB®ªáfDaéJa‰ý'–šå¯J™†|˜bþ5Á ºã,Ó?f4ô°Y/˜e—¼¶Á0T\M‚S¤VsáU©+ñÚçÐkGêø<ƒ‘É‹%Ñî¾(M|à‹V_m¥*ü—ƒY'[áÒX1ug…W?– Sæ “fÓµP“µQ-ç2qå¹ýG¡m^P"^¶ÌÕq;»7iþm¢²ÏKVn…áÏÅÐ1«P.;HEAqòÞµò¹wƒA÷ÑD`hk£vøäóŒè½Ñ£GÎ÷ˆz$:«¬ó󽂾yÐX·º¾¯á:½sí7á3.àhýIEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/phone.png0000644000175000017500000000142011042273435021604 0ustar cajuscajus‰PNG  IHDRóÿa pHYs  ÒÝ~ügAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF†IDATxÚbüÿÿ?###!2÷¯@¤ S? #CÂëo ÷_30‡à†'ø¾}ÿ3 €ˆ2 mþ‡•Kº tµ5¾0ˆ3\½õœáãßo ¿~~g ¢ øöù=#‡ÃÝç¿Þ½ÃÀ.fÀð—ñÃÿ¿ˆ‰>½~ $£ÃðëÏ?i G1®_ Ÿ_?c`†@e€¨¤ÓÿŸ ß>}d`ÿû–“‹‹áí³» Ìlì ˆ b&¾U`bø•ÏÌ!Ì ªcÄ +ÂÆpìø9n>fVö…DМ¬ ó¿ÿ)ðç÷f¦ ¿dxrç:ƒ ¤â†Z¯… ?Ïgø÷Ëáû·ï ÿþüdøÏÀÌpbß1E­ìÜ|‰ 5Ä‚#ÚD¹ÿôÿüþ5áã§o ÛÙ¹øNí[ÃÀ+"Å *¯¸­ÃäH-@¡³â¿‚ª8ƒÃÿß õŸ?ÿUxúþ+ÃÏŸ?¸ùEÎïZÌÀÌÌÆ ¨oŸ¸µÝèL@1‚’òäƒ /o\®ÿúùƒÃ±=;¬‚³¾þá`øô×@E—ö,g`åàbP4°KÜÔ¬·ÙR€‡ÁŸ¿ ûy8fö÷2üâVd¸}ÿÃo6†¯3œÛ±AXVõƒª¹»!ºf ° rW2Üÿû‡AáÏo†¯ß0¼}|›áÙí <¢ÀÓÞŒ²Ä•e2°…@Ã@ùÇ'Ÿq$°ðð0üþþ•ƒGàƒ¡[ô6Nž‰s’™à‹)€b¹ (¨û=ƒO ÀR×í_Ô8IEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/server.png0000644000175000017500000000155711002130510021772 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<IDATxÚbüÿÿ?% €X–.½Èð÷ï?0þýDÿgøóçÿüeðn|ýúí£‡÷ï%20°}üùóÇoþýcg8wn@± šÒüd˜“ˆ¨`­’š¬ƒ¨”óg?ýú'òøÁ£hÆÇÈ:ˆ‰‰ Âøóçÿ·áÙnc¯¹ÇÅSÇAQU€™™AX”ÁÎÝÖVJ^aûïß¿uAÁ@±5þ×HP»ZCKÜ_NA™‘‰‘áÛw†Ÿ?ÁŽbøó›››™ÁÙÛV›™™eÇÙ§¢ÿº† €XxyÙgijÊ%++ 01332ü*þþ $?AílìŒ VRLÌ[N=“üïß¿UÄ"//¬¦&ÈUÌ@PÃ/ a “X€üÿ@¯üò´½§/ß²óçü ¦×_Þ0\ýu¬‘(üïÒ ffˆ!,@Í<œ ÚÊ ¾>ŠÌ@  @Lþ­xQɰàæ*†ßELP÷ƒ4³2A4³³30ˆ 30(H•¨äâÿ ÿˆéÕ›S_72|úø“áå'†Wï 6³±B » ¨šƒ ‚AÀƒ‡Ÿ~ýúý €X®Þ¼˜öêÀ“9…yßÿ20|òá ƒÐ–wþþ1Œèt6 ×®|gXµbד5«§ÎyýúÜZ€bùõëÛ¯KWç¯]£óÊÐL§YCOñÍ{†Ï_!ÈË }†G~1lÞ°÷ÅÊ哿=x°PöÈÄñ+3Ã÷ïßZwlÚýüÍk«éÚ¦Úl 9÷õ‹ ;6ïzµaÝ´÷îîYüïß«HÆ@ð¤ÌÊÊÌðûÏÏy»¶m~úåëïe&úBv~·qí¤%7nl›Ôx ¨ìzf ”¼LeÀdܹeýBß™SÎ{?}zyËÏŸïObÓÄHiv0Ú'3Ýù/rIEND®B`‚gosa-core-2.7.4/html/plugins/ogroups/images/terminal.png0000644000175000017500000000141211002130510022265 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéÁIDATxœm’Ïk\uÅ?÷½ï{óœ¯N[užÑĉ‡´!E&DLDîE!‹.\„ü.ºªÝT܈;AZ³0DFÐ ƒ”I´¥MfœIæ53ïû¾_i)sv÷rÏáœ{¯ÌÌÌÌÍÎÎ~èû¾JÓ”‡Q(°Ö""h­íÂÂÂùùù÷®lllÜ+ ÑÖÖ¥R cÌ £ZDh4DQ„çy”Ëåó­VëW•ËåìÚÚ‹‹‹ ÑÏ€ã8looS­V™œœ4Žãd”µÖæóy:›››}ÉGˆãÏóh·Û°êAƒõõu¢(ÂZ{L‘ãZDØÝÝe||œJ¥r<£\× ^¯Ól6Éçó(¥´Öh­I’„â8>$*uMDp]Çq0Æ µÆƒµc Æ’$¡Óé`­ÅZ{bOÊq”R„aH±X$›Íâû>Žã`­EkÍ^·K’ ˆ{=Ò4=q)%"ˆJ)|ß'‚ @)…1†û©fì ÇóÝ}Ö”(‹¢”ê ¨R©ÄÔÔa:ÈdP®‹¶»ó—n/óäëg¹ûÌ{4_:ÇÍßö^™˜8ÿØéÓOÈÊÊÊ­jµZ9²›¦)q’ Ó#‚ýôQc‰{cÔμIðËçôj¤xé²¾þÍ×?ÉàààÅéééwD$0‡áô°µ/Zð~KÓß?º]{{äÕJ±5jheòä2{oñÝõïïÎÌͽ&ýæ x÷ÂeøøòH}xìܳŒ?  Ü:¥m:×®þ3õåjYõP ÏÁãËàÆqóW ²Ã`Ig°î —¸áøék^;@/ZªéÔªòÄ~̲^"È»±[¿ ;¶¿~¡6þEo”"J^µé4ûIEND®B`‚gosa-core-2.7.4/html/plugins/groups/0000755000175000017500000000000011752422547016354 5ustar cajuscajusgosa-core-2.7.4/html/plugins/groups/images/0000755000175000017500000000000011752422547017621 5ustar cajuscajusgosa-core-2.7.4/html/plugins/groups/images/environment.png0000644000175000017500000000133511002121753022654 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7Šé”IDATxœ¥“Mk$uÆUÿwOOwgòâîâz‰.âe=íAÈg‚ xË̓ä*¹ ^ý öäªBaut+‰DÍÎ&“—Ìôtÿ_<ÌèØ‚¢Š¢xŠzxÍO¾êõª"ø°èÆH\TUµD‘UDùõ·gƒ½½½Oäèèè|kkëîùÅ%j "‚ˆ!ˆc$ƈ÷žN–rkc•ýýýGvmu%9ùë%ù„;›wYéåTU‡¢ì`Œ"ŒF5£ÑŒfÖÐï¹×‹|óŇ”eQ)1Di’^Í ãÚ0˜*ƒ ¼×&ㆷ7:¼{;çj" ç–V»´­Ã{ÔEEÎáÚ–étN©ŽÄMIîä÷ßÊè_×´M‹wŽ<£ÑïV„þ‹·“ arc(så|ä¸o_ñËÉ„à<7“†áÐá½GTUQUFÃ)'Ï_0™ÌhŒåø|Ê ÃqJ±^ððÁÌnj.þ¼b6m—óÿ!M,Îþ>»f6¼aµ´ØDxöû€Ì ÝÜpz: 6ˆÎ{Ū(¢†nÙ!SKšZVË”‡Ü¢k!n®Ð¿ªùþ‡SònJÝTï<**¨@Qd”UÎÆFÁËë9ß>þ‡"OyþǘÇ?_P·Ðëu)ËYfñÞ`UÀ‡ˆEŒE³Œ:bHxôÝM©ƒÅdho¼(nÉÀ›$U‘°ÿÑ&C–Z’Ô`TD¢´­g>o™× ãI—7{ºü‚1öÉOO···×?ß~g©yÎá\‹sçÞë2 Þ§4­£náìììBÖÖÖìîî~–çyå½1Æ…þ—¦òÿa~!`Œ‘ËËËëÃÃï_×Íü ï'G¬k×ÏIEND®B`‚gosa-core-2.7.4/html/plugins/groups/images/select_group.png0000644000175000017500000000154411347630613023021 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéIDATxœ…“_h[uÅ?÷_þ4ÉMSÓ´5Ýfi»v´q¸neê:-¨µsÙVн¨ æ‹AÅ_öªhŸ”¹‚Œ‰Œ¹uâh·Zuk“.íÚ%MzóÇ&7ɽ÷çC· "ì<|ßÎá|9çH<ácá#G޾ÙÓë6òFá»±3ßN}}ý`íA\<}òËýò¡˜ÈLŠ+éIq%sUŒ§ÇEÿhßY@åþùïÉ<óp€åi›ÙÓ•à~jIZä››Ÿd#hŠÏ€÷ g8Æ-¾Ø¨ë>¸ëè‰ïÄZöá<ï\š¸v¶îÞ ©Ïiòê¸Tã@Á„¤ÇÓÊ.sSÀ¿mÇñѾýÐcQɱ@’Ø{éÙ†KÛ8_~_K ¿ªÔJðPM&³Lbó…èþWÞˆ´÷F'ç  k»‰'éiú˜FÝE¹"_µY+_®þå|µ)nnÝš5-,ÇÁã’A€YsÈZ‚ì!d @ ¯å!mX¤ç~ø È(ÞHçž}CÃ{u¨×5ü>M•±k*¶zƒ@}‘âß!L3Lз…Zg¾?9µò‡“áw 7?5ÓØ±ó¹§žè‰tDT"ºŠŠÆõôynºFY“§Y±gY©Í,ÍPt’–ºs?‰/ï¥PÎÞJ¬eŒ”‰¿ QΩ$SKÔÚâ¯@•ÀqÀ¬‚eBýN9èbPØú»Ÿ?ur¤Åï)ZÊ6nÍA—ûXÍÚ4·ÿL8~( Þ ;¡,«Ôoôé‘×^µ…E DÂI7bÕ%}xµÿ50æGQ4ñұܓx 8˜#îûò'ÂR‰3×úAª;ÎD®¼àºîN<¶þã·ÞQ~HºFH倂 :.ÇE®DWï ,î9K{z±õ†!´Ö›|ëŒåÀ–Û?zeÇß'¢îT:††&¤³ R)‚´N~fˆnYë8 ®é›·W(saϲåØpåU¸dU‚l3¤ãYsLa×ãaËlˆÆ~úÌP{ý9`ÿØû´ÖK¥º…p®ç#•É i^+Zæ·‹T:³‘øšŸßû¥à´”È.Y´ ·~ðqÙ»× È4AzifÂMAº>.¿â ¬^½ B QÛ°ùd&Ž£ûX@J i 7ZCf’€?CÇ "ðK_X ïÀ›àðÎû3m-­Á¦õ°tÑbåB8¤ãW $¿§Ö]½MMÍgAÝ8æÿ.N’Å‘& ˜É15“C¹\æÏB䦧1qb”Ç)pâ!*‡Ÿzðë·¥ñÈ[ý®Uó–twBRA0YH%„„dÂbÉân¼§ïâ UwcÖ9®‡7®·ñjTûö¿Œ÷<‡01èê~²™4ÂbÇŽƒ-I]`f&?pͺç2©` j ²U‡’¤cI£áH뮹ò¥’?w^/<ϳ«åùV®^‹ûÖØU³0Ú&àPw~ûøãH’d!Þ€Þ÷~GvÜw‰Ë}Ê $ÈXƒ))à ÒIMˆ¥‰¿Ûsé¦ús€ˆÜl6Sq·t­û !%‹r€“#sAW2|-„H½i8ªd+ü3k¸Ž™L\‚‰Š<+ó$D\*Ðw¸õ™3’ÄRÊ0 ¡¬‘<©PÔF Á¬Œ Ù M\_ßç]~ (‰¿Nå¢ÀÞ`ãKÌ‚A,€¢¿}z7þïù=IÝ^øß»Öœ{nÏù­óNÓ=ˆ5ˆ¨2gt´·byï;>„Ó ýªÛ~§ÃÂ(Y 3.V0‰MŒÃùˆ ¸nƒ]Ý-®#P­T¨Œd SÃÆs5!›Rp\w'Þ‡Ü^œ³^¨:A”ŸÄ£ÛC17 L¶nïÜðécÌ>[òˆ˜BÔ‚ˆçT!À#ˆ‡I!ÔCx ´´µNŸ˜@89bCˆ½hfGŽÙõq‰˜¦ Œº«Nâ¯$Qøåø®])“XdlìóHÖЕŠ"•¼ÿ×O?…Óƒs¤±9ÝÒˆÑ' &XoF¤0¿k ü_€WYö3"àÂë?óÐè®ï]Nº|%'NÚ–/„1-ˆøýÐ&¢’êß…¸§ÃØÎ{´Ùk˜‡ •¶ÍDà°ƒœü;†G®Ÿºë`!”úW®óŸ²äV N U¥¤ÚÈÑq¥šèèÉBªy7ªØ¶m[C&“YÏbßÝhmõ“ !ÄßȠɳݗ4%kO±ÍMM"­M­ŸüÅí—À9¡šû¥;diâGW\{c×’ùN{ïª%`L¼8Ê¢CUiˆd*Þ«€`t‚'·/%Jù™ôȉü{{ל‹Æ¶…(‡á'ã½[¿:òëoÞ¼àêybÎ'²‘™äÞAÇ!L¹Ò|4Ó” ÐÌÁáQ³sÏa[}Útx“ò²?VR,ñ}LÀIÁŠ/LCç& ó@[B*+ ÄÕ§0>'ÊãeÞ²(7°ßWŽ‚J·,Ž¿mäÑo/›³¿uÑþ#cEÒq™E°òI‘0sùŽOÆ#½=Œø”VÝ©¿å›BjŽW-¹‚žÝÒÉX‰¯|Z8Ð:†r=ıơgw✋ÖTš&¨’2RuQ®š“€¡ýOô¸žïgùLÐÅ›6¡nJmð|Rªîç¶7£pxC­[ ) µ® €²™µ 9IÂÆ8€„xÃŒã_|×h Síô QÝËëþ(¯”Žã­,KÜèa»:±Æ3Ɇ‰1á76ø-KžCS å­؃¤üYF×6„ì1[ÑÆ††1·" † gñÂÅâ}öqœÀ¡S„KõþÓ Ø±c Ý¥vcðJÊ9J^$‘Û¸X↰ ÊÔÚ@¦ÛàÏ_Îa”Z*¯Eœ‡™ìG2ÛFÅ°ÆØ°ªÕ|%!¤cçÆ”‘J¥8W`tlŒ=°—¢gåå¸ä†[ì=’$AFðß.X1vŒÀ°{÷ndš»VJˆö<çFßw3®£l½GZýqTF…öáÜ1áz|Ï£¨xÆzJ#âkC®T.‘?I ¢z¬’réuq¦Zm„ë#r›ÐÔÙ T=ùÚÎû©³sÑÞÃіïœ|`–ž|úà<.YßᆆÆ@¾k RJBJa ‚k¤<e++ ;X28µ7 )íjºlŒç˜V^%ô0ÂrÖÛ¬gY½9~l˜ÛùýÃCO<¿kbÛSû‹ÏØ?T/>@¯ Øÿò1504þP[KÃÚÖyYk¬’Ь «‡m¢êªÕŒƒ8]>ZØkmÕ`,€=åF3Û³ûÞ På0•J±F_ÉÄ Ï‰ê8*ä ñk¹©ÜàèðtÿˇrGŽM=:^žÊÿÍ^[ýÿ?p“”òíó‘ <+ åÛq–s1“XCÛ„¯}ŸþiùÒþ§Ð!§@›Pl(q‘Ž4¤çЉé~žúãþ;ýÔ3¯:€ùesSúý6l…l&°¡Ã¨K@­<ÆL"Ôâ|ç®=/]ù«/%Ô ‰J³YÎF_Æî„!@k²ÆÛ’K ˜4wZÙdÀ4¶zhC—õ]°¼gòÑ]{…!ó÷ë~­]:IB\iTuÓ0µÑLªÎr]¹ñŒP¼!1š6r©¬V+ÂÆ­€`÷ÛØ­‹FŒA¥“š×ü†ûò¤¬[ÀØäDK'‹=Ï­%¬}X9Nl*†øÓI„Dk»òdìÖÂö‹°ŸïÒ¨Ît.øüÄTþ ç,íX”ÍRk²Ç:Õ˜F™dÒþ)YL§ÌÅ›g7U^UoVXIB¡¤÷ô:rtìŽÔ ÆÝþDDãN§!±®½­ñêÎŽæ‹›3íM)„äî+*ÆŒ¶ùQ™ªÏ×ͺm­°wu>æ§s¥cLJ'~784õ+öôoTè}ö³ëP¿€Spç„LË/”—V X²tÚ_xN7‡Ó%e“5’!ŸE8D¤ª=J+)´”²Ä:f´¦)^õáR9ÌÂ~è'Ðpçòd æñÍ›q¦ ð6øâïCмHœ¿"+ôˆ´ïª†TVD"†k!Ç’Xñ~‡tD¦µ£•^™¢òK“¸ë®Í8‹³ø+Æï)›ð}ÁÕIEND®B`‚gosa-core-2.7.4/html/plugins/groups/images/mail.png0000644000175000017500000000117311002122253021226 0ustar cajuscajus‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  ’ù¥tIMEÕ 8õð…(IDAT8ËÅ“AKTQÇ×¹Ïy“ŽÃXf-f¶¬ËšSF#J ÄŒV­ƒ>F»ð[´rS)$”a%fYÒ€ÕÐ8Õ€ÙˆN>ÇÞ›yçÍkñ&ÜÔË…s/¿óçÎÿêÖkþß4ÀñqÄq%hD Jìà— ù]ÕÙàæí»@œ­‰öÚ«ìá]'H)A£)ëàyQò™,¸–_¾E¿^e`¸‹ª™@‰€´%ˆh´_å8ÌܟƲ~ "Ô Ž?azbŠ­õ¯ ¥=“DÐx.éùçLÜ›$Žp¾/I(d 0„Îs¼ ½aya%Ûô2 ÊösSÙÚ°h9ÜBÇ©ã˜õ:T*"”8y¦“lz›Õ•]žL> õÈ1ª;2éO|/¹ÞCì@Ó4ñ¤ˆRªf¢ë@CŒ•¥y¾­Y¤®Ž°[Ú`aî)ÅÂ&ÉîvŒx¯fÑvÔáDW?‹>Zר;>[kÏXÏåI^F×—‰57Ñ?t϶AkB†"u9Å‹™Çìk4Ù0JX‡ó¹%²óô^£1ª78Ú$6Z{44Çé$“þ@î}3\(ØÞ´8ÝÝGµºJ¥¾ :€ ÔaW-|?†á[(ªœ½ÐÃâì žç£üùKöÆØ.{(  HÖnõÏ·ñM¾ÕÓOa’—IEND®B`‚gosa-core-2.7.4/html/plugins/groups/images/asterisk.png0000644000175000017500000000142011002121753022130 0ustar cajuscajus‰PNG  IHDRóÿa pHYs  ÒÝ~ügAMA±Ž|ûQ“ cHRMz%€ƒùÿ€éu0ê`:˜o’_ÅF†IDATxÚbüÿÿ?###!2÷¯@¤ S? #CÂëo ÷_30‡à†'ø¾}ÿ3 €ˆ2 mþ‡•Kº tµ5¾0ˆ3\½õœáãßo ¿~~g ¢ øöù=#‡ÃÝç¿Þ½ÃÀ.fÀð—ñÃÿ¿ˆ‰>½~ $£ÃðëÏ?i G1®_ Ÿ_?c`†@e€¨¤ÓÿŸ ß>}d`ÿû–“‹‹áí³» Ìlì ˆ b&¾U`bø•ÏÌ!Ì ªcÄ +ÂÆpìø9n>fVö…DМ¬ ó¿ÿ)ðç÷f¦ ¿dxrç:ƒ ¤â†Z¯… ?Ïgø÷Ëáû·ï ÿþüdøÏÀÌpbß1E­ìÜ|‰ 5Ä‚#ÚD¹ÿôÿüþ5áã§o ÛÙ¹øNí[ÃÀ+"Å *¯¸­ÃäH-@¡³â¿‚ª8ƒÃÿß õŸ?ÿUxúþ+ÃÏŸ?¸ùEÎïZÌÀÌÌÆ ¨oŸ¸µÝèL@1‚’òäƒ /o\®ÿúùƒÃ±=;¬‚³¾þá`øô×@E—ö,g`åàbP4°KÜÔ¬·ÙR€‡ÁŸ¿ ûy8fö÷2üâVd¸}ÿÃo6†¯3œÛ±AXVõƒª¹»!ºf ° rW2Üÿû‡AáÏo†¯ß0¼}|›áÙí <¢ÀÓÞŒ²Ä•e2°…@Ã@ùÇ'Ÿq$°ðð0üþþ•ƒGàƒ¡[ô6Nž‰s’™à‹)€b¹ (¨û=ƒO ÀR×í_Ô8IEND®B`‚gosa-core-2.7.4/html/plugins/groups/images/new.png0000644000175000017500000000161711002120005021071 0ustar cajuscajus‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ .6psŒˆIDAT8Ë…“[L›Çߥ¥( ¬ Š,f0˜£0¶Œ8Lf4Ø9¢Ën‰ãÁd&Í4$.1ºd\²¨ñÁòà%.v]2:Í4)#*td,ÛÌ]˜t-ÐË÷}LJ"îmÿ‡órÎùçœÿÿ…‡ dA ½}×ëëVúk“3ÉÙ3'{¾ùêâÀôÃzqlT÷zW⃉ J$~Azc½²ùðÆ³€Îá¼­òLy“Q“±îta«çÕÛÊ-¾¾ú9(&"`ÓÜ8Zœ;èa?×øb™ÀU»£q×+Û»Züe[±ž³úZþ8ë:R÷ËÔ Jìº`Y0›‚›æ Ž SËù«Ö<üÎw/·5øËEa‹ï³ô¯âü⋸˦ÈσŒÙx4«ŸdbyßS¯yW×ù¯Ï‚ à±5áKYWzœ;‹i…ñ{&·O.þš¹b}¹LP²²¢2‘20, ‡]TÖ"a¤)dÅÉí°€ÓpKÄþ<÷;МÞêM[[[Vx Èc#ß­cÓUÌ¬Ž©RP4Gçù0®^áÒÚÝd«g6ß¹{ÙŠsIÉIèôí9öÍÚêÊ AþN@àû\º½ÁÇéá;¤-•Ýõ•œ½â8„gÉ…Åĵ‰éxr*E~@!ðƒ‚å™äôð–s¾‚S'† õ¥Š(Ss @åóGCo V™ÜO9[í/ô¹!ø°xbÉð1 Ýajúï+­Yàß"þ*¯Ë¦š¨j®Ì4…tFç174Í¿å‘&†ƒõµœ{s¼K¯~²mgÕê —ª§qäiØm9Ó†Ð9òà±Aó{Ðåãî0JÇuÿ¶ÇJtT1ñ¸5\vh=£-i†ápNƒ¬ç§QXoXZ°ü–0¹@㞣Ÿ}24-?߉fD&Dd\D¢Y !Bžîèê‘bvÛÀüˆ¬„r÷¦yNoMk]Só¶šÚ5{‹‹=hš27?¿ð×õñ£úîND{%Ä?–`h‡°=ø~ÿÈòET£ÅIEND®B`‚gosa-core-2.7.4/html/plugins/groups/images/samba.png0000644000175000017500000000124311002121753021371 0ustar cajuscajus‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  d_‘tIMEÔ &(2*­0IDATxœÅÒ=LqÆñï]¯×+M TzmTÄbRÔ`ÆÄ(!!²029828˜8Ó8°šHÜd1ÆÜŒ«F‚˜à  ba)ÐÇËQ®½»þÿN ¥†ÄÉgü%Ï'ù%üï(GÅG²Ò-ç*s „Ú…Ôö˳‰‘»c´£n&©8¸»†áKœâ+1%“›¹è6¯ (*š¢£+úâPzd²°ß¾Ì8ï_ôyß§ G}¤dÛÒX,‰LÁ‹=\ØÑð…J‹a’2Rï€Z!nÏuæª_?¡†(z+bÁØãËÞ4ò°[ëÉO Ô¿ íoâuJ]ý¸q¨:ò1…e½Â– |'ô™hw=ðÜ`Ëvù)‰#¹šÞÂ2¿á4La—ÂT\A2eõ ?Tõñ:àÙVJžÂúA€¦°ŠÊ*]ñCñ8M;¸¾Cº±˜Þ¸Øvh¶xòºœUάlH´f ¿Âvwi‹æ¹”Þ!»Áw!atÖNsŸ7µ/Aîb«:¼Vô ê’H@!ݼÌIsÓüŒQÀOdëw`í ¦äZ ,³±íÐÖ¼D‹Q[¾„p3xZg= $cj€§!]’LÈøí~÷¦ªñØ”UðM4wyÌÕnLöê¦ 0?·FÆÔhˆùŒ&VP|Ï6Ü_ªt&”ÞùßLJ)®[9Y.ôÉÊ:Šô¶{Éó7­ã:ÿœ?=eßÞ àaOIEND®B`‚gosa-core-2.7.4/html/plugins/groups/images/menu.png0000644000175000017500000000167711002121753021265 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<QIDATxÚb,Ùú÷" 3ƒÄ«¯ ÿÞ}g`á?¾þf`ø÷ þC13+Ûó¥9³¿ŸšÚäþÉ‹ï?in6á¿@Å_~20üúÃÀðöÄF&`dbbø4ü÷ïf@®8?‰‹®ø¿ßf2@ãþ%†üÒ†ýcxôä Ãÿ¿ÿþÿÿäÿbàæeh<òçÏ c` 7; 7H#¼þð—áÛ×? êÂì <\, ï?32¼|óáׇo <Ìœ| Á  †#÷ÿ>ÚðÿÛïÿÿ¿üýÿÿÁë?ÿ¯ÞûõÿÛ÷ÿ¿ÿüÿÿÃ×ÿÿ¯=üÿÿüÝÿÿŸ¾ýÿÿè‰'¿u }Z ® †ÃP¾ xýíßÿ‹w~ƒ5ÍúÿHúöÿÿí'ÿÿßzüÿÿçoÿÁ`ëΛßyù¤B@úˆ Ê ÿðé?;;Ã'``ýøÅÀÀÆ Ä, Üœ b‚ l@oº¹¨q88‡¤µˆ0|ÀšAø×oF†˜>cáÆÊ›·?^½zËÀÌø‡á'0jß}Š}a`Ð3²ÒjÑ &PÀýòD3B4mÿTü¥G/ÞgغÿË×?Þ5¾ú4ä3¿ ˜0,eˆ…‘‘‘‘âf`°H 10ò@œ â«ÊK1ˆòó0ñ³$q1å~~ÿ4þ?+@±übdäú´k ?Αù•C D%.ÆÏ ªÀ &Fhx-»zñäk ó @±ÔäçLaüùј^þ12°2µÕ6ظXËqƒ¼ñâ=Äk<À@ü 4œ¨Q˜`.\ýÀ°{çªK@îÈ"}r@¬Ä’Ž)eÏñýe'oÿÿåÑÿÿo>ýÿÿ…oßÿûïãŸy¨6ˆˆ `rðH­Þ´ÿÉ—S÷þÿ¿ÿ˜ÈþÓïÿÿO_|ùßÝ'íPM5«€Ô# $¢èobá-!!$ËÊÌÈòòåÛ?§N¸÷êÅ­ý@é½@ü”ú§PÀJ,Po2@³ð[ þ M Ô€i‰–ºoIEND®B`‚gosa-core-2.7.4/html/plugins/users/0000755000175000017500000000000011752422547016176 5ustar cajuscajusgosa-core-2.7.4/html/plugins/users/images/0000755000175000017500000000000011752422547017443 5ustar cajuscajusgosa-core-2.7.4/html/plugins/users/images/select_template.png0000644000175000017500000000100011042034367023301 0ustar cajuscajus‰PNG  IHDRóÿabKGDÿÿÿ ½§“ pHYs  šœtIMEÕ·+ÆÝIDAT8Ë’½jTQ…¿sîádžÔF­$ÓIÀ'°2ÊÖwP,´³ õ | *ÁAˆ` ãÌósÏÙÛâIÌ8«Y°7{±ÖÞÛ\»÷õåùæÔfNf…2iž‰­|&úžý¤¯K4w¨ïQöoºs«ƒëWw0Ùæ-L'ÐÖÐV ]†¬;@ °2BÞ]rΘ°±Êp6€0‚!‡ì=„³ŸàçJ)à*çŠ/»µ¸Ë#ek ”Cè1úæwíîcxøÃâ*À˜#-ÃBpVÅ)59Y%eEE±ZX "UÁ¢º”@« {ß²µ"²”ÀÙjÂʰ»¤D Mc±üá@DŽz|"PŠ.AEü`-Xkþë nüÝŸ}€™‡à!FC zâ+¯]l0ÆâÞ|<¸óyü¶N>‘CGN‘œ:JÊÿt°³Kï ªÌýÓµÁŠ¥hE6Žl”b”©¯¹>xÅó«Øz¿Í£ÍÜ~}‹'O‘uøg™çê9,IEND®B`‚gosa-core-2.7.4/html/plugins/users/images/user.png0000644000175000017500000000455011362006411021114 0ustar cajuscajus‰PNG  IHDR00Wù‡sBIT|dˆ pHYs11·í(RtEXtSoftwarewww.inkscape.org›î<åIDATxÚÕZ]Œ]UþöÞç÷þÍok§¦EZK£jLùI Š/†›h4áE“†ú`;J|0ñˆ©ÑD,F DE0¶$QkšV uœÒ™)3s§½wî=÷œýã:ûœœHˆ@ËŒw\w¾³öÚ§³çûöZ{÷œ=ÃŒ1ø6Ž´§~4Þ{ðàn´eÍÀ¡ñq§3Œû<á|9êt6Ã?Møç„#Ž'muÿõ_ùÆ‹«RÀs?Ýÿi(õ›¨‚Ìó}øažÂñ=á€&þ}³6{ÛŽ{åªðü£ûïŠÚ‡ŒIÇÓ`œ#(•–ªðK%øA ®ç I‚¸Õ¬‡Q4rÅ®»›øæàCÚ ?ûþ–8Š$ÖÌõ<$qÆ8G¸”ß ÔŽ¢%@ë¾6ÔK>ÙýE,Õ R)®•„L:pý Œ8*‚¶^Iig^ÊÚfœ‘çŸøëS}½«xæÁo]G|FZ­6ZQ!•K\_„ç8èó|"©¡HD܉ TÎÅŠÚ`œ²Ñù6€wM@;Ï¡6ÐÏ}ö7„bN;†“Ç_™™F©RE­§ŸÄ•a’\°¬Ä„@’È¡®.âçÙÿâ\}ñº[wÞ Ç À½ŒDpÇ]0ýÖi8D´Ö×ŸŠ…VJE8õê1L½ñ:\/@£ÕÜôÅ»¿;Ù• (­G!ˆ$x ŒÆ¬¾Ô‘bÎ5l¹âJtÚ-ÌÍ̠טìÎ"fÌ÷ÃÐø 0óKQg¢hS#›¶ˆ6•–7Ôµ]ˆQµZËùæ„­euN–ù¼ oãr­Žë NôTWœ~ù`?í:S}UK2'ö.‰ïV;ÔÛ?`†/Ù°³+’$Þ³aãF§Vö Vï6»IXè¼Â>6:Ú®èN )Çùç9£ÂqQ°2¹‡yg»ˆ-Š~×Âhý«®Ø|íJ&o2'Ð&#_Ô;ã¹¹B€.²@fÛ2‰K<OumkÇã¸5Mä­E hK8 Å©W`©H¤Ð¶/Ž£'/½iÏl×|tšOÅŸ§äŒ%.©©¤Èg\« &ó •ødfývµ§»s»v©8Ö±Tb‰AvÈÇ€Nräm• 4 …QŠÇiÕõ§Ñákvµaä/µ’–¸E!B!'¯Id’Ýã2ytÕ¼+•ƒÆÂ,Œaði-TÖ#삦¸V !8ËdÒà'¥Rð€ùeÀÈææ··;ê0Ün‰¶®9D†ÚŽ@:VDBâD‚‚bbÓ~ápøžÏuŠ÷åüù¿Õ‘ÖæIÇa»®ûò²˜™YØZotž¨TümaàYNd9xÎSƒ1õ­ÁÉ_€Y™Ïd±†9ê ~' ùûE ˜œœ½qn±ýô`_µB OÉ’'pjsVì,4ŽõaEL¢8çM­Ùí¥’óÜÅ,âp®=ÑS+UÊeÏκ,i‘–N.|( 'C¡¶kCWŒÑ¿ÐÁ&NÍ쯆þ`¥ìà Ÿ]cà Ίœ`°}”>G^NÚd ~mÔÀR»ó  :±Þ„Ž­ñü®çdµ¼v–,›}cÛv\¥™¨;<(>ð8uzþ*ÙIþV)ŽcÆ.N› ƒ•4;~’H˜"Î2¢•¾a` rè}3pàÀ7nÇ÷„oëÜ ­AHGb¹ÇJ¡ \ºd7„‹ÝØû ¸úê«=Íô­LÆ~RËëQk»%J¬ÐÇþVÇd@ƒ<£;š}þ ¢g›`¬÷‡jÆB)F™è™}£‹ !µâ(RIv4í«ÞSÀ‘#GÜf¢~àyãÅam¶ €XJ»¥V¦zƒÒôE°žb Çe8;׸ýWÛ·o—'&f˜_hHÎ×¥K–Xë¥T6Žàˆ¢xEÎK•`ן+„ýyS§’£¯L=À¼ç.4>Þ¿î— }óòˆ¾´i¤¯R­„ÙÌ“€¾ž²-¥ÅÅ&zzJ¬ÈücíÂlOqÉËÑN¶õE©äÛfœ$DXØ{Q»ƒ“Ó 'ß<ûxƒñÞÿµ& Ù{ @!dœ}Õ;>qâÚµk×Ü=¼®o¬V+õÖ*(—|Äà8RUõèÜ#f³ÙO+++›•JFEÁív£V«ã8ìîî–UUýÙ0´øF:NƒÁÉ®®.R–å½ÅÅůÍfÓäñxhš¦»)Š2$“É÷gÿâŸü~ÿ½d2©I’¤MMM½–eo,--ýEQÛØØ8 …B“º€a˜_¥Réäøø¹\n Egggïg³Ù¼Õj%æææ^õõõ]ÓÂáðŽãÈZ­Y–3§‹jµº™H$>ooo7½^ï%A"g Ãt›L¦n‹Å‚ÃÃÃJ¹\þÖoÆãñiI’¾ìïïcgg§r¦¿Ë庹ººz”J¥´™™™·¨ö Çq·FFF±,{]÷ˆ<Ï?æyþV7 £?5PꥒÙIEND®B`‚gosa-core-2.7.4/html/plugins/users/images/fax_small.png0000644000175000017500000000142311041622050022075 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéÊIDATxœ}“Ík\UÆç~ÍmqlF‡‰ &T‘j¦D4PÍîDPp#Ø”ü Á£EÑ­û !›l])¹¤¸2Ö‰À|Ü™0¹s>]Œ‰Y^xÎy~¼¼¼¼â¬­­}Üï÷Y–Çãñèò:çäÎÎÎS@\þ ^X^^þ2Š¢Ûa"„Àó<<Ï Ñh|†áûJ©çþuc£Ñ¸¹¾¾~wccãÇÕÕÕFY–H)QJ¢µJ©êÉÉÉË<Ï»¸¸PþÖÖÖ·›››?äy´Z­?ÿôø—0ðƒAO }FÔaš2L =zÝ”ÖýVK;ýöááá‘$I{eee!Iâ8&5oð¢sŽ5 à‡µŽ¾Oµö'GÑ”÷xøýïƒ *EQ ¤da~žg¿Kžw-¡`c¹}3⽆ã4os¿öKw–š”ÒeY†Òš0ŠøîÓ×ùæ#‰Ö­5eY’ç9BøH9Á™;¼ÃªTh«+”’¢(ÐZ#„ ,'(¥ÐZa´!Ë ²<ÇZ‹Æ¬±+ð}°ëJk´šv ´Æ‹µ˜Vc  €ÿÖZô¿Y–ÓªƘ+¸­5ƘéAcDQhcÐRR@VðâÞ}/çƒø.B¬µWËäû>RJ<Ï‹ƒn·{>;;ûfõÖ-ÎÓ”`~?¬P¹o¹”V8çpΡ”º4r||L’$Ï‚v»4›Íw=Ïsã,c 'b¦| ­4#=º2c(Ë’ÝÝÝ_÷÷÷¥iú„8Žæææ¾¨×ëõzýó8Ž?ÙÞÞ~*¥tyž»~¿ïÎÎÎ\§ÓqÃáйÅÅů®ÂT–åi§Ó9½ž‰jµú2 CÂ0¤R©\ Ñ9G­V#Š"ïÓ¸··w¦éÌd2)®ë¾ï ¥½^ïKí/bÌ®{‹õIEND®B`‚gosa-core-2.7.4/html/plugins/users/images/select_user.png0000644000175000017500000000117411362006411022452 0ustar cajuscajus‰PNG  IHDRóÿasBIT|dˆ pHYs»»:ìãâtEXtSoftwarewww.inkscape.org›î<ùIDATxÚ’MkAÇŸyٗ즻ÍÛFR+mJ@AªÖ‚ò…~‚¢=y¼ôâÁ‹ŸÀ³býBA{¥„F jh ؤl·™Ç*”M›< <¿yæ?ƒ”R0Šõ—(!Ý ×d Þ<}tf8dïÂ0Ê—ª5pg—¨øÔ¹«·p H Ï©ò`Ã/¨yÄ´_A2ȹîÔùÅE@N„úgüüó[c,Á·«¹J¹0@†U ¦ ¦a¥ýÚLý;h޽«pÏs;€0 JI˜ð&Zc šÍf¢~ (é%JR÷²n¬µ¿¶õAÅl|\gùúåí±CL± ýÍOå˜ ÈOéøcO$œ;[hÌ_Ëõ!˜ž­ë>VЈj¯·÷ðw?ÜÒŠäÔ‡âô¼2J "¥l1Æp.‚ÌŸØínbLž9.Å“4}Œñ¡¦@]2Múò@0dœlµíOU}öL@Á(ô ¤ÚÍÙF`™”¥G|éôî}×Ð>ÐÂ#Kþ-)¼pïúÁ+ìôªY%RoaJ1œ™W*`,†0bRç4w¢èÿÏ`eeÕ fJÍK ³·r¶}Z*áJ¶T¡é±÷Y¼ùþCû æ“kËË9hþX•öÿ±ÆÂIEND®B`‚gosa-core-2.7.4/html/plugins/users/images/wizard.png0000644000175000017500000000107311042041367021437 0ustar cajuscajus‰PNG  IHDRóÿasBIT|dˆtEXtSoftwarewww.inkscape.org›î<ÍIDAT8•’?hÓAÅ?›Æui°µX´%RAAÈ'Å©¤q‹”BJ@›Á!:' *u1"J¢ÍR)¨ƒÍ¤¥Š¦Sÿä—æ÷œZCú7Þpß;Þ½{÷D=«¯=’Ýóµ¸b°8Ù?n›²‹ÉƒW‹ctT }Wª³}ù™œ¶l(P}ÞsYVQ*çdÏ_—ªõ{îØ[ p4žwPë‘«×±÷èiôœ.Œ{?0ÁÔ“Ü5`A’M#$a]b{íM÷{1g«Vª¯$ë±dõK£¹ŒÎÕ2hP«Tøø¬V²·u8²µ½§%ÑŸw˜ tîfpöecÌÅFFÒÿ…1h±ÞóÁ¹ƒ=Ó/Y·îÏäÿ¼ë¬Ðvx„›?¤/+ž°"È©_LG‡ÏŽE"y<žS@ëÒ…ëþ‚$þÞæ\f”€;“ÉÌI }S=XÞ€VID£Ñóñx\>Ÿï àÚ´@=Óéôçp8œ<ëö`-¤R©¿ß¿/ cÚ6 q5&‰B,ûìlÚ@6›*•J]¡PhØãnÚ$¼^ïƒx<þصܡf_ x t, üN ioàrËIEND®B`‚gosa-core-2.7.4/html/plugins/users/images/small_environment.png0000644000175000017500000000133511041613432023671 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7Šé”IDATxœ¥“Mk$uÆUÿwOOwgòâîâz‰.âe=íAÈg‚ xË̓ä*¹ ^ý öäªBaut+‰DÍÎ&“—Ìôtÿ_<ÌèØ‚¢Š¢xŠzxÍO¾êõª"ø°èÆH\TUµD‘UDùõ·gƒ½½½Oäèèè|kkëîùÅ%j "‚ˆ!ˆc$ƈ÷žN–rkc•ýýýGvmu%9ùë%ù„;›wYéåTU‡¢ì`Œ"ŒF5£ÑŒfÖÐï¹×‹|óŇ”eQ)1Di’^Í ãÚ0˜*ƒ ¼×&ㆷ7:¼{;çj" ç–V»´­Ã{ÔEEÎáÚ–étN©ŽÄMIîä÷ßÊè_×´M‹wŽ<£ÑïV„þ‹·“ arc(så|ä¸o_ñËÉ„à<7“†áÐá½GTUQUFÃ)'Ï_0™ÌhŒåø|Ê ÃqJ±^ððÁÌnj.þ¼b6m—óÿ!M,Îþ>»f6¼aµ´ØDxöû€Ì ÝÜpz: 6ˆÎ{Ū(¢†nÙ!SKšZVË”‡Ü¢k!n®Ð¿ªùþ‡SònJÝTï<**¨@Qd”UÎÆFÁËë9ß>þ‡"OyþǘÇ?_P·Ðëu)ËYfñÞ`UÀ‡ˆEŒE³Œ:bHxôÝM©ƒÅdho¼(nÉÀ›$U‘°ÿÑ&C–Z’Ô`TD¢´­g>o™× ãI—7{ºü‚1öÉOO···×?ß~g©yÎá\‹sçÞë2 Þ§4­£náìììBÖÖÖìîî~–çyå½1Æ…þ—¦òÿa~!`Œ‘ËËËëÃÃï_×Íü ï'G¬k×ÏIEND®B`‚gosa-core-2.7.4/html/plugins/users/images/default.jpg0000644000175000017500000000470611041606710021563 0ustar cajuscajusÿØÿàJFIFHHÿþCreated with The GIMPÿÛC    $.' ",#(7),01444'9=82<.342ÿÛC  2!!22222222222222222222222222222222222222222222222222ÿÀÈ‘"ÿÄÿÄ;!1V•Ò"7AQu³aq#¡2Rb±BDr‘ÁÑñÿÄÿÄÿÚ ?ô;.˵j¬[z¢¢ÚÁ¦ž\2™òI%Nsܱ5UUU¹ªªíÌï5ÏáL—CÒ,Nï-¯J¥öšP?¨– `|º‘¨– `|º’€?¨– `|º‘¨– `|º’€?¨– `|º‘¨– `|º’€?¨– `|º‘¨– `|º’€?¨– `|º‘¨– `|º’€?¨– `|º‘¨– `|º’€?¨– `|º‘¨– `|º’€?¨– `|º‘¨– `|º’€€mû»ËkÒ©}¦”ý‰ÝåµéT¾ÓJ0 ¿bwymzU/´Ò€Ÿ±;¼¶½*—Úi@·ìNï-¯J¥öšPö'w–×¥RûM(À6ý‰ÝåµéT¾ÓJ~ÄîòÚôª_i¥ó¦Õz±šH™«sÚ~ˆëʦž‘"¶¢)ÜÔFOä›Àª©ªŽ–$r+ÕŒW«©¤¨›òET?qLÉ dÍ^ÚŽE_#Ç–éÅ#§©£«T©cÓEõí1É|”ýÁ‰×E<-£¨ŸE­OËÒW&ϦïÝ@õ†×ÂêÖÒ¢®“™óäÉZäú*)÷–VDÕW.Ü•Q¨»W/#Îê_Y;kgki2‰XG$ªxªJŒ_ð’FÙâ¬Uk²bÈV}²\óÐ)ê#ª§dñ.lzf™Ÿ7WBÚ¨`Ï5™XôTVìðÞyZWâ8M4qË Z™æ‹½>àGc2btŸ±y°jˆ¡¬Š%{¥Y2VŸǢ¾Ëwí·#6ï\ÔÒ¯c§²±öU½Õ¡™VUn–Š#Uw*mÜf ‡´°ùp?…ø}4íXê*’J§5wµ½”Ëý(ÕýH?…ö<¦•ÉŒ±…ÒÉ£ ÿ1*mÛý)³?5Ùæzu}k±Zæ9ËùIÛv^‰š ÖZ«%lrQ3I©¤“5¹*fž?OàŠ°ç«©ÓÈØÖMäîÓ7g÷ÿ’Ô oØÞ[^•Kí4 'ìNï-¯J¥öšP!¯ù§J$tRG,wÊ|J›Xï¿r@ßt FIQIVŒ2|´®Ý*àøf'%*ÉÈ®k‘Z潨ºLÝ’¢ìTð8³ÙV…Ïé¡Â¡Ã¥{WåUSfÍøfÜòTúcï.3©`©j¹Q\¨×¦ye½6œŠ ^çLœç"5舺^K÷8×Q͇â4U £5<®‰éäæ®KýŽ9¥q\ ԪĪêkm¸eªsÕó9Îz9î]ë’.Gæ+2Ïš‰Õ-¶irk´\ÔtŠ­û®yÕÙÖü(ÂÙ £? ,ÑLÔþ}5vª9dq|§K¢åT\·®õUÚvÔÔøF A%‡CEÏlŽF¹Uì²EDUÏw‘À©§­†½Ñ¬Z …4³råšyÿÒicÑÆÙäžßÚn“ÛŸŽåEÿb䇰Û¢¶XUµq¦’=3í5|Ë€0 ¿bwymzU/´Ò€Ÿ±;¼¶½*—Úi@ãVáô˜„_.ªJß Ój~§$ÓÅnÒÒÓÁ+–(â—OESI®OåTSéQoauNêHÒHÞjµ2ÚŸC´uÌÁé–9¢¨k'ŽEØŽb"µ<³>1Û´TôΆ•¿'7éf›EóC·u5ÖÞ_#$’•‘ªŠŽbe¹O»0št’e•­š972F¢è}”ç€8ÔÔÔsà‰®j5vªìC’ß±;¼¶½*—Úi@OØÞ[^•Kí4 Ûö'w–×¥RûM( û»ËkÒ©}¦”`~ÄîòÚôª_i¥?bwymzU/´Ò€ aÙw¥«KbÛÔõ. ña”Ì’9+âk˜ä‰¨¨¨®ÍfGy¯và|Æ kÝŸÅx1‡¨kÝŸÅx1‡¨÷gñ^Ìaê÷gñ^Ìaê½ÙüWóz†½ÙüWóz€¯và|Æ¡¯và|Æ kÝŸÅx1‡¨kÝŸÅx1‡¨÷gñ^Ìaê÷gñ^Ìaê½ÙüWóz†½ÙüWóz€¯và|Æ¡¯và|Æ Ä?ÿÙgosa-core-2.7.4/html/plugins/statistics/0000755000175000017500000000000011752422547017227 5ustar cajuscajusgosa-core-2.7.4/html/plugins/statistics/images/0000755000175000017500000000000011752422547020474 5ustar cajuscajusgosa-core-2.7.4/html/plugins/statistics/images/statistics.png0000644000175000017500000000042611426477024023374 0ustar cajuscajus‰PNG  IHDRÍ'‰sRGB®ÎébKGDÿÿÿ ½§“ pHYs  šœtIMEÚ ,f¾–IDAT8ËÍÓ¿ Â@ÅñÎà"®aéÖ–N‘Â%\!„L¢8„`¬› !4BðÁ»âǽoñîwL œQ  .Â, w•Fá!§} ì Pí¬Ï°²e6¤ sõ)Ño>Ig°î —¸áøék^;@/ZªéÔªòÄ~̲^"È»±[¿ ;¶¿~¡6þEo”"J^µé4ûIEND®B`‚gosa-core-2.7.4/html/plugins/statistics/getGraph.php0000644000175000017500000000135711430727621021501 0ustar cajuscajus gosa-core-2.7.4/html/plugins/posix/0000755000175000017500000000000011752422547016177 5ustar cajuscajusgosa-core-2.7.4/html/plugins/posix/images/0000755000175000017500000000000011752422547017444 5ustar cajuscajusgosa-core-2.7.4/html/plugins/posix/images/plugin.png0000644000175000017500000001063111035061216021433 0ustar cajuscajus‰PNG  IHDR00Wù‡`IDAThÕ™yp]Õ}Ç?çœ{ߦÅÒ³$K²mI`lL1 Fn IÍjHC2M-i–t&¤tÒ6Îd™NgÚi˜f2é„6CÖS: %˜Ži°Iâ [2¶dYë{zw;Kÿ¸÷= ,Ùþè¹ï¼åžs~ßßïûÛÎÎ9þ?_Þ/óðÀÀ @¤Ÿ}ÏÃó<´Ö8ç(‹²³³sÝÚµk7 …µ-ÕjÕ|ø:ôbE”!įµ¿øe(´ÐÆœµ¬]»vë–-[îºôÒKohmmõÃ0$’DcŒAç)òù<Åb!|í™ÿøŸvïÞóÝZmîõ|¡ð+[àWF!¿sýõ×ÿõEïz×ÕÖ9¦&'©Õjh­±Öb­¥¾¶”²qçr9Z[[ikkcttlâÉ'Ÿ¼׳»þÎS^ •üíè #.Üxá=7îØñ¥|>Ÿ¦V 2> ”Rg_W(BÐÞÞNOo/û÷íßýð#ß9;;û¼ïù¿=«V­* m{àò­—øÄ‰è$aÆ ô._ÎäÄ»wïajj’|>ÆÜ(ŠèîîfhhÌÕæØµk¯9ÂÊ•+BßÿÁ÷?=|lø[ù|î7 ¯omùòËßûØúõëß;<<̹çösã7ÒÝÓ €’Š™™yäaž}öYòùùÇ45•°ÆâyŠ(Šð²°úÐCñøã¥R‰ë®»ŽvìÀhM’hú²{1ùä[i~ppð\cÌWµNRòG·ÝÆ’Ö%h­ÑZ³õŠ­ô÷÷sÇwR*•Ò³pé—…u%õ¤e­åš«¯aÓE›¸æškéééÁCP xß•Wñ¾+¯djjŠ$‰Ë¾!9çÒµ»Þ’B«×¬ùžÑúæÞÞ^n½õ¹å–[Ã¥JI Å":I( cR5Ê ’qDuÎ[‰k~7BŒÑ(¥ÐÚ€€$Nˆ“cÒ܆!~Ï=“Bgµ@ÿÀŧÇÇo‚€îîn~oûv‚ ÀB„$qÒ&uȪ¯"Nþb옾qüZÄØgq³?Æ™9¤LŸwÎb²¼ 8ç0ÆP,¸ù#AkM¥Razzæo”’­g«8Î  R™½gnnŽJ¥Âµ×^GÛ’6´ÖÙ¯.M5"õ!!!àøƒˆÿ^ÃîYh!w|ypbß'0N eºmÝúiòu8ë¨!›6mâ¼óÎ#Žc&''z¢(ú”‹‹ºè·==½Åbq»Rжöv.Þ¼¹¡}ç,6#·È¬Ä-—Qi¾§À,0—Ž•h=£Þõ$I’–SÙ<‡ÃÙtͺ‚+®ØÒÕó>™Äñ;044ôþmÛ†*—ËÍÖZ.¿|+]ÄI’nd,Öºtã†û¸Lók¾ÉÁ⻃êôf&ÂsDßǡⷩ߇3Ñtóu“µk°ÖR­Ty÷æÍ¬éëÃCÛ’%ƒ[·n}üƒüàÖ7ËÛÈK—.íܸqã׬µ7=õÔSœ:u €÷¼ç=ÄqŒµ)BȈµ8i±6¥„sà{޶fÁéøR&“-L£qÂ,M„|“jݵÓPˆEƒ1­5QSÈçÙ²å2^;r„½{÷ròäÉ«ûûû¯¾êª«¾ýÊ+¯Ü9:::Y’R^Q,¿c­í ð®\.óð#²lYJyär>9?‡ï{¬ëy åy©©¥$Žcfgg‰¢¨Q’‰ÌZžçÑÜÜŒïûèLXeç8މã˜(Š Âk-?Ý»—Û?ý)¬µ ™ŠÅ"J©csssŸ´ÖþÈpέ¬Õj…7›ç¼óϧ½½L'äók,ZêÌ o“FOçPJQ*•ð<¯‘lÞ|c°Æ`´AkƒNt&µ‚ц( YyÎ9ô._Îñ‘‘ÆÜ J@wÜsýÀg…”?«?ÜÕµ¬±¡1c33›Ôü¦avÓØÜ9‡ïû E …Åb‘B¡H>ŸÇÏå16S·‚Ñ5êŸÓšÉ£³³sžïž÷"pПÉ<ïιI૞çõ8H³®Ñ­I5žö² æf·BJ;o©ÒðèÖJpóŠx£æõè”$IZ±JEggWcŸ\.÷ƒ$I¾¶ÐšgôÄι.!ÒÄÒÔÜÜp¬:´!mëºÔ…”ÈúïY˜Ä¹Ôa3§Mµ¿Pà:€„$IÀ”‚+V6dB¬z³¼‹5õ¹4»j¤”T+Õ¬tH뙺ê]&|]peVZDÝ?²šÂ-°Íh§µÆhC¢5:Ñ$:!N¢(&NâÔI‚’r¹Ü,‚Ž· ¥tJ©ÔѬ¥V«á¨7ñ®YR¡l#ŽcPY!W·Òéå²zgÞyd¼Oˆ£(>NÁèD“Ëå©76i¨vgä­ÅÔêÚÃëq”&­5ù8¡X,Ëå0FáyJY”’!H TÏ´YÂr…N›Ž'Ùûël–“4gJy[BÊI¥<”g¨ÕjiѦ5B¤š­§û\>É¶ê æiöɬ`ú€Ñ ¢—&Î*Ò©©iÒÅâ)…T’ÉÓ)ë‡co ç^TJá{SSSÈL›Õ¹)äôÊ-PèF‰K0f žñQZgôQ)2' –toaLJ¹ÔœfúõÇši&+ÝZÞEyé2ppâ䉆‚Œ1Ç߀6v'‚©|¡Ð~ôèQff+X“P›ÚŇ~ÿ2š›V1ºÿËŸø)IñVtRÆóU£iiœ¶e'u ð†ò!Õ|¢56™ ?À%뎱ü‚/R©h{lÆ ¡abb‚œï#¥Â»ç ÊŸ ‰ÇÃÐ>“Ïçå—ö`ã_𱽇Ξ1Š­£¬Ù|;}åÇ öq4C¤§qa„!a…a5Æ Â€0‚€ ŒˆÃ¼ðQ—¿@ßæ?!ß¼ŽžãìØ±e‡>v”‘áãäóEížµÖ¾ð¶¾r÷Ü¿BlV/!ø W —–%Ç †dä(=ÜB§ÿ/üœ0¨„!µºpAÐx_ êB×@ƒ $ kĵ½tå¿KϺ@Ÿ€ø5Êã\ñÞN†þí-XkøÜmÑ·œ[Pe×¢-¥>TìüúÛö^¸qpùú ëhïˆÁŒ€Ð bp5PK¨xšç_ð5ŸC¨N”J«Uñ|@1NKt7¿{Õ…¥=`+ JàràðW¸S=f¤b1¸lN2òó=üäå+ˆükð¼"2sb‚$ä“ï°uãsô ¾ÜÈ"r)ëƒZþ2†éïÞM×÷¾YÔÅ×ue)³¯JÄ,ˆ$½]D`ât´`é]±œþS»Ø{|›?¯Ñ.¼/ÐRBÎ{UÍÿŲ•[SZ ¤4¤£Íƒ6VÀRèjób¢. þÅäjaJgGàâùÑ(é3Ð×ÌøÜóŸéÆ/u³ z­§ä¼*-úÛ\0XBÚ)ˆ5¨bJOÌüèLF' nްòúØõþYD‡N“ éBÒæ6ñ&6e§h+åÙÐw”Ó/> ö<¿D½ñOkº¬ov1¾ÞɆկÒRZÑ8È 2Ó¼ÈF§›š0|ލzì̆å¬,½ÔöÂ2²„Í@˜Ì4Ë[Š\ºî0ϼü,ùÎÌó'ËaakϱiàV,m‚ð4¨<(›ú—ÔóÚǦ“턇!9Nh[LÔ³X€u8 øä–jÉÎüÁf·‰Áj” 9§-Ïêža¦tB.—>ŸF#‰§,«WåYݦ‘ÑHÆ€2©ðÊdÂk`ô,ħÀZVèç$Ó@È0'2"û ³)Nƒ5)Gmºw^M3Ø¿Ž×«Ëp4e€ÓÐê©%t– M¥_+—ÒÆˆZj.›¤k;ë¢àõ“Øå€Èâ³ËÂ碎Íñ…UíT‰¸Ç ©ö“$UÒüÉHÃâ:0¼tü#S/ãù-ø¾B ²š§B_Ç!–÷XT.›'aÓD’JSÿo#ôä4¯½2ÂοÿžøÚÜ"ýl·FB{˳ÑïËuä¤ÛPR¬o)ºóה͖åeÖ©Vr$ÌÓ5‹€ûÇÔá/>¸äÅç_jÖÖÊ’T¢@zxž ®¸¤šÿËO_¼¶lWágdªa|ˆ§Iª#/Ëï;:ªŽœœVŽŸR?;rÌ;2:®jJŠØYkíÙ-°¬{…è?w­(/õ=÷B>o_õ}×¶¤É|u9:oã9³›/î9µ­³unôÖbèÖÝOXñ#+;öõyQšË„˲²PR’]xòðøA•?vå9búb©ÀhìØlÛáGWþϾåCG'›^¯Ôr3‰öf“U”ÕóÖIÿ%•Ri–mȺ¨¾ôå¿ÍÍmB*ßÂ奤$…h–Â5+6ý™–®¦ÑîÞüñ¾¦ÂL‡ñUt2ZsdlfÝdtÄR*—@‘U¨ç¬(æNû]-¯.íñŸ«´ÉÍÅã'’sMÇ+gŒkµB´*BÔ„sªRºjZ¿Yk“ÖÖV;44äÞ’BÇþ§$™ÈI\^JÛ,MÒ"¥nRœór%VJç¤pž0~G2«»uH´qÂ9'@ ”t¾/]SÁÐâùROxN‡Và!…B œó“¥ØÉ¦ÐÉâ"7‡Ìלj«:W p±Bè$I\WW×Ù)dtû+Â\ãù以U ¥q~w Õž ›rˆ‚ž%]Ú< ç@Ä‚B±Œ¾ úbk5Eÿ4K|ç¤,ãá²³‹ô)„qØšÁNjl-&©:¢)‰K|×¶=pM[´sÖ)¥Z_€œS8ÏQ,Çø±@åüR(¼‚‡ÊùHßC(R¥LOÏ›9Šª©K8'æ31 „OÞkBȸ$ËÐõSá"­ø„2H¡Ñ±A bÊ0÷ªB!Z.siü¿ÏÍ$DÚRìûÁïxy‰é$’”Ô(‰!…ái%Œ èìˆ<=µžïŽ-"se j!l–áÓ°ž¢´iLsÎB³EtXÜ´EN;šV&À|?K"[j)_âð;Ód#&Aæ²ÃÂË ~¢ ¬SÔ¢Q‹Ëë#ÄüŸZN¤ì@œÉQ‹Úqy(ú5„Èd"{8q¸ˆ¢êømŽÂJG|lQgý?éˆ};pþ¯™IEND®B`‚gosa-core-2.7.4/html/plugins/posix/images/members.png0000644000175000017500000000154411131316721021573 0ustar cajuscajus‰PNG  IHDRóÿagAMA¯È7ŠéIDATxœ…“_h[uÅ?÷_þ4ÉMSÓ´5Ýfi»v´q¸neê:-¨µsÙVн¨ æ‹AÅ_öªhŸ”¹‚Œ‰Œ¹uâh·Zuk“.íÚ%MzóÇ&7ɽ÷çC· "ì<|ßÎá|9çH<ácá#G޾ÙÓë6òFá»±3ßN}}ý`íA\<}òËýò¡˜ÈLŠ+éIq%sUŒ§ÇEÿhßY@åþùïÉ<óp€åi›ÙÓ•à~jIZä››Ÿd#hŠÏ€÷ g8Æ-¾Ø¨ë>¸ëè‰ïÄZöá<ï\š¸v¶îÞ ©Ïiòê¸Tã@Á„¤ÇÓÊ.sSÀ¿mÇñѾýÐcQɱ@’Ø{éÙ†KÛ8_~_K ¿ªÔJðPM&³Lbó…èþWÞˆ´÷F'ç  k»‰'éiú˜FÝE¹"_µY+_®þå|µ)nnÝš5-,ÇÁã’A€YsÈZ‚ì!d @ ¯å!mX¤ç~ø È(ÞHçž}CÃ{u¨×5ü>M•±k*¶zƒ@}‘âß!L3Lз…Zg¾?9µò‡“áw 7?5ÓØ±ó¹§žè‰tDT"ºŠŠÆõôynºFY“§Y±gY©Í,ÍPt’–ºs?‰/ï¥PÎÞJ¬eŒ”‰¿ QΩ$SKÔÚâ¯@•ÀqÀ¬‚eBýN9èbPØú»Ÿ?ur¤Åï)ZÊ6nÍA—ûXÍÚ4·ÿL8~( Þ ;¡,«Ôoôé‘×^µ…E$*uMDp]Çq0Æ µÆƒµc Æ’$¡Óé`­ÅZ{bOÊq”R„aH±X$›Íâû>Žã`­EkÍ^·K’ ˆ{=Ò4=q)%"ˆJ)|ß'‚ @)…1†û©fì ÇóÝ}Ö”(‹¢”ê ¨R©ÄÔÔa:ÈdP®‹¶»ó—n/óäëg¹ûÌ{4_:ÇÍßö^™˜8ÿØéÓOÈÊÊÊ­jµZ9²›¦)q’ Ó#‚ýôQc‰{cÔμIðËçôj¤xé²¾þÍ×?ÉàààÅéééwD$0‡áô°µ/Zð~KÓß?º]{{äÕJ±5jheòä2{oñÝõïïÎÌͽ&ýæ x÷ÂeøøòH}xìܳŒ?  Ü:¥m:×®þ3õåjYõP ÏÁãËàÆqóW ²Ã` ™4…Vœ¥ŒŠˆ‘•/¾•3Œ¬z©†0u³°~ô{sîÀØ«C^@+ºØ[¥yà&+ãµj¬ Må‹N½™Fžˆ'}Ž?ÂÿH.ª 7¹nÂþ F56ÀU&‰ Äë³`VØë!IEND®B`‚gosa-core-2.7.4/html/plugins/bugsubmitter/0000755000175000017500000000000011752422547017551 5ustar cajuscajusgosa-core-2.7.4/html/plugins/bugsubmitter/images/0000755000175000017500000000000011752422547021016 5ustar cajuscajusgosa-core-2.7.4/html/plugins/bugsubmitter/images/bugsubmitter.png0000644000175000017500000001004711042051706024225 0ustar cajuscajus‰PNG  IHDR00Wù‡gAMA¯È7ŠétEXtSoftwareAdobe ImageReadyqÉe<¹IDATxÚbüÿÿ?ÃPÄÄ0Ä@ y#1Š~ofpüú™•‰ÁqÅ!†©É“^…ÿñ€§?€"ˆþogxÿÃÿÿÇø ÃÿÏ+nFÛ1è¥8@ðÃû_Ë.ߟÄäó13=Ý@xcàûEV†{ ¶@/Tp?ÃÃÛ '¾ÿ`Ø'ÉÏÀÌ/ÂPΠ¿ Œ’ _Î?`(2«gXÒÄií€bAæ|XÏ ÈÃɰàí†â ‹¾ý`Páø”8ÄžPE6 ò  ïÁ˜ìxEf9ÃÀóýƒ TǨ'h ˆÙñ¼\ ˜…ì¸Ù¼+üüdàægÐ'^¤l/IJ@¬ ÄH¦}d`øÂ ¤,ÊðqãyPœ0ü u> xú½a" /0Bãå¿be æCÒñˆñO þÄÂ@ÌÄ’@,Ä7€ø"íG +ùØžŠò0$øÆ°C¤˜!ªã75=@püÚÂp˜U˜@tq¨|Iÿ`' Ç!#4µs±‹ñ9`Ѓ’Ÿ Ðì“ wž2ìÐibH… Õ<@ŒH¥Í†G@†[1+’ª§@|Gd‡bV¨'¾± #’Ý §¿îúÿÃt¿ Í@!X1L1 DEöjä ¾ #þÄÇqx ³AóƒÔC§€ø9ÄŒ@3~b`Ø}bhÁC p)ôa0ÌþC“,a‘|5ÂüføñäÃsn.I1`Êg…:‹Aä)Ä£ÿeÑ·Ÿ ?^|døEíÚ €X¾®c0š,×op 2h€= ÊPÏ Ô¥§ ×[w0ìXuŽá&4'€²1So<ƒuƒ§‚,°LBŽvhææ`©Å¯ËÀQó•!þá;†ý§ÂsÅ%@1þÞȰ Xúø‚“’Å0p–aþ6†mIK¶y ‰ìÔ‹ŒÐY¸5™Á55˜!]TXÀ²#åŸÐÚÈ~,îßf¸úþ+毿¶…Ìc8 ßäz €˜kꘑÎu 43Â0°ÌXp€a÷É '€¼+PO€Ê$`ªfø ¥ßï;Ïpýô †C¦z bâ àaƒfäÿüÅ ,øxÄ„xl˜’T„n1äßñ–4ñ}óèÀâOäx €ÿoÏ-DZ`}zðÃ~‡ UP|ÁS €ŸÄÃà ‹å,Á1À-@^}‹PühÒ™Ë ¯§_ý÷ï?ÃÿŸN}z|½óD›ÇhH”gˆ :¿JtÌ,Úeô¡ 569,^|²¿ßœ_}Z¦¡@1ýù,U˜ ÀPçýBÂÀt,,Ê ¿¤€ay]¸±ÁÞŸøóó'óOPåµRzøì€TB31ЬÿÀL-ðï9ƒ:Ã1Fæß ~ö%Þ1Ý}Ë`z˜ž9Y® 2¼’âb¸f)ÊÀ#oQ/åTâ MÂ(!@1ñÄ1D1F0Øh•2¤–/cèþôh ¬™€ž¡¥ŠƒBM4ÃæãSŠ0ò#‹Þ»ÏŒ‡óÒ…¯›®#Ì‘”b`ÐVýÌÿ-…Áçÿ,6v^`¬ýaøúó3ƒâ£Ï 7>3°þüÏÀûòÃï¯ß?Û× FÔ@ fhX~ó™áñÑ[ —| 8dyÌÁõ;¦6E§Üh÷Ä`.u†G[2|W÷ÏÓbµ~õ™á‡#CÜ>`ºé±!›Á,ÓD€Y•ÿÉi†ûBV Ÿxå˜9˜˜Ø™€~üÍÀ÷Ÿ‘Aü#Ã}>6¡ûŸ~}õûË«W¡•(<#ZóŒéï<†wLŒÀe!¢(m:q¯ÿ ]¿öÛKó+P«ÏeÉË ?v–l8Àa`C±ë[Âþ÷¶e¬Üü‚Èr‚,Ü ·8^cAôäíÇ/OÌzw~ñ~hq ö@¡DÇÏY Al\ kÁ ã Õ!4r¡qúNï°¨å‚v’žCì8 ô Ý4†BnYµ†õK²8¥MɃ‘Aè/'Ã&>Nž«ïø ¿oߟýxs·öÑ2¿U ›%CüÿÏà.U íäL,íBþCÿ-TƒZ|@|Z§¼À¢¤WêY `i ¬?ÿ{õÓ×Ç·ÎI1‹ùýñáv6f`eø¬?´~ÿex¡lw¸+2<5—“bæ•k‡Vxœ„â`Ú¶¨:×J3A;' ü(ÄN@¬€;àÅÒP31öò°Þ<ÆÀ0ç$Ãjh\zj÷D˜$ýûóñ+?;ÿfÖØÐæãaøÃÃ+&êÜêÄŠ€ø«ÿï@K ^¨c}€v“Ôfhs€ê!kÒ[Ž/ù°¥óôÞÆÀ°ê"úõWÀÝ¥‡ÐÖ(ž^<ݾ<‹ ˜yA˜IˆAŒîÊŸ@10ƒz"„âÞ\†ÌÏîü>qì`H}6§?l°lÿõê NhHbÚ@lÅÚ˜Yå%Ðñ÷v@?å(Ãvh‚{ˆ4óûb[ùÙo^ld& f65`E°ÐƒW ¬î¼øpzÈ㌄ÞÞøûèÃ^ –Ï ‚?€iúáe†ás¦°üex%ö‚Aá÷;VN`úeeô X< éȃ±<4L_B=LóåÇÙÇ çëw“Î5 ¾ÍòÈ­Ï¿ÊÑ)ììB",@GÿÖ- H…èùG /Ötÿùüäñ»„îWž1|dga8§ÁÁ`òÃ%»>†™O?0\ßv•a°+yP‘‘A‘í-ƒŸPõi4ݼмˆ„AÅì¨G€ÃK`,¾aUdØxæÃZ¨^ak–Üž?õ¶NIC5ÐkWzž~ƒx€ãÅgn Wµ¿?Þïùóþæ €bÄÑ]ç€]ÉB­~m°Nbðôd˜/—äm„·?!Ï[³_  A ˜Å„õ¡&‚Ô+³[ŽÞ2`X¬½…ë÷ï‡ïn­?Þ³GûŸ9ùÖÿ?€¶®öI~"Éò]ÁÀqçù×/—¦¶êê?ÔÀGP«aƒ% ,Ĩ)Îðê/¬ôG´V¿“Ó`=Ùwˆa޶‘¹>Ëⓦ¦jÀò€R¿ÆÂÝK mšóî0J3Èsþ–×µ \¾îmûÿ?ß¶ýûýíÛ6Öÿ¼¼úl\<Ùoq³芟h£HŸT%ß}ãVÝ–„«¾…yâº80yýù‡V€¦\6²ÞeØ¿á ÃÉ)k"¥_F3ˆo=Ž…‡ÀÞôÓ{ ÕÊëî°€ƒâáV†‡?Yµ-‡¤<²”ÐÿäŸÀ ËÄÌÄpÿ;°ð˜Ù?¡ÙÎuÈC?ÿ0üýôˆ €XH- Á`¥õX’peÜÀÌzw 0™ßcxP»“ajP3ïNî&Ó…  Áb«… Vkä3|¶Á¤}ÿ›‰á=0Ù]xKÀbvhe JŸÿ20}øÎðóáæÇD²œ§1XÅPùë6ƒƒšƒò¯¿ ?Š73Ìõ …t<ÜÞð²2¼V`ÈsØÏðå‰Ã nH©ÄMéo%Ñ@ ’3þeàÙ{‡á׋c Âþ+@1’^ëfh…–=\ÐÅ “ªc,bŠ‹.ë 3|zT03þc`ûö‡á;?R—ú´ÙA$à~òŒáŸ83ËÍ ÿ¯8ÿå`(À®9³)°a€Ð1ÎçÐö&(Ó¿zvxî a VüÖo°¯¿TŽ¿f½öêÏûß,_e8þò0A*Ãûh& BCZ4oeË»o ìçþø{ÿØ©¯‡SB@o¹ÓA°¬ô:Ìò ©¤ú÷òÄâs’šÁº¢¯YT…¯¾þñöȼ7•,åa•þ)úFX ¤ý›'Ä È@ÒÈÇ)?´eûš÷x8ؾeùquêÊŸï‚âÔ7x@´˜ÏÇÐËãs÷ðKšr=ÞV»þÍ™Å'ÿþøxõÃÕ;~¿ypHŒÃ6ø­¥¤†¥K`éÀÆñƒõã†ÿ,L ÿ9™!1ò,l¯ß20Ý¿ûâ×­y[ÿÿþxÚþý@Œ ´¬ÐrCZÕ½†Ë\ªy·ÞÞ.V…8î-$þ¸î}`à;}þÅïOÏŸ1ª½ÍQxÏ,—?2pνñãû¹Úží>Àé&숖óÄ¿¡Ž¾m¬}„zà=hü @^&(&¿ üw^0|¹±z÷ÛÑSþ=~róÈÆïØ÷kÝ~\éYtüèxù{Xî Ú‚?X&2þÿVå<—>2ügbÁå~Þ=|ìË¥é i”ëßo.-à`Ê^Ï|ü-÷ÿ‡wîÿ¸6e#Ðñg¡CçÞˆ‘a€LÌþú~{1°ð©2°ð þùòâÅ«5ÎíÐŒ Jß_¸Ì{Bÿ~¼£ðóÆŒGˆÖ8ÝFn7ЀxZÆ(A MhJx í<ƒ¶¿x mYVhsû4/¡4dh <ÀmñrB[8LÐdñij… )‰ÿÁ5Z @ŒC}¹ @€ͨ‹Ò.÷–eIEND®B`‚gosa-core-2.7.4/html/plugins/password/0000755000175000017500000000000011752422547016677 5ustar cajuscajusgosa-core-2.7.4/html/plugins/password/images/0000755000175000017500000000000011752422547020144 5ustar cajuscajusgosa-core-2.7.4/html/plugins/password/images/plugin.png0000644000175000017500000000636411035060224022141 0ustar cajuscajus‰PNG  IHDR00Wù‡gAMA¯È7Šé «IDATxœÅZ{l[UšÿÝëûòµ¯ß‰c'Nœ&4!%¥ÅIÛè4³íŒ:¥‹TñªÙΪB¬VH»ZXUb©ÄhW V,£J«’)1”¡ƒÔÂ,m¤C m]È6:IS7vœ‡c;~_?®Ïþaí”nã2ü¤+_Ùç|ç÷;þÎw¿ï³)¬?ü°Š¢¨{ôzý/+++d±Xê8Ž#étZYXX¸võêÕ?ù|¾·Ýn÷× «Y£\P+ÜÒÒÂmÚ´é©¶¶¶_vttÜU__¯bYétºhŒ¢Àó<EÁÄÄDþøñã?ùä“ßx<žwׄ=V @£ÑT8pàð¾}ûþ®­­ Ñhýýý²ÛíMMME3™Œ"Š¢Êétêï¹çóöíÛQ100yíµ×þµ¯¯ï%ɵ²Tìñx<$“ÇgZZZ¾ (ê×þ@€÷ØKÓô3.—ë³£Gæ#‘¹|ù2Ùµk×üPäñÐCuŒŒ±±1òØcùX–ý5€ªp7 §¨8%Izæ©§žº633CNŸ>MºººŽ`þ¢ävœ8q¢055Ež~úé9ÏX‡òÜÑh4¾øâ‹Ñ©©)òæ›o***~²¶ŒoÂ^ ¤»»›Æß¨Y© ‡Ãņ̃Ÿ~J¼^/Ù½{÷ëèï‹ßm iµZKggçCÙl§Nú*‰ü€¥‹ø|¾7ûûû¯Bpß}÷íвZÂ7ã¶Z«ªªl ˜˜˜ø£«\'<99y%ÂápØ+++7®Òηp[ ÃXÔj5‰Dǽ«](•J…dY†F£Ñh¬_­›±œ/’l6 Žã V« €ÜjE‘#„@–e¤ÓéUÛ¹·033s- eDQ„Ãápà;„Àªªª:𦠳óóó3«µs3nK(Œ\½zõlKKËή®®Ÿõöö6år¹¡ÿ;Æår±6›U«ÕäøñãYÊÁƒí<ÏÿÔb±¸ ƒÆãñ¤š››·Ê²ŒóçÏ˲<ò sæÌ™]]];7oÞl{ä‘Gž}çw~ár¹jï¾ûîMMM[š››«õz½‘¦iåÑGIY­ÖM{÷îµØl¶%C±X ‰D.—«²··× Ýß—ˆÛ‚çùu/¼ðÂdoo/yï½÷<ðÀ¿½òÊ+£W®\!¹\ŽÜ @€\ºt‰ŒŽŽ’ÉÉI2;;ûgc{{{§×­[·çûàWV2g±Xö<ÿüóo777“É$t:6mÚ†a  …–Þ7·ÛžžX,H’„¶¶6ÔÕÕ¦i æ÷ìÙó“ééé¾ï"@UΠT*5.BGccc3˲H¥Rðz½˜™™A @6›…N§ƒ×ëÅ™3gN§aµZát:a6›á÷û!I¦§§‘J¥`µZa·Ûéd2ÙØ××÷€ôš 0™L5<´mÛ6}<‡¢( „€‚B¡€B¡€P(„T*…|>Š¢0;; ‡Ã›Í¿ßD"«ÕŠ™™b²X,¨«««=}úôl0übµÊÊIÚÚÚ~ÕÞÞî°X,èììÄÖ­[a4‘Íf QAÓ4!p:Ðjµðx<€;v"‘Ìf3‚Á "‘œN'ºººþ ßÎhËF9q]³qãÆŸK’EQ $I‚ÙlF8F<Çââ""‘X–EKK ŒF#R©nܸ»îº ƒ©T E¦id³YP…ÆÆF;€ Ók"@See¥•aŠC)ŠB.—C>Ÿ‡(Š`Y:V«ù|Ùl²,ƒa¤ÓiȲ I’Àqb±!à¸â†çóy°,+WC(Ã…8ŽãX–¥!Kï•|_Qäóyär9(в$¬ô9˲KsX–]Ú}•ªxô2™ ¢Ñh+¬ÍW$ ‹%âñ¸œÉdP(–”HÞêžEQÀ0ÌÙ\.Žã R© @–e …$ÖL€àÄÄÄÅh4Šl6»J„KQèæûL&ƒššˆ¢ˆ\.‡B¡µZ Žã ÕjÁ²,ÆÇÇñå—_^YK…³gÏžžÆââ"ÿl§ou d³YÔÔ‹·p8Œd2 žça0 (ŠÂ»ï¾;:99y ßá9PV½~ýú‰¢Ñ(‰Ä·—®|>EQÐÐгٌx<޳gÏB¯×Ãn·C’$Ð4 ­V Nǘ]-y Ì€Üõë×C6›­«ªªJ £ÑÍnCÓ4†AEEªªªÍfáv»Á²,œN' b±FFF Š"ÚÛÛ“““ÄãñœZkH§Ócn·Ûk³ÙvÙívµ P4MC°, Qa6›!I‰úúú@Ó4Ö¯_µZB¡€t:@ €ÑÑQ´µµ¡©©©õäÉ“îD"1±¦ “É\µZ­í-Z­L&±°°I’Àó<æææpîÜ9 ‚aðúÞÌÍÍMe2»ÃáØ\Š*±X MMMðz½8vìØïc±XÏmL,~ýõ×_ôôôôªT*ÝîÝ»ï(¹£ ðx<¨­­EkkkK__Ÿ'/Û½X‘ µ¶¶ªAˆó<¿”urŽãà÷û3>ŸÏ€,cfÀ‰æææ8Ã0KÁ@ÔÔÔ`hhüsÏ=÷²N§k\ŽSÙQèÕW_uétº£­­­›)ª˜ýf2°, –e199éGùE‰¶¾¾~K)íŠÑÌ`0àúõëÄþýûkÏŸ?ÿ¯¿þú¯p›M)K€Ëå²±,ûQUUU5MÓÈår(½*Šžç144äPVÇÍd2és¹œy|| à ŸÏC¯×£¢¢õõõ˜››ÃÂÂ6lØÐ `=Ïwàv»c÷Þ{ï”ÉdªÖëõ`„är¹¥|hfffÀb9öÂápðÈ‘#oµZÿÚjµVwtt´šÍf¡”ÚívD"¸Ýî0–)vÊu¡ä[o½õ¬ÉdzŸ¦ik]]†,Ë0›Í˜Åôô´å&YÇó¶ÇãùÃ0 »víú !“É ›Í‚Š¢0??À2µBÙ‡xãÆq†a"¢(¢P(@¥R!•JÁh4–[7ÈåÚC1ÔFª««b)ÅP©TKÑüü¼ËlJ9ß÷ÄOüìÁ|Ùb±4”¨Õjð<ŸÏ'Çb±),¾Al‘H„/uzzzñÿ¤Ë!™L/]ºô"н!« v£Ñèä8N“H$®.7¿Š?~üŸÇ<Ï×ÔÖÖ(ÆísçÎ%»»»ÿtáÂ…wDW#ÅsydY¦gff8€Ôr“ËJ%2™Ì¬,ËLKKË.QAQÞÿýÀáÇ»¯]»öŸ°²|;¸ŒÖËA³wïÞî—^z)ïr¹Nø[uXyQôƒÂIÓôã(þ'Bú¡ÉÀÿc‰Ö×ÀIEND®B`‚gosa-core-2.7.4/html/index.php0000644000175000017500000003653611602021272015171 0ustar cajuscajusget_cfg_value("core",'theme'); if (file_exists("$BASE_DIR/ihtml/themes/$theme/blacklist")) { $blocks= file("$BASE_DIR/ihtml/themes/$theme/blacklist"); foreach ($blocks as $block) { if (preg_match('/'.preg_quote($block).'/', $_SERVER['HTTP_USER_AGENT'])) { die(sprintf(_("Your browser (%s) is blacklisted for the current theme!"), $block)); } } } /* Fill template with required values */ $username = ""; if(isset($_POST["username"])) { $username= get_post("username"); } $smarty->assign ("title","GOsa"); $smarty->assign("logo", image(get_template_path("images/logo.png"))); $smarty->assign('date', gmdate("D, d M Y H:i:s")); $smarty->assign('username', $username); $smarty->assign('personal_img', get_template_path('images/login-head.png')); $smarty->assign('password_img', get_template_path('images/password.png')); $smarty->assign('directory_img', get_template_path('images/ldapserver.png')); /* Some error to display? */ if (!isset($message)) { $message= ""; } $smarty->assign("message", $message); /* Displasy SSL mode warning? */ if ($ssl != "" && $config->get_cfg_value("core",'warnSSL') == 'true') { $smarty->assign("ssl", sprintf(_("This session is not encrypted. Click %s to enter an encrypted session."), "".bold(_("here"))."")); } else { $smarty->assign("ssl", ""); } if(!$config->check_session_lifetime()) { $smarty->assign ("lifetime", _("The configured session lifetime will be overridden by php.ini settings!")); } else { $smarty->assign ("lifetime", ""); } /* Generate server list */ $servers= array(); if (isset($_POST['server'])) { $selected= get_post('server'); } else { $selected= $config->data['MAIN']['DEFAULT']; } foreach ($config->data['LOCATIONS'] as $key => $ignored) { $servers[$key]= $key; } $smarty->assign ("server_options", $servers); $smarty->assign ("server_id", $selected); /* show login screen */ $smarty->assign ("PHPSESSID", session_id()); if (session::is_set('errors')) { $smarty->assign("errors", session::get('errors')); } if ($error_collector != "") { $smarty->assign("php_errors", $error_collector.""); } else { $smarty->assign("php_errors", ""); } $smarty->assign("msg_dialogs", msg_dialog::get_dialogs()); $smarty->display (get_template_path('headers.tpl')); $smarty->assign("version",get_gosa_version()); $smarty->display(get_template_path('login.tpl')); exit(); } /***************************************************************************** * M A I N * *****************************************************************************/ /* Set error handler to own one, initialize time calculation and start session. */ session::start(); session::set('errorsAlreadyPosted',array()); /* Destroy old session if exists. Else you will get your old session back, if you not logged out correctly. */ if(is_array(session::get_all()) && count(session::get_all())) { session::destroy(); session::start(); } $username= ""; /* Reset errors */ session::set('errors',""); session::set('errorsAlreadyPosted',""); session::set('LastError',""); /* Check if we need to run setup */ if (!file_exists(CONFIG_DIR."/".CONFIG_FILE)) { header("location:setup.php"); exit(); } /* Reset errors */ session::set('errors',""); /* Check for java script */ if(isset($_POST['javascript']) && $_POST['javascript'] == "true") { session::global_set('js',TRUE); }elseif(isset($_POST['javascript'])) { session::global_set('js',FALSE); } /* Check if gosa.conf (.CONFIG_FILE) is accessible */ if (!is_readable(CONFIG_DIR."/".CONFIG_FILE)) { msg_dialog::display(_("Configuration error"),sprintf(_("GOsa configuration %s/%s is not readable. Aborted."), CONFIG_DIR,CONFIG_FILE),FATAL_ERROR_DIALOG); exit(); } /* Parse configuration file */ $config= new config(CONFIG_DIR."/".CONFIG_FILE, $BASE_DIR); session::global_set('debugLevel',$config->get_cfg_value("core",'debugLevel')); if ($_SERVER["REQUEST_METHOD"] != "POST") { @DEBUG (DEBUG_CONFIG, __LINE__, __FUNCTION__, __FILE__, $config->data, "config"); } /* Enable compressed output */ if ($config->get_cfg_value("core","sendCompressedOutput") != "") { ob_start("ob_gzhandler"); } /* Set template compile directory */ $smarty->compile_dir= $config->get_cfg_value("core","templateCompileDirectory"); $smarty->error_unassigned= true; /* Check for compile directory */ if (!(is_dir($smarty->compile_dir) && is_writable($smarty->compile_dir))) { msg_dialog::display(_("Smarty error"),sprintf(_("Compile directory %s is not accessible!"), $smarty->compile_dir),FATAL_ERROR_DIALOG); exit(); } /* Check for old files in compile directory */ clean_smarty_compile_dir($smarty->compile_dir); /* Language setup */ $lang= get_browser_language(); putenv("LANGUAGE="); putenv("LANG=$lang"); setlocale(LC_ALL, $lang); $GLOBALS['t_language']= $lang; $GLOBALS['t_gettext_message_dir'] = $BASE_DIR.'/locale/'; /* Set the text domain as 'messages' */ $domain = 'messages'; bindtextdomain($domain, LOCALE_DIR); textdomain($domain); $smarty->assign ('nextfield', 'username'); /* Translation of cookie-warning. Whether to display it, is determined by JavaScript */ $smarty->assign ("cookies", _("Your browser has cookies disabled: please enable cookies and reload this page before logging in!")); if ($_SERVER["REQUEST_METHOD"] != "POST") { @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $lang, "Setting language to"); } /* Check for SSL connection */ $ssl= ""; if (!isset($_SERVER['HTTPS']) || !stristr($_SERVER['HTTPS'], "on")) { if (empty($_SERVER['REQUEST_URI'])) { $ssl= "https://".$_SERVER['HTTP_HOST']. $_SERVER['PATH_INFO']; } else { $ssl= "https://".$_SERVER['HTTP_HOST']. $_SERVER['REQUEST_URI']; } } /* If SSL is forced, just forward to the SSL enabled site */ if ($config->get_cfg_value("core","forceSSL") == 'true' && $ssl != '') { header ("Location: $ssl"); exit; } /* Do we have htaccess authentification enabled? */ $htaccess_authenticated= FALSE; if ($config->get_cfg_value("core","htaccessAuthentication") == "true" ) { if (!isset($_SERVER['REMOTE_USER'])) { msg_dialog::display(_("Configuration error"), _("Broken HTTP authentication setup!"), FATAL_ERROR_DIALOG); exit; } $tmp= process_htaccess($_SERVER['REMOTE_USER'], isset($_SERVER['KRB5CCNAME'])); $username= $tmp['username']; $server= $tmp['server']; if ($username == "") { msg_dialog::display(_("Error"), _("Cannot find a valid user for the current HTTP authentication!"), FATAL_ERROR_DIALOG); exit; } if ($server == "") { msg_dialog::display(_("Error"), _("Cannot find a unique user for the current HTTP authentication!"), FATAL_ERROR_DIALOG); exit; } $htaccess_authenticated= TRUE; } /* Got a formular answer, validate and try to log in */ if (($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['login'])) || $htaccess_authenticated) { /* Reset error messages */ $message= ""; /* Destroy old sessions, they cause a successfull login to relog again ...*/ if(session::global_is_set('_LAST_PAGE_REQUEST')) { session::global_set('_LAST_PAGE_REQUEST',time()); } if (!$htaccess_authenticated) { $server= get_post("server"); } $config->set_current($server); /* Admin-logon and verify */ $ldap = $config->get_ldap_link(); if (is_null($ldap) || (is_int($ldap) && $ldap == 0)) { msg_dialog::display(_("LDAP error"), msgPool::ldaperror($ldap->get_error(), $this->dn, 0, get_class())); displayLogin(); exit(); } /* Check for locking area */ $ldap->cat($config->get_cfg_value("core","config"), array("dn")); $attrs= $ldap->fetch(); if (!count ($attrs)) { $ldap->cd($config->current['BASE']); $ldap->create_missing_trees($config->get_cfg_value("core","config")); } /* Check for valid input */ $ok= true; if (!$htaccess_authenticated) { $username= get_post("username"); if (!preg_match("/^[@A-Za-z0-9_.-]+$/", $username)) { $message= _("Please specify a valid user name!"); $ok= false; } elseif (mb_strlen(get_post("password"), 'UTF-8') == 0) { $message= _("Please specify your password!"); $smarty->assign ('nextfield', 'password'); $ok= false; } } if ($ok) { /* Login as user, initialize user ACL's */ if ($htaccess_authenticated) { $ui= ldap_login_user_htaccess($username); if ($ui === NULL || !$ui) { msg_dialog::display(_("Authentication error"), _("Cannot retrieve user information for HTTP authentication!"), FATAL_ERROR_DIALOG); exit; } } else { $ui= ldap_login_user($username, get_post("password")); } if ($ui === NULL || !$ui) { $message= _("Please check the username/password combination!"); $smarty->assign ('nextfield', 'password'); session::global_set('config',$config); if(isset($_SERVER['REMOTE_ADDR'])){ $ip= $_SERVER['REMOTE_ADDR']; new log("security","login","",array(),"Authentication failed for user \"$username\" [from $ip]"); }else{ new log("security","login","",array(),"Authentication failed for user \"$username\""); } } else { /* Remove all locks of this user */ del_user_locks($ui->dn); /* Save userinfo and plugin structure */ session::global_set('ui',$ui); session::global_set('session_cnt',0); /* Let GOsa trigger a new connection for each POST, save config to session. */ $config->get_departments(); $config->make_idepartments(); session::global_set('config',$config); /* Restore filter settings from cookie, if available */ if($config->get_cfg_value("core","storeFilterSettings") == "true") { if(isset($_COOKIE['GOsa_Filter_Settings']) || isset($HTTP_COOKIE_VARS['GOsa_Filter_Settings'])) { if(isset($_COOKIE['GOsa_Filter_Settings'])) { $cookie_all = unserialize(base64_decode($_COOKIE['GOsa_Filter_Settings'])); }else{ $cookie_all = unserialize(base64_decode($HTTP_COOKIE_VARS['GOsa_Filter_Settings'])); } if(isset($cookie_all[$ui->dn])) { $cookie = $cookie_all[$ui->dn]; $cookie_vars= array("MultiDialogFilters","CurrentMainBase","plug"); foreach($cookie_vars as $var) { if(isset($cookie[$var])) { session::global_set($var,$cookie[$var]); } } if(isset($cookie['plug'])) { $plug =$cookie['plug']; } } } } /* are we using accountexpiration */ if ($config->boolValueIsTrue("core","handleExpiredAccounts")) { $expired= ldap_expired_account($config, $ui->dn, $ui->username); if ($expired == POSIX_ACCOUNT_EXPIRED) { $message= _("Account locked. Please contact your system administrator!"); $smarty->assign ('nextfield', 'password'); new log("security","login","",array(),"Account for user \"$username\" has expired") ; displayLogin(); exit(); } } /* Not account expired or password forced change go to main page */ new log("security","login","",array(),"User \"$username\" logged in successfully") ; $plist= new pluglist($config, $ui); stats::log('global', 'global', array(), $action = 'login', $amount = 1, 0); if(isset($plug) && isset($plist->dirlist[$plug])) { header ("Location: main.php?plug=".$plug."&global_check=1"); }else{ header ("Location: main.php?global_check=1"); } exit; } } } /* Fill template with required values */ $smarty->assign ('date', gmdate("D, d M Y H:i:s")); $smarty->assign ('username', $username); $smarty->assign ('personal_img', get_template_path('images/login-head.png')); $smarty->assign ('password_img', get_template_path('images/password.png')); $smarty->assign ('directory_img', get_template_path('images/ldapserver.png')); /* Some error to display? */ if (!isset($message)) { $message= ""; } $smarty->assign ("message", $message); /* Generate server list */ $servers= array(); if (isset($_POST['server'])){ $selected= get_post('server'); } else { $selected= $config->data['MAIN']['DEFAULT']; } foreach ($config->data['LOCATIONS'] as $key => $ignored) { $servers[$key]= $key; } $smarty->assign ("server_options", $servers); $smarty->assign ("server_id", $selected); /* show login screen */ $smarty->assign ("PHPSESSID", session_id()); if (session::is_set('errors')) { $smarty->assign("errors", session::get('errors')); } if ($error_collector != "") { $smarty->assign("php_errors", preg_replace("/%BUGBODY%/",$error_collector_mailto,$error_collector).""); } else { $smarty->assign("php_errors", ""); } /* Set focus to the error button if we've an error message */ $focus= ""; if (session::is_set('errors') && session::get('errors') != "") { $focus= ''; } $smarty->assign("focus", $focus); displayLogin(); // vim:tabstop=2:expandtab:shiftwidth=2:softtabstop=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/html/getFAIstatus.php0000644000175000017500000000337011663707407016435 0ustar cajuscajusget_entries_by_mac(explode(",", $_GET['mac'])); foreach($res as $entry){ echo $entry['MACADDRESS']."|".$entry['PROGRESS']."\n"; } ?> gosa-core-2.7.4/html/robots.txt0000644000175000017500000000003211311373431015404 0ustar cajuscajusUser-agent: * Disallow: / gosa-core-2.7.4/html/helpviewer.php0000644000175000017500000002344611424325206016236 0ustar cajuscajusget_cfg_value("core","language"); if ($lang == ""){ $lang= get_browser_language(); } $lang.=".UTF-8"; putenv("LANGUAGE="); putenv("LANG=$lang"); setlocale(LC_ALL, $lang); $GLOBALS['t_language']= $lang; $GLOBALS['t_gettext_message_dir'] = $BASE_DIR.'/locale/'; $domain = 'messages'; bindtextdomain($domain, LOCALE_DIR); textdomain($domain); @DEBUG (DEBUG_TRACE, __LINE__, __FUNCTION__, __FILE__, $lang, "Setting language to"); $smarty->compile_dir= $config->get_cfg_value("core","templateCompileDirectory"); $smarty->assign("title", "GOsa - "._("Help browser")); /* HELP management starts here ... */ /* Generate helpobject */ if(session::global_is_set('helpobject')){ $helpobject = session::global_get('helpobject'); }else{ $plist = session::global_get('plist'); $helpobject['lang'] = $lang; $helpobject['helpconf'] = array(); $helpobject['currentplug'] = ""; $helpobject['file'] = "index.html"; $helpobject['helpconf'] = $plist->gen_headlines(); } $lang = $lang[0].$lang[1]; $helpobject['lang'] = $lang; $defaultpage = "index.html"; // alternative file, shown on error, or on first call $prefix = "node"; // Prefix of the generated help files $suffix = ".html"; // Suffix of the generated helpfiles $maxresults = 10; // max number of results shown in result list $minwordlength = 3; // Word less than 3 chars will be dropped in search $allowed_chars_in_searchword = "'[^a-z0-9 %_-]'i"; // Remove all chars that would disturb our search like < or > ... /* Default pages */ $backward =$defaultpage; $index =$defaultpage; $forward ="node1.html"; $helpdir =""; /* Every class which is called within a tab, stores its name in the Session. * If session::global_is_set('current_class_for_help') is true, * get the helpfile specified in the xml file and display it. * Unset this Session entry, to avoid displaying it again. */ if(session::global_is_set('current_class_for_help')){ /* Create new XML parser with the path to the Xml file */ $xml = new parseXml("../doc/guide.xml"); /* Generate help array */ $str = $xml->parse(); /* __LANG__ is used as placeholder for the used language*/ $helpdir= @preg_replace("/__LANG__/i",$lang,$str[(session::global_get('current_class_for_help'))]['PATH']); /* If there is no entry in the xml file for this class, display an error message */ if($helpdir == ""){ $smarty->assign("help_contents","

    "._("There is no help file specified for this class"))."

    "; $header= "".$smarty->fetch(get_template_path('headers.tpl')); $display= ( $header.$smarty->fetch(get_template_path('help.tpl'))); echo $display; session::global_un_set('current_class_for_help'); exit(); } /* Save filename */ $helpobject['file']= $str[(session::global_get('current_class_for_help'))]['FILE']; /* Save path to the file */ $helpobject['currentplug'] = $helpdir; /* Avoid displaying the same help every time */ if(isset($_GET['pg'])){ session::global_un_set('current_class_for_help'); } }elseif(isset($_GET['plug'])){ /* This displays helpfiles depending on the current $_GET[plug] */ $ui= get_userinfo(); $tmp = new pluglist($config, $ui); $path = $tmp->get_path($_GET['plug']); $helpobject['currentplug'] = $path; $helpobject['file'] = "index.html"; $helpdir = "../doc/core/".$helpobject['lang']."/html/".preg_replace("/^.*\//i","",$helpobject['currentplug']); if(empty($helpobject['currentplug'])){ $helpdir= ""; } } /* this Post var is set if another page is requested */ if(isset($_GET['pg'])){ if(preg_match("/\//",$_GET['pg'])){ $arr = explode("/", $_GET['pg']); $helpobject['currentplug'] = "../doc/core/".$helpobject['lang']."/html/".$arr[0]; $helpdir = $helpobject['currentplug']; $helpobject['file']= $arr[1]; }else{ /* PG should contain a filename */ $helpobject['file'] = $_GET['pg']; /* If empty, force displaying the index */ if(empty($_GET['pg'])){ $helpobject['currentplug'] = ""; $helpobject['file'] = "index.html"; } /* Create new helpdir (The path where the requested page is located)*/ $helpdir = "../doc/core/".$helpobject['lang']."/html/".preg_replace("/^.*\//i","",$helpobject['currentplug']); /* If helpdir is empty, force index */ if(empty($helpobject['currentplug'])){ $helpdir= ""; } } } $helpdir.="/"; /* Save current settings */ session::global_set('helpobject',$helpobject); /* * Display management */ $files = array(); $f = opendir($helpdir); while($file = readdir($f)){ $files[$file]=$file; } /* Some replacements */ $backwardlink = " \""._("previous")."\" "; $forwardlink = " \""._("next")."\" "; $back = $for =""; if($helpobject['file'] == "index.html"){ $back = " "; $for = sprintf($forwardlink, $prefix."1".$suffix); }else{ $current = preg_replace("/^".$prefix."/","",$helpobject['file']); $current = preg_replace("/\.html$/","",$current); if(isset($files[$prefix.($current+1).$suffix])) { $for = sprintf($forwardlink, $prefix.($current+1).$suffix); } if(isset($files[$prefix.($current-1).$suffix])) { $back = sprintf($backwardlink, $prefix.($current-1).$suffix); } if(($current-1) == 0){ $back = sprintf($backwardlink, "index.html"); } } /* If there is no helpdir or file defined, display the index */ if(isset($_POST['search'])){ $helpdir = "../doc/core/".$helpobject['lang']."/html/"; /* read all available directories */ $index = readfiles($helpdir,$prefix,$suffix,false,false); $smarty->assign("help_contents",((searchlist($index,search($index,$_POST['search_string']),10)))); $header= "".$smarty->fetch(get_template_path('headers.tpl')); /* I don't know why, but we must use utf8_encode to avoid dispplay errors */ $display= ( $header.$smarty->fetch(get_template_path('help.tpl'))); echo $display; }elseif(((empty($helpdir)))||($helpdir=="/")){ /* Generate Index and display it */ $smarty->assign("help_contents",genIndex()); $header= "".$smarty->fetch(get_template_path('headers.tpl')); /* I don't know why, but we must use utf8_encode to avoid dispplay errors */ $display= utf8_encode( $header.$smarty->fetch(get_template_path('help.tpl'))); echo $display; }elseif((is_dir($helpdir))&&($fp = opendir($helpdir))){ /* Readfile gets the content of the requested file, * parse it, rework links images and so on */ $index = readfiles($helpdir,$prefix,$suffix,false,$helpobject['file']); $lastresults = session::global_get('lastresults'); /* if this page is result from a search, mark the search strings */ if(isset($_GET['mark'])){ $matches = $lastresults[preg_replace("/^.*\//i","",$helpobject['currentplug'])][$helpobject['file']]; $index[$helpobject['file']]['content'] = markup_page($index[$helpobject['file']]['content'],$matches); } /* Display the help contents */ $smarty->assign("help_contents",$index[$helpobject['file']]['content']); $header= "".$smarty->fetch(get_template_path('headers.tpl')); /* I don't know why, but we must use utf8_encode to avoid dispplay errors */ $smarty->assign("backward",$back); $smarty->assign("forward" ,$for); $display= utf8_encode( $header.$smarty->fetch(get_template_path('help.tpl'))); echo $display; }else{ /* There was a file requested which actually doesn't exists */ $smarty->assign("help_contents","

    ".sprintf(_("Help directory '%s' is not accessible, can't read any help files."),$helpdir))."


    "; $header= "".$smarty->fetch(get_template_path('headers.tpl')); $display= ( $header.$smarty->fetch(get_template_path('help.tpl'))); echo $display; } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/html/getbin.php0000644000175000017500000000367111340457662015343 0ustar cajuscajus gosa-core-2.7.4/html/themes/0000755000175000017500000000000011752422547014641 5ustar cajuscajusgosa-core-2.7.4/html/themes/default/0000755000175000017500000000000011752422547016265 5ustar cajuscajusgosa-core-2.7.4/html/themes/default/images/0000755000175000017500000000000011752422547017532 5ustar cajuscajusgosa-core-2.7.4/html/themes/default/images/btn-logout.png0000644000175000017500000000112111341526551022317 0ustar cajuscajus‰PNG  IHDRµú7êsRGB®ÎébKGDÿ‡Ì¿ pHYs¯¯^‘tIMEÚ3 åAñ§"tEXtCommentCreated with GIMP on a Mac‡¨wC§IDAT(Ï=ÈÏkÓ`€ñç}Ó4 bÝÄÊÜ„]ÜmÊ—Ú3ç–ÓzÑîÕOÁÇ+_åsma€µ¹¦ü޼.Ög‰Å¿›¾KSjÏQúñ^÷’…¹XI­·4ÖÔݳ)œX=£'N»å¼,_…|ߤ#¬ì[“ˇœv+6`¬íl4DÍy«¯qfsE,ÔÀH‰4¤ªG©Ú‘·rô]€ÌΈ£4ÚèaCÙIÕÊeö'€•µK# ü™Žü?ªNDSáÁØh,…Éæ5 |K(ßÞ>™âë7}éJøÛŸTОtßKi@ÒIæ“•tàL{g½cE²s{î¨X—L|HªYy‹”mF´‹Gu~ì:$¥øvÐmˆԥ!- žöŽ´Q]vé1Ù_‡Ùe¢üúÎUô¸ øI¦ÁNÂgÀuIEND®B`‚gosa-core-2.7.4/html/themes/default/images/title-bar.png0000644000175000017500000000546111341526551022123 0ustar cajuscajus‰PNG  IHDR(aØgAMA± üa DiCCPICC Profilex–wT×ÇßÌl/´]–"eé½·¤.½H•& ËîKYÖe°7D"ŠˆV$(bÀh(+¢Xì "J F•ÌÆõ÷;'ùýNÞw>ó}÷žwçÞûÎ(!a¬@¶P"Žô÷fÆÅ'0ñ½D€6p¸¹¢Ð(¿h€®@_63u’ñ_ àõ-€Z®[„3™éÿïC‘+K€ÂÑ;?—‹r!ÊYù‘LŸD™ž’)c#c1š ʪ2NûÄæú|bOó²…<ÔG–³ˆ—Í“qÊó¤|”‘”‹òü|”o ¬Ÿ%Í üez6Ÿ“ †"Ó%|n:ÊÖ(SÄÑ‘l”ç@ ¤}Å)_±„_€æ ;G´D,HK—0¹&Lgg3€ŸŸÅ—H,Â9ÜLŽ˜Çdçd‹8Â%|úfYP’Õ–‰ÙÑÆÙÑÑÂÖ-ÿçõ›Ÿ½þd½ýäñ2âÏžAŒž/Ú—Ø/ZN-¬)´6[¾h);h[€êÝ/šþ>ä híûê{²yI—HD.VVùùù–>×RVÐÏë:|öü{øêù ¢‚¡[£°R¡Fá„ ”"MÑF1L1[±Tñ°âeÅ'Jx%C%_%žR¡Ò¥óJ#4„¦GcÓ¸´u´:ÚÚ(G7¢Ò3è%ôïè½ôIe%e{ååååSÊC „aÈdd1ÊÇ·ïT4U¼Tø*›TšTT¦Uç¨zªòU‹U›Uoª¾ScªùªeªmUkS{ ŽQ7UPÏWߣ~A}b}Žëîœâ9ÇæÜÕ€5L5"5–iÐèјÒÔÒô×iîÔ<¯9¡ÅÐòÔÊЪÐ:­5®MÓv×hWhŸÑ~ÊTfz1³˜UÌ.椎†N€ŽTg¿N¯ÎŒ®‘î|ݵºÍºôHz,½T½ ½N½I}mýPýåúúw ˆ,ƒtƒÝÓ†F†±† Û Ÿ©-5j4ºoL5ö0^l\k|ÃgÂ2É4ÙmrÍ6u0M7­1í3ƒÍÍf»ÍúͱæÎæBóZóA Š…—EžE£Å°%Ã2Är­e›ås+}««­VÝV­¬³¬ë¬ïÙ(ÙÙ¬µé°ùÝÖÔ–k[c{ÃŽjçg·Ê®Ýî…½™=ß~ýmšC¨Ã‡N‡ŽNŽbÇ&Çq'}§d§]Nƒ,:+œUʺäŒuöv^å|Òù­‹£‹Äå˜Ëo®®™®‡]ŸÌ5šËŸ[7wÄM×ã¶ßmÈéžì¾Ï}ÈCǃãQëñÈSÏ“çYï9æeâ•áuÄë¹·µ·Ø»Å{šíÂ^Á>ëƒøøûûôú*ùÎ÷­ö}è§ë—æ×è7éïà¿Ìÿl6 8`kÀ` f 7°!p2È)hEPW0%8*¸:øQˆiˆ8¤# ÝzžÁ<á¼¶0¶-ìA¸Qøâð#pá5#m"—GvGÑ¢’¢G½ŽöŽ.‹¾7ßx¾t~gŒ|LbLCÌt¬OlyìPœUÜŠ¸«ñêñ‚øö|BLB}ÂÔßÛŒ&:$%ÞZh´°`áåEꋲJ’Oâ$OÆ&Ç&N~Ï ãÔr¦RSv¥LrÙÜÜgIsKÛ–6žî‘^™>!` ª/22öfLg†e̜͊ÍjÎ&d'gŸ* 3…]9Z99ý"3Q‘hh±Ëâí‹'ÅÁâú\(wan»„ŽþLõH¥ë¥Ãyîy5yoòcò( z–˜.Ù´dl©ßÒo—a–q—u.×Y¾fùð ¯ûWB+SVv®Ò[U¸jtµÿêCkHk2×ü´ÖzmùÚWëb×uj®.Y￾±H®H\4¸ÁuÃÞ˜‚½›ì6íÜô±˜W|¥Äº¤²ä})·ôÊ76ßT}3»9uso™cÙž-¸-Â-·¶zl=T®X¾´|d[è¶Ö fEqÅ«íIÛ/WÚWîÝAÚ!Ý1TRÕ¾Sç–ï«Ó«oÖx×4ïÒØµi×ônÞî=ž{šöjî-ÙûnŸ`ßíýþû[k k+àäx\S×ý-ëÛ†zõú’ú…‡Eêjpjh8¬q¸¬n”6ŽI§¾ökÎ×:úçöŸð8wÝçúÅ7®Þœw³ÿÖü[·‡nón?¹“uçÅݼ»3÷VßÇÞ/~ ð ò¡ÆÃÚŸM~nr:5ì3Üó(êѽîȳ_ry?Zø˜ú¸rL{¬á‰í““ã~ãמ.x:úLôlf¢èWÅ_w=7~þÃož¿õLÆM޾¿˜ý½ô¥Ú˃¯ì_uN…O=|ýzfºøÚ›CoYo»ßž›É_õÁäCÇÇà÷g³ggÿ˜óüI°)˜ pHYs  šœƒIDATH í”Ë !ÁX¡ýáÑßn=r^P[kG gc -bç`ÁÅöÞI“çÕ²Ö✣Í G·…?çÞ±°¿":P>çôt…Ô¬÷ò †&/¥xMCjùgª’Òƒ pV 9PTKbøs~ýˆì9¿ï¼Öê5 ©}”²AJ¶­Ä’IEND®B`‚gosa-core-2.7.4/html/themes/default/images/logo.png0000644000175000017500000001011411341526551021167 0ustar cajuscajus‰PNG  IHDR}&éÉ”sRGB®ÎébKGDÿÿÿ ½§“ pHYsaa¨?§itIMEÚ4 ` ˆÌIDATxÚí[k\ÅuþNïÝ«a¸ ÃhXV£eµl$„á! óqa^±ÀR¢ˆ1`Ë"Œƒ\¡ v™D!Ø6P€y„‡)0…!A1.‹‡xŒ^â!‹<Œ—ñx2F£ËìÝ;ý出U7—ÙÙY…MöTÝš»·»Ï9}NŸÓçôé¦a¦a¦a¦a¦áäÿËDIŠˆðŒWœˆÌBi}ì•NÒ‘мï`Àþö°+€q›¼`=€QiÆÇ~¡CD´ù{{˜ `À€”U€­`ƒˆ¬ìfal#±FÀ§`?Cc'3Ïÿð&€§¬‘ ;jý!ZL/É“I®$¹•Ãf’÷‘üK’½¦Š¼’\JòA’[جêRáö}€äÅ$7v‰3É’œßß»Â÷#y§÷’üÓ@ÿt’ÞýÛ¦@ã8’ë:àÒÚFIžò±Q<É3I'˜l™äKæyg‚>%c¡îû í‘¼æ}(Á·»¤sÉfüzºíÚÆHžúqq鶙ܯú‘œcžHþÉ[Hú±1ϒܵ+°í$S1ïÒê ð‰à«]¸ô ºP(;(ßòF’’û?Dr™ÔS$?ÓŘÃ#‹åE’ûNe'©HÞp8‰õµƒ€äI“,¬#¸Ç'ð ï|‚äj’ùX[«MÿÛþ€t—"™|¿ÑûþNp›ˆ¼c¾h¢Ûù&¥)x\D6í{Xà!yjŠôþÀ•æÏ€Gùþ-€lPDÚw°À-"Rˆáî‘É=üÌd!¡™C”Æ«VxÊd ÀQ¾k2´ák+€ƒDäÍPÙàBÙ¬pY··ÉoÙ¶4ɫ۸p ‘<(Ò?Gr9É¡xD>íƒI6bnSÇ\èr’3»õ‘'êÖ/kX«šä@œŸ&ù»ØØ¨Å_ð*üòo|×¼¯éfOEòIà,0ß2$WuáZß!y¸Óg¢â_™üw2ý¨2ìïïH»³W$-‹ÓØÜ ’7w,ïþ¨¢H>lx¸Æ|[j™šlðž‘}ü7$g™ï×·Z-FÝ!Ú]K²‡¤Còóí ’³;Ð]±r‹?ŠóœXÿA’Ÿ4Þaq‡ç`’‡Ìšq§üíöð{ºðçI†#<“ä3¡Òç“<‚ä óíN›iu8@rÍøø8ÇÇÇ­‹H“<ÂLèY’¯ŒG…¦íB ù2É•fìr’.ÉG"øž´ÂoC{Y«Õ²ý´¥að>Ô¦ÿLÚ˜'9ÒáÉ“ü-ÉÓ̸«c Wc$ÏîRÀóIÖ-óX^×M´ƒZLr!Éþ)(´ßŒYhâ¥ÉúÏ$y„§¯:tìp·Öz‰R ZkP& ;L)5àVO:ŽóS­õ<½ D)%J©¾`Çqp6€f*µMa~Úqœ“ü¢ˆc,¡µ†R aJ,Hº· ˇj­w7|"|¿ç›ã8)s^°È¶i­EkMÃ_ѯv5Bk-–Ž^#7{¬ë8ÀÉöà™#ÝÉõn‘Õèä,3îOÌqs À’¿ð}y¥]öà&­õ¥Ô‰ÈÍíÏ#ù´±Hm¬íq“Ï"9×äãžé¿ɵ ^Crži›Ar6Éa3f6ÉûLßÐô_MåŒkzillŒãããÓö½Õjm¶¸cûÿ:Ó7ío›ÇòxšñZåFÚŸ›‚å ¶Z­Myéž—Œ¢­eÿ4JÇ>ö›9Vþr ÿ$Ž%ù ÉűqG“,¼O“\hÛÚYúß÷7+6ÔZ÷:ŽS7E‹±÷TlD6|¾Ùl.VJÁqœ×lšbúÛÔN‰ˆ&ùû lQ¤' ÉÄ0€×,Oaî†Ûê:ÖZ•Rp]·¡”*ÄXÈHœÖj¡”ceXK÷<¯ Õl6w³tDÛ+SØBg‡a8#ëIÄZºã8ÅH‘é{Fãð®ô†a˜pço8ÚEn$)7n¼ÖÖºê›3™Ìù7n\qcÔZ+û@òùüyJ©–ëºcétúëÇ©;Î6’ÃÃÃËEäú6tƒM›6U|ߟmð‹RŠF9€?)}C:^šN§]Ü@5‚£££§[ tZkd2™ªè8N µv­’  ðä®"²y’ý|^¹\^bøÜ¾8ÀuÝM‘`pc&“ÙP­V(¥P,ÿ:‘H•N§_ ù2€GDäÁ˜¡³È~»HH7›ÍÁr¹ü;/×u«‘±Wvâ{¢è]D„"rƒQüõFcv&“ÉŠÈ[$ÿ©V«ÝiݨU~ÔbÌ{ÏÐÐÐõ"ò4I/‚ŒQøE"òý‰.xž·¾R©`a­T)…jµzÉ»mÄ/"5/Äç066æÆù3[Ä:©‘Lzž÷v½^Ÿ§ãûþ^fqu<\ÑZ/o4Q:V¹\î?Eä׆Ç_“üß÷o ‚`7­5|ßÏ6›Ícë8ιccc«\×ý¦ˆ¬èaaß*—Ë7\L¶v^-=Žã¼1Q1)¾˜&rï´—ˆüdOµZ]f÷¹‹ä¬B¡p…ÖºÇAÑ@F)…;|àMº®»exxøâN 7ÞâI¥ÔiÑýÑx©×ë ’ÉäM$¿$"¥ í¹…BáDãUh¶ (¥H$ìÉ»ÙlvM½^Ÿgù,Þ„ïûËH>ÞÆ²B¡ð%3Φ”6å •R·Ädº’ä›Î/—Ë'û¾¿G$-M‹ÅSÒéôÉÏŠH…äp½^¿©Z­.² N§ÓëS©Ô J©gÃ0kÄ]ÛSʹÖóôõõ=$"÷Edºs£Ñ8κúd29Ò­Â'UzÔMüîèèèR¥FGGÏÉf³û“¼ÀxÛ–MÍaÉ€O†aø…B¡ðy¥J¥Ò $op~—·H¯ÊårÇ”J¥#Ç¥Í霸®kß`†ïû{ZWi¶‚èé[Kkíxž7 àZ[V5sÛJrE2™\Òl6=¥”õ Ûé)¥A& ÃŒÁgñ2Ài­U:ÞH$–‰HÝFíÕjõ®F£‘SJ!•JDòy"šrZœßóV·v>Ífs>É9Æfø×Z­¶82nÃTÎæn:!%£{lµZ=ÀíÉd²J¥^#Y1®n·F£1·V«íß+#G“­IÜ»‘:ɳúúú~R©TFã†H–ðžÜØ~·‘ÿ¶OŽN§ÓËEäU£ì– tDd É¿-•J·†aØ3Ö›ífçy_Œb"R"yu³ÙüÔëõa·“\  ¦µÞ§T*mqçr¹‡6‚ã~ÚË$g…axo¥RYÚs¹Üõzýß÷ÍØ"òͪô˜pX^©TNÑZ»QA´ûúúp…ˆ<3Y×Añ À Î.—ËÇÛãÕv´£Ð××w?€"ò|—sÛÀEårù ë;)=›Í®uçZwGVbË[1ià!Aôk­•뺛•R¯xÀƒ"ònlÞ{¸0‚O)¥BÇq^p¿ÉÿOö;ù[þNCëþ‡þ‡›¢RT‚/Zz¡æ¼š3š3Ñf  ¯Pxû1ASC !ûÓþQ3>²`Ÿß×: ìDª9ªÁˇs#s3ÇZçmªfª¬V9‹ªP9‹9sQssGs/ss?sKsXsAsGªÅªÃ¬V¬U¬Vã^ÍuÇ3ljÇTljV‰ã‰9Tlj9‰slj㉪‰lj9TV‰9TljV;ãÇ{VVV#ã=ªs9ª¬-sÿìªBs<ã‡sPãTsPª#ãTã99ÿàs9‡ã‡ãPã‡ãT‡sHªãs9ÿússD!=œ+¬QªÂs3ss9s=œs5ªå ö-s\¬Tå kÿï3Zd1ª3ª,ªWœ†sG9ª`ªRì-s]¬^¬^¬gãrÇ3Ç3Ç3Ç3Ç3Ç3ÇTV‰V‰V‰V‰9ÿØ9h9ÿ«9ÿ×Çlj9T9T9T9T9T¬V9TÇ{Ç{Ç{Ç{V#V‰ãs4s4s4s4s4s4BsPsPsPsPsP9ÿÀ9r9ÿ­9ÿØãPã‡ãPãPãPãPãPd1ãããããsãsÇ3s<Ç3s<Ç3s<ÇTsPÇTsPÇTsPÇTsPljÀTÇãTV‰sPV‰sPV‰sPV‰sPV‰sP9TãT9TãT9TãT9TãTljãÇã 9ÿ™9ÿ™9ÿì9ÿì9ÿ¼9ÿ½9X9E9‰9‘G‰ss9ÿ¦ljssã‰9jã‰9ã‰ã‰Õã9ljã‡ljã‡lj㇫ÿêÉ…ã‡9TãP9TãP9TãPTPlj‡lj‡lj8V;sHV;sHV;sHV;sHãªãÕãªÇ{ãÇ{ãÇ{ãÇ{ãÇ{ãÇ{ã9ÿúV#sV#ã=Dã=Dã=D9Žs¨Ç3s<B9TãV;sH㪪ªª$ªÿǪȪ'ªLªÿòªÿ¤ª¹¸nÇ$ªÅÓ.?$Ê$™ÿæk€´ÿÐ9ÿ©Ç3ljωÀSV‰ã=lj9T9‰ljVª‰lj&T9TljV‰ÍZãV#‘?Vy`jS9ÿ×V#ëPœMãk9‰¨ëPâŽsÚVÌM¯BãkSZ9‰vs åsBãP *óy)OyP’¨¹P› ÂQ9ÿÙ¨ãP¨ÂQZ‰‰‰±TV;9‰5ÿÕsÀ€‰â‰úÿùÀ‰Ç3À‰lj‰‰³V‰;ÿú.ÀˆÀˆâ‰ª‰lj9TÀ‰V‰ÇTãúÔGV؉Ÿn ‰'‰õÕ‰À‰±6@‰À#s<ñ^ëUsP¬ÿïú5ëŽëŽŽëÕãPÕã‡sPë:sRsë¥S«ÀÕ&Õëk4Õ«ÿÿsPã UkPsH9@ÿÚ9ÿàÀ@ã ŽsÕ剓9ÿú9ÿú9ÿúV#sªPªPs>kÿì9‹9‹9Š9‹———sŠsˆÍAá)ëUÕUª\ª]ÕÁªÿ~Vþ‡+lssÀžs 6é)ë‰}%UÍX¬r¬T¬g¬£¢¢¢ô5å+–Ì´†¬Ud´HÕ˜Ç1ÿd+d«dd1d1Õ¬dÕ"Õ«ÿöØ««ÿö««ÿö««ÿö«ÿö«ÿö«ÿö«ÿö«Ù««Ù«Ù«ÿö«ÿö«ÿö««Ù«Ù«ÿö«ÿö«ÿö««Ù«Ù«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«««««Õ«g«ÕÕ{ÕÖmÖmëžë‘ëžë‘ôÕ§Õ²Õ)Õ)Ös+±kÑUFÚQ@;@<ÀfBÄã#ã#ªŒªªgª#ª5ª+ª-ªÿ½ÇqÇgªWWÿåÿåÿÏÿ®ÿûøÜ€B~’ÿÇÉÝ~ŠŒ¡Î O\_‘…ó    " & 0 3 : < > D  ¤ § ¬!!!!"!&!.!^!•!¨"""""""")"+"H"a"e###!%%% %%%%%$%,%4%<%l%€%„%ˆ%Œ%“%¡%¬%²%º%¼%Ä%Ë%Ï%Ù%æ&<&@&B&`&c&f&kððûÿÿ  ’úÆÉØ~„ŒŽ£Q^€ò    & 0 2 9 < > D  £ § ¬!!!!"!&!.![!!¨"""""""")"+"H"`"d### %%% %%%%%$%,%4%<%P%€%„%ˆ%Œ%% %ª%²%º%¼%Ä%Ê%Ï%Ø%æ&:&@&B&`&c&e&jððûÿÿÿãÿ®ÿGÿ/þ…þ„þvü ýÐýÏýÎýÍý›ýšý™ý˜ýhãzãáòáñáðáïáìáãáâáÝáÜáÛáÖáœáyáwásááá áàþà÷àËàšàˆà/à,à$à#ààààßóßÜßÚß>ß1ß"ÝDÝCÝ:Ý7Ý4Ý1Ý.Ý'Ý ÝÝÜÿÜìÜéÜæÜãÜàÜÔÜÌÜÇÜÀܸܿܳܰܨܜÜIÜFÜEÜ(Ü&Ü%Ü"‹À bcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?w6   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a„…‡‰‘–œ¡ ¢¤£¥§©¨ª«­¬®¯±³²´¶µº¹»¼pcdhvŸnj#ti<†˜7q>?fu143:kzv¦¸bm6@;2l{€ƒ•   ·}¿8Žw ‚Š‹ˆŽŒ“”’š›™ñKRoNOPxSQL@EYXUTSRQPONMLKJIHGFEDCBA@?>=<;:9876510/.-,('&%$#"! ,E#F` °&`°&#HH-,E#F#a °&a°&#HH-,E#F`° a °F`°&#HH-,E#F#a° ` °&a° a°&#HH-,E#F`°@a °f`°&#HH-,E#F#a°@` °&a°@a°&#HH-, <<-, E# °ÍD# ¸ZQX# °D#Y °íQX# °MD#Y °&QX# ° D#Y!!-, EhD °` E°FvhŠE`D-,± C#Ce -,± C#C -,°(#p±(>°(#p±(E:± -, E°%Ead°PQXED!!Y-,I°#D-, E°C`D-,°C°Ce -, i°@a°‹ ±,ÀŠŒ¸b`+ d#da\X°aY-,ŠEŠŠ‡°+°)#D°)zä-,Ee°,#DE°+#D-,KRXED!!Y-,KQXED!!Y-,°%# Šõ°`#íì-,°%# Šõ°a#íì-,°%õíì-,F#F`ŠŠF# FŠ`Ša¸ÿ€b# #б ŠpE` °PX°a¸ÿº‹°FŒY°`h:-, E°%FRK°Q[X°%F ha°%°%?#!8!Y-, E°%FPX°%F ha°%°%?#!8!Y-,°C°C -,!! d#d‹¸@b-,!°€QX d#d‹¸ b²@/+Y°`-,!°ÀQX d#d‹¸Ub²€/+Y°`-, d#d‹¸@b`#!-,KSXа%Id#Ei°@‹a°€b° aj°#D#°ö!#Š 9/Y-,KSX °%Idi °&°%Id#a°€b° aj°#D°&°öа#D°ö°#D°íа& 9# 9//Y-,E#E`#E`#E`#vh°€b -,°H+-, E°TX°@D E°@aD!!Y-,E±0/E#Ea`°`iD-,KQX°/#p°#B!!Y-,KQX °%EiSXD!!Y!!Y-,E°C°`c°`iD-,°/ED-,E# EŠ`D-,E#E`D-,K#QX¹3ÿà±4 ³34YDD-,°CX°&EŠXdf°`d° `f X!°@Y°aY#XeY°)#D#°)à!!!!!Y-,°CTXKS#KQZX8!!Y!!!!Y-,°CX°%Ed° `f X!°@Y°a#XeY°)#D°%°% XY°%°% F°%#B<°%°%°%°% F°%°`#B< XY°%°%°)à°) EeD°%°%°)à°%°% XY°%°%CH°%°%°%°%°`CH!Y!!!!!!!-,°% F°%#B°%°%EH!!!!-,°% °%°%CH!!!-,E# E °P X#e#Y#h °@PX!°@Y#XeYŠ`D-,KS#KQZX EŠ`D!!Y-,KTX EŠ`D!!Y-,KS#KQZX8!!Y-,°!KTX8!!Y-,°CTX°F+!!!!Y-,°CTX°G+!!!Y-,°CTX°H+!!!!Y-,°CTX°I+!!!Y-, Š#KSŠKQZX#8!!Y-,°%I°SX °@8!Y-,F#F`#Fa#  FŠa¸ÿ€bб@@ŠpE`h:-, Š#IdŠ#SX<!Y-,KRX}zY-,°KKTB-,±B±#ˆQ±@ˆSZX¹ ˆTX²C`BY±$ˆQX¹ @ˆTX²C`B±$ˆTX² C`BKKRX²C`BY¹@€ˆTX²C`BY¹@€c¸ˆTX²C`BY¹@c¸ˆTX²C`BY¹@c¸ˆTX²@C`BYYYYY-,Eh#KQX# E d°@PX|YhŠ`YD-,°°%°%°#>°#>± ° #eB° #B°#?°#?± °#eB°#B°-,zŠE#õ-¿P/¯@GÐý¿ýýoû@û€õõ õñð5/ðŸð_ï/ï_ïoïŸïßïæä åä=âà'áà=ß=ÝUÞ=Uݸ²</A  @ÿÀ@(FÜÿÛÚ<ÔÒÓÒ&`ÑÑÀÑ`ÑѰÑÀÑàѸÿÀ³ÑF¸ÿÀ´Ñ F¸@¿¾&@»)AF@»"'F¸!@#¶=¸¸· ·· ·@·`·p·@·`··Ð·ð·¸ @ H=µ`µ µÐµ¸ÿÀ@µ F²_²±</A ?O@@(&)F¯/¯?¯Ÿ¯¯@¯F­p­€­à­ð­«ª5ªP&¹²<¸¶©¨¼<@‡P<ž›'›'œ›'€›˜F(Ÿ—¯—–F5””“&’‘&Œ ŽŒ&_oÿ@FŒ@Œ F‰‰†…_…6‚F‚vP&uP&tP&sP&)pppôpÖpæphpYp¸ÿð@tp FonHnF2U3U3UÿaP&`_2_P&^ZH\F'[ZxZF12UU2Uo?_S@S(,F@S"F@SFRQ(QOPOO)OYOiO¸@)F%IFHF!GF5øF˜F2UU2UUÿ¸² ¸@= @ 0p?_/Ooßÿ?_ïo_€¸±TS++K¸ÿRK°P[°ˆ°%S°ˆ°@QZ°ˆ°UZ[X±ŽY…BK°2SX°`YK°dSX°@YK°€SX°±BYststust+++++++st++++st++++++ssu+++++++++++++++++ssssttt++++ss+s+s+tu++++s+s+s+++++sss+++st+st+st+s+st+stu+t++++s++st+++s++su+++++++sts+sssssssssÌÌ}y:wÿìÿìÿìþW%õëÁÓº°Ï')äôÆLßÑŵ©ýØ€·ý?Û]%ª€uüy! 1=ÿà”à”DàsØÅœÍËôNÿ×Ì0Es´¦s€¢˜ƒ®þ¼¶ÿö¶¼ÆŠ`ðî¾Hj¶ý“‘g‘aÙAªþoþh“˜âQ¾®þ¹þ¤^¯ÕUò¦D©,,,,Fx*2”pšÖ^ Ìàü$v¶  ’ ú z ú 0 Ô Z 0bšâ@HäXÊ$dšXšÚJjæDÀ¨ Ì’8 ŒÜ*RŠ Ê n â!0! ""Z"æ#J#†$$j$š%@%¦%î&l&Ú'6'Ö(&(~(¢(ø)t)¬)ê*V*|*è+<, ,h,ú-v..P/6/z040Ö161d22*2Œ2æ3>3À3æ4F44ª585x5Ü6:6X6n6Œ6ô7 7$7<7T7n7†7þ88*8B8Z8t8Œ8¢8º8Ò9D9\9t9Œ9¤9¼9Ö:6:þ;;.;F;`;x;È<` >"><>T>j>€>˜?„”„œ„¤„¬„Ò„Ú„â„ê…^†Ø†à‡$‡jˆ¼ŠPŠšŠð‹B‹ÀŒ@Œ¨Œ°&šÈŽ2Ž:€ d|Ø‘2’P’”’œ’Ð’Ø’à”r”z–l–t–®–ø˜p™ìš>šª››h›Öœ8œRœöt|¼ŸŠŸ’ ( ’¡¡0¡<¢²¢à££0£<£T£`£z£†£ž£ª£Æ£â£ö¤ ¤¤*¤f¤˜¤Ô¥¥b¥º¦(¦`¦¸¦ö§6©È©è©üª0ªdªzªª²««X¬®T¯¯ê°t±,±º²F²®²Ð²ð³³8³f³”³Â³ð´8´€´Ðµ^µÚ¶¶b¶z¶ä·‚·š·Ð¸0¸Ð¹R¹Ž¹ìºHºvºœºÒ»»(»B»d»†»¨»Ê»ð¼¼<¼b¼”¼º¼ä½½B½|½ª½Ú¾¾B¾r¾¬¾Ú¿ ¿D¿x¿®¿òÀ&À^À¤ÀÚÁÁTÁŠÁ¾ÂÂN˜Âôà Ã$Ã<ÃTÃlÅ„Ç`É É.ÉNÉjɒɠɮɼÉÊÉØÊ"ÊtÊ¦ÊØË*ËlÌÌœÍLÍÆÎ^ξÏDϘÏÒÐДÑÑlѶÑÖÒÒVÒÊÒüÓÓäÔÔ2ÔTÔtÔºÔðÕÕtÕ¤ÕîDdU.±/<²"í2±Ü<²"í2±/<²"í2²#ü<²"í23!%!!D þ$˜þhUú«DÍÁç@[–  ™ © V f  † – Æ Ö ö 9 I Y  Ë™ É F v † Æ Ö æ  I ™ ©  ô ¶ Ö æ  ¸ÿ€@¡¥HF V 4 &  › ¸ÿÀ@ —šHÄ Ô ä  ¸ÿ@¶“Hd  ¸ÿ@@.‰H ô à Â Ò ° ‚ ’ ¢ T d t F " 2   ¸ÿ€@IpxHr D T d 2  $  hä ô Ò ¦ ¶ Æ r ‚ ’ D T d 6    ö â  ¸ÿ€@(PUH6 V f v "   ð Ô ä À ” ¤ ´  ¸ÿ€@;?H  $ 8ä ô ° À Ð  ¸ÿÀ@-,1H   ð ” Ä Ô ä ` p D T t „ ” ´ Ä  ¸ÿÀ@H  /í?9/^]_]+]qqqrrr+rr^]+]]]]q_qq+qqrrrrrrrrr^]]]]]+qqqqqqqqqr+r+r+^]]]]+]]qqqrr^]]]qqq9/^]í3210#!!Çæ &þÚ ª×úþò‡‚D6@#˜/Ÿ˜Ï 0@©?3í2/]qí/]]qí10#!#!'Ûþ9Û‚ÿþÿ#Rsòµ M¸ÿÀ³ M ¸ÿà@& L   R¸@ R  ¸@    ! ¸ÿÀ@2 H  ®  ® ¯ Ï ÿ O¯Ï  ± /3?399//]q]q33í2233í22/+33Ì2299//Á‡+‡+ć+‡+Ä10‡ÀÀÀÀ‡ÀÀÀÀ‡ÀÀÀÀ‡ÀÀÀÀ+++3##!##53#533!33!!E×öRœPþÍP™O›¼FÏîT™R3TœT¤ýoH5F^þ´•þƒ}þƒ}•L”þþ”þ´LÿhVð5@I5¹-ÿÀ³ H.¸ÿÀ@ H@ H@ H4¸ÿÐ@ M M'¸ÿè@ M@ M2¸ÿø´ L¸ÿè@ L L-#6"" G*n);¸ÿøµ H;n¸ÿÀ@H)) An¸ÿÀ@[&5HKn¯ ¿  @H @H Gt0@€F.@-6 H6u!* ***$F@!À!`p€ °!!"//99//]q]9922/]]í+23333/]í2/++]íÞ+í9///]+í+í3Í29/3Í210+++++++++++#5.'%.#.54>753.'24.'>V8u¶~mr©wI6S=N–uHBw¥bmk–h@þøWP V¥Oý²5G,2D(J"32#3%2#".54>4.#"32>4.#"32>ç8`IK_77`ƒLH€_7ûAΘÑûÕH€`88a‚JI_76`ƒÄ"2"%5"#4$!3#ü"2"%6"#4$"3#°}¬i..i¬}„­g))g­ýÌ)f­„}¬j..i¬~„­f)üWrCDrVToDCpuVqCCqUTpDDqZÿ쇉8FTÅ@. LG( LI L L( L¸ÿè@- L  L?I9II/GBJ!@ H/O0¸ÿÀ@H'VM¸@#0JB $RO4/G!4_o *47.54>32>73267#".'#".4&#">.'326Z3Z|I *(ZgQ…`5BmŽK3zG8LÑ"^A-Z+ ;7L3^TH!Q_m=~¸v9 LAMQ3ZB&RMŠ9SY<[l”49HVG0d--5>ü¿V¼g'rQ.P;"0m‚}6@ ˜€ ¸ÿÀ³H¸ÿÀ@ H©?í9/++]qí10#!bÛ‚ÿfþW¨Ì.@ñ ñ` p  ñ¸ÿÀ· H ??/+í3/]qíÔí10.54>7!MpI##IpMPrI""IrPþWoÜèûŽùçÛotâèõ‡ˆõèáuþWDÌ?@)ñ ño   ñ`Oï0  ??/]]]qqí2/]qíÔí10>54.'!PrI""IrPMpI##IpMþWuáèõˆ‡õèâtoÛçùŽûèÜo‡K@+        ?3/]393333/]/933107''7'73ìëDúº¸’•º¾úDï×ohÅ=Õyüü{Ó=ÅhV¡Y± Q@,  ª@ 0 ­ ²?3í2Æ]q+Mæ9/3í2Æ_^]+Mæ10#!5!3!Çâþqâ’9þh˜à˜þhà‹þð1"@ —– 0  ›¨ /æí/]ýíÆ210%#>5#!°(¹0$!BCn]N##NRR(1P™Xµº¼?í//105!P™ôô‹¬1@– 0›/í9/]í103!‹!1þÏÿ×%Ì0¹ÿð@ M L¸ÿð³/?/82/]8310++3#îþâ)õú Qÿì–'&@nÏ)n@  s#s?í?í/]íÞqí10#".54>324.#"32>Jƒ³jj²€HG‚µng±Iþæ0M7;P10N97N2ÁÊþë«KJ«ËÕ¦CC¦þéÕ•Ãs./tÓ‘Âu00uÂ: S@$4D+;K noϸÿÀ@ H t?í2?3Í29/+33/]3í2/10]]35!5%!!]þ®a CÑÁÓÝåûPÑG!–"7@o!$n p_ s s?í?í3/9/]í3/íÎ2/í1035>54&#"%>32!G0Š—•wJ^[Z_þå >s­xr°x>Nz•ŒsŽÃi©yqr@^ZaaS’n?5f“^c ‡vprAç/ÿé)–;u@K&n'7 o1'11' o= o @H 6s,O&Ÿ&&&#s,s ` p ° À 0 @ € Ð  ?3/]qí?í3/]9/í9/+íÞí9///í9í10#".'%32654.+532>54&#"%>32)?~»|нy= !8Q7ep5Q^*b\*WF,a]Wkþç U¨^|²r6$IrNW€R(‡`™l9Fs’K-K6dg?L)ã*K:Wc`Xc’`/kU= ;Xoh v@:?o?OoŸ¯Ïßÿ ?Ooÿ@H n€¸ÿÀ@ Ht??39/33í29/+]q33í223/+]qr310!!5!34>7!¬þôýS:¼þ8 þ¹œþáÓüoÑž7:5 )/.þ?ÿì:(‚¹!ÿൠM !!¸ÿà@H! o¸ÿÀ@4&5H* n_ o  s$ß$ï$$$ ts? ß ï @  ?3/]]qí?í9/]qí3//]íÞ+í99//3+310+#".'%32654.#"!!!>32:C„Àv°yE 4L6i}9S5FZþî1Oý°*€Uh¤r<Õj³ƒI9eˆN!>0†~8Z@"5&Ñþœ%5Dz«Kÿì)–0i¹ÿø@ Mnn¸ÿÀ@1&)H2)oßïÿ$tßïP`.s P .s?í?3/]í9/]]q3í/qí2Þ+í9/í10+#"32.#">324.#"326)o4o$H*o_o ¸ÿÀ@!&/HSHo_ o  @&/H $Cu99M/uMu?í?í9/í99/+]íÎ+99//qí9íí910#".54>75.54>324.#"32>4.#"32>4<|¾ƒ‚¿}<0Ph7;^B#=v¯s{³t8#B_<>kN,þ¼*G64F*(H9>o˜ZMwV3  Q-5X?"#@YGÿì'–$8b@> M%o nÐàð:/o_@&)H4to *s  s  ?3/qí?í9/]q3í/+]íÎq9/íí210+#".'%32>7#".54>32%4.#"32>'þîü[‘lK[E9Z@#BS^0\–j9C~·tz»~Aþ×6N3/J42L1'K;$×þ‰þŒ&P~W%KH6n©s'<(Az­mp°y?S­þ÷À?O_ Ÿ¿Ï@Pp€œ?_Ÿ¿@"Hœ ¨/æí/+]í^]]]qqqqrr+r^]]]]qqqqrrr^]]]+qqqrrrr^]]]]qqqqrrrr^]]]qq/^]ÄýíÆ2í10!#>5#!Ç (¸1$ ðþæýRCn]N##NRR(V}YÍh@8R°R°?_ /]]]3/]39=/33/3ÞÔÁ‡+Á‡+ÄÁ‡+‡+Ä10 Vü¿AB‡äþ»þ¼ãU#X)H@3 @­ß?O@H­0p @`p À/]qí/+]qí/]3Î2105!5!UûýJßßýÙÝÝV}YÍh@8R°R°_ ?/]2/]]]39=/33/ÄÎ2Á‡+Á‡+ÄÁ‡+‡+Ä1075 5V@üÀ}ãDEäþyþ¾^m–#'B@ '– $$–)– 0 %$¸±?í3/?í9/9/]íÞí9/3í210!>54&#"%>32!m#:JNK<&þõ?ZfW9sj3VA*þã K‚½}x¼ƒEýI!BdO?86=I0UyZGJW3237332>54.#"32>7#".54>$324.#"32>7>VLƒ¯c*G2F[m;_L D€ºvf‚ 'œu/;oX5R ìš…൉]/"Ei޵nV “‡=><Š¢¼n‚ܱ†Z-?w«Ù’Ë)Á]ýy8N07\H6#ad0_TE Õï¬`+A+&,VC*DnŠEsܬi]Q˜þO|%2*Lˆ¼p~ØžZ?rž½ÖrW£ŽvT/*9 z"@19g®Èk‹Ü´€FvÈþø—/O9 )F]jp5r„.YƒT+*&3‘â@OR ^R ^ @H Çט†'Ww—§·ç¸ÿÀ@ÿÊÍHÈÇ×瘆w(÷È·¦—xG·çˆ˜gw8˜öÔäŶ“£„euTC$4ôåԵŤ•†dtCS4%óÔäŶ“£„ufTE$4håõÔų ’t„bP2B$@×ðâÄÔ²¤‚tRbD6$äôÖÄ¢²”v†dR4D&8òäÖ´¦„vTd&FÄô °dt”P4D„”´ÄäpDd°ÀÐ_  ?2?39/9]3í2//]^]_]]]]qqqqqr_rrrrrrrrrrr^]]]]]]]]]]]]qqqqqqqqqqqqqqrrrrrrrrr_rrrr^]]]]]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrrrr^]]]]]]qqqqqqqrrrrrr^]+]qqqqÖ^]+9‡+‡+ÄÀÀÁ‡+‡+ÄÀÀ10!!!! .'!m}ýç}þÙ\ý’    ‹•hþ˜úÛ#G;&&:G#þk‰j(d@#[_ o  #Z* *0**¸ÿÀ@'#H#Z 0"__oï#_#_?í?í9/]qrí9/]í2+]Þí9/]í910#!!24&#!!264.#!!2>jV•Æoý?…}ÆE…ˆ«³þ†ywþ°R}qR,Mg<þŠ:dI*’k™a-+X…Zx¥¯Õ_Pþ£Wþ 8L.þl/PTÿì–)c¹(ÿø´ L"¸ÿø@7 L\\+0+%[0 _ 0 ` àð_ ?í3/]q?3/í/]]í]Þí3/í10++%2>7#"$&546$32.#"SyY;d–ÏŒ·þô¯UU¬²ŠÏ—cþü:YxLkšc//dÔ/L`1aL’pEmà Ÿ¥ »e:iVG-S@'E€³on·„J‰q X¹ÿà´ L¸ÿè@1M M8 MM [0@Z0@__?í?í/^]í]qÞí10+++++#!!24.+32>qj¸û‘ýÆþ¤Ænþ×Cx§eÑúY—o?˰þõ´\Rªþú´{°q6üG>{¶‰ R@5 0 @  Z 0__oßÿï _ _?í?í9/]qí/]í2]Î99//q103!!!!!‰TüÓðýVäþžäþ䉘 ?@& 0 Z 0_/@1H_??í9/+]í/]í2]Î9/10!!!!°Ñý/þÙþLäýûäTÿ캖-p¹,ÿè³ M,¸ÿø³ M&¸ÿè³ M&¸ÿø@/ M\)\ / /0/)[0_$__?í?3/í9/í/]]í]Þí99//í10++++%2>75!5!#"$&546$32.#"&@veQþ¨f0ˆªÉq»þò®SX³·…Ï›iþðy±,`™m+;Q3vnãçü=k­yA‰´ ¦@R^  DI ¸ÿà³ M ¸ÿà³ M ¸ÿø@ M L L     ¸ÿÀ@ H 0 Z 0 ¸ÿà@ M ?2?3993+3/]í2]3/+833/839910+++++]]‡++Ä!!!! Xþ®þÙ'{Xý¦‹‡…ýþýý¬üÓ‰¤"@PZ 0_?í?/]í]Î103!!‰'ôûcä‰!0[¶. L ¸ÿà@ L L¸ÿø@ÿ L&&.\02Ë2½2‹22;2K2k2/22û2ï2«2Ë2Ÿ2[2{2‹2O2;2/2 2Çë2ß2›2»2Ë22K2{2?2 2+2û2ï2»2Û2Ÿ2¯2„2k2_2K24222ô2Ë2¿2¤2{2‹2o2T2;2/22—ë2ß2Ë2´2›22 2+2K2{22;2K2k2‹2»2Û2û2û2ï2Ä2«2Ÿ2‹2t2[2O242 2gÿ2@¯ä2»2Ë2¯2”2{2o2D2+22 2ô2Û2Ï22;2K2k2‹2»2;2[2{2‹2«2Ë2û2/227Ë2ë2´2›2t2K2$2 2û2Ô2»2¯2„2k2_2@22?2à2ð2Ï2 2?2O222 2 \ 0&&.?22?399//3/]í22^]]]]]qq_qqqqqqqrrrrrrr^]]]qqqqrrrrrrrrrrr^]]]]]]]]]]]qrrrrrrr^]]]]]]]]]]qqqqqqqqqqqrrrrrrr^]]]]]]]]]qqqqq_qqÞí2293310++++!46767#.'&'!!67>7!þÒþ þú‹ü    ø‰V3l-52OG@<4üî4<@GO:80j'üªüìZ*1540,*&ú‰=p@$ H \Ï@P`p€ 0 À ¸ÿè@ H \ 0 ¸ÿà@ L L   ?2?399//++/]í22+]qrÞqí22+10!!!&'.5!ãýšþúQo=,,&X(üÁûº*.'b23úTÿìã–'w¹&ÿȳ M&¸ÿà³ M ¸ÿà³ M ¸ÿØ@> M M M[¿Ï)0)@)`)p)€) ) )ð)[À 0    _#_?í?í/]]qí]qÞqí10++++++#"$&546$324.#"32>ãb¸þ÷§±þ÷²Y]µ ¬¬ µ^þÓ5h™eg›h45hšelœe0Ç¥þòÀhmà Ÿ¥ »ef¼þ÷¤o³€EE€³on·„JK…·‰N¹ ÿø@/ M[0`p€Z 0_/@!H_ ??í9/+]í/]í2qqÞí10+#!!!24&#!!2>=~Â…þ¢þÙy‡Æ‚?þ׃ƒþÏ9B_?Ã[©‚MþAv¤hmqþ7">WTþmã–$8€@ 6 M62¸ÿø@J M2,([%[¿:0:@:`:p:€: :ð:/[0*_  _4_?3/í3/í?í/]]í]qÞqí99//í10]]]]]+]+3267#".'.546$324.#"32>ãG‡Â|6DP.<6vF_ŽiI–á–K]µ ¬¬ µ^þÓ5h™eg›h45hšelœe0Çí·y:I)Ê 9g‘Xv¾ü“¥ »ef¼þ÷¤o³€EE€³on¸„JK…¸‰p@K( L[ ? O  p 0 Z 0__o¯@!H_?2?í9/+]í9/]í2]qÎq2/]83í9910+!!!!2 4&#!!2>Qþ¹þ¦þÙÀ„Å„A/SrC}þ‘‡}þ†‚B_=ýé;m›aOƒfEý°Ñgdþ`9N;ÿì–=m¹;ÿè@B M! M*Z)2Z)) Z? Z  O _ o  2-_$**$_ 0 0 @  ?3/]qí?3/í99/]íÞí99//íí10++#".'%32654.'.54>32.#"F“垌֙_ .QyV–Ÿ@jŠK5!Ó„ÜŸY',RtGHyW0'^¨ç?…Ðqü¦YS')V„[Püž‘Ô‹CH£µ M¸ÿð@ L M M¸ÿð³ M¸ÿè@1 MÀŸ`/ /_p °à0`À¸ÿð@!?oŸ¯¿ïÿŸ ??39//]q83/]qr83933]]]]10++++++)!67>7!BþÕý÷4" !1üw-^'.*)-&_/‰‹0¦¹!ÿè@ L  L/ L¸ÿè´ L¸ÿð@ L( L L¸ÿØ@ L)! )/000 002¸ÿð@ÿy¹™Ù‹ I$k292Y2+22é2Æ2I2i2‰2©2;2 2)2Ï 2W‹2y2f2I2;2&2 2Æû2É2é2»2‰2©2{2292Y2i2Ù2ù2Ë2™2¹2‹2}2[2?2O2$2 2k2‹2«2Ë2ë2_22+2K22–2W´2›22t2[2O22;22Û2û2Ï2k2‹2«2_2422ô2Û2Ï2´2‹22$2D2d2jû2Ô2@¤»22„2k2P2D2+22ë2Ä2‹2«2242T2t2û2Ô2»2¯2”2{2o2P2D2+229´2Ô2ô2›2t2K2[202$2 2ð2à2Ï2 2O2o222ð2ß2°2Ÿ2p22O2_2)/ ?2?3399//3^]]]]]]qqqqq_qrrrrrrr^]]]]]]]]]]]qqqqrrrrrrrrrr^]]]]]]qqqqqqrrrrrrrr^]^]]]]qqqq_qqqqqrrrrrr^]]]]]]]^]^]]]]]qqqq/^]]]q833/^]83933333310++++++++).'&'!!67>7!67>7!þ¢¿   ¾þ¢þ•+°  ®J²  ª+/%f07;;831,üÑüð@|194JF@>9îý;??FG8<3z9D Ž@   ¸ÿð@+°    / _  ? o Ÿ Ï ÿ ß  0  ¸ÿð@ ?2?39/333/]82/]]qr8399//q83839310]]]! ! ! ! þžþžþÈèþA8996þTÕ1ýÏåœþòýdý#5§@ ¸ÿð@ÿ K[‹›ËÛ +K[k‹›«ËÛ Z¤ + ; [   ; K k { » Ë û Î + ; k › « û » Û ë ” K {  { ‹ » ë û œû ä   ; K ‹ › Ë ô [ « Û  $ 4   4 D t „ ¤ Ä ô l¤ ´ Ô ä ‹ p  0 ` ° à ð Ÿ  @ p € ð ß   0 € À :ÿ   Ð à @D  P  ° à ð  ` p O 0  À ð Ÿ p € _  0 @ ??39/33/]]]]]qqqqqqrrrrr^]]]qqqr_rrr^]qqqrrr^]qqqr^]qq/^]íÆ]q82+Mæ82910!! !?þÚþ 5RV5Bý¾B?ý¬T=¨ p¹ÿà³ M¸ÿð@ M( M M¸ÿÀ@H  ¸ÿÀ@ H@ H__?í2?í2/+]3+_qÎ99//+310++++)5!5!!¨û•úýRöý#ÑÉçÍü3sþW‘Ì+@ð 0õõ?í?í/]qí3/]Ä10!!!sþìþWu¾ú¿ÿ×&Í,@ M M¸ÿð³/?/83/]8310++33þâî#)öú þW7Ì)@ð 0@õõ?í?í/]í2/]Ä105!!5!þêþW¿ø¾ø‹-E¹ÿè@ M M¸ÿð@ @H?33/2/+83Î829=/3310++ #!šþºþ¼ã‡B‰ðýüÿìÿ…ÿT·»/rí//105!™úNNBŸ?Þ0@!ƒ„‚p Œ/?_Ÿï/]qí/]íýí10 5!–þ¬ûŸ+þà<ÿì€N5D‰¶1 L¸ÿð@% M M L62 F"À)Ð)))"F¿FOFG¸ÿÀ@)H?54.#"%>32327#"&'#32>5‰N{V.CtœXé(;(þÛ @q¥oežn:# ((-je 8¯Ê-Q=$G;6X="+SzN`ƒQ%7;O2#;-GuV/2c_þv&<)˜ heep  #B9MK.Kb3‡ÿìÌ$4M@%GÏß6p6 -FиÿÀ³$(H¸ÿÀ@ H(O 2O ?3í???3í/++]í22qÞqí10#".'#!>5!3>324&#"3261fk0`VHþï3²uh–a.þÛlq+TB((@T+kt!{Ï—T.J663(#SÕþb =p`S•Ìy¸²"UmjŒT"±Pÿì7N 7@FFO"GO  @O?í3/]?3/í/íÞ]í3/í10".54>32.#"3267RÁ€@F„Á{i£vIþå `XqhÝPl  Gy¬P’Í|‡Ó‘L8a„LScº±þŠed K‰i?Tÿì\Ì$5D@*%Fß!!@$(H!7p7/GÀÐ0*O1O ??3í?3í?/]qíqÞ+]í2210!.5##".54>3234&4&5!4.#"32>L1¯zf•a/1fl5bTDþã(AS+6S9Ý*TB))46i[T–Íy{ΕT.H3 '26‹û O{"#kS!*ZŒcþ$V‘Pÿì-N'O¶F%F¸ÿÀ@''+H)/)O)_)o)Ÿ)$GR$$R Q?2/]í?í9/í/í2]Þ+í3/í10".54>32!3267"!.Ju»„FS¸f€µt6ýJ6V=J^ Al¡s+K7"¤nEÕ›Ôƒ:Y ß‡DuU1?B.hW9±?dFƒƒ#®ÌW¹ ÿà@ L¿€_F0¸ÿÀ@HQ O??3í2?í/+q3/3í22/]3/]q10+!#5354>32.#"3ÙþèžžHz[0]%-'3 Õ|ü„|¾q>iN, µ 1 U¾TþNZO3ET@3$4Fß//@$(H/GpGF>GÀÐ0*9O$!AO Q?2/í?3í?3í?/]qí3/íqÞ+]í2210".'%32>5<765##".54>3234>7!4.#"32>Tk£sE cP2S;!1±zg•b/2gll«0 Dƒ¿q(@S*6S:po*SB(þN+Mk@!AJCnQ:i^Q‘Éy}Ë’O\g73($‚Tüáv¯t:ÞfˆR"*Xˆ^¯²!SŠdÌa¹ÿà@&M Fà ð  !! !p!! !°!ð!ï!FиÿÀ³$(H¸ÿÀ@ H P?í3?3?/++]í2]qrÞ]í10+>32!4.#"!!¤9¬wb‡U&þè.J53S5!þá8S  '0  EmýÏÏùZÆ&>.vûFAlP,uÌ Ž@$W g      &6F–  ¸ÿÀ@ H / FиÿÀ³$(H¸ÿÀ@ H{‹ H ?2??9/933+]/++]í2]3/+833]39910]]]]]!!!! Bþßyþç‚.þ„™êTþjÌü®ÀþZýl¨ÌE@0F¿pß@P °`ÀÐ??]]qqqqrÞ]qqí103!Ìú4‡žO9¨¹(ÿð´ L¸ÿà@U L 9F -Fä,ô,,;T;„;Ô;ä;;;›;»;Û;T;;;/;;;°;Ð;à;Ÿ;`;€;/; F 0 Ð  ¸ÿÀ@$(H 3P!&- ?22??3í2/+]í2]]]]qq_qqqqrrÞ]í9/í210++!4.#"!4.'!3>323>32!4.#" '?-+F3þç 4›l|—CQ_8Y{M#þé'?-*E3_?iK*-SsEý¼H#JC5 5@@|pysCZ7@p˜XýQ_?iK*+OnCý¯‡dO#a¹ÿà@&MFà#ð##%% %p%% %°%ð%ï% FÐ  ¸ÿÀ³$(H ¸ÿÀ@ H P ?2??í3/++]í2]qrÞ]í10+!4.#"!4.'!3>32L.J53S324&#"32>“EŠÎ‰„ʉFCˆÎŠ’Îƒ=þÚ~x|„#@Z6>aB"|ΕSR”Ï}yÍ–TT•ÍzÁ®°¿aŒZ++ZŒ‡þWQ$6]¹"ÿà@M M%GÏß8p8-FиÿÀ³$(H¸ÿÀ@ H(O 2O ?3í???3í/++]í22qÞqí10++#".'#!4&'!3>324&#"32>1fk0_VIþç3²ug–a/þÛpo*SA)(AR*6T9"{ЖU-I6(5;þaêS‚$(48k\T”Íz¹³#UmjT#+[ŽTþWZO!2D@*" Fß@$(H4p4,GÀÐ0.O'O?3í???3í/]qíqÞ+]í22104>324>7!!46767##".%4.#"32>T2gll«0þé1¶zf•a/ë(@S*6S:ß*SB({Ï•T\g73($‚SûÂ6i_T–ÍlŒS!*ZŒbþ$V‡þO^¹ÿè´ L¸ÿÀ@ HŸÐ/_¯ FиÿÀ³$(H¸ÿÀ@ HP ???3í/++]í2]]q3/+10+34.'!3>32.#" *9P;1 7&iu<#NG9 ;FE;]A# ë ª§ýíHÿìO;˜¹:ÿè@ M! L¸ÿð@ M2F*F)¸ÿÀ@F H)) FÏßO=P=0=°=@=/= F 2/Q$Ò*p**/***$Q  ?3/]í?3/]]]í99/í]]qrÞ]qí99//+íí10+++#".'732>54.'.54>32.#"A|´sg¦}T÷ *>S50S="1UsAD„h@ ðR °.°À±Où° À¹Áêðv °.± °À±Où°À²...¶ .......°@01!!! !!´Ñ-ϸþäþ×Ûâþ×þèÿ;üÅ;ûÆrüŽ:d: º¶ L¸ÿè´ L¸ÿè@3 L L          ¸ÿÀ@ H ¸ÿð@OŸð à O Ÿ  ?2?39/3]]q/]83333/+]833393‡ÀÀ‡ÀÀÀÀ‡ÀÀ10++++! ! !! 3üþþÕŒþ‡/çæ1þ‡ˆþx/ þžbýøýÎþWh:#¹$?° ͱ?°3°/°Ö± °901%!#"'52676?!Hú&þTQW_šeL5U@3)þT)ñIûÅRY È*f0/DÇ: P@2GGïÿ @ À Ð  O_PP?í2?í2/]]qrÎ/99//]íí1035!5!!Dþ )ýçJǨËÉý\Í!þWòÌ-W@6( L( L! ,,(ð_  Ÿ¯0P" õ +õ+õ?í?í9/í9/]]33/]í22/3910++".54.'5>546;#";-EmM( 75.54&+532++9]O!8K+*K9!O]9ÅŠ!323267TK‘KBm.'C=:3ˆT)RPN&-k0D€4 =?F*  Õ&.  2*ÛÂþ¹è:s@ÿ–  ; K [ { ‹ »  + ; k û Ê « ë û [ › « » Û ë  [ k ‹ › Ë š + K [ ‹ Ë  @ÒÖH @¾ÁH @©¬H @”—H´ ;  @‚H @vyH d  + ; K iû Ô  @adHt „ ;   û ä € [ k { $ 4 ë Ô » ” ¤ 0 $   8” ¤ ä ô { ‹ T d  ð à ß @ P À ?@   Ï  @ P p € ° ¸³?í?9/^]]qqqqq_qrrrr^]]]]]]]qqqqqrrrr+rr^]]]++qq++++qr^]qr^]q9/^]í3210!3È þÚ æ ,þòûÕü+3ÿáD$:±?°%/°Ö°Ͱ°ܱ22°ͱ22°° ܰ"2° Ͱ!2° °&Ö0167#5&'&5476753&'úC)@B*âxiq¹¢ÞxqwuÛ¢¯ngþæn`©<\þ®[9,˜ ’em¿½‘‡ã鎌¸¸d]‘ˆ)^–0›@ M( L%#'n n)  0n¸ÿÀ@7&5H)2@&=#5354>32.#"!!!267^ 327'#"&''7.732>54.#"†…ƒ0p<+L9!!9L++L9!!9Ljö³¸ÿè@ M M  ¸ÿð@e;¯/OŸß  pðPÐàP` ð \ ;     € 0 @ Ð   ¸´  ¸@O     ??399//]q33í23í29/]qr^]33í2292/^]qr83^]3/]qr^]83^]993310++]!!!!!5!5!7!5!! !þþ®Rþ®þðþ°Pþ®þ”!!³’¢“ìì“¢’Îý¬Tœþ9¢®=´«¸ÿÀ@ H@ P €    ¸ÿÀ@ H?/99//+]/+2í210!!œþú¤ üöû• üõ5ÿ “K]ʹVÿà³ MW¸ÿà´ L¸ÿà@ LF L$¸ÿè@ LJ( LDQILH5H"HHIY"TH?I¸ÿÀ@H"I??I",_-H,@H,QDYD2¸@'-à--- '0'@'' ¸·ð?2/]í/]3/]í9933/+íÎ9////+í99íííí9910++++++2.#"#".'732654.'.54>7.5464.'>?W™xQï'9I)pi.Ng9U—pB3I/)C/:x¶|g§Uí .DX5z~*T~T?†mG8O0&E3ëÓ GoN]d0Qi8)H4“BhI"1;A'5& 0JlP,QE60=O2NZ1DnP%-<$AP-:)!-HkN1P?01AP0•¤üÅ'6) IE'5% "4¯›Šc@J  P € ° à  0 ` À ð A…_…o/?_ï@+324.#"32>%32>7#".54>32.#"Æ4^ƒ¡¹dc¹ …^44^„¡¸d–Åqp`¦ÞT›ˆnP+`¥Ý~Þ¦`üÊ8T9)@0!  9TtOh˜d00b•dNtS9œ />):T5Ãd¹¡ƒ^44^ƒ¡¹dd¸¡„^4rÄþù–~Ý¥`,Oo‡›TÞ¦``¦Þ>hK**3/+UD)?qœ\`šk:%?S.).%'He-Õö‹2Aйÿà@ L L( Lá 8à(à ð  ¸ÿÀ@4H  C?áo@H9æ 3?Ÿ@HäÞ/#3ä,¸?2í23?í3/+qr9/í/+]íÜ]+]2í29/í10+++"&54>?54.#"'>3232>7#"&'#'2>=as.Ng9“&%¾+KjEAiL)! ?GQ"o#7&\6).Õia4>4>ÃH&Ã04<2ÉCBÉ5_5o55@Hp44¸ÿÀ@H4C55C4+È+È?í?í9///+]+qíí93/íÞ]í99//í2/83í29910++#".54>324.#"32>##!24&+326Æ4^ƒ¡¹dc¹ …^44^„¡¸d–Åqp`¦ÞT›ˆnP+`¥Ý~Þ¦`þE²u²J™˜`NÕÛKE…BCÃd¹¡ƒ^44^ƒ¡¹dd¸¡„^4rÄþù–~Ý¥`,Oo‡›TÞ¦``¦Þþå9þÇ/q^vþ°;9<öGÿï¬| ²¹/í//10!5!|ûs¬^ZÛ‘'O¹ÿè´ L¸ÿè@, L  L L¬¬0 @ ` p À  #®®?í3/í/]í3/í10++++#".54>324.#"32>Û3WuBBuW22WuBBuW3ž,;##<--<##;,VBsU11UsBCsU00UsC#=--=#"=..=14ö u@E  ª@ /_o  ­ ­@ Ï@!HÀ_@/]]]Æ+]+3Mý2æ/í9/3Ä_^]+ÄMý22ôÄ10#!5!3!5!¢àþo‘à’ûýÃþ«UßTþ¬ßý=ßß3¶’!K¹ÿØ@* Lâ   # ââ_ o   äÞåÝ?í?í3/]9/í3/íÎ]2/í10+'>54&#"'>32!5KTTC*'*U Â+HfBGiE",DSM?j¶y5Q@638"*1b.P<" 8M-5P@534Š,¬~’5m@B"á#0á-#--#á7 á0ä ("Ÿ"ÿ""@H""ä(Þ ä€ P ` p  ß?3/]qí?í3/+]q9/í9/íÞí9///í9í10#".'732654.+532>54&#"'>32~–ŠTqG!½7615)183-$.+*3º2Mc9DfC"IO-A)cp$;J' -0/1%~#',,- 3M33E'@[.9WŸUÞ*@‚„ƒŒ/?_Ÿï/]qí/íýí105!Wüþ¬Ÿ +þì†þV!:'G@Fï"ÿ"") Fàðà¸ÿÀ@ H P  ??33í??3/+]qí22Þqí210!.5##"&'#!!32>5! +1:!4Qþç(C42D*N+1@%0* 7þƒäý£@hK)-QsFBü¸"IC6Gþø/O@+ M—O _  —Ÿ0`€¸³/3?í29/]/]]í3/]9/]í10+###".54>3!¬œÃ›Q…`52_ŠXuòúúú¾-X†XT…]2­D@ – 0›/í/]í10! 1þÏ`þWô̹ÿس M¸ÿè@% M@ Mˆ K4  $¸ÿÀ@/_dHà 0P`0`p;p °€°Ààð¸ÿÀ³SXH¸ÿÀ³DJH¸ÿÀ@!58HÀð/ ’?í?9/Í^]]]qq+++qr^]q_q+r/^]]/]í9/33310+++#"'532654&#*73ôGtU-8*K>8B >!^[ë'F3v% #"¬RRR¶j† T¹ÿà@ H H  à  0¸ÿà@ HÜäÝ?í2?3+Í]29/33/3í2/]10++535733R¸­´¯ª¶yÔlzuý©y-ÕÉ‹'Q¹ÿè´ L ¸ÿè@) L L Lâ)â  @H åÞ#å¸?í?í/+]íÞ]í10++++#".54>324.#"32>É+U~TP{T+)S~TXQ&È!1!!3##0!4#1M€\33[€NK\44\K;N//N:7!32>7#".!r#:JNK<& ?ZfW9sj3VA* K‚½}x¼ƒE·þß8BdO?86=I0Ux[GJV=Xf8P0 YœtD8i–_þòÿÿ3‘&$šV´&¸ÿÊ´%+5+5ÿÿ3‘&$›æ@ &Z%+5+5ÿÿ3‘+&$œ@ &%+5+5ÿÿ3‘&$Ÿ@ & 0%+5+5ÿÿ3‘Õ&$ž@ &%+55+55ÿÿ3‘&$P¾¢@ 8%+55?55°’@[ ZR^+ ; K   ?_o_ _ _ o ß ÿ ï   _ _?2í?í299//]qíí/]_qÎ9///]q9‡+‡+ÄÀÀ3í210!!!!!!!!#!£þ>¬þϼÇýCýæûó=¿\hþ˜ãþÝþ…㨠8C>þoÿÿTþW–&&xé ¶!1*%+5ÿÿ‰&(š5´ &¸ÿô  %+5+5ÿÿ‰&(›®@  &<  %+5+5ÿÿ‰+&(œs@  & %+5+5ÿÿ‰Õ&(žs@  & %+55+55ÿÿÿØÕ&,š´&¸ÿº´%+5+5ÿÿhf&,›@ &J%+5+5ÿÿÿ«Œ+&,œÆ´&¸ÿÿ´ %+5+5ÿÿÿ×bÕ&,žÈ@ &%+55+55q!u@N L L[#€#Z _/  ¯  @36H @+1H @$)H @"H @H _ _?í?í9/+++++]3í2/3/3í2qÞí9/10++#!#53!24.+!!32>qj¸û‘ýÆþ¤Ænþ×Cx§eÑdþœúY—o?˰þõ´\RÛTRªþú´{¯p5þ“Ûþ•=zµÿÿ‰=&1ŸŽ@ &/%+5+5ÿÿTÿìã&2šÌ@ (&), %+5+5ÿÿTÿìã&2›@ (&T(+ %+5+5ÿÿTÿìã+&2œÅ´)&¸ÿÿ´.( %+5+5ÿÿTÿìã&2Ÿ¾´(&¸ÿø´3C %+5+5ÿÿTÿìãÕ&2žÆ¶(&¸ÿÿ´,* %+55+55V¨Vª }¹ÿè@!H#3C !H, < L ¸ÿè@;!H#3C!H,<L 0 P   @`pÀ  Àð¸ÿÀ´ H²?+]q3/]310]+]+]+]+ 7   Vdþ ž``žþ `žþ þœFf`œþ¢`žþžþ¢ bþšTÿ·äÁ&2è¹0ÿð@ M* M$ M$ M¸ÿø@ M M¸ÿð³ M¸ÿè@ M L ¸ÿð@ M M M¸ÿè³ M¸ÿð@ M L ¸ÿè³ M ¸ÿð@; M+*'[ 4'[0*+."_  ._ ?3/í?3/9í9/]]3íÞ29í910+++++++++++++++++7&546$3273#"'4&'32>%.#"“šml]µ ¬g±JRÁŽprb¸þö§Ô”[a++ýã+k?le0üÆ)+-f>g›h4IÚc!²¥ »e'#uË^þã´¥þòÀhMd¥>üüK…¸lc¨AE€³ÿÿ{ÿìJ&8šI´&¸ÿ¼´%+5+5ÿÿ{ÿìJ&8›ù@ &l%+5+5ÿÿ{ÿìJ+&8œ‹´&¸ÿþ´ %+5+5ÿÿ{ÿìJÕ&8žŽ@ &%+55+55ÿÿ#5&<›µ@  &_ %+5+5‰B@'[ Z 0__ _o_ o    ??99//]]íí/]í22Þí10#!!!!24&#!!2>=~Â…þ¢þÙ'R‡Æ‚?þ׃ƒþÏ9B_?á[¥|Jþåé?s¢gn|þ%$AXÿì©Ì?‡¹>ÿð@ L L¸ÿð@, L9FF2@ H2@ H22'FAŸAPA&FÐ''¸ÿÀ³$(H'¸ÿÀ@ H'9"P-'O?íÄ?í9/++]í]]Þí9///++íí10+++#"&'532654.54>54&#"!4>32©,_’fG><>=QJ2KXK2!292!]Xglþç<{º~r¨m5!2;2!2JXJ28IzX1Î  E9.D;9I_B.E:25>(ANü ïo±{B6[zD6UD6-)17AUqÿÿ4ÿìxÞ&DøC®´E&¸ÿ™´FI)%+5+5ÿÿ4ÿìxÞ&Døt @ E& EH)%+5+5ÿÿ4ÿìxù&DøKÇ´F&¸ÿâ´KE)%+5+5ÿÿ4ÿìxÄ&DøR°´E&¸ÿÒ´P`)%+5+5ÿÿ4ÿìxŠ&Døi×¶E&¸ÿ×´IG)%+55+55ÿÿ4ÿìx•&DøP )¶J&¸ÿÙ´OE)%+55+55BÿìÈN=LU¯@  L  L&¸ÿà@& L&R0GDD /8F99SF¿/Ï/ß//W_W WG¸ÿÀ@7HJGO _ o  D0QRR>MQ$)$/$5>O8 888?33/]í2?3/]3í29/3í2/]í3/+í]]Þqí3/í9/3í29910+++"&'#".54>?54.#"%>32>32!3267%2>="!.å—Ü?MeOO~X/Ex [ð+?(%;*þÛ Ar¦rÙtE­`€µt6ýJ7U;J^ Al¡ü˜9\B#˜0U@&K3+K7"¤nqt2T="+SzN`‚Q%7;O2#;-GuV/k92Y ß‡AqS/?B.hW9Ä1Oe3- #B9MKí?dFƒƒÿÿPþW7N&Fx# ¶ (!%+5ÿÿPÿì-Þ&HCÝ´(&¸ÿß´),%+5+5ÿÿPÿì-Þ&HtK@ (&b(+%+5+5ÿÿPÿì-ù&HKß@ )&.(%+5+5ÿÿPÿì-Š&Hiô@ (& ,*%+55+55ÿÿÿÀ½Þ&ñCÿ~´&¸ÿ¡´%+5+5ÿÿrpÞ&ñt@ &S%+5+5ÿÿÿ­Žù&ñK­@ & %+5+5ÿÿÿØcŠ&ñiÈ@ &%+55+55Pÿî“ß'5§¹ÿø@ L@ L¸ÿØ´ L%¸ÿð´ L¸ÿÐ@ L.(G%!'!¸ÿÀ@, H!'!'7.G%'&&!+OP`!3O ?í?99//]í933/39/íÎ99//+3/]9í910+++++#".54>32.'57.'!%4&#"326XEtT.D‰Î‰„ÊŠGCˆÎŠ.Z"F.þܦ9…D%(Q' d~x|„#@Z6}†òF¡µÊozÌ“RIƒ·nkµ„JHn5z¸F.X*.q¼üº ’PsK#ÿÿ‡dÄ&QR @ $& /?"%+5+5ÿÿPÿì“Þ&RC´$&¸ÿÕ´%( %+5+5ÿÿPÿì“Þ&Rtz@ $&^$' %+5+5ÿÿPÿì“ù&RK´%&¸ÿÿ´*$ %+5+5ÿÿPÿì“Ä&RRø´$&¸ÿÿ´/? %+5+5ÿÿPÿ쓊&Ri@ $&(& %+55+551ª4ª M@( ª  ­@­ ­²?íÖ]í+Möí9/ÄýÄÆ_^]+Mæ10535!53ºîý‰ý†îÁééþxààþqééÿÉÚm#/€¹ÿÐ@ L 0 L L¸ÿÐ@ L L¸ÿè³ M¸ÿà@( M'($G 1G ('+!O+O ?3í?3í9/3íÞ29í910+++++++#"&'#7.54>3273&#"4&'32>“EŠÎ‰c¡@q·Å;;CˆÎŠh£?e¸¸;6üä—aB"|ΕS.+|×IÁtyÍ–T+(rÎJÄs\GÍE°¿/Q"þ4%#+ZŒÿÿÿì\Þ&XCÙÿÿÿì\Þ&Xtxÿÿÿì\ù&XKüÿÿÿì\Š&XiÿÿþWhÞ&\tFþWÌ"2O@#GÏß4+!FÐ""¸ÿÀ³$(H"¸ÿÀ@ H"0O&O @5;H !???+3í?3í/++]í22Þqí10!3>32#".'#!4&#"3263²ug–a/1fk0_VIþçÛop*SA)(AR*luÌþ2<k\PŽÃtuÆQ-I6(5;þa±¬¦ O†ecƒN ¥ÿÿþWhŠ&\iñÿÿ3‘©&$MŒN@ &%+5+5ÿÿ<ÿì€[&DMó´G&¸ÿë´EF)%+5+5ÿÿ3‘&$¡†@ &&%+5+5ÿÿ<ÿì€â&DN´E&¸ÿæ´JV)%+5+5ÿÿ3þb‘&$Qµ ¹ÿ§´ %+5ÿÿ<þW€N&DQa³P¸ÿd´PP))%+]5ÿÿTÿì&&›5@ *&™*-%+5+5ÿÿPÿì7Þ&Ftg@ !&y!$%+5+5ÿÿTÿì+&&œÌ@ +&00*%+5+5ÿÿPÿì7ù&FKæ@ "&'!%+5+5ÿÿTÿìÚ&&O¾@ *&!*,%+5+5ÿÿPÿì7Ì&FO ¶!#%+5ÿÿTÿì+&&¸@ *&,2%+5+5ÿÿPÿì7ù&FLÖ@ !&#)%+5+5ÿÿ‰q+&'f´&¸ÿ¿´"%+5+5ÿÿTÿìÁÌ&G˜[K@ Ax@@ %+5?5ÿÿqTÿìÙÌ,=|@7,,)-Fß@$(H??7GÀÐ0+R,,2Q# ¸ÿÀ@H,,9O ???3í99//+]3í3í2/]qíqÎ+]22/í2229/105!3#!.5##".54>3234&4&=!54.#"32>;„„þð1°zf•a/1fl5bTDþâ"(AS+6S9Ý*TB)A‹‹ªüUO{")46i[QÆvwÇP.H3 '26~ªüÐh…N'T†_þ¢!R‰ÿÿ‰©&(M^N´&¸ÿí´ %+5+5ÿÿPÿì-[&HMõ@ *& ()%+5+5ÿÿ‰&(¡a´ &¸ÿ÷´ %+5+5ÿÿPÿì-â&HN´(&¸ÿû´-9%+5+5ÿÿ‰Ú&(Om´ &¸ÿú´  %+5+5ÿÿPÿì-Ì&HOñ ¶(*%+5ÿÿ‰þW&(Qí³¸ÿj´ %+]5ÿÿPþh-N&HQÏ´33¸ÿô´33%+532!4.#"!#535!!!¤9¬wb‡U&þè.J53S5!‡ŸËÓ åþý8S  '0  Em»ÀÀ>ø^Æ&>.vûFAlP,ÿÿ‰þ9´&.’´'¸ÿÒ´  %+5+5ÿÿþ9uÌ&N’y¹ÿÙ´  %+5u: €¹ ÿø@ M( M M ¸ÿè@ M M  ¸ÿÀ@ H  FиÿÀ³$(H¸ÿÀ@ H ?2?39933/++]í23/8+3339910+++++!!!! Bþßyþç‚.þ„™êTþj:þ@ÀþZýlÿÿ‰¤&/›­´&¸ÿm´ %+5+5ÿÿjhf&O›O@ &M%+5+5ÿÿ‰þ9¤&/’™¹ÿä´%+5ÿÿþ9¨Ì&O’: ¶%+5ÿÿ‰¤&/˜r@ Ç%+5?5ÿÿÌ&O˜°K@ y%+5?5ÿÿ‰¤&/OÕýŽ ¶“%+5ÿÿqÌ&OOý޹ ÿÀ³H ¸ÿÀ²H++¤ E@&/?  Z   _?í?99//923/33/í2Î9/]10357!%!‰‰‰'3þÍôãAáB¼ýѓߓþtç)Ì z@PàðFï  ¿pß   °  `  ï € ° À Ð :  5   ??99//92]3]]]qqqqÎ]qq22/]í22/]r10!57!7¨þç}}Íý31E×EÄýØJÕÿÿ‰=&1›ç@ &Z%+5+5ÿÿ‡dÞ&Qt„@ $&d$'"%+5+5ÿÿ‰þ9=&1’ü¹ÿû´%+5ÿÿ‡þ9dO&Q’› ¶.$"%+5ÿÿ‰=+&1ˆ´&¸ÿû´%+5+5ÿÿ‡dù&QLò´$&¸ÿí´&,"%+5+5ÿÿÿê,'QÈ ÿ_B¹ÿ¶@+$$%À¯ à po?]]]]]]qqqqqq5+5…ÿìK•9P¹8ÿø@. LZ5;)Z 0)_/$ _?2/]í???í2/]í2Þí9/]10+".'732>54.#"!4.'!3>32ˆJs\H Ê%,46C$ CgGL†c9þÙ  a{‘Qu¨j2*g®-C+«*!-V€R'^†U';cƒHü¹D%\ZL?EE>dF'@…Ì‹þ¥‚Ð’N‡þWdO3g@+2 L Fà.ð..55 5p55 5°5ð5ï5%FиÿÀ³$(H¸ÿÀ@ H%P) P?í???í3/++]í2]qrÞ]í910+"&'532>54.#"!4.'!3>32E8S  '1 .J53S.›?iK*-SsEý¼H#JC5 5@@|p@p˜XüÑAlP,ÿÿTÿìã©&2MÆN@ *&() %+5+5ÿÿPÿì“[&RM @ &&$% %+5+5ÿÿTÿìã&2¡µ´(&¸ÿ÷´-9 %+5+5ÿÿPÿì“â&RNP@ $&)5 %+5+5ÿÿTÿìã&2 1@ (&o)2 %+55+55ÿÿPÿì“Ì&RS@ $&d%. %+55+55Tÿö°Œ+¹&ÿè³ M ¸ÿè@K M[+;K++---@ H#[0__oßÿï( _ (_?2í2?3í29/]qí/]]í+_qÎ9///]í210++!#"$&546$32!!!!!.#"3267à&k6±þ÷²Y]µ ¬8c0¡ýe^ý¢Äü^,g›h45išd.V&j¿ Ÿ¥·bãþÝþ…ã‘ B|°on´FPÿìKN*:C_@@G++ %F&&AF¸ÿÀ@"'.HE€E1G Q@@6;.O"6O%%%?33/]í2?3í29/í/í]Þ+í3/í9/í29910"&'#".54>32>32!32674&#"32>"!.hv¹BEĄʉFCˆÎІÂBG¾j€µt6ýJ7U;J^ Al¡ý’~x|„#@Z6>aB"û+K7"¤nOPLSR”Ï}yÍ–TPIQHY ß‡AqS/?B.hW92Á®°¿aŒZ++ZŒà?dFƒƒÿÿ‰&5›Í@ & %+5+5ÿÿ‡ Þ&Ut¶@ &I!%+5+5ÿÿ‰þ9&5’¹ÿÔ´'%+5ÿÿ‡þ9þO&U’9¹ÿX´(%+5ÿÿ‰+&5f´&¸ÿ©´%%+5+5ÿÿ8ù&UL8´&¸ÿæ´ &%+5+5ÿÿ;ÿì&6›Ô@ >&‰>A %+5+5ÿÿHÿìÞ&Vt9@ <&[ %+5+5ÿÿHÿìù&VKÆ@ =&B< %+5+5ÿÿ;þW–&6x¦ ¶/E> %+5ÿÿHþWO&Vx ¶C< %+5ÿÿ;ÿì+&6Z@ >&@F %+5+5ÿÿHÿìù&VLÍ@ <& >D %+5+5ÿÿþWÍ'xC7ÿÿþW‘8'xœWÿÿÍ+&7!@ & %+5+5ÿÿÿîÕÌ&W˜oK@  ""["" %+]]5ÍO@‡    ok  + { ‹ › ;  [ k « » ; { ‹ Ë Û  + ; [ k { « ë û Z ËÛë´ K[›‹»Ë@*4H t„¤´ô¸ÿÀ@ÿÞáHk{T;$ÌðÔ仄”¤kT;Ûë°À$Tdt¤ûàÔ«”[D+šû„´Ô[4 »@P$4äôÀ¤´‹pTd;$hûäË 4DT„ôËÛ´‹t;[$ ëûÐÄ›D 7ô{‹›@C»Ëo+;K K[‹«ÛÿÏß 0p _ _  ??9/3í2í2^]]_]qrrrrr^]]]]]]qqqqqqqqrrrrr^]]]]]]]]qqqrrrrr^]]]]]]]]]qqqrrrrrrrr^]]]]+]qq/^]+]qrr3í2Æ]qr^]r^]+Mæ99103#!#53!5!ääþÙããþ9¶þ“¾ýŽr¾määÿî‘8q@H( L_F  O_o@&,H  O  Oß¿ïO?í/]q3í2?3/3í2/]+q3/2í2/]3/3/10+"&=#535#53733#3#3267¤|†‰—X°Í͹¹32.#"!ŽHz[0]%-'3 þè«>iN, µ 1 ûq¨þW ®K¹ ÿà@( L  n  u P`p u ??í9/]3í2/3Î9/33í2910+.#"3#!#737>32á  A9 Ô$Õûþçûž%ž 1V‚\31,ßB=k¾ûñ¾‡>iN, ÿÿ3‘D&$'P¾“›ó-3@!PB@B0B BB8g=@%%+55+5?55]]]]5ÿÿ<ÿì€Ü&D'Ptcþ7@Pr@r0r rrJ&[mp)%¸ÿÛ´OE)%+55+5+55]]]]5ÿÿ°&†›ä´&¸`´%+5+5ÿÿBÿìÈÞ&¦t¯@ V&€VY .%+5+5ÿÿTÿ·ä&˜›@ 3&T36%+5+5ÿÿÿÉÚÞ&¸tz@ 0&b03 %+5+5ÿÿ;þ9–'’ß6ÿÿHþ9O'’kVÿÿþ9Í'’–7ÿÿþ9‘8'’ŠWŸáù y@=& 6 F )9I &6Fƒ)9Iƒ 0@p ÀÐð¸ÿÀ@%HŽ/?_Ÿï/]q3í2/+]qí]/í]933]]10#'##53áŸËÓ å»ÀÀ>Ÿáù y@3)9I&6F)9Iƒ 0@p ÀÐð¸ÿÀ@%73'P~Y4£$2?"$?2"¤3W~Ÿ3YuB'>**>'BuY3ÈýáÌ@ FS?í9/í105!ÈýÏÏ'p#l'L¹ÿè´ L¸ÿè@* L  L L‡‰‡_ Ÿ  @H ””#‘/íôí/+]íôí10++++#".54>324.#"32>#(E]44]E((E]44]E("/.""./"n5]E''E]54]E((E]4-""-/""/LþWЕ@m M M  K[ˆ  Û´Kô[‹4Ët 7Ë@,1HO?ŸÏ@"%H@H ‘?í?++^]qr_r+r^]]]qqqrrr/^]í/]9/810++".54>73326793W?$ 07™?B1-5?þW3J20Q>+ *s5*3 ‰!ÿòŸþÄâ¹ÿØ@ L LDdt”¤¸ÿÀ@mH   $!4!!!ô!à!Ä!Ô!°!”!¤!€!d!t!P!4!D! !!!ð!Ô!ä!À!¤!´!!t!„!`!D!T!0!!$!!A!¸ÿÀ@6@H /?_Ÿï/]q2íýí3+_^]]]]]]]]]]]qqqqqqqqqqqrrr//^]+]10++".#"#>3232>73,YTK" ‰/VI-ZTI! ‡.VŸ&/& --fX:&/& .-fX:ÿ¤ Ì =@( ‚ „ƒ‚„ƒ Œ/?_Ÿï/]q2í2/íýí/]íýí10#53#532ŽáëXŽáë " +þÿ" +¹Ÿÿä4@#‚Œ/?_Ÿï/]qí/]Í3/]í105!¹EÝŸ!$%þàn¦JU h± ¸ÿÀ@ H ‚   ¸ÿÀ@#H@HŒ/?_Ÿï/]qí+Ô+2í2/]Í3/]í3/Í3/+Í1053%53!53i;íµþ’ÈLȦ!Ž%þv)ÞÞÞÞÿÿ$‘‚&$Tÿkÿž`³¸ÿ5µ%¸ÿÀ³ååH¸ÿÀ³ääH¸ÿ€³ààH¸ÿÀ³ßßH¸ÿÀ³ÝÝH¸ÿÀ³ÜÜH¸ÿÀ³ÚÚH¸ÿÀ³ÙÙH¸ÿÀ³ØØH¸ÿÀ³××H¸ÿÀ@ ÖÖH@ÔÔH¸ÿÀ³ÓÓH¸ÿ€³ÒÒH¸ÿÀ³ÑÑH¸ÿ€³ÍÍH¸ÿÀ³ÌÌH¸ÿÀ³ËËH¸ÿÀ³ÊÊH¸ÿÀ³ÆÆH¸ÿÀ³ÅÅH¸ÿÀ³ÄÄH¸ÿÀ@ ÃÃH@ÁÁH¸ÿ€³ÀÀH¸ÿÀ³¿¿H¸ÿÀ@ ¾¾H@ººH¸ÿ€³¹¹H¸ÿÀ³¸¸H¸ÿÀ³··H¸ÿÀ³³³H¸ÿ€³²²H¸ÿÀ³±±H¸ÿÀ³¬¬H¸ÿÀ³ªªH¸ÿÀ³¦¦H¸ÿÀ³¥¥H¸ÿÀ@ ££H@¡¡H¸ÿÀ³  H¸ÿ€³ŸŸH¸ÿ€³žžH¸ÿÀ³H¸ÿ€³œœH¸ÿÀ³››H¸ÿÀ³ššH¸ÿ€³™™H¸ÿ€³˜˜H¸ÿ€³——H¸ÿ³––H¸ÿ³••H¸ÿ@³””H¸ÿ€³““H¸þÀ³’’H¸þÀ³‘‘H¸ÿ³H¸ÿ@³H¸ÿ@³ŽŽH¸ÿ³H¸þÀ³ŒŒH¸ÿ³‹‹H¸ÿ³ŠŠH¸ÿ@³‰‰H¸ÿ€³ˆˆH¸ÿ³‡‡H¸ÿ@³††H¸ÿ³……H¸ÿ@³„„H¸ÿ@³ƒƒH¸ÿ³‚‚H¸ÿ@³H¸ÿ€³€€H¸ÿ³H¸ÿ³~~H¸þÀ³}}H¸þÀ³||H¸ÿ³{{H¸ÿ@³zzH¸ÿ€³yyH¸þ€³xxH¸þÀ³wwH¸ÿ³vvH¸ÿ³uuH¸ÿ@³ttH¸ÿ€³ssH¸þÀ³rrH¸þÀ³qqH¸ÿ³ppH¸ÿ@³ooH¸ÿ€³nnH¸ÿ³mmH¸ÿ@³llH¸ÿ³kkH¸ÿ³jjH¸ÿ@³iiH¸ÿ³hhH¸ÿ@³ggH¸ÿ@³ffH¸ÿ³eeH¸ÿ@³ddH¸þÀ³ccH¸ÿ³bbH¸ÿ@³aaH¸ÿ€³``H¸ÿ€³__H¸ÿ@³^^H¸ÿ³]]H¸ÿ@³\\H¸ÿ@³[[H¸ÿ€³ZZH¸ÿÀ³YYH¸ÿ@³XXH¸ÿ³WWH¸ÿ@³VVH¸ÿ€³UUH¸ÿ€³TTH¸ÿ@³SSH¸ÿ€³RRH¸ÿ³QQH¸ÿ@³PPH¸ÿ€³OOH¸ÿ@³NNH¸ÿ@³MMH¸ÿ€³LLH¸ÿÀ³KKH¸ÿ€³JJH¸ÿ³IIH¸ÿ@³HHH¸ÿ€³GGH¸ÿ€³FFH¸ÿÀ³EEH¸ÿ€³DDH¸ÿ@³CCH¸ÿ@³BBH¸ÿ€³AAH¸ÿÀ³@@H¸ÿÀ³??H¸ÿ€³>>H¸ÿ@³==H¸ÿ€³<öKýµíb¸þ÷§±þ÷²Y]µ ¬¬ µ^þÓ5h™eg›h45hšelœe0;äp¥þòÀhmà Ÿ¥ »ef¼þ÷¤o³€EE€³on·„JK…·ÿÿ‰°,ÿÿ‰´.H‚¤@1R  ^ R^ 0¸ÿÀ³%)H¸ÿÀ@#HÀŸ`/ ¸ÿð@@%)H@#H?2?9/++q83]]]]3/++]q82933Á‡+Á‡+ÄÁ‡+‡+Ä10%!.'&'!!HþÏþß þÞþÌ +u0^&-)*.'^-ü‹ÿÿ‰!0ÿÿ‰=1TÓ L@   ¸ÿÀ@ H @H0 _ __?í?í9/í/]]+Î+9////10!!!5!5w9ûÇ\ûäü·äüGääWääÿÿTÿìã–2‰='@ZÏ Z 0`?2?í/]íÞqí10!!!! ýþÚ´ûsúÿÿ‰3Z M@+\ [ Z0_  _?í2?9/33í2/]]íÖíÎ99//]í1035 5!!!ZÀþQçýGsþv êû³éäþ‹†þBäÿÿÍ7ÿÿ#5<?ÿõS‹ (3õ@ÿ(\/ [!5§5·5×5ˆ5w5f5'5G5W55å5õ5Ö5Ç5¨5–5…5v5g585H5%555ÈØ5É5´5¥5†5–5w5X5E5&5655ø5ç5Õ5Æ5·5˜5‰5w5f5W5F5'5755õ5æ5Ç5×5¨5—5v5†5g5H5955&55˜Ø5ø5Ä5µ5¦5—5h5U5F5755ù5æ5Ç5×5¨5—5b5r5S5D5@ÿ555&55ó5ä5Õ5¶5Æ5§5–5„5u5V5f5G565'555gô5å5Ö5Å5¶5£55‚5t5f5R5D505"555ö5ä5Ö5´5¦5’5„5r5d5V5@525$555æ5ö5Ò5Ä5¶5”5¤5†5d5V545"5557â5ò5Ô5Â5°5¤5p5d5P5D555T5t5„5´5Ô5ä5;5 55ô5Û@55”5Ä5[5k5{54555)[O_o0_/_' ?Ý2í2?Ý2ýÄ/]í^]_]]]]]]qqqqrrrrrrrr_rrr^]]]]]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrr_rrrrrr^]]]]]]]]]]]]]]qqqqqqqqqqqrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrr^]]]]]]]]]]]]qqqqqqÞí9/33í22104&+32>5#".54>;5!32+;#"*ž¥TwM$ý”6”Ü’GJ•à–**–à•JG’Û•6ý”$MwT¥žÚ˜ªýq2YzýcÇX–ÆnwÊKžžKŠÃwnÆ–XÇåHzY2ªÿÿD;`#2@ÿÈ%Ø%è%¹%ª%›%‰%h%x%Y%J%)%9%%Ø%è%É%º%x%ˆ%¨%i%Z%K%9%% %Çú%Û%ë%·%Ç%ˆ%˜%y%j%(%8%% %È%è%ø%¹%ª%›%8%H%h%ˆ%)%%Ø%É%º%x%¨%i%Z%K%% %—ú%è%Ù%·%Ç%ˆ%y%j%(%% %û%ç%È%¹%ª%ˆ%s%`%B%R%4%%&%â%ò%Ô%Æ%©%@ÿ–%‚%t%f%%%gò%ä%¶%Æ%Ö%’%¢%„%F%V%v%2%$%%æ%É%¦%¶%”%†%t%f%B%4%%&%ö%Ô%–%¦%Æ%y%V%f%$%%%7ò%à%Ô%À%¤%´%‹%t%P%D%+%%%ä%Ë%´%%T%d%„%;%$%%ô%Û%”%{%%%4%T%d%Z ZÄÔ‹d K:ðÔäÀ¤@m´Dt„ ûï´Ô›$4Td„ ôÐÀ¯`O 0 % Z Dp  0    _ ??339/3í2/]]q^]íÞ^]]]]]_]]qqqqqqrrrrrrrr^]]]]qí9/3í2^]]]]]qqqqqqqqrrrrrrrrrrr_r^]]]]]]]qqqqqqqqqqrrrrrrrrr^]]]]]]]]]]qqqq_qqqqqqqrrrrrrrrrr^]]]]]]]]]qqqqqqqrrrrrrrrr^]]]]]]]]]]qqqqqqqqqq10!#".5!;!32>5!#Èþé(чA#JsQ  QsJ#A‡Ñ«þU«CƒÂÏþ-PpF ùý FpPÓþ1ƒCS–5q¹ÿð@B M M,$ @$`$Oo$$1[Ï7 Z°111À&&&&##&_%_?í?3í22/3//]q2/qíÎq2/í99//]]3310++267>3!!>54.#"!5!2.54>$5¥¸b0h¡q >ýaµ¢7išbc™j7£µýe> p¡f0b¸–Rœßf±™€3ä5Vç”ežl99lže”çVþËä3€™²fß›Rÿÿÿ×bÕ&,žÈ@ &%+55+55ÿÿ#5Õ&<žR¶ &¸ÿû´ %+55+55ÿÿPÿìÖä&~TN@ :&:=%+5+5ÿÿMÿì«ä&‚Tîõ@ 8&N8;%?¸€³ååH?¸@³ääH?¸€³ããH?¸@³ââH?¸@³ááH?¸@³ààH?¸@³ßßH?¸@³ÞÞH?¸@³ÝÝH?¸@³ÜÜH?¸@³ÛÛH?¸@³ÚÚH?¸@³ÙÙH?¸€³ØØH?¸@³××H?¸@³ÖÖH?¸@³ÕÕH?¸@³ÔÔH?¸@³ÓÓH?¸@³ÒÒH?¸@³ÑÑH?¸@³ÐÐH?¸@³ÏÏH?¸@³ÎÎH?¸@³ÍÍH?¸@³ÌÌH?¸³ËËH?¸@³ÊÊH?¸³ÉÉH?¸@³ÈÈH?¸³ÇÇH?¸@³ÆÆH?¸@³ÅÅH?¸@³ÄÄH?¸@³ÃÃH?¸³ÂÂH?¸@³ÁÁH?¸³ÀÀH?¸@³¿¿H?¸³¾¾H?¸@³½½H?¸³¼¼H?¸@³»»H?¸³ººH?¸@³¹¹H?¸³¸¸H?¸³··H?¸³¶¶H?¸³µµH?¸³´´H?¸³³³H?¸³²²H?¸³±±H?¸@³°°H?¸³¯¯H?¸³®®H?¸³­­H?¸³¬¬H?¸³««H?¸³ªªH?¸³©©H?¸³¨¨H?¸³§§H?¸³¦¦H?¸³¥¥H?¸@ ¤¤H?À££H?¸@ ¢¢H?À¡¡H?¸@   H?ÀŸŸH?¸³žžH?¸³H?¸³œœH?¸³››H?¸³ššH?¸@ ™™H?À˜˜H?¸@ ——H?À––H?¸@ ••H?À””H?¸@ ““H?À’’H?¸@"‘‘H?ÀH?ÀH?ÀŽŽH?ÀH?ÀŒŒH?À‹‹H?¸@ ŠŠH?À‰‰H?¸@ ˆˆH?À‡‡H?¸@ÿ††H?À……H?À„„H?ÀƒƒH?À‚‚H?ÀH?À€€H?ÀH?À~~H?À}}H?À||H?€{{H?ÀzzH?€yyH?ÀxxH?€wwH?ÀvvH?ÀuuH?ÀttH?ÀssH?ÀrrH?ÀqqH?€ppH?ÀooH?€nnH?ÀmmH?€llH?ÀkkH?€jjH?ÀiiH?€hhH?ÀggH?€ffH?€eeH?€ddH?€ccH?ÀbbH?€aaH?À``H?€__H?À^^H?€]]H?€\\H?€[[H?€ZZH?€YYH?€XXH?€WWH?€VVH?€UUH?€TTH?€@ÿSSH?€RRH?@QQH?€PPH?€OOH?€NNH?€MMH?€LLH?€KKH?€JJH?€IIH?€HHH?€GGH?@FFH?€EEH?@DDH?€CCH?@BBH?€AAH?@@@H?€??H?@>>H?@==H?@<7!!.'32>7.#"\AUoHÔÑãÜIu[B ( 60#$*þò  þ,E0'L?/ #7M30H.í8^E&'E]675/…:M—‚9 B?7.aŠY*-\‹]J…d;(XŒŽþWÌ >l¹ÿð´ L¸ÿð@ L1 4F@ H +F@! FиÿÀ³$(H¸ÿÀ@ H0O11&9P &O?í??í9/í9/++]í2Þí9/+í910++#"&'#!463232>54.#5>54.#"4o«we“7 þæù÷l¦q9#=Q.9s\:ý 9AF":X;$P~Yq,C/6P5•X›tB7'9\5þ׬íÜ/Z‚RIoR8 7]‰ô #A[88^D'Ærc$?/EoOþXk:šµ  M¸ÿØ@ M    ¸ÿÀ@ÿ HkT +K›ûÏ4„”¤äôÛ¤ÄëÔ{›d ++Kk›«»[k‹›»ÛûO ;ÿ»„K[k4 l+;K‹›Ûû›«»Ûëdt„K»„K[4 :‹›«ëtK[àЯ @p€àð¿ Oo ±¸ÿð@O@ M ?2?/33+/]82^]]]]]]]qqq_qrrrr^]]]]]qqqqr^]]]]]]qqqr^]]]]]qqqr^]qq3/8+39/^]9_^]33310++!>7!!>7*ÔÉ'þu% þÞ5:ý€ >MOIG?{ûü7nu~F†ÕXVÿì„Ì2¹ÿà· L.¸ÿÐ@ L///2/2)G4 G0)).@H.¸ÿÀ@HO L/¸ÿÀ@ L/O0O$?í?í2+9/+]+3+/]íÞí99//]3+9910+4.'32>".'#".54>75!b 7H(CkL):Y=Fa<„ '+' C:\?!GŠÉƇGI©`þÈUçEufX(Li†SBpQ./RsjþÛ5r€’Tl¹†LEºun¬„_!:“¾Mÿì«N7h@? L  L*F00##095GO0//'R+$$$Q  ?3/]í?3/]í9/Í9/]í3/]9///9í10++%267#".54>75.54>32.#"3"K‰:!Mg‰\kžh3*Mj?=_A"8lfFr^N"¢*eETX3XxEB{^8U¨M<Œ"B4!/TtF9]B(*BW3?jM,(A-{98A90; ±A:HJBþoÌ6¹ÿø@ M% M L¸ÿè³ M¸ÿè@ M&0@54.'.54>75#!5!D(Ga86s^< ·  #A\:@…lD.Pk{ƒ@ "$" þŽ>ƒ{lQ/¦8E+&CkT*WQDJ%(*%3$'Jz`P§©§ ”A½¾=Œ•›˜”kþXdN#b¹ ÿè@' LFà#ð##%% %p%% %°%ð%ï% FÐ  ¸ÿÀ³$(H ¸ÿÀ@ H P ????í3/++]í2]qrÞ]í10+4.#"!4&'!3>32M,G45W=!þæ  @TlH]…U)þXKe=)PsKý»SDy*01//L5,\eû‡ZÿìùË%C@!F@"&H' F0¸ÿÀ@"&HO/  Q Q?í?í9/qí/+]í2Þ+í210#".5322>7!"!.ùðäl«v>éèy¯p6þ-'D4 þ‡ 3A)'D3 z1BÝþƒþŒ\ºÀvx]¼þçý /oºŠŠ¹p/r-l³††³l-‰ó: w@Z 0 L0 L @ H F?O>¿ï¯¿ÏÿpÏß °`ÀÐ??]]qqqqÞ]]qqr^]í3/+10++3.5!Ç 5@F!Nü© @<3u: €¹ ÿø@ M( M M ¸ÿè@ M M  ¸ÿÀ@ H  FиÿÀ³$(H¸ÿÀ@ H ?2?39933/++]í23/8+3339910+++++!!!! JþÝþç#þ„™Çjþ£:þîþ2ý” T#­¹#ÿð@ M M¸ÿà@ M M!¸ÿð@ M#    ¸ÿð@  ¸ÿÀ@ÿ H%k%T% %+%K%›%û%Ï%4%„%”%¤%ä%ô%Û%¤%Ä%ë%Ô%{%›%d% %+%%+%K%k%›%«%»%[%k%‹%›%»%Ë%Û%û%O% %;%ÿ%»%„%K%[%k%4% %l+%;%K%‹%›%Û%û%›%«%»%Û%ë%d%t%„%K%%»%„%K%[%4% %:‹%›%«%ë%t%K%[%%à%Ð%¯% %@%p%€%à%ð%¿%% %O%o% %%%@ P?2/í9/3^]]]]]]]qqq_qrrrr^]]]]]qqqqr^]]]]]]qqqr^]]]]]qqqr^]qq3/+82/^]839/9_^]3310+++++).'!'.#"'>32TþÚˆ   ! ¶þ×Ú,+0 60c9QtYG"Î -9>:0W_[þSîIE`=  +\Žbþ`]:'†@#Fß"ï""@@DH"@25H"@$(H") FÐà¸ÿÀ³@DH¸ÿÀ³25H¸ÿÀ³$(H¸ÿÀ@$ H) )p)) )°)ð)ï) P  ??33í??3]qr/++++]í22Þ+++]í210!.5##"&'#!!32>5!Q&zV4Wþç+F42P: ,56ci0* 7þÚý£@hK)-QsFBü¸"IC6:V¹ ÿг M¸ÿÀ³ M¸ÿð@ M  L M M ¸ÿð@F¹f I¹–¦¸ÿÀ@qÍÑH ÊÉVv–6FVÆæ"öâÔ °’„pRbD0"—âòÄÔ¢²„”rTd¸ÿ@@ÿˆ‹HðâÔÀ¢²”€brTB4&ôæÒÀ¤´€dt@P4gôÐà´Ä „”`DT ÔäË „`pDT 0ðÔä°dt”¤@$47p€°Àð_@ЯoP/?¿ïÿP@ ? ?3?3^]]]qqqqqqrrr_^]]]]]]]qqqqqqqqrrrrrrrrr^]]]]]]]]_]]]qqqqqqqqqqqqqqr+rrrrrr^]]]]]]]]]]]]]qqqrr^]+]]qqqÎ/í/8393310++++++!!>54&'!?lNþõþz)8O2NcÚÝÖ^:üµP”‘“NQw--qBþoÌH°¹ÿà@ M< L, L L¸ÿø@ M>F*/9$*C9@ 7CC7¸??9/999í9í2/+]íÖ]í2/9////+]+93í10+++++'>54.'.54>75.54>75+5!D(Ga86s^< ·  #A\:@…lD4o°|CwW32Oa/ DPLLŽE‚e=5Ys=d¡q=¤5D-&CkT*WQDJ%(*%3$'Jz`L˜_"="5>3!Ø804,s@‰þ•  þá$a•$,13 |ý³H7¸ •ˆs|‚Úº JL£¸Ô}„Æ ¾yþW£O-=@G/&Gïÿ@$*H¸ÿÀ@ H O)O?í??í/++]qí2Þí10#".'#!4>324.#"32>£@wªk7[M>þÙE„¿yrÉ–XþÚ%D_9;S54„M5Q6vÅŽO%27 þWîwÁˆJO–Ú‚ZŽc4.W}Oþð9E2[‚OþoØO9W¶  L ¸ÿè@ M6 M¸ÿð@ M--# F ;F#3O*..*¸??3/í99/íÞí2/9/10++++'>54.'.54>32.#"T,Mj>(SOF4!%²  *Lg>-]XL:!2Ry¢is±;‹*2:"7UA- ½:J3%  +@X='RL@J$(*%2$ +=YzQ;‘–oCKB•$0MdhdPÿìQ:/R@"(G@3!#".'4.'#"32>’D‡ËˆˆÍŠE_©ëŒ‚à '/1<0þÚ%JDvX3}yA_@Êi°~GJ‹ÊÒŠB¾(^l|$?reV$-[Š^±¯,Svÿëp:!r@U( L/?¯ F 0 €    oŸÿŸ¯ßï#`#p## #Ð#à#OO ?í2?í]Ì]]qr2/]9/í2/]10+"5>3!!3267#"&5'OE5 +36§þÏ+0277›| Æ ¾ý¼(4 ² Œ„ÿìT:K@% MF p °ðï Fïÿ¸ÿÀ@ H P?í?3/+]í]qrÞí210+#"&5!32>54.'!T;}ˆðã_l;R4$,*#;ˆÛšRÝè‰ý’ˆ‰.ežo?Šp%(q†•PþWjR%/8@Ç-FF &F1Ù1¤1´1Ä1v1–1T1F1$14111â1Ä1Ô1–1¦1¶1y1f1T1F1 1Èä1ô1Æ1Ö1™1d1t1„161V111ô1æ1©1¹1”1v1†1I11"11ö1ä1Ö1²1¤1v1–1B1411&1˜Ò1Ä1¦1¶1b141D1T1&1ô11¸ÿÀ@7‚…H‰1&1F1V1v1 1¶1æ1ö1t1„1f1)19111gö1É1»11¸ÿÀ@®]`HI1&161æ1ö1É1´1¦1Y1i1y1D161 1û1í1À1Ð1¤1´1‹11$141D1d1 17ð1ä1‹1›1Ë1t1K1[1/1?111Ð1à1¯1¿1`1p11?1O1 11ð1O1o11Ÿ1Ï1ß1011)R!-Q??3í2?3í2^]]]]qqqqqqr_rrrrrr^]]]]]]_]]qqqqqqqqrr+rrr^]]]]]]qqq+qrrrrrr^]]]]]]]]]qqqqqqqqrrrrrrr^]]]]]]]]qqqqqqqÞí/í9/3í2910#.54>746324&#">jQ‘ÆuîyÉJ7! !.'!'.#"'>é5!!.5!!…B[97{ÂŒþýˆÃ};;[=°ErU`ýz³u;þk•;u³zpý¡UqE‹QÿìqO=@ÿ =..(=F<<3F((F &?¹?”?¤?†?t?f?4?&???ö?Ä?²?¤?f?–?D?6???Êé?Ô?Æ?¤?–?y?f?T?B?4?&? ?ò?Ô?ä?Æ?‰?©?t?f?)?I??ô?â?Ô?Æ?”?‚?t?f?9?I?"???šô?æ?Ä?v?†?–?¶?T?F?$?4??ù?â?Ä?Ô?¶?y?™?&?F?V?f? ?ù?@Þ¶?Æ?æ?‰?™?r?d?V?)?9??hö?Ù?Ë?©?V?f?†?–?9??&?æ?ö?É?»?¤?†?–?i?[?I?&?6? ?é?Û?–?¶?Æ?y?k?V?4?&? ?8û?â?Ð?Ä?«?Ÿ?{?d?K????+?ð?°?À?à?Ÿ?P?`?€????O?_??¿?ß??<<8O#. Q-?3í2?33í29/^]]qqqqq_qrrrrrrrrr_rr^]]]]]]]]]qqqqqqqqqqrrrrrrr^]]]]]]]]qqqqqqqrrrrrrrr^]]]]]]]]]]]]qqqqqqqqrrrrrrrrrrrr^]]]]]]]]]qqqqqqqqÞ^]í/]í9/í99/9/1032>54.'7#".'##".54>7326=!ã^U6I,=`DyÀ…G:o¢hJrT::TrJh¢o:G…ÀxD`>,H6VaÚŽœ0ZNHƒjI ½]“ɀȉH &V>A(%+5+5ÿÿ‰Õ&(žy<@ & %¸ÿÀ³ääH¸ÿÀ³ããH¸ÿÀ³ááH¸ÿÀ³ààH¸ÿÀ³ÞÞH¸ÿÀ³ÝÝH¸ÿÀ³ÛÛH¸ÿÀ³ÚÚH¸ÿÀ³ØØH¸ÿÀ³××H¸ÿÀ³ÔÔH¸ÿÀ³ÑÑH¸ÿÀ³ÎÎH¸ÿÀ³ËËH¸ÿÀ³ÈÈH¸ÿÀ³ÅÅH¸ÿÀ³ÂÂH¸ÿÀ³¿¿H¸ÿÀ³¼¼H¸ÿÀ³¹¹H¸ÿÀ³¶¶H¸ÿÀ³³³H¸ÿÀ³°°H¸ÿÀ³­­H¸ÿÀ³ªªH¸ÿÀ³§§H¸ÿÀ³¤¤H¸ÿÀ³¡¡H¸ÿÀ³žžH¸ÿÀ³››H¸ÿÀ³˜˜H¸ÿÀ³••H¸ÿÀ³’’H¸ÿÀ³H¸ÿÀ³ŒŒH¸ÿÀ³‰‰H¸ÿÀ³††H¸ÿÀ³ƒƒH¸ÿÀ³€€H¸ÿÀ³}}H¸ÿÀ³zzH¸ÿÀ³wwH¸ÿÀ³ttH¸ÿÀ³qqH¸ÿÀ³nnH¸ÿÀ³kkH¸ÿÀ³hhH¸ÿÀ³eeH¸ÿÀ³bbH¸ÿÀ³__H¸ÿÀ³\\H¸ÿÀ³YYH¸ÿÀ³VVH¸ÿÀ³SSH¸ÿÀ³PPH¸ÿÀ³MMH¸ÿÀ³JJH¸ÿÀ³GGH¸ÿÀ³ H¸ÿÀ³ H¸ÿÀ² H++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++55+55ÿì¬3t@H L M-!Z 5@3-.0-Z?00 .0..'_Ðp0_1._?í3/]??í29/]qrí3/]Æ]í2+MäÞí910++>32#".'732>=4.#"!!5!$g~Ku«o5*f©€Jv_L Ê%,46C$ >H €==H €<7#"$&546$32.#"!!QxV:üb”ÌŠ´þø¬TSª¯ˆÌ•aÿ9WuK[Žc8"ýÝ8d‘Ô/L`1aL’pEmà Ÿ¥ »e:iVG-S@'2_‰WäYe7ÿÿ;ÿì–6ÿÿ‰°,ÿÿÿÕ`Õ&,žÆ¶&¸ÿþ@ÿ% @ååH @ââH @ááH @ÞÞH @ÛÛH @ÚÚH @××H @ÔÔH @ÓÓH @ÐÐH @ÏÏH @ÌÌH @ÉÉH @ÈÈH @ÅÅH @ÁÁH @¾¾H @½½H @ººH @··H @¶¶H @³³H @¯¯H @¬¬H @««H @¨¨H @¤¤H @¡¡H @H @ššH @™™H @––H @’’H @H @‹‹H @‡‡H @„„H @€€H @}}H @yyH @uuH @rrH @nnH @ggH @ccH @``H @\\H @UUH @QQH @JJH@ @CCH @??H @88H ¸ÿÀ³77H ¸ÿÀ³44H ¸ÿÀ³33H ¸ÿÀ³22H ¸ÿÀ³11H ¸ÿÀ³..H ¸ÿÀ³))H ¸ÿÀ@ ((H @&&H ¸ÿÀ³%%H ¸ÿÀ³$$H ¸ÿÀ³##H ¸ÿÀ³ H ¸ÿÀ@H @H @H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ·H @ H++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++55+55ÿÿÿìç-ÿðx&/x¹ÿè³'H¸ÿà@ H¥µÅ¸ÿð@5 H\!,Z'[1+_!_!o!!ï!!!,``,_?í?í?í9/]qrí/]Þí99//í2í+]++10#!!#"&'532>7!!24&#!!26xAƒÃ‚ýMþ¥1-5AUnH:(%$#&C‡¬{¸y=þÖ‹Šþª\Œƒ¯ZžtCþ¤¡ù¹~N" ÷8b›Ú“ÙýÏ32!4.#"!!5!%[hv@ëíþäDkNX¥BþÙþ9¶þÁâïþ ÁHiC! ý_ääÿÿ‰å&´›¬@ &K%+5+5ÿÿÿùÿì>&½ø—J´&¸ÿô´!)%+5+5‰þh6 ì@ÿ \Z Z ´ ‹ t `  $ D T ë Ô » ¯ € d t P D   Êë À ´ › € D t   + à ð d ¤ ´ Ô ; K   Ä Ô ô [ k «  4 ™Ä ä ô ›  t ` T 0 $  ä › » „ P D +  » Û û 4 D d t „ ¤   iä ô Ð Ä › t + [ ð ´ ä @uK { ‹  $ Ô { ‹ « » d P 4 D   7Û Ä › « p 4 T d û ä Ë ¿ ” + ; K k û T „ Ä Ô  +  ` ¸²?3??Äí_^]]]]qqqqqqrrrrr^]]]]]]]qqqqrrrrrr^]]]]qqqqqqqrrrrrrrrr^]]]qqqqrrrrrrr^]]]]]]]]]]qqqqq/^]íÞí9/í10!!!!!cþ&'iþ'þh˜ûsúþhÿÿ3‘$‰wUµ M¸ÿè@, M [0 Z_ _ o ï   __?í?í9/]qrí/í2]Þí9/10++#!!!!24&#!!26wAƒÃ‚ý%ýÞ{¸y=þÖ‹ŠþxŽŒƒ¯ZžtCãþ²7!!Õ¹úüxúœ"@7-=þãþú $-6ôýt˜þhŒ> ºÍk½ûs™êU¿¸¦=ÿÿ‰(ÿúE-û@#&)'- -Z'  ('''&'''/¸ÿð³¸ÿð@ÿ  ë/Ù/Ë/½/«//‹/V/ /9/Ö/¹/¦/i/‰/[/I/&/ /Çé/Û/ //9/Y/i/‰/¹/Æ/æ/ö/©/v/Y/F/)//ö/¹/Ù/v/–/ /)/Y/—ö/ä/Ö/Â/´/¦/”/f/†/T/B/4/&///ä/Ö/´/Ä/¦/’/„/r/`/R/D/2/$///ò/à/Ò/Ä/²/¤/‚/’/t/`/R/D/2/$/@è//gô/â/Ô/Æ/¢/²/”/‚/t/b/T/F/2//$//ô/â/Ô/Æ/²/¤/–/t/„/f/D/T/2/$///ö/Ä/Ô/²/ /”/€/d/t/P/D/ /0///7ð/ä/Ð/„/¤/Ä/p/d/P/$/D//ô/Ð/”/¤/Ä/€/T/t/ //Ð/ð/¿/p/ /O/ //)& ¸ÿð@ L ,(?22?339/3339+32^]]]]]]q_qqqqqqrrrrrrrrr^]]]]]]]]]_]]]qqqqqqqqqqqqqqrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrrrrrr^]]]]qqqqqqqrrr^]]]]]]]]qqqqqqqqq/^]833/833/]833/839/3í2999910!".'!.'!3!2>7!!##" þ£þÄÇ %+.û,Æ0F8009F0Æ,û.+% ÇþÄþ£Gd ý€ -=G$—þ¼Nj@Wý©@jNDþi$G=- üô€ ýœ.ÿ쥕8¹(ÿø@X L\ /* Z* * *Z4:\@ H/__oßÿï %_% _0 `p ð?2/]qí?í3/]9/]qí9/+]íÞí99//í9/9í10+".'%32654&+532654&#"%>32~~ÁŽc :OhC†Ÿ©;;—{l?^E/þô^ˆ¶vt¼†I(Ih?CsU1JÍ4c]]7\D&kaeYã`d[`(DZ1=\”j94_ˆTEoS9 1QqI]šo>ˆ7m@) M  M \ @P`p€ 0 À¸ÿà³ M¸ÿè@ M\ 0  ?2?399///]í22++]]qrÞí22++103!!!46767ˆeLþúýŸüÍ2b'.*Fú?(X&,,ûÃÿÿˆ7>&²—’J@ &# %+5+5‰åZµ M¸ÿð@, L  Z 0a?2?39/í99/]í23/]833/839910++!2>7!!#!‰'4>L1Î,þ÷2.( åþ¿þŠ ##þÚý©@iNDþk#H>. üô€ ý£ÿðO¹ÿè³'H¸ÿà@ H¥µÅ¸ÿð@ H\ Z  `` ?í?í?/]Þí9/í+]++10!#"&'532>7!!øþi1-5AUnH:(%$#&C¸þäþ¤¡ù¹~N" ÷8b›Ú“Ùúÿÿ‰!0ÿÿ‰=+ÿÿTÿìã–2‰7#@Z Z 0`?2?í/]íÞí10!!!!ý•þÚ®ûsúÿÿ‰3ÿÿTÿì–&ÿÿÍ7ÿì Œ¶ L¸ÿà@C L  94d„”´ä4d´ä´ä0 ¸ÿð@`?í?39/3/]83/]_]]qr^]839_^]339/10++#".'732>?! !(Oa}VGC=R&N,#71.ýÔ3„*+>S~V+ö.K7%¤ýX¨Gÿõ‹ (3]@(\/ )[ IY @&+H[!¸ÿÀ@ÿ&+H!5ë5É5»5©5‹5›5i5y5[55)5I55É5é5»5i5‰5[5)595I55 5Çû5í5Û5¦5Y5i5‰5F5)55 5ù5ë5É5»5©5‹5›5i5F55)55É5é5»5i5‰5[5)595I55 5—û5é5¦5i5‰5F5)55 5û5É5é5»5™5©5‹5r5`5T5@54555Ô5ô5»5t55+5;5[55@©gÄ5Ô5ô5 545D5t5”55»5Ë5ë5û5”5p5d5@54555ë5Ô5[5‹5»55$57¤5Ä5Ô5ô5‹5D5t5+55Ë5ë5û5”5¤5p5@5`555Ï5ï5 5_5o555 50_/_'€     ??99//]3í23í2^]]]]qqq_qqqrrrrr^]]]]qqqqqqqqrrrr^]]]]]qqqqqq_qqqqqqrrrrrrrr^]]]]]]]qqqqqqqqqqrrrrrrrrr^]]]]]]]qqqqqqqqqÞ+í/+^]í9/33í22104&+32>5#".54>;5!32+;#"dž¥,3TwM$ý{O”Ü’GJ•à–CC–à•JG’Û•Oý{$MwT3,¥žÚ˜ªýq2YzýcÇX–ÆnwÊKžžKŠÃwnÆ–XÇåHzY2ªÿÿD;‰þhÉ Sµ\À  ¸ÿÀ³"H ¸ÿÀ@$H Z @%H @H Z 0 `¸??í2?3/]íÜ++í3/++qí10!!!!3Ïûº'9Ãþh˜ûsûsýtn<@$ MZ Z @H 0   _ ??39/3í/]]+íÞí210+!#"&5!3267!î'_n|CðÝ?kR\­F'#âïàþ?HiC! ¡ú‰ s@0ZZ 6 '   ô Õ å Æ µ ¦ • † u  ¸ÿÀ@ ÔØH  Ò ¸ÿ€³ËÑH ¸ÿÀ@ ÆÊH• ¥  ¸ÿ€³½ÃH ¸ÿÀ@ ¹¼HÅ Õ  ¸ÿ€³°¶H ¸ÿÀ@«¯HÕ å õ Æ µ ¦ • v †  ¸ÿÀ@ ¡H  › ¸ÿ€@ÿ—šHå Ô µ Å ¦ • † s d S E 4 %   ô Õ å Æ µ ¦ “ ‚ p d R D 2 $   ò æ Ô Æ ° ¢  r ‚ d R D 6 $   hâ À Ð ´   D d „   ô à Ô À D d „ ¤ ´ ;    ô à T d „ ¤ Ä Ô @ 4    8ô ‹ « Ë ë p @@ 0 P ¯ Ï ï 0 P p  ï @ P p   À  / Z 0 `?í2?33/]í^]]]qqqr_rrr^]]]]]]]]qqqqqqqqqrrrrrr_r^]]]]]]]]]]]]]]qqqqqqqqq_qqqqqqrrrrrrrrrrrrrr+^]+]]]]]]++q++r++^]+]]]]]]]]qqqqÞí9/í103!!!!!‰ÐÑûsûsú‰þhí·\– Ö  ¸ÿÀ@H ZZ ™ Ù  @H ¸ÿÀ@ âåHdR¸ÿ€@©ÛßHâòÔÆ´¦„”rdRD2$ËôæÔƤ´’†dtRD2$ôæÒ´Ä¦”†rdRF4&òÔ䯴¦”†t¸ÿÀ@ ¡H›¸ÿÀ@ÿ—šHôâÔ´¢”€r`TB4"äôÖ´ ”‚vdVD6$ÖæÂ´¢€t`4T gôÐİTt”+äôÐTt”´ÄK4Ðàðݤ„pdPD0$7¤Ää€ @`@@4`€ÀàÿP`€ °Ð?ZO_ 0¸@  `?í22?33?/]rí^]]]]qqr_rr^]]]]]]]]]]]]]]qqqqqqqrrrrrrr^]]]]]_]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr+^]+]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrr^]]]]]]]]]]]]]]+qq+Ü+^]í9/í3/+]í103!!!!!3#‰»ºÃúûsûsûsýt˜¬;@#[Z __oï __ ?í?í9/]qrí/Æí2Þí102#!!5!4&#!!26Ã{¸y=AƒÃ‚ý;þ8ï}‹Šþ˜nŒƒP7!5!.#"'>32#".'7ž_d8ýÝ"8cŽ[KuW9ÿa•̈¯ªST¬þø´ŠÌ”bü:VxÔ7eYäW‰_2'@S-GVi:e»þö¥ŸþôÃmEp’La1`L/‰ÿìê–.n@ , M M(¸ÿè³ M(¸ÿø³ M"¸ÿè@, M%Z  [¿Ï0 Z 0  _ `  *_?í??9/í?í/]í2Þqí9/3í10+++++#".'!!!!>324.#"32>êZ«ö›–ç£_ þèþÙ'e¥âŽŸö¨WþÓ,Z‡Z\ˆY,,Z‡[aˆW(Ç¥þòÀh\¥åŠý¤ýχؖQf¼þ÷¤o³€EE€³on·„JK…·#7o¹ÿè³ M¸ÿø@ MZ p 0 ¸ÿð@[ 0__ ?2?í9/í9/]]í3/]83]]qÞí29910++3.54>3!!!3!!"#}CrS/A„Å„ÀþÙþ¦þ¹#=_B‚þ†}‡PEfƒOa›m;úýéÑ/N9 dÿÿ<ÿì€ND^ÿì Þ8@@&**4 GÐ 0Gß:`:p:4O)O?í?9/í3qÞqí/]qí99/104.#"32>2!".54>7>7>z!>Y7;`E%%BY4;_B$ÁûìþæþôÉ‹IA‘è¦Apg`1a¶fXŒjL1Hjõa€M!M€_`KKoþûþúþ÷þýFœú´ÀÁs  ë  0EhŽaCsT0›:"-a¹ÿè´ L¸ÿè@ L*G F/$FиÿÀ³$(H¸ÿÀ@ H "R$$#RR?í?í9/í9/++]í2Þí9/9í10++2#!32>54.+32>54&#§]«M'CX1;cJ)ïÛý¾ãB\9<`DØÐ@V3`r:>hQ4R:% #>Y=›:üu$8'*;$°þü2#C>::¹ÿÀ@ HFиÿÀ³$(H¸ÿÀ@ HO??í/++]í3/+10!!þ‹þæ:¾ü„:þhî:@KH†æö ÷™v†9I   FŸ`pH O ¸µ O?í22?3?í/íÜ]]í99//]3]]]]q3]q3/í10#!#3>7!3#Bì(+,”ýÁõ}876ò’õ|ŠÞ­~+¾þhV/†Ï'Ñü„ýª˜ÿÿPÿì-NHÿï½:)ûµ" M¸ÿð@ M L ¸ÿè@ L" ((H)!)) ¸ÿð·!  ¸ÿÀ@ÿ H +Ÿ+„+;+[+k+/++Ë+ë+û+¿+¤+[+{+‹+O+++Ì++?+O+++¯+¿+ï+ÿ+ +/+?+_+o++Ÿ+¯+Ï+ß+ +/+O+_++Ÿ+¿+Ï+ï+ ›?+O+o+Ÿ+¯+¿+ß+ï+ +Ï+ß+ÿ+°++_+o+++?+_++¯+Ï+ï+k?+o++¯+ß+ÿ++/+_++Ÿ+Ï+ÿ+¯+¿+ï++?+O++ ++:ï+ÿ+Ð+++¿+`++O+ð+ß+À+@B¯+€+o+P+?++ÿ+à++Ï+p+?+_++ +" )!?33?3393339933^]]]]]]qqqqqqqqqrrrrr^]]]]]qr^]qqqrr^]qr^]_]]]]]qqqqq3/+8333/83339/^]3í2999910++++"&'!.'!3>7!!##X:ßþ×>,؈'8+&ü&+8'ˆØ->þ×ß üÉþ,;=7}þÿKV+ Úþ& +VKþƒ8<ýÅÔþ75ÿìµN9y¹7ÿè´ L(¸ÿè@= LH /*F* * * G5;O;H/R% +R% Q?2/]í?í3/]]9/í9/í]Þí99//í9/9í10++"&'732654.#52>54&#"'>32í³Ü)ñ &4@"PY+NmA?hK)NH=3%í Ir–X[”i9&C[48fM.8q« ”,'=*O@2># ± !9-( 'B\:EwW1Ž]:a¹ÿð@ L L ¸@ß  @$(H и³Ð¸ÿÀ³$(H¸ÿÀ@ H ?2?399/++]í2]Þ+]í210++!!4>7!”ÀþüþMþÔ:þPVMûÆ&<@<üû:ÿÿŽ]ô&Ò—*@ &#%+5+5Ž:e¹ ÿè@ L FиÿÀ³$(H¸ÿÀ@ H ¸ÿÐ@ H ?2?393993/+8333/++]í29910+!>7!!#!Ž$)5'~Î 5>þáé2þæ:þ0 (RKþƒ<8ýÅÊþAÿì†:Z@=)÷¸™©„vg+;K¿ÏßFOO ??í?í/Þí9/]3]]]]]]]qq10!!#".'532>7!lþÊ*,3F^A-/' &+$#);|¸þêˆP!¿F~É ÅûÆ\:Ú¶ L ¸ÿè@ L H  ¸ÿÀ³$(H ¸ÿÀ@ÿ H H @$(H`$4T ôß„Ä ;kÍÔä°t„¤[4D›»4dtëÔ»¯Td„ šÔ{‹»dK4 ë”´ÄK$ô›Û„+;kiDt´ä+ëûÔk‹»4T”Ô{dK$ 9ËÛû°Dt”¤@G+ûïË¿¯pOÀàð 0P`   ?33?3993^]]]]qqq_qqqqrrrrr^]]]]]]qqqqrrr^]]]]]qqqqrrrrrr^]]]]]]qqrrrrr^]]]]qqqÞ+^]í2/++]í293310++!##!>7!#4>7fÕþäöt´( &¯nöuGF@ýŒ:ýÏA•HH•A1ûÆtCIGF: R@Fß@$(H  FÐ  ¸ÿÀ³$(H ¸ÿÀ@ H O ?2?39/]qí/++]í2Þ+]í210!!!!!©ƒþæþ}þæ:þT¬ûÆÏþ1:ÿÿPÿì“NRF:>@Fß@$(H FиÿÀ³$(H¸ÿÀ@ HO?3?í/++]íÞ+]í10!!!Fþæþ}þæ:ûÆ|ü„:ÿÿ‡þWQSÿÿPÿì7NF:²:ü@O(8ˆ˜HXh¸È @H@HF'B'gw‡Wg·Ç¸ÿÀ³FRH¸ÿÀ³69H¸ÿÀ³14H¸ÿÀ³+.H¸ÿÀ@ H´ £ „ ” u c  ¸ÿ@¾ÜßH  ä ô Õ Ä µ £ € b r T B  0   Êä ô À Ð ’ ¢ ² „ P ` p 2 B $   ð Ò â Ä ° ’ ¢ „ r d P 2 B   $ ð Ò â ´ Ä ¦ ” r ‚ T d 6 F  "  šô Ö æ  ¸ÿ€@ ’–Hv b  ¸ÿ€@KŒH  ä ô Ö Ä ¶ ¢ „ ” f v B $ 4   Ö Ä   ¦ ¶ j† ¶ Æ ö  ¸ÿÀ@>nqHd  & F V  ä ô ¦ Æ Ö ‚ ’ d t F V 4 "   æ ö  ¸ÿ€@CFH† – d t V D & 6   9 ¸ÿÀ@C58H´ Ä † – ¦ b @ P $ 4 à ð ” Ä Ô € ` p  @ ` p À Ð  ¸ÿÀ@ HO?í2?+^]q_qqqrr_rrr+^]]]]]]+]qqqqqqqqrrr+r^]]]qqqqqqqqqqrr+rr+rr^]]]]]]]]]]qqqqqqqqqqqrrrrrrrrr^]]]]]]_]]]]]qq+qqqqq/+++++^]q^]íÆ++^]qr+Mæ10!!!!:xþÑþæþÑ:¾ü„|ÿÿþWh:\RþW­Ì6GWò².P¸@ÿ-7¶ÆÖö!AGHG %YÔYÆY²Y¤Y’Y„YrYDYTYdY"Y2YYYäYôYÖYÂY´Y¢Y”Y‚YdYtYVYBY4Y&YYYÈôYæYÄYÔY²Y¤Y’Y†YdYtYBYRY4Y"YYYöYäYÖYÂY´Y¢Y–Y„YFYVYvY0Y$YYYòYäY²YÂYÒY¤Y–Y„YvYdYVYDY6Y$YYY˜@ÿôYâYÔYÆY´Y¦Y”Y†YrYDYTYdY2Y$YYYòYæYÄY¶Y¤Y–Y„YfYvYBY4Y"YYYôYÆYÖY²Y¤Y’YtY„YfYDYTY6Y$YYYhæYÄY¶Y„Y¤YFYVYvY4YYôYæYÄYÔY²YdY„Y¤Y@YY$YäYÀYtY”Y´Y0Y$YYY8ðYÛY„Y¤YÄY[YY$YDYÄYÔYôY°Y¤YY Y@@3YPYpYYßYÿY YÀY_YYŸY Y0YYCUOK3234&4&5!>324.#"32>%4&#"326­-^b,WPCþû-¡p^‰Y+-^c1ZM?/¤k_‰Z+üT#8H%/H2À%H9$‡aa$H9##8H$^e"{ЖU-I6(5;þaYi[T–Íy{ΕT.H3 '26‹ý¾k\T”ÍykS!*ZŒcþ$V‘k¹³#UmjT#²ÿÿd:[þhØ: B@ H F FиÿÀ³$(H¸ÿÀ´ H ¸·O?í2?3?/++]íÜí3/í103!!!3#ƒ’õ:ü„|ü„ýª˜S::@#( L Fß@$(HF¿ P ?2?9/í3/qíÞ+]í210+32>7!!#".5k$=-!;:<#þç+U\d9JrN(:þ~!9*  ñûÆŸ+RuI¶: ¾¹³ ¸µÆÖ¸ÿÀ@ÿ(+H  Ä ¦ ¶ ” † t F f   $ Æ Ö ö ´ v ¦ b T F 4 &   Éô æ Ô ¶ Æ ¤ † T d F 4  & æ  ´ ¦ ” † t 6 F f $  é v † ¦ ¶ Ö d 6 V )   ˜â ´ Ä Ô ¦ ” † r d R D 6 $   ä ô Ò Ä ² ” ¤ ‚ d t F V 2 @í$   Ö æ ö ´ Ä ¢ ” † t f T F   " hô æ Ô Æ ² „ ¤ v T d F 4  ò ä Ö Ä v – ¦ ¶ d R D 6 $   ö Ô Æ ´ v † ¦ d 6 F   8ô Ù ¢  „ P p  @ ¯ Ï ï   0 @ `  ° Ð à   @ P p ¸³Ð¸ÿÀ@ H O?í2?33/+]í^]]]qqqqqr_rrr_rrr^]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrrr^]]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrrrrr^]]]]]]qqqqqqqqqqrrrrrrrrrr^]]]]]]]]]]qqqqqqqÞ^]+]í9/í10)!!!!!úw<;:ü„|ü„|þh¬:¼¹@ H ¸µ– ¦  ¸ÿÀ@(+Hy ‰    ¸ÿÀ@ÿH ´–¦„&6fôæÄ¶¤f–TF$Ê–¶Öö„fD&6ôæÄ¶¢”fv†T&F¶Öö”Ff† šðÒâĶ”¤€brTF$4öâÔÀ²¤’t„VfD6$ÖöIJ„”¤@ÍvTdF"2göäÖ´¦”†tVfD&ôæÔ¶Æt„bP$4äÛ”Ä@Pp4 7Ôô°”¤€$4Tdk‹›»ÛûTôÛTd„+;¸³Ð¸ÿÀ´ H¸@ O ?33?í22?/+]í^]_]]]]]qqqrrrrrr^]]]]]]]]qqqq_qqqqqqrrrrrrrrrrrrr^]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrrrr^]]]]qqqqqqqqqrrrrrr^]]]]]]]]]]]qqqqqÜ+^]q+qí3/í9/í103!!!!!3#=<’õ:ü„|ü„|ü„ýª˜&€:K¹ÿè´ L¸ÿè@# LF F¿Ïß R O R ?í?í9/í/Þqí9/í210++2#!!5!32>54.+­ëè9t¯výíþ‹¼E]78\B½‡š¤MzU-|¾þMþ(':%&7$F: x¹ÿè´ L¸ÿè@* LF`$ Fß@$(H€Ð FÐ  ¸ÿÀ³$(H ¸ÿÀ@ H R   R ?3í?39/í/++]í2]Þ]+]í9/]]í10++2#!!32>54&+!¹ëò54&+¹ëò7!5!.#"%>32#".4 lP:P3þË52O9X` þåIv£i{Á„F@€Áo¬yGh de%GiD¾=cE%cSL„a8L‘Ó‡|Í’P?i‰ÿì…N(a@!G/ o ß  G* FÐ  ¸ÿÀ³$(H ¸ÿÀ@ H O?O&O &O?í???í9/rí/++]í2Þí9/]3í10#".'#!!3>324&#"326…B…Ç„u·ƒM ÄþæÈM¶vÇ~:þÚtnsy ;S2r||ΕSE²mþ1:þTc¥vBT•ÍzÁ®°¿aŒZ+¯ÿÿ:e¹ÿè@ M M  LF¸ÿð@ ?F0‹R@HR ?3?í9/+í9]/]í3/]83Þí29910+++ !.54>3!!#";BþðþÍB2U?#@z²qçþæÀfg\aгþM× /KeBOuL&ûƳØINHMÿÿPÿì-Š&Hiô@ (& ,*%+55+55 þWdÌ7¬¹5ÿè´ L0¸ÿè@. M!! Fà3ð3399 9p9ð9ï9# FàиÿÀ³$(H¸ÿÀ@ H#R (P---- --¸ÿÀ@H--P?í??99//+]qí33í2/++]3/]3í22]qrÞ]í99//10++"&'532>54.#"!#535!!!3>32E8S  '1 .J53S.r?iK*-SsEýå—ª‹‹ªˆ A9. |p@p˜XüúAlP,ÿÿ-Þ&ÍtØ@ &W %+5+5Pÿì7N$Z@5 FF @ H &GOO y‰- O@ ?2/]í?3/]]í9/í/í2Þ+í3/í9/10".54>32.#"!!3267RÁ€@F„Á{i£vIþå `Xek5þËnfPl  Gy¬P’Í|‡Ó‘L8a„LSc‡ƒ¾Œed K‰i?ÿÿHÿìOVÿÿªÌ&ñþOÉf¹ ÿÀ³-.H ¸ÿÀ@ #$H @ H ¸ÿÀ@H @H @H ¸ÿÀ³H ¸ÿÀµH¸ÿÀ³22H¸ÿÀ@ -.H%+5++55++++++++ÿÿÿÚeŠ&ñiÊ‚@&% ¸ÿÀ³ääH ¸ÿÀ³ããH ¸ÿÀ³ââH ¸ÿÀ³ààH ¸ÿÀ³ßßH ¸ÿÀ³ÝÝH ¸ÿÀ³ÜÜH ¸ÿÀ³ÛÛH ¸ÿÀ³ÙÙH ¸ÿÀ³ØØH ¸ÿÀ³ÖÖH ¸ÿÀ³ÕÕH ¸ÿÀ³ÔÔH ¸ÿÀ³ÒÒH ¸ÿÀ³ÑÑH ¸ÿÀ³ÐÐH ¸ÿÀ³ÎÎH ¸ÿÀ³ÍÍH ¸ÿÀ³ËËH ¸ÿÀ³ÊÊH ¸ÿÀ³ÉÉH ¸ÿÀ³ÇÇH ¸ÿÀ³ÆÆH ¸ÿÀ³ÄÄH ¸ÿÀ³ÃÃH ¸ÿÀ³ÂÂH ¸ÿÀ³ÀÀH ¸ÿÀ³¿¿H ¸ÿÀ³¼¼H ¸ÿÀ³»»H ¸ÿÀ³¹¹H ¸ÿÀ³¸¸H ¸ÿÀ³µµH ¸ÿÀ³´´H ¸ÿÀ³²²H ¸ÿÀ³±±H ¸ÿÀ³°°H ¸ÿÀ³®®H ¸ÿÀ³­­H ¸ÿÀ³ªªH ¸ÿÀ³©©H ¸ÿÀ³§§H ¸ÿÀ³¦¦H ¸ÿÀ³££H ¸ÿÀ³¢¢H ¸ÿÀ³  H ¸ÿÀ³ŸŸH ¸ÿÀ³œœH ¸ÿÀ³››H ¸ÿÀ³˜˜H ¸ÿÀ³••H ¸ÿÀ³””H ¸ÿÀ³‘‘H ¸ÿÀ³H ¸ÿÀ³ŽŽH ¸ÿÀ³H ¸ÿÀ³ŠŠH ¸ÿÀ³‰‰H ¸ÿÀ³††H ¸ÿÀ³ƒƒH ¸ÿÀ³‚‚H ¸ÿÀ³H ¸ÿÀ³||H ¸ÿÀ³{{H ¸ÿÀ³xxH ¸ÿÀ³ttH ¸ÿÀ³qqH ¸ÿÀ³ppH ¸ÿÀ³mmH ¸ÿÀ³jjH ¸ÿÀ³iiH ¸ÿÀ³ffH ¸ÿÀ³bbH ¸ÿÀ³__H ¸ÿÀ³[[H ¸ÿÀ³XXH ¸ÿÀ³TTH ¸ÿÀ³PPH ¸ÿÀ³MMH ¸ÿÀ³IIH ¸ÿÀ³FFH ¸ÿÀ³BBH ¸ÿÀ³;;H ¸ÿÀ³44H ¸ÿÀ³00H ¸ÿÀ³))H ¸ÿÀ³$$H ¸ÿÀ³##H ¸ÿÀ@ ""H @ H ¸ÿÀ@H @H @H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ²H+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++55+55ÿÿÿàþW©ÌMÿìk:$/Ÿ¹!ÿè´ L¸ÿè@c L)÷¸™©„vg+;K%Foo¿Ïß +F¿Ïß1@1/R%OO %R?í?í?í9/í/]Þqí99//]]]í23]]]]]]]qq10++!!#".'532>7!!2#%32>54&+dþÒ*,3F^A-/' &+$#)3ëò54&+ëò32L.J53SÀ4‹µ¹¼?í//105!>öÀËËÀ‹µ¹¼?í//105!ÀËËÀ‹µ¹¼?í//105!ÀËËÿÿÿìþ…ÿT'BþúB‹?®A@- —–O_o¯¿¿Ï 0ž ¨?ýí/]]qrí]íÆ21054>733‹(·0#?ÃCn\O##NRR(þû‹?®+@ —  – 0 Ð  ¨ ž ?ýæ/]ý]íÆ210#>5#!®)¶0#¾Cm]N$$NQS(ŠþïB@- —  –O o  ¯  ¿ Ï  0    ž¨ /æí/]]]qrý]íÆ210%#>5#!¯(¹1$ BCn]N##NRR(‹?®)@—– 0  ¨ž?ýí/]í]íÆ210##.=ª#0¶)þü(SQN$$N]mC×?h]@+ —–¯_Ïp—–_¿¸ÿÀ@ Hž ¨?ÄýÄýÄ/+]qí]íÆ2/]qrí]íÆ21054>733!54>733C)¶0#ý3(·0#?ÃCn\O##NRR(þûÃCn\O##NRR(þû—?h U@6 —   –P    —–? 0¨ ž ?ÄýÄöÄ/]]rý]íÆ2/]qý]íÆ210#>5#!#>5#!h(¸9LþR)¶0#ÁDo]N$H¥QÀDo]N$$NQS(—þÃh|@Y —  –/ O  O o    o ¯  —–o¯@+.H@ H 0 ž ¨ /ÄöÄýÄ/]++]qý]íÆ2/]qrý]íÆ210%#>5#!#>5#!h(¸0$þR)¶0#BCn]N##NRR(ÂCn]N##NRR(ŠÿvêÌ 8@  Á¾Á0@ À ¸²/?ö2í29/]æýæ910#5!%›þ´LÿMÀû¶JÌxþˆÌˆÿsêÌU@$  Á¿Á0@ À ¸µÀ¸±?ö2í2/ö2í29/]3öÆý2öÄ91053%%%%#5Þþ«U×Uþ«Tþ¬×þªVÔÌdþœÌþÊþÍÌþœdÌ3A}‹É:¹ÿè´ L¸ÿè@ L  L L /3/Î]2/10++++#".54>32‹/Pk=4.#"32>2#".54>4.#"32>2#".54>4.#"32>~Å,ÇüŸ:hN-.Ni<32 (>I²¦&1@*nk€,;$`[þ¡ÿ.("# . lyþODp@G  Z   _  _@`pO¯ / ?  /     _ ??í99//]q]qrí3í2/33/í22Î99//10!!!!!#53!¦}ýƒ:þÆþã‚‚»±þtо•þþ•êÐ^–8Ã@' M)( L-((.'+n  n)8n¸ÿÀ@&5H):@&=#535#5354>32.#"!!!!!267^ 54.'.54632.#"4.+32>“"A0}qhQl…Pnñ:ƒÄ‚AVX}““ " è³S^>ÇYO$=,#>V41aL/²«•°É'0EC :O00eQ4úu%GhBKSCeD" z{¢q0M8ýÛ=o_/V'òò¦þ%1 K†<_D=0 ! !9V?sy|& $ ";Y¤CY6þ$9] ÿìO–=³¹ÿà@ M7..3%n$$n?9-3o 9¸´60¸@G-//ÏïOÏï(s%%/%%%s @P @ ð ?3/]qí?3/]í99//]q]q3í23í2/]32í22Þí3/í9310+%267#".'#73.5467#73>32.#"!!!!’HV  >lžl}·|F (Mu(WL´we˜lA þè TJ/J7#GþÑTþÐ7RÇ\RPŠe:NÃt•#•{À„D7aƒLJR GpQ•  •CrS/6ÿðß‘!59Mæ@  L L4¸ÿè@ L. L* L$¸ÿè@ L889667¸ÿð@599ð9977979"D´,µ:´_"o"""O´µ´Ÿ¸ÿÀ@0$'H`pÀO¶· /?¶ 8?¶1·I¶'6??íôí??í3/]ôí3/]]qq+q/]íô2í2Þ]íôí99//]]qr883]3]10++++++".54>32.#"3267#".54>32#34.#"32>£c‹W(?f‚CKqP/ ¼B;UEFT74>324&#">FPU’ .?UnF©Ÿ@D!E%\›uSƒ\0A{°oD¨69". 6U:Ãjk3g_S=#§£¦à  †D„h@'LnHb©‹n&É`VET(6þ°EVd‰+?²¹*ÿè@ L$ L  L¸ÿè@ L H¸ @6´"""" ,´A/A¸ÿè´ H ¸ @% 0 @  ;¶1¶'''   ¸!³ ?33ä?399//]]99//íí/]í2+]Þ2í99//3íí2+10++++!5!!#!&'.53#".54>324.#"32>ô{û ýZò)«òB+U~TP{T+)S~TXQ&Ö,. +. ¦¦G./([(üÁû°12+c,3úoM€\33[€NK\44\K8J--J79L..L}*2v¶ L¸ÿè@A L Å@-2,/-/,Ä---ÅoO_ß4 -Ñ%+/Ê-0?3í2?3Þ]qí2/]íÆ+Mæ9/í2910++#367>73#46767#.'&'%##5!#¦ø‹   ó¥ šƒ• þ´ó¢þÓ77-ýT8"''$=þ¸H=#')#7 ¢þ ö‹‹UЖ9q¹ÿð@C M M0(  (0(@(`(p(?O((5Z;"Z550****''*_)_?í?3í22/3//]]2/íÎ2/í99//]]q3310++267>3!!>54.#"!5!2.54>œú®]/d›m; ý‹WvH 3a[[a3 JwXý„=oe/]®ú–Rœßf±™€3ä5+es„Ježl99lžeJ„se+þËä3€™²fß›RXÿÞ|H"/B@#I1/I0¸³//)¸² ¸±?í?í9/í9//]í2Þí9/10".54>32!32>7.#"k‚ƆE,Lfv€?qÁŽQüÅ@NX.Kt]M"H$SnË;L]53WJ<"]Ìob }]<O’уþœ-# 73!;H:‚RR‚:H;Ý)"bADp*$*pDAb"VÿÃð@ @ €/ÍÌ299/Í105>73.'#Õ"bADp*$*pDAb"V ;H:‚RR‚:H;ü#¢d^D@  €/Í/ÝÌ29910.'3#>7!5;H:‚RR‚:H;ü#"bADp*$*pDAb"VÿÃð@ @ €/ÝÌ299/Í10%>7#.'53+"bADp*$*pDAb"V¢;H:‚RR‚:H;Ý¢d^D$@€@ €/Í/Ì299ÝÌ29910#.'5>73!.'3#>7;H:‚RR‚:H;þ;H:‚RR‚:H;)"bADp*$*pDAb""bADp*$*pDAb"ÿÃð&@@€@ €/Ì299ÝÌ299/Í105>73.'>7#.'5Õ"bADp*$*pDAb""bADp*$*pDAb" ;H:‚RR‚:H;ý;H:‚RR‚:H;ÿHð#(@#  /Ì299ÝÞÍÌ299/3Í210!!5>73.'>7#.'5àþ Å"bADp*$*pDAb""bADp*$*pDAb"hPX;H:‚RR‚:H;ý;H:‚RR‚:H;5ÿç±¼-Ca@+  M  M¸ÿà@ M%%.F@ HE:F¸ÿÀ@H3R?)%% O)?O ?í?í3/9/3í/+íÞ+í29/10+++]#".54>3236454&#"7>32.#"32>±  Z}¡e^‚Q#,D`}NLzjo974-'kBn—^)þü)2)C5( "2 3WC/‹1iji0u¿‰J@mO;ˆˆ~a:VL,­¾ Í"\šÌþ‹$>-+F\a`(.L6Q†ª+¹­@  M M¸ÿð³ M¸ÿè³ M¸ÿð@+ M M   0P€ Ðð¸ÿÀ@7]`HO9@`°Ðà¿ß Pp  _?í?9/3]]qr^]]+qrÆ^]293310++++++35!.'!+p‘þ ÏDתûVט/aR9:Sa-ýOÌþ9Ê$@Z Z 0`/2/?í/]íÞí10!!!°ýCþÙþþ9Tù¬Hø¸†þ9D Š@)P`@-H[O [  [ 0¸ÿè@2 H_O_oï/?O¿ßÿ*:H _/í9+]?9/]q3í9+/]ÄírírÎ99//]í+r105 5!! !†^ý¶qýýÜKþ9 ˜ãýGý8äU9X@ @­²?í/]Î105!U9ààÿçjT©¶¸@ ¸@¸ÿÀ@C Mo  Ÿ ¿ ß ÿ  / _  Ÿ ¿ ;° Ð ð ¯ Ï ï p O o ¯ ­?/9/í]qqr^]q//+839/9333‡+‡}ć+Á‡}Ä10##5!3p¨þò¸7Ûœºò¦ý…PHØmÄ#3Eu¹"ÿè@ L L L¸ÿè· L4'/¸²G>¸µ$9¸´*C¸@/ ? O ? O  Ï ß  /]q33í2/33í2/]íÞí9910++++#"&'#".54>32>32%"32>54..#"326m/VvHg¨AESa8FxV1/VxHg¥ACP_7K|X0þ¥);`GJ…e;p1T>"4`ŠUM†c9o€1T>#4a‰q`e^f5G))H5»/J35H*'G6_˜`Ç ³/Í/Í103!!˜^jû8Çû—^ÿþ­@ ¬ ¬ ®/í/3/í/í104>32#4.#"Dz§bc©{Fg5_‚NN‚^4tÀŠLLŠÀtþb›l98lœdþÿþ9¾Ï%Q¹#ÿè@! L L!F  0ÀиÿÀ@#&H'&P P/í?í9/+]qí3/2/10++".'532>54>32.#"+*%>$,<$4e–c(W?$,<%3e•þ9Ù5H*Wc6 Û 6G'ûWc6+97>ˆ@! M=0 L<0 L+¸ÿÀ@" L,0 L M0 L0 L0 L ¸ÿÀ@$ L 0 L:@+ 9%­.¯6­*­¯­ ?/]2íýí3/3íýí3/ÄÞÄ10+++++++++++"&'&#"5>323267"&'.#"5>323267.K‘K„Y'C=:3ˆT)RPN&-k0D€4 =?F)K‘KBm.'C=:3ˆTS L244D€4 =?Fô)/ !Õ'-  2*Ûþ,  Õ&..2*Û%H+¹¹ÿø@. M  %5E  * : J  /?  ¸ÿÀ@M%(H?@$(H@"H­ 0 0 °  0 p  @ ` p   À  ­ß?O@H/+]q3Æí2/]qÆ]q3í2/++]3Î+299//]3]92]910+#7#5!!5!33!!ÍÕÛG¦þZ…Óƒüþ—¦#þþÝJßþþßþ¶ÝdôGP B@   @¸³ ¸´?¸·?/]í/]í9/í/]33Î22105!5!5!dãüãüã¼””ý8””d””13 ƒ@#R°R° ¸ÿÀ@$%(H @$(H@ H­0@/]3/39=/33/í/++33/Þ+Ä3/Á‡+Á‡+ÄÁ‡+‡+Ä10 5!1üÀ@ûþwAZãþèþéãþãßß13 @#R°R° ¸ÿÀ@#%(H @$(H@ H­0@/2/]39=/33/í/++Ä3/Î+22/Á‡+Á‡+ÄÁ‡+‡+Ä105 55!1?üÁûþããþ¦þ¿ý‰ßß7 #@i y iy/Í/Í/ÍÝÍ10]]3 %! ÍÍü¶úþƒþƒ{ýúý…RªþVd´Gò,@ ª P­?_?/]/]í/]í/]107!!dãü®´>’þT"ýšÒª¶  H ¸´ //ÍÍ/íÌ10+#47632#"'.'&#"µ“TR€?K3% !$ ýšVÄ{{?0(4 ''#iýšµª ¹ÿà´ H ¸´//ÍÍ/ýÌ10+3#".54>3232765"“Z(g>2%!%ªø¨Í}86'"%)jÿö%µ¶´¸±ü?í33105! ¿%‘‘Øý“iH»´þú??öí103#Ø‘‘HöKý“µ¶"²º³þ¸±ü?í?öí310!!#(ýi‘¶‘ûnÿöý“¶"»µþ¸±ü?í?3öí105!# (‘%‘úÝ’%µH"²½³üú??íöí3103!!‘—üØHûn‘ÿö%H"»µú¸±ü?í?3ôí105!3 —‘%‘’úÝý“µH'³ º³þ¸³üú??í?öí23103!!#‘—ýi‘Hûn‘ûnÿöý“H'±º·þú¸±ü?í??3ôí3105!3# —‘‘%‘’öK’ÿöý“µ¶(² º¶þ¸±ü?í2?3öí3105!!# ¿ýi‘%‘‘ûn’ÿö%µH(² º¶ú¸±ü?í3?3ôí3105!3! —‘—%‘’ûn‘ÿöý“µH 3³ » @ þú ¸²ü?3í2??3ö2í23105!3!!# —‘—ýi‘%‘’ûn‘ûn’ÿöqµj%· ¸²ý¸±û?í?í3233105!5! ¿úA¿Ù‘‘þ˜‘‘Ùý“ÒH*A ¶þú?2?3öíôí103#3#Ù‘‘h‘‘HöK µöKý“µj 1µ º³ þ¸²ý¸±û?í?í?öí23310!!!!#(ýi—ýi‘j‘בü"Ùý“µ¶ 3² ¿  ² ¸´ üþ?3?í2ôíöí310!###µþ‘ב¶‘ûn’ûn#Ùý“µj ?´ A   µý þ¸±û?í?3?íöíôí3310!!#!!#ÙÜüµ‘htþ‘j‘úºo‘ü"ÿöý“j 1± º·  þ¸²û ¸±ý?í?í?33ôí3105!5!5!# —ýi(‘q‘בú)Þÿöý“Ò¶ 4A   · þ¸±ü?í2?33ôíöí105!### ܑב%‘úÝ’ûn’ÿöý“Òj ?´ A   µ ýþ¸±û?í?3?íôíöí3310#!5#!5!Ò‘üµt‘þtjú)F‘ú)Þ‘qµH 1µ ½  ²ý¸³ûú??í?íöí233103!!!!‘—ýi—üØHü"‘בÙ%µH 4² A    µüú?3?3íöíôí3103!!33A‘ãü$‘×Hûn‘#ûnÙqµH ?´  A    ²û¸´ýú?2?í?íöíôí33103!!3!!Ù‘Kü$h‘ãýŒHúº‘×ü"‘ÿöqH 2¼ ·  ú¸²û ¸±ý?í?í?33ô2í105!5!5!3 —ýi—‘q‘בÞú)ÿö%ÒH 4A  ·  ú¸±ü?í3?33ôíôí10!5!333Òü$ã‘ב%‘’ûn’ÿöqÒH ?A   µ  ¸µ ûú¸±ý?í?3?í33ôíôí10!5!3!3!5!Òü$K‘þ‘ýŒãq‘Fû‘‘ý“µH 6¶  º ³ þ ¸²ý¸³ûú??í?í?öí2233103!!!!#‘—ýi—ýi‘Hü"‘בü"Ùý“µH 8² º ² º·  þú¸±ü?í?3?3ôí2öí3103!!#3#A‘ãþ‘þ˜‘‘Hûn‘ûn µöKÙý“µH Iµ A  ² û¸·ý ú þ?3?3?í?íöíô2í23310#3!!#3!!j‘‘×tþ‘‘ãýŒý“ µúº‘ü" µü"‘ÿöý“H 8¹ ² ¸@  þú¸²û ¸±ý?í?í??33ö22í105!5!5!3# —ýi—‘‘q‘בÞöKÞÿöý“ÒH ;A   @ þú¸±ü?í?3?33ö2íôí105!3#3# ã‘‘h‘‘%‘’öK’#öKÿöý“ÒH Iµ  A   µý þ¸´ ûú?3?í?3?íôíö2í233103#3!5!#!5!A‘‘þ˜‘ýŒã‘‘þtHöK µû‘‘ú)Þ‘ÿöý“µj 9´  ºµ  ¸µ ûþ¸±ý?í2??í33öí33105!!#5! ¿ýi‘ýi¿q‘‘ü"Þh‘‘ÿöý“µ¶ :² ¿  @  þ¸±ü?í22?33ôíöí3105!!### ¿þ‘ב%‘‘ûn’ûn’ÿöý“µj J´  ºµ½³û ¸µý þ?3?3í2?íöí33ôí3310#!5!3!!#!5j‘þt×tþ‘túAý“Þ‘‘ü"ב‘ÿöqµH :@   ½ µ ýú¸±û?í3??íôí3333105!3!5! —‘—úA¿Ù‘Þü"‘þ˜‘‘ÿö%µH :² ¿ @ ú ¸±ü?í33?33ôíôí3105!333! ã‘בã%‘’ûn’ûn‘ÿöqµH L@  A   ³ ý ¸µ ûú?3?3í2?íôíôí3333103!!3!5!5!A‘ãýŒþ˜‘ýŒãþ¿Hü"‘oû‘‘þ‘‘ÿöý“µHL¶  ¸²¸@ þú ¸´ û¸² ý?3í2?3í2??33ö22í2233105!5!5!3!!!!# —ýi—‘—ýi—ýi‘q‘בÞü"‘בü"Þÿöý“µHM³ » ²»@  ú  ¸¶ü þ?3?33í22?33ô2í2ö2í23103!!###!5!33A‘ãþ‘בþã‘×Hûn‘ûn’ûn’‘’ûnÿöý“µH ]µ» ¶  »²¸·ûú ¸µ ýþ?3?3í2?3?3í2ö2í233ô2í233103!!#!5!3!!#3!5!A‘ãýŒ×‘þt×tþ‘þ˜‘ýŒãHü"‘úºÞ‘‘ü" µû‘‘m«H¶ú/?3310!!«úU«mÛý“«m¶þ?/3310!!«úU«ý“Úý“«H·úþ??3310!!«úU«ý“ µý“ÖH¶úþ??/310!!Öý*Öý“ µÕý“«H¶úþ??/310!!«ý*Öý“ µ*gýõ«£ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§1µ¡™•‘¥¸¶¤mUE- y¸@ xlTD, xeM5‰¸@ ˆdL4ˆqYA)}¸@ |pX@(|aQ9 ¸@ Œ`P8Œu]=%¸@!€t\<$€xˆ|Œ€€Œ|ˆx„ œ˜”¤¤©iI1!…¸@hH0 „„§‹‡¸´„£gck¸·h d`h_[W¸·T\XTŸSOK¸·HœPLHC?G¸·D@32#".732>54.#"§Fz¤^^¥{GG{¥^^¤zFV9b…LL†c::c†LL…b9d^¥{GG{¥^^¤zFFz¤^L„c99c„LL†c::c†²‰#ú¶ /]Í/Í102#"'&5467>76jnk5R·¶S4lú9R46n9··:m64R9)¬ƒ· /ÍÝÍ/ÍÝÍ103!32>54.#")ƒüEx [[¡xEEx¡[[ xEƒû}A[ xEEx [[¡xEEx¡)¬ƒ+"@" '/ÝÝÎÝÎ/ÝÝÎÝÎ103!4>32#".'32>54.#")ƒüQ:c…KK…c::c…KK…c:MEx [[¡xEEx¡[[ xEƒû}AK…c::c…KK…c::c…K[ xEEx [[¡xEEx¡s…cu"· /ÍÜÍ/ÍÜÍ10#"'.5476324'&#"3276c%%%V3eK#%HJfgGJL33FF3331HH13}5V%#%H%V5fHJJGgF3333FE6116±ÿåy¬!-9D“@] $ t $t+{+{D"(?4.(.(.1%+7+>:h:Y:G:::b¹^0Hþ²³³²þ€×[²²[×€Ù™šš™ÙØ™šš™W .. -- .. --þ¿‰‰#º_[Ñÿ噬)4`@7*/$'!04h4Y4K4=442-_oO-_--- /Ì99//]^]Î3]]]]33Î2/Í99//Î3Î310#"'&54676324&#"326%4&#"326327'#"'™´³ýý³´ZZ²þþ²ZZý. -- .Ó, // ,ý®0^¹b>L‘“LHþ²³³²þ€×[²²[× -- .. -- ..þÜ[_º#‰‰Fÿs;3F‹¹/ÿð@ H4.4$w##¸ÿð@M H H;;  H;/4#4;B ß p ?   9+>€Ðà0/43?3O33/^]ÍÜ]]]]Í/ÍÜ]]]]Í10]]]]+]]++]]]+373#'#5.''7.'#5367'7>7"327654'.‰B 965º-¸-,××,(¸1¶7:"B?n0¼+¶(.×× P´(½9p6Eu0bb0uE‹`cc1u;Ù  ¶-¸;q9>€_¸1¶(,=20dˆ‰b2/aaЉc02ÚP&/b@>+ï+ÿ++"à"ð""P'ð''€@%(H /Í+Ü^]2Íqr/]3Í2/ÍqrÜ]Íqr9/3Í210.'&547>32!!#!5!"327654&'&Ü7Z#GS,e>SW;=>B.*PlzS++VSzmQR ¦FþúF‘;G,+G>>=T,G;Qú¯AQF@(1A;NN?  33FF;A1?J7€77B??/^]Ì]ÍÜ]Í99/ÍrÜ]Ì]Ír9910.'.'.547>323267632#"'.'#"'&547632"327654'&ÿ6%( ? .@$    íTVWvvWTTUzGSšZ>==@XY<>><      "O-@" '*R*îQm}VXTTuuWV+ >=X[===>ZW>>;Ï/(@& 0 ` p  "@ H"O_/]//+3/]/10#"'!727>'#"'&547>7>76 (_E#%?BXc$&£‰üè}V+B,-„SZB?N9En&8Ï6_,+i?~BCF_?B¿“WVc %%1E[wK`_B?[J;*U/;q9S<ÇK/@9M?4=C /)//99//]923/]Î10)7>7>7654&5#"&'&547632.'.547>3267>32#"&'.'Fü¶Tl)@4:Z+X-;a)OII]P3N(a„2+C.=Ÿ#!K2dmy;*&StsOP"4&sN&(PNmVb(%)LtvSP<3=-Q}.-L'fÿéZy'&@) @ P p €  ///]Î10^]].'.'.'.547632>32b*gL8E+%DFfbN/"ŽX2U#F)N7>-qEEt/'xSEj( #&b<^Q2€P;`ÇN¥]]5(–o]ŸH: 9‡Pwc; kM”Ä;!0@! @O_o€! //ÍÌ]9/9/ÍÜ]ÍÍ2103#>54&'&'#"&547632éL™3:0./9@%%Hl9:Q0*ýÚ%#Jj9:;b&J5-L9<ð²þg•u˜#RÌ#p¹ÿà@' LFß%ð%/%?%##_! F  0  ¸ÿÀ@H Q O!  S?í?3?33í2?í/+q33/í22/]3/]]Þ]2í210+5!!!#5354>32.#"39þçý‡þèžžHz[0]%-'3 ÕýÏÏû:ûÆ|ü„|¾q>iN, µ 1 U¾#RÌg¹ÿà@% LFß!ð!/!?!_F 0¸ÿÀ@HQO ?2??3í2?í/+q33/í22/]3/]]Þ]í10+!!!#5354>32.#"3:ý‡þèžžHz[0]%-'3 ÕÌú4|ü„|¾q>iN, µ 1 U¾ŒþW ÿÆD¹ÿس M¸ÿè@" Mˆ@ M’ÿ ’?í/]qí/]Ä+/]í10++#"'532654#*7>32 GtU-8*K>q &9#[jç,G3v% Em\­D"@–_¿Ï›/]í/]qí10! 1þÏgþ9\ÿ² '@ / ?    ¸ÿÀ³ H /+Ä9//ÄÍ]9/10#>5#53\"‰-1lõÌ,G=30T&Ï#¶™† T@3/?o@H  à@P`å ÜÝ??39/33í29/q33í22]3/+]q310#5!533354>2·þ¨<ÓgþæÊBŒŒ”°þHŒº$ 5¬€&q¹ÿØ´ L%¸ÿØ@< L á( á Ÿ¯äï"ÿ"""åÜä` p  ß?3/]í?í9/]í3/]/íÞ]í99//3310++#".'732654&#"#!!>32€'LpJDeF(¾$1:44"3²ïþ¯ O.9[?!«7^D& 8I*  @<5>•Šˆ#@Y+¶p,@á ï  å ÜÝ??í2/]Î]29/í10#4>7!5!p@_>Á(Ie<þfCO‰ˆ’YS“‹ˆHŠ-¬y%5G^¶ L¸ÿè@. L6 @&á,á 6áI@à ;ä11C)äÞCäß?í?í9/í99/íÞ]í99//íí9910++#".54>75.546324&#"32>4.#"32>y#HoLLoH#*5) .O8 9M.'=+Z:Vh2G*5++=$//$þß!"-7&ÿ½ ëôb¹ÿè@ L L@p ÀÐð¸ÿÀ@"5#53f"‰-1lõï+H=30`.Ïg¼\I @@  @ /Ì]9//Í]291046733#g,(“-1lõNWu/0`.ÏWúT @ƒ„‚_@ H/+]í/íýí10%5!«þ¬ûúò+þWúU @‚„ƒ_@ H/+]í/íýí1057!Wüþ¬úþ+òÿåúÆ+ _@D& 6 F )9I &6Fƒ)9Iƒ0`@p Ð_@ H/+]3í2/]qí]/í]933]]10#'##53ÆŸËÓ å——ÿåúÆ+ ?@(ƒ0`@p Ðƒ_@ H/+]2í2/í/]qí93310#53373Ìåþþ ÓËŸú˜˜úšÕ)@…_…_@ H/+]2í2/í3/]í1053!53ÕÅýuÂúÛÛÛÛÿÏúÛX¹ÿØ@= L L 0P`@p ÀÐð @H  _@ H/+]2íýí3/+/]]q10++".#"#>3232>73ü,YTK" ‰/VI-ZTI! ‡.Vú&/& --fX:&/& .-fX:ÿ®ú 1@p €  ?p€ _@ H/+]2í2/Í]Ô]Í]10#573#5732„×ëX„×ëú"ü+ó"ü+ÿûð¿L@8ƒ P€ °0`Àðp Ðƒ _@ H/+]íí2/í/]]qrí10".'332>73[P~Y4£$2?"$?2"¤3W~ð0Oh9 2##2 9hO0VŒ H$ÿ´<ÿÛVÿ´_ÿ´bÿ´iÿ´rÿÛxÿÛÿ$ÿ´$7ÿh$9ÿh$:ÿ$<ÿD$Yÿ´$ZÿÛ$\ÿ´$ ÿ)ÿ)ÿ)$ÿ/ÿÛ/7ÿh/9ÿh/:ÿ/<ÿD/\ÿ´/ ÿ3ÿÛ3þø3þø3$ÿh59ÿÛ5:ÿÛ5<ÿ´7ÿ7ÿ7ÿ7ÿ7ÿ7$ÿh72ÿÛ7Dÿh7Fÿh7Hÿh7LÿÛ7Rÿh7Uÿ7Vÿh7Xÿh7Zÿh7\ÿh9ÿD9ÿ9ÿD9ÿ9ÿ9$ÿh9Dÿ9Hÿ9LÿÛ9Rÿh9Uÿ9Xÿ´9\ÿ´:ÿ:ÿ×:ÿ:ÿÛ:ÿÛ:$ÿ:Dÿ´:HÿÛ:Lÿî:RÿÛ:UÿÛ:XÿÛ:\ÿÛ<ÿÛ<ÿ<ÿ<ÿ<ÿh<ÿh<$ÿD<Dÿ<Hÿ<Lÿ´<Rÿh<Sÿ<Tÿh<Xÿ<YÿI %UÿUÿU LYÿhYÿhZÿ´Zÿ´\ÿh\ÿhVfÿÉVmÿÉVqÿVVrÿFVsÿÉVxÿFV€ÿ´VŠÿ´V”ÿ´[rÿÇ[xÿÇ\^\_ÿF\bÿF\fÿ²\iÿF\mÿ²\sÿ²\vÿ²\yÿh\{ÿ´\|ÿ´\~ÿh\ÿ´\„ÿ´\†ÿ´\‡ÿ´\‰ÿ´\Œÿh\ÿh\“ÿh\—\\™ÿh]rÿÇ]xÿÇ_fÿÉ_mÿÉ_qÿV_rÿF_sÿÉ_xÿF_€ÿ´_Šÿ´_”ÿ´_ ÿaÿaÿa_ÿ!abÿ!aiÿ!a|ÿ¾a†ÿ¾a—^bfÿÉbmÿÉbqÿVbrÿFbxÿFf_ÿÉfbÿÉfiÿÉfrÿÇfxÿÇhfÿ¢hmÿ¢hsÿ¢hyÿÑh~ÿÑhÿÑhƒÿÑh…ÿÑh‹ÿÑhŒÿÑhÿÑh“ÿÑh–ÿÑh™ÿÑh›ÿÑifÿÉimÿÉiqÿVirÿFixÿFm_ÿÉmbÿÉmiÿÉmrÿÇmxÿÇoþúoþúo_ÿhobÿhoiÿhpÿÝp‘ÿÝqÿqÿqÿqÿqÿq^òq_ÿhqbÿ\qfÿÛqiÿhqmÿÛqsÿÉqvÿÛqyÿhqzÿhq~ÿhq€ÿhqÿ¬q‚ÿhq„ÿhq†ÿÛq‰ÿhqŠÿhqŒÿhqÿhq’ÿhq“ÿhq”ÿ…q•ÿhq—\q˜ÿhq™ÿhqšÿhrÿrÿrÿrÿhrÿhr^r_ÿFrbÿFrfÿ²riÿFrmÿ²rsÿ²rvÿ²ryÿhr{ÿ´r|ÿ´r~ÿhr€ÿ¬rÿ´r„ÿ´r†ÿ´r‡ÿ´r‰ÿ´rŒÿhrÿhr“ÿhr—\r™ÿhs_ÿÉsqÿÉsrÿÇsxÿÇt–ÿåt›ÿåuyÿÛu~ÿÛuÿÛuŒÿÛuÿÛu“ÿÛu–ÿÛu™ÿÛu›ÿÛvrÿÇvxÿÇx^x_ÿFxbÿFxfÿ²xiÿFxmÿ²xsÿ²xvÿ²xyÿhx{ÿ´x|ÿ´x~ÿhxÿ´x„ÿ´x†ÿ´x‡ÿ´x‰ÿ´xŒÿhxÿhx“ÿhx—\x™ÿhÿÇ‘ÿÇ”ÿ¶ƒyÿƒ{ÿσ~ÿƒ€ÿ¾ƒÿ´ƒ„ÿσ…ÿ´ƒ†ÿσ‡ÿσŠÿ¾ƒŒÿƒÿ´ƒÿƒ‘ÿ´ƒ“ÿƒ–ÿƒ™ÿƒ›ÿ‡yÿ¼‡~ÿ¼‡ÿ¼‡ƒÿ¼‡…ÿ㇋ÿ¼‡Œÿ¼‡ÿ¼‡ÿ¼‡“ÿ¼‡–ÿ¼‡™ÿ¼‡›ÿ¼ˆyÿçˆ}ÿáˆ~ÿçˆÿ爃ÿ爋ÿ爌ÿçˆÿçˆÿ爒ÿሓÿ爖ÿ爘ÿሙÿ爚ÿማÿç‹yÿç‹~ÿç‹ÿ狃ÿç‹‹ÿ狌ÿç‹ÿç‹ÿç‹“ÿç‹™ÿçŒÿÇŒ‘ÿÇŒ”ÿ¶yÿÇ~ÿÇÿǃÿLjÿ´ŒÿÇÿÇÿÇ“ÿÇ–ÿÇ›ÿÇŽÿÇŽ‘ÿÇ‘yÿÇ‘~ÿÇ‘ÿÇ‘ƒÿÇ‘ŒÿÇ‘ÿÇ‘ÿÇ‘“ÿÇ‘–ÿÇ‘›ÿÇ“ˆÿç“ÿÇ“‘ÿÇ“”ÿ¶”yÿ¶”~ÿ¶”ÿ¶”ƒÿ¶”Œÿ¶”ÿ¶”ÿ¶”“ÿ¶”–ÿÕ”™ÿ¶”›ÿÕ–ÿÇ–‘ÿÇ–”ÿÕ™ÿÇ™‘ÿÇ™”ÿ¶›ÿÇ›‘ÿÇ›”ÿÕžÿžÿžÿåžÿåžlÿ²ž{ÿ²¤ ÿ3¥ ÿ3ª®Lªµª¸ÿ媹ÿ媻ÿͪ¼ÿšª½ÿ²ª¾ÿͪÁÿdªÇÿͪʪËÿåªÛÿåªÜÿåªçª ÿ˜«ªÿ²«°ÿÍ«±ÿ嫵ÿÍ«»ÿ嫼ÿÍ«½ÿÍ«¾ÿå«¿ÿÍ«Áÿ²«Äÿ²«ÇÿÍ«ÉÿÍ«Ýÿ嬪ÿš¬®ÿ嬰ÿ²¬±ÿ嬵ÿͬ¸ÿͬ»ÿ²¬¼ÿ²¬½ÿ²¬¾ÿͬ¿ÿ²¬Áÿ²¬Äÿš¬ÉÿͬÜÿå¬ßÿå¬áÿ²­ÿ­ÿ­ÿå­ÿå­lÿ²­{ÿ²­ªÿ­®ÿÍ­µÿÍ­¸ÿå­»ÿå­Êÿå­ÌÿÍ­Îÿ²­Ïÿ˜­ÒÿÍ­Õÿš­Öÿ²­×ÿÍ­Øÿš­Úÿ²­Ýÿ²­åÿ²­æÿ²­èÿ²­éÿ²®±®½®¾ÿå®Áÿå®Ï®Ñ3®Ø®Ý°±°¸ÿå°»ÿͰ¼3°½3°Á°ÄL°Ê°Øÿå±°ÿͱµÿͱ¸ÿå±»ÿͱ¼ÿ²±½ÿ²±¾ÿͱÁÿ²±ÉÿÍ´±L´»ÿå´¼3´½3´¾ÿå´Á3´Ç´Ê´Ñ´ÛÿåµÊ3¶Ê¶Ûÿå¶áÿ帪ÿ͸®ÿ帰ÿ帵ÿ͸½ÿ͸¿ÿ²¸Éÿå¸Îÿ͸Õÿåºþåºþͺÿåºÿ庪ÿLº®ÿº°ÿ庱ÿ庵ÿº¶ÿ庸ÿ庻ÿͺ¼ÿ庽ÿ庾ÿ庿ÿ²ºÉÿͺÊÿåºÎÿºÏÿͺØÿͺéÿ廪ÿÍ»®ÿå»±ÿ廵ÿÍ»¶ÿ廸ÿÍ»¼ÿÍ»½ÿ廿ÿ²»ÁÿÍ»Äÿå»Çÿå»Ê»Ëÿå»Ð»Ûÿå»Þÿå»áÿå¼ÿ3¼ÿ¼ÿå¼ÿå¼lÿͼªÿ¼®ÿͼ°3¼µÿͼ¸ÿͼ¾ÿ²¼Éÿå¼ÊÿͼÌÿ²¼Ïÿš¼Òÿ²¼Ôÿ²¼Õÿ¼Öÿ˜¼Øÿ¼Ùÿå¼Úÿ²¼Ûÿ¼Ýÿ²¼ßÿ²¼ãÿå¼åÿ弿ÿå¼èÿå¼éÿͽÿ½ÿ½ÿͽÿͽlÿ²½{ÿ²½ªÿf½®ÿ˜½µÿ²½¸ÿͽ¾ÿ²½Çÿå½ÉÿͽËÿͽÌÿ²½Íÿ²½Îÿ½Ïÿ½Ðÿå½Ñÿš½Òÿ²½Óÿ²½Ôÿ²½Õÿ½Öÿš½×ÿ²½Øÿ½Ùÿ²½Úÿ²½Ûÿ½ßÿͽàÿ²½âÿ²½ãÿ²½èÿ²½éÿš¾ªÿ;®ÿ˜¾µÿ²¾¼ÿ²¾½ÿ²¾¾ÿå¾Áÿå¾Éÿ˾ÕÿÍ¿±ÿ忸ÿË¿»ÿ²¿¾ÿ²¿ÇÿÍ¿Øÿå¿ÝÿåÀÊLÀÏÀØÃÊÄÉÿ²Ä ÿ3ƪÿÍÆ®ÿ寰ÿ²Æ±ÿÍÆµÿ²Æ¶ÿÍÆ¸ÿ寻ÿÍÆ¼ÿ1Æ¿ÿ˜ÆÁÿfÆÇÿ²ÆÉÿ²Æ ÿfÇ®ÿÍǰÿÍDZÿåǵÿ²Ç¾ÿåÇ¿ÿÍÇÉÿÍÇÎÿåÇÐÇÕÿÍȪÿÍÈ®ÿÍȰÿÍȵÿ²È»ÿåȼÿÍÈ¿ÿ²ÈÁÿåÈÎÿÍÈÐÈÕÿÍÊÑÊáÿÍËÎÿÍËÐÿåËÑÿåËÕÿÍËÖÿåËÛÿåËÝÿåËßÿÍËáÿÍËäÿåËçÿåËéÿåÌÊÿåÌËÿåÌÏÿåÌÐÿåÌÕÿåÌÖÿåÌØÿåÌÛÿÍÌÜÿåÌÝÿÍÌÞÿåÌáÿ²ÌäÿÍÌéÿåÍÿLÍÿ3ÍÎÿ²ÍÕÿÍÍØÿåÍÛÿåÎÑÎÛÿåÎÝÎäÿåÏËÿåÏÐÿåÏÖÿåÏÛÿåÏÜÿåÏÝÿåÏßÿåÏáÿÍÐÊÐÏÿåÐÑÐØÿÍÐÛÿåÐáÿÍÑÊÿåÑËÿÍÑÏÿåÑÐÿåÑÑÿåÑÕÿåÑÖÿÍÑØÿÍÑÛÿÍÑÝÿÍÑÞÿåÑáÿ²ÑäÿÍÔÕÔØÿåÔÛÿåÔÞÿåÔáÿåÔçÿåÕËÿåÕÏÿåÕØÿåÕÛÿåÕÝÿåÕáÿÍÖÊÿåÖËÿåÖÑÿåÖØÿåÖÛÿåÖÝÿåÖÞÿåÖçÿåØÎÿåØÐÿåØÑÿåØÕÿÍØÖÿåØÛÿåØÜÿÍØÝÿåØßÿÍØáÿÍØçÿåØéÿåÚÎÿÍÚÐÿåÚÑÿåÚÕÿÍÚÖÿåÚÜÿåÚÝÿåÚßÿåÚáÿÍÚçÿåÚéÿåÛÊÛËÿåÛßÿåÛáÿËÛäÿåÜÿfÜÿLÜÎÿåÜÐÜÕÿåÜØÿåÜÛÿåÜÝ3ÝÿfÝÿLÝÿåÝÿåÝ{3ÝÊÿåÝÎÿÍÝÏÿåÝÐÝÑÿåÝÕÿåÝÖÿåÝØÿÍÝÚÿåÝÛÿÍÝÜÝÞÿåÝßÝçÿåÝéÿåÞËÿåÞÎÿåÞÏÿåÞÕÿÍÞÖÿåÞØÿåÞÜÿåÞÝÿåÞáÿÍÞéÿåßËÿåßÏÿÍßÑÿåߨÿÍßÛÿÍßÝßÞÿåßáÿÍßçÿåàÊàÑàÛÿåãÊãØÿåæÜÿLæáÿLçËÿåçÎÿåçÐÿåçÑÿåçÕÿÍçÖÿåçÛÿåçÜÿåçßÿåçéÿåèËÿåèÎÿåèÐÿåèÕÿÍèÖÿåèÛÿåèÜÿÍèßÿÍèáÿ²èçÿåöÿföÿLöÿåöÿåölÿÍøÿøÿføÿåøÿåølÿÍø{ÿÍÿ´ ÿ Vÿ´  ÿ´ÿ3¦ÿ3¼ÿLÁÿ1ÄÿLV^¾=Wœæ JzTù , u .ð +÷ ¼  M >\ (¼ û &" ô^ (Ï  8; \’ þ VŸCopyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.Copyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.Liberation SansLiberation SansBoldBoldAscender - Liberation Sans BoldAscender - Liberation Sans BoldLiberation Sans BoldLiberation Sans BoldVersion 1.02Version 1.02LiberationSans-BoldLiberationSans-BoldLiberation is a trademark of Red Hat, Inc. registered in U.S. Patent and Trademark Office and certain other jurisdictions.Liberation is a trademark of Red Hat, Inc. registered in U.S. Patent and Trademark Office and certain other jurisdictions.Ascender CorporationAscender CorporationSteve MattesonSteve Mattesonhttp://www.ascendercorp.com/http://www.ascendercorp.com/http://www.ascendercorp.com/typedesigners.htmlhttp://www.ascendercorp.com/typedesigners.htmlUse of this Liberation font software is subject to the license agreement under which you accepted the Liberation font software.Use of this Liberation font software is subject to the license agreement under which you accepted the Liberation font software.http://www.ascendercorp.com/liberation.htmlhttp://www.ascendercorp.com/liberation.htmlÿ'×¢  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a£„…½–膎‹©¤ŠÚƒ“ˆÞ žªõôö¢­ÉÇ®bcdËeÈÊÏÌÍÎéfÓÐѯgð‘ÖÔÕhëí‰jikmln oqprsutvwêxzy{}|¸¡~€ìîº    ýþÿ !"øù#$%&'()*+,-./012ú×3456789:;<=>?@AâãBCDEFGHIJKLMNOP°±QRSTUVWXYZûüäå[\]^_`abcdefghijklmnop»qrstæçu¦vwxyz{|}~Øá€ÛÜÝàÙß‚ƒ„…†‡ˆ‰Š‹Œލ‘’“”•–—˜™š›œžŸ ¡Ÿ¢£¤¥¦§¨©ª«¬­®¯°±²³—´µ¶›·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,²³-.¶·Ä/´µÅ‚‡«Æ01¾¿2345÷6789:;Œ<=>?@ABCDEFGH˜Iš™ï¥’JKœ§L”•MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰¹Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­uni00A0uni00ADuni037Euni00B2uni00B3uni00B5uni2219uni00B9AmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflex Tcommaaccent tcommaaccentTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongs Aringacute aringacuteAEacuteaeacute Oslashacute oslashacute Scommaaccent scommaaccentuni021Auni021Buni02C9tonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammaEpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsi IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdanuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonos afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061 afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109 afii10110 afii10193 afii10050 afii10098WgravewgraveWacutewacute Wdieresis wdieresisYgraveygraveuni2010uni2011 afii00208 underscoredbl quotereversedminutesecond exclamdbluni203Euni2215uni207FlirapesetaEuro afii61248 afii61289 afii61352uni2126 estimated oneeighth threeeighths fiveeighths seveneighths arrowleftarrowup arrowright arrowdown arrowboth arrowupdn arrowupdnbseuni2206 orthogonal intersection equivalencehouse revlogicalnot integraltp integralbtSF100000SF110000SF010000SF030000SF020000SF040000SF080000SF090000SF060000SF070000SF050000SF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000upblockdnblockblocklfblockrtblockltshadeshadedkshade filledboxH22073H18543H18551 filledrecttriaguptriagrttriagdntriaglfcircleH18533 invbullet invcircle openbullet smileface invsmilefacesunfemalemalespadeclubheartdiamond musicalnotemusicalnotedbluniFB01uniFB02uniF005middot commaaccent foursuperior fivesuperior sevensuperior eightsuperior cyrillicbrevecaroncommaaccentcommaaccentrotategrave.ucacute.uc circumflex.uccaron.uc dieresis.uctilde.uchungarumlaut.ucbreve.uc ÿÿ¡ LNDFLTcyrl$grek.latn8ÿÿÿÿÿÿÿÿ TbDFLTcyrl&grek2latn>ÿÿÿÿÿÿÿÿkernhÚü(6Tftºð&djx‚xŒ²¼²@bxŽbxÌâìräö²¼&4~´ö& NX‚”Â&ÂÐêêð2l²>dŠ´ºÈî H ’ ž Ä â ð ö : d ’ œ Î  " 4 V p ¦ À Ú ü . \ r ” æ6DNX‚¬ÂÜâð$ÿ´<ÿÛVÿ´_ÿ´bÿ´iÿ´rÿÛxÿÛÿ ÿ´7ÿh9ÿh:ÿ<ÿDYÿ´ZÿÛ\ÿ´ ÿÿÿ$ÿÿÛ7ÿh9ÿh:ÿ<ÿD\ÿ´ ÿÿÛþøþø$ÿh9ÿÛ:ÿÛ<ÿ´ÿÿÿÿÿ$ÿh2ÿÛDÿhFÿhHÿhLÿÛRÿhUÿVÿhXÿhZÿh\ÿh ÿDÿÿDÿÿ$ÿhDÿHÿLÿÛRÿhUÿXÿ´\ÿ´ ÿÿ×ÿÿÛÿÛ$ÿDÿ´HÿÛLÿîRÿÛUÿÛXÿÛ\ÿÛÿÛÿÿÿÿhÿh$ÿDDÿHÿLÿ´RÿhSÿTÿhXÿYÿ %ÿÿ Lÿhÿhÿ´ÿ´ fÿÉmÿÉqÿVrÿFsÿÉxÿF€ÿ´Šÿ´”ÿ´rÿÇxÿÇ^_ÿFbÿFfÿ²iÿFmÿ²sÿ²vÿ²yÿh{ÿ´|ÿ´~ÿhÿ´„ÿ´†ÿ´‡ÿ´‰ÿ´Œÿhÿh“ÿh—\™ÿh fÿÉmÿÉqÿVrÿFsÿÉxÿF€ÿ´Šÿ´”ÿ´ ÿÿÿ_ÿ!bÿ!iÿ!|ÿ¾†ÿ¾—^fÿÉmÿÉqÿVrÿFxÿF_ÿÉbÿÉiÿÉrÿÇxÿÇfÿ¢mÿ¢sÿ¢yÿÑ~ÿÑÿуÿÑ…ÿÑ‹ÿÑŒÿÑÿÑ“ÿÑ–ÿÑ™ÿÑ›ÿÑþúþú_ÿhbÿhiÿhÿÝ‘ÿÝ!ÿÿÿÿÿ^ò_ÿhbÿ\fÿÛiÿhmÿÛsÿÉvÿÛyÿhzÿh~ÿh€ÿhÿ¬‚ÿh„ÿh†ÿÛ‰ÿhŠÿhŒÿhÿh’ÿh“ÿh”ÿ…•ÿh—\˜ÿh™ÿhšÿhÿÿÿÿhÿh^_ÿFbÿFfÿ²iÿFmÿ²sÿ²vÿ²yÿh{ÿ´|ÿ´~ÿh€ÿ¬ÿ´„ÿ´†ÿ´‡ÿ´‰ÿ´Œÿhÿh“ÿh—\™ÿh_ÿÉqÿÉrÿÇxÿÇ–ÿå›ÿå yÿÛ~ÿÛÿÛŒÿÛÿÛ“ÿÛ–ÿÛ™ÿÛ›ÿÛÿÇ‘ÿÇ”ÿ¶yÿ{ÿÏ~ÿ€ÿ¾ÿ´„ÿÏ…ÿ´†ÿχÿÏŠÿ¾Œÿÿ´ÿ‘ÿ´“ÿ–ÿ™ÿ›ÿ yÿ¼~ÿ¼ÿ¼ƒÿ¼…ÿã‹ÿ¼Œÿ¼ÿ¼ÿ¼“ÿ¼–ÿ¼™ÿ¼›ÿ¼yÿç}ÿá~ÿçÿçƒÿç‹ÿçŒÿçÿçÿç’ÿá“ÿç–ÿç˜ÿá™ÿçšÿá›ÿç yÿç~ÿçÿçƒÿç‹ÿçŒÿçÿçÿç“ÿç™ÿç yÿÇ~ÿÇÿǃÿLjÿ´ŒÿÇÿÇÿÇ“ÿÇ–ÿÇ›ÿÇÿÇ‘ÿÇ yÿÇ~ÿÇÿǃÿÇŒÿÇÿÇÿÇ“ÿÇ–ÿÇ›ÿLjÿçÿÇ‘ÿÇ”ÿ¶ yÿ¶~ÿ¶ÿ¶ƒÿ¶Œÿ¶ÿ¶ÿ¶“ÿ¶–ÿÕ™ÿ¶›ÿÕÿÇ‘ÿÇ”ÿÕÿÿÿåÿålÿ²{ÿ² ÿ3®Lµ¸ÿå¹ÿå»ÿͼÿš½ÿ²¾ÿÍÁÿdÇÿÍÊËÿåÛÿåÜÿåç ÿ˜ªÿ²°ÿͱÿåµÿÍ»ÿå¼ÿͽÿ;ÿå¿ÿÍÁÿ²Äÿ²ÇÿÍÉÿÍÝÿåªÿš®ÿå°ÿ²±ÿåµÿ͸ÿÍ»ÿ²¼ÿ²½ÿ²¾ÿÍ¿ÿ²Áÿ²ÄÿšÉÿÍÜÿåßÿåáÿ²ÿÿÿåÿålÿ²{ÿ²ªÿ®ÿ͵ÿ͸ÿå»ÿåÊÿåÌÿÍÎÿ²Ïÿ˜ÒÿÍÕÿšÖÿ²×ÿÍØÿšÚÿ²Ýÿ²åÿ²æÿ²èÿ²éÿ²±½¾ÿåÁÿåÏÑ3ØÝ ±¸ÿå»ÿͼ3½3ÁÄLÊØÿå °ÿ͵ÿ͸ÿå»ÿͼÿ²½ÿ²¾ÿÍÁÿ²ÉÿÍ ±L»ÿå¼3½3¾ÿåÁ3ÇÊÑÛÿåÊ3ÊÛÿåáÿå ªÿÍ®ÿå°ÿåµÿͽÿÍ¿ÿ²ÉÿåÎÿÍÕÿåþåþÍÿåÿåªÿL®ÿ°ÿå±ÿåµÿ¶ÿå¸ÿå»ÿͼÿå½ÿå¾ÿå¿ÿ²ÉÿÍÊÿåÎÿÏÿÍØÿÍéÿåªÿÍ®ÿå±ÿåµÿͶÿå¸ÿͼÿͽÿå¿ÿ²ÁÿÍÄÿåÇÿåÊËÿåÐÛÿåÞÿåáÿåÿ3ÿÿåÿålÿͪÿ®ÿͰ3µÿ͸ÿ;ÿ²ÉÿåÊÿÍÌÿ²ÏÿšÒÿ²Ôÿ²ÕÿÖÿ˜ØÿÙÿåÚÿ²ÛÿÝÿ²ßÿ²ãÿååÿåæÿåèÿåéÿÍ$ÿÿÿÍÿÍlÿ²{ÿ²ªÿf®ÿ˜µÿ²¸ÿ;ÿ²ÇÿåÉÿÍËÿÍÌÿ²Íÿ²ÎÿÏÿÐÿåÑÿšÒÿ²Óÿ²Ôÿ²ÕÿÖÿš×ÿ²ØÿÙÿ²Úÿ²ÛÿßÿÍàÿ²âÿ²ãÿ²èÿ²éÿš ªÿÍ®ÿ˜µÿ²¼ÿ²½ÿ²¾ÿåÁÿåÉÿËÕÿͱÿå¸ÿË»ÿ²¾ÿ²ÇÿÍØÿåÝÿåÊLÏØÊÉÿ² ÿ3ªÿÍ®ÿå°ÿ²±ÿ͵ÿ²¶ÿ͸ÿå»ÿͼÿ1¿ÿ˜ÁÿfÇÿ²Éÿ² ÿf ®ÿͰÿͱÿåµÿ²¾ÿå¿ÿÍÉÿÍÎÿåÐÕÿÍ ªÿÍ®ÿͰÿ͵ÿ²»ÿå¼ÿÍ¿ÿ²ÁÿåÎÿÍÐÕÿÍÑáÿÍ ÎÿÍÐÿåÑÿåÕÿÍÖÿåÛÿåÝÿåßÿÍáÿÍäÿåçÿåéÿåÊÿåËÿåÏÿåÐÿåÕÿåÖÿåØÿåÛÿÍÜÿåÝÿÍÞÿåáÿ²äÿÍéÿåÿLÿ3Îÿ²ÕÿÍØÿåÛÿåÑÛÿåÝäÿåËÿåÐÿåÖÿåÛÿåÜÿåÝÿåßÿåáÿÍÊÏÿåÑØÿÍÛÿåáÿÍ ÊÿåËÿÍÏÿåÐÿåÑÿåÕÿåÖÿÍØÿÍÛÿÍÝÿÍÞÿåáÿ²äÿÍÕØÿåÛÿåÞÿåáÿåçÿåËÿåÏÿåØÿåÛÿåÝÿåáÿÍÊÿåËÿåÑÿåØÿåÛÿåÝÿåÞÿåçÿå ÎÿåÐÿåÑÿåÕÿÍÖÿåÛÿåÜÿÍÝÿåßÿÍáÿÍçÿåéÿå ÎÿÍÐÿåÑÿåÕÿÍÖÿåÜÿåÝÿåßÿåáÿÍçÿåéÿåÊËÿåßÿåáÿËäÿåÿfÿLÎÿåÐÕÿåØÿåÛÿåÝ3ÿfÿLÿåÿå{3ÊÿåÎÿÍÏÿåÐÑÿåÕÿåÖÿåØÿÍÚÿåÛÿÍÜÞÿåßçÿåéÿå ËÿåÎÿåÏÿåÕÿÍÖÿåØÿåÜÿåÝÿåáÿÍéÿå ËÿåÏÿÍÑÿåØÿÍÛÿÍÝÞÿåáÿÍçÿåÊÑÛÿåÊØÿåÜÿLáÿL ËÿåÎÿåÐÿåÑÿåÕÿÍÖÿåÛÿåÜÿåßÿåéÿå ËÿåÎÿåÐÿåÕÿÍÖÿåÛÿåÜÿÍßÿÍáÿ²çÿåÿfÿLÿåÿålÿÍÿÿfÿåÿålÿÍ{ÿÍÿ´ÿVÿ´ ÿ´ÿ3¦ÿ3¼ÿLÁÿ1ÄÿLh$)/3579:<IUYZ\V[\]_abfhimopqrstuvxƒ‡ˆ‹ŒŽ‘“”–™›ž¤¥ª«¬­®°±´µ¶¸º»¼½¾¿ÀÃÄÆÇÈÊËÌÍÎÏÐÑÔÕÖØÚÛÜÝÞßàãæçèöø ÆÔ.™¿ÿ€È Uœgosa-core-2.7.4/html/themes/default/fonts/LiberationSans-Regular.ttf0000644000175000017500000041723411376667572024477 0ustar cajuscajus0FFTMMü‚ê€GDEFÏ \ GPOSòØëŠ Ì´GSUB“<‚K |POS/2÷††¸`cmap f¢  cvt CCê„fpgmsÓ#°¤gasp  Lglyf6^Ë,$ä¶Theadöð<6hheaK¥t$hmtxþNCÀþ`þôg¢¢RTŒ/ZžÀ·š3š3Ñf  ¯Pxû1ASC@!ûÓþQ3>²`Ÿß×: ìDª99¹×Ws sIVH‡hªª !¬d9¸ª[9»9sPsœsgsNs/sRshsisYs`9»9¸¬e¬d¬esT¡VV¨ÇhǨV¨ã¨9gǨ9½ V¨s¨ª¨Ǩ9aV¨9aǨV]ã.ÇžV  V.V-ãA9’99Á sÿáªjsWs„WsVsW9sVsŽljÇÿΊNJªˆsˆsVs„sVªˆ99s…Çÿý1¬"·¬"¬\ªòs‡s:sqsÿþ·ssª-åösS¬dåkÿï3zdAª)ªªHœŒLP9»ªwªPìsS¬8¬8¬IãƒVVVVVVÇhV¨V¨V¨V¨9 9Ž9ÿÒ9ÇǨ9a9a9a9a9a¬Ž9GǞǞǞǞV-V¨ãŽsWsWsWsWsWsWBWsWsWsWsW9 9‡9ÿÓ9sVsŒsVsVsVsVsVdAã,s‹s‹s‹s‹sŠVsWVsWVsWÇhWÇhWÇhWÇhWǨëVÇsVV¨sWV¨sWV¨sWV¨sWV¨sW9gsV9gsV9gsV9gsVǨsŽÇs 9ÿ¸9ÿ¸9 9 9ÿÒ9ÿÒ9\Ç9½9Â᪉ Çÿ™V¨ŠŠs¨Ç[s¨Ç~s¨UŠs¨¬ŠsÇǨsŒǨsŒǨsŒÕÿþÉ¥sŒ9asV9asV9asVaVǨªˆǨªǨª8V]9V]9V]9V]9ã.9ã.ã.9Çžs…Çžs…Çžs…Çžs…Çžs…Çžs… ÇÿýV-V-ãA1ãA1ãA1ÇŠsÀVsWB9Gã,V]9ã.9ªªª3ªÿݪœª3ªPªÿ骪ͪW9»Fÿõ´ÿòÿè2ÿ»ØAÿ»Çÿ°VV¨h¨X=V¨ãAǨ9a9½V¨X ª¨Ǩ3Z9aǨV¨òlã.V-buV.¯‘ûW9V- V‘Fsjlj`… VšŽtV‘F‡VsjsjljŠœŠ•VsV…O„ÛVðV)`…0U3´‡?SÇÿÍ`…sV`…?SW¨ë.U¨ÀhV]9½9 u¨Õ.©¨7À¨V@¨V¨U¨kV¨cÕCÀ¨À¨©¨@ª¨Ǩ9aÀ¦V¨Çhã.7vV.ë¨U U¨€¨U.¨@¨Ài¨Ç`sW•x@ŽëŽ«sWZ«1xŽxހЫ €ŽkŽsVUŽs„Wª#•V•Ž+zkŽ•Ž-ÀŽ+Ž7ŽUsWs ëŽW9lj9ÿøÇÿÎ@ €Žs €ŠkŽé¨JŽ Çÿý Çÿý ÇÿýV-ª[ª[skÿáÇÇÇÇ~ªKªKªKsŠsˆÍQ7€UÕUªXªY¹ªÿÀVþ`ëess:ÀžsE–•¼¼%lÍX¬P¬=¬]¬‘¢¢¢ô8å–ë´š¬ed3´WÕ˜À1ÿžd8dA«dd?dAÕ¬dÕ"Õ«ÿöØ««ÿö««ÿö««ÿö«ÿö«ÿö«ÿö«ÿö«Ù««Ù«Ù«ÿö«ÿö«ÿö««Ù«Ù«ÿö«ÿö«ÿö««Ù«Ù«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«««««Õ«g«ÕÕ{ÕÖmÖmëžë‘ëžë‘ôÕ§Õ²Õ)Õ)Ös+±kÑUFÚQ@;@<ÀfBĪwªóªªª5ª+ª-ªÿåÇ|Ç‚ZjZH˜˜‡- ÿé/ HÿèøÜ€B~’ÿÇÉÝ~ŠŒ¡Î O\_‘…ó    " & 0 3 : < > D  ¤ § ¬!!!!"!&!.!^!•!¨"""""""")"+"H"a"e###!%%% %%%%%$%,%4%<%l%€%„%ˆ%Œ%“%¡%¬%²%º%¼%Ä%Ë%Ï%Ù%æ&<&@&B&`&c&f&kððûÿÿ  ’úÆÉØ~„ŒŽ£Q^€ò    & 0 2 9 < > D  £ § ¬!!!!"!&!.![!!¨"""""""")"+"H"`"d### %%% %%%%%$%,%4%<%P%€%„%ˆ%Œ%% %ª%²%º%¼%Ä%Ê%Ï%Ø%æ&:&@&B&`&c&e&jððûÿÿÿãÿ®ÿGÿ/þ…þ„þvü ýÐýÏýÎýÍý›ýšý™ý˜ýhãzãáòáñáðáïáìáãáâáÝáÜáÛáÖáœáyáwásááá áàþà÷àËàšàˆà/à,à$à#ààààßóßÜßÚß>ß1ß"ÝDÝCÝ:Ý7Ý4Ý1Ý.Ý'Ý ÝÝÜÿÜìÜéÜæÜãÜàÜÔÜÌÜÇÜÀܸܿܳܰܨܜÜIÜFÜEÜ(Ü&Ü%Ü"‹À bcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?w6   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a„…‡‰‘–œ¡ ¢¤£¥§©¨ª«­¬®¯±³²´¶µº¹»¼pcdhvŸnj#ti<†˜7q>?fu143:kzv¦¸bm6@;2l{€ƒ•   ·}¿8Žw ‚Š‹ˆŽŒ“”’š›™ñKRoNOPxSQL@EYXUTSRQPONMLKJIHGFEDCBA@?>=<;:9876510/.-,('&%$#"! ,E#F` °&`°&#HH-,E#F#a °&a°&#HH-,E#F`° a °F`°&#HH-,E#F#a° ` °&a° a°&#HH-,E#F`°@a °f`°&#HH-,E#F#a°@` °&a°@a°&#HH-, <<-, E# °ÍD# ¸ZQX# °D#Y °íQX# °MD#Y °&QX# ° D#Y!!-, EhD °` E°FvhŠE`D-,± C#Ce -,± C#C -,°(#p±(>°(#p±(E:± -, E°%Ead°PQXED!!Y-,I°#D-, E°C`D-,°C°Ce -, i°@a°‹ ±,ÀŠŒ¸b`+ d#da\X°aY-,ŠEŠŠ‡°+°)#D°)zä-,Ee°,#DE°+#D-,KRXED!!Y-,KQXED!!Y-,°%# Šõ°`#íì-,°%# Šõ°a#íì-,°%õíì-,F#F`ŠŠF# FŠ`Ša¸ÿ€b# #б ŠpE` °PX°a¸ÿº‹°FŒY°`h:-, E°%FRK°Q[X°%F ha°%°%?#!8!Y-, E°%FPX°%F ha°%°%?#!8!Y-,°C°C -,!! d#d‹¸@b-,!°€QX d#d‹¸ b²@/+Y°`-,!°ÀQX d#d‹¸Ub²€/+Y°`-, d#d‹¸@b`#!-,KSXа%Id#Ei°@‹a°€b° aj°#D#°ö!#Š 9/Y-,KSX °%Idi °&°%Id#a°€b° aj°#D°&°öа#D°ö°#D°íа& 9# 9//Y-,E#E`#E`#E`#vh°€b -,°H+-, E°TX°@D E°@aD!!Y-,E±0/E#Ea`°`iD-,KQX°/#p°#B!!Y-,KQX °%EiSXD!!Y!!Y-,E°C°`c°`iD-,°/ED-,E# EŠ`D-,E#E`D-,K#QX¹3ÿà±4 ³34YDD-,°CX°&EŠXdf°`d° `f X!°@Y°aY#XeY°)#D#°)à!!!!!Y-,°CTXKS#KQZX8!!Y!!!!Y-,°CX°%Ed° `f X!°@Y°a#XeY°)#D°%°% XY°%°% F°%#B<°%°%°%°% F°%°`#B< XY°%°%°)à°) EeD°%°%°)à°%°% XY°%°%CH°%°%°%°%°`CH!Y!!!!!!!-,°% F°%#B°%°%EH!!!!-,°% °%°%CH!!!-,E# E °P X#e#Y#h °@PX!°@Y#XeYŠ`D-,KS#KQZX EŠ`D!!Y-,KTX EŠ`D!!Y-,KS#KQZX8!!Y-,°!KTX8!!Y-,°CTX°F+!!!!Y-,°CTX°G+!!!Y-,°CTX°H+!!!!Y-,°CTX°I+!!!Y-, Š#KSŠKQZX#8!!Y-,°%I°SX °@8!Y-,F#F`#Fa#  FŠa¸ÿ€bб@@ŠpE`h:-, Š#IdŠ#SX<!Y-,KRX}zY-,°KKTB-,±B±#ˆQ±@ˆSZX¹ ˆTX²C`BY±$ˆQX¹ @ˆTX²C`B±$ˆTX² C`BKKRX²C`BY¹@€ˆTX²C`BY¹@€c¸ˆTX²C`BY¹@c¸ˆTX²C`BY¹@c¸ˆTX²@C`BYYYYY-,Eh#KQX# E d°@PX|YhŠ`YD-,°°%°%°#>°#>± ° #eB° #B°#?°#?± °#eB°#B°-,zŠE#õ-± @¾Ÿ@ŽÀý¯ýý Oû ûõP(òF(ñF*ðF+_ïïïOï_ïï¯ï åäãâFâ@âFáàFÏàßàïà@à36FàFÝ=ßUÞ=UßUÜÿÕÕÕÕ@ÊFϽÀ<ÁP&¼¾(ÿ¹P¸p¸€¸¸ÿÀ@ÿ¸2F·?·O·o··Ÿ·¯·p² ²°²²µ°µµ³?³ï³€°°°°À°Ð°/¯?¯ ­°­À­Ð­/¬?¬Ÿ«ÀªÐªO©©/©o©¿©ÿ©œ›$P›o–¿––F•”””ÿ”0‘@‘€‘p€ÀÐOŒ_ŒoŒ†FÿŸ…„ƒ1ts?sP&on<nF5U3U3Uÿ`P&_P&\F1[ZHZF12UU2Uo?ïQÿQ@Q58F@Q%(FÏ@TPIF HF5GF5¯FßFïF€F2UU2UU?_/Ooßÿ?ïo€¸±TS++K¸ÿRK°P[°ˆ°%S°ˆ°@QZ°ˆ°UZ[X±ŽY…BK°2SX°`YK°dSX°@YK°€SX°±BYtstu+++++stu+++t++ssu+++++++++++++++++s+tstusts++tus+stsststtsts^sstsss+ss+++s+tu++++++t++^s++^st++++ss^ssssss^ÌÌ}y:wÿìÿìÿìþW´½¯ ˆ~¬¿Ã«›¹ª”™‡jƒ¤´`jy˜¬¸§"3ÃkÛÉáÉ’¨k’·k›{ò’Rnׂ‰ Ÿi`¤[^‚^eoŠ¥z€ÿó ü§ƒ‰–iq¨ù§®µHj¶ý“‘g‘aÙAD©,,,,`æðTžö2r²ÚP– Þ D â Œ Î ž P ~ È  J ’d¬@ Þ(Ê`Â,X¸@¶À^(&’*¢þ @ ” ¾ ò!"¬"Ê"ô# $6$¬%6%¦& &î'X'¦(f))D*ö+d+Ô,p--b..r.æ042V3â5|66ˆ7~7ð8p9Ž::´;T;Ú<Þ> >€?v@8@˜@ÂA¢A¸BB^BØCnCšDDZDzDäE E–EþF FJFlFøGG(G@GXGrGŠGþHH*HBHZHtHŒH¢H¸HÐI@IXIpIˆI I¸IÒJ4JìKKK4KNKfKÄLŠL¢LºLÒLêMMNN*NBNZNrNŒN¤NºNÐNèOœO´OÌOäOüPP.PnQ Q"Q:QRQlQ„RR"R:RRRjR‚R–RªRÂRÚRòS S"S6SNSfS~S”SœT:TRTjT‚TšT²TÆTÚTîUUU6UNUfU~U–UªU¾UÖUîVV~WWW0WHW^WtWŠWœW°WÈXšX¦XÂXÚYÔYèYüZlZ„ZšZ®ZÂZØ[[[.[†[Ð[è\\\(\@\X\d]]”]¬]Ä]Ü]ô^^(^È_Š_¢_º_Î_â_ú``*`B`Z`r`†`š`²`Ê`Ö`â`úaa`aÒaêbbb2bJbbb|b–b°bÊbìccc0cHc`czc’cªcÂcÖcîddfdÞeÚeþff.fFf^fjfvf‚fŽfÄfúg0gxggøhDi–ièjj^jšk¬kÔllNlpo^oŽp¸pÀpÈpôqrqzq‚qŠr,r4r„¦…,…ì†^‡‡(‡B‡Z‡r‡Š‡äˆhˆ€‰0‰8‰@‰X‰`ŠŠ‚Šð‹‹ ‹h‹p‹ä‹ì‹ôŒ‚ŒŠtŽJެŽÄ:ÀÈÐØ&®‘>‘F‘„‘ð’@’œ’ú“p“Δx••¼•Ä–h–ø—$— —¨˜œ™B™Ä™Üšjšò›¤œœ œTœ\œdœœœ¤œ¤êžBž”žøŸZŸ¾ ( º¡8¡¨¡Â¢b¢z£ ££Š£¤£¬¤†¤ü¥€¥˜¥°¦¦6¦d¦|¦”¦¬¦Ä¦Þ¦ø§§(§D§`§‚§¤§Æ§Ò¨¨4¨f¨–¨ì©L©ª©æª@ª†ªÈ­`­‚­”­Ð®® ®4®X®Â¯¯Ö±>² ²Þ³Œ´b´úµº¶(¶Z¶Œ¶¾¶è··D·r· ·è¸0¸€¹P¹ðº º’º°»"»¼»Ô¼½F¾6¾®¾â¿:¿’¿À¿ÚÀÀNÀfÀ€À¢ÀÄÀæÁÁ.ÁTÁzÁ ÁÒÁøÂ"ÂPۼÂèÃÃRÀðÃêÄÄHĂĶÄìÅ0ÅdÅœÅâÆÆLÆ’ÆÈÆüÇDÇŒÇÖÈ2ÈJÈbÈzȒȪÊÂÌžÎ^ÎlΌΨÎÐÎÞÎìÎúÏÏÏDÏ–ÏÈÏúÐLÐŽÑ>ѾÒnÒèÓ€ÓàÔfÔºÔôÕ@Õ¶Ö Ö~ÖÐÖâ××~×üØ2ØæÙ$ÙLÙzÙ¢ÙÌÚÚ8Ú\ÚªÚîÛ*DdU.±/<²í2±Ü<²í2±/<²í2² ü<²í23!%!!D þ$˜þhUú«D͹¬@ž[–¦–9IY@H & É Ù v ¦  )  ×I & Ù v )  y V  £© ‚ T d t ‰ b r D T " 2   ò Ô ä ²  ” ¤ r ‚ T d B  $ 4  n ¸ÿ€@fmHI  @^bH- =  ¸@™UXH €QTH} _ o  €GKH ÀCFH €?BH} [ k = M  )  7ë û Í Ý « »  @-0H; K [  - Ë Û ë Ÿ ¯ ¿  + ; k {   Ÿ ¿ Ï @ `   p_œ?/ýÎ]]^]]]_qqqq_rr+rrr^]]]]]+++qq++r+r+^]]]]]]]]]qqqqqqrrr^]]]qqqqrr^]]]]q/^]+]íq3/í10#353g”ÄÆÂôúÉÉWÆ€h@!0€ `p€`pP`°À¸ÿÀ³%(H¸ÿÀ@ H0€o/? ?3Í]2/qrÍ]qÜ++]qrÍ]q10#3#3jޏþy¸Æ»þE» iyÖ@†ZZDD6D&6D&6         Ð OŸ?O   /3?399//]q]q3Í23Í2/33‡ÀÀÀÀ3‡ÀÀÀÀ/3‡ÀÀÀÀ3‡ÀÀÀÀ10]]]]]]]]]]!!#!##53#5!3!33!!€NþåXnVþ•TnTÉáNüYnXkXnXÓý@PjNuþlþh˜þh˜lql˜þh˜þhlþqÿrRì0;F.@\šš –D…'Š9š9‰5™5„%v†–F?V?†?4&d&t&%"7/ A 0001o)o1 11 101P1p11¸ÿÀ³#H1¸ÿÀ@uH1o@H753.'#4.'>Ùõ"ª .NqNM”tG@sž_|d‘fB®zu;rgX@$8r¯w| /Qj:AlM*ý\(F_7Hd= ¹¥%5W@'ð2S€bT|S,ƒƒ-PsK!^i þC)8OmHMƒd>¢?P3 þ,8QÅ6J2!¥!4DIÿôÔ+?SÔ@ v†y‰*¸ÿè@ H% H  H¸ÿè³ H¸ÿè³ H ¸ÿè@ H H H¸ÿð@T'6´ ²´,, ,,@,,, ,P,`,p,à,ð,,@´²J´'ï'ÿ''@ H'O¶"¸E¶1¶¸;¶?íôí???íôí/+qríôí/]qrýôí99//883310++++++++]]#".54>32#3%2#".54>4.#"32>4.#"32>Ô3WtBBsU10VuDBsU2û;›šûß@rV12UtBCtU11Vvú+?(*@,+?)'?,ûð*>(+A,+@*&>,²}«i--h«~…®g))g®ýÉ )f¬ƒ~¬k..j¬ƒ¬f)ü%cƒN !Nƒb_€O""O€|b‚N !N‚a_‚O""O‚Hÿì6‰9IY@I‰Œ${*‹*bRrR‚RfGN[NI+Y+i+60†0%(,#|#Œ#,<\  *  *¸ÿè@8 H *0)&E6BI!I:-,ŒJJM:,P,:,,: 6¯66¸ÿÀ@= H6PH? O  MbErE6EFEJ0)M,&E ?QÀ?UQ3P?í?í/]]qí9]]]]/]í/+]q9///]]99]Ííí910]+]]]]]]]]]]]]]]"&'#".54>7.54>32>732674.#">.'32>©`:L]m@u«n53[~K (U…]I{Z2Bp”S>’U=Q‘#kF5j1 ;Kþ–0E*`d%AtV2JY¤Bq{#HmI,OD7 B=0&73#.5*ZŒa®^‰X++X‰^®aŒZ*‹þêÜiiÝëþ‹‹þìÜiiÜêýŒ þX+ÌH@ ˆ ˆ WW¸ÿè³H¸ÿè´H¸ÿð@ò  ??/]ýÌ]8210++]]]]#>54.'3+*ZŒa®^‰X++X‰^®aŒZ*ŒýêÜiiÜìþ‹‹þëÝiiÜêþ‹!²ýk@KM]mK[kBRCS  _ 0/ ?  ¿ Ï   ðß?Ì]]]/]]Ì3Ì]ÝÌ]3Ìqr910]]]]% '7%73È-þæ¹w–œw½þè- ˆZg„IúHÿHøI†k)d´Gž G@.Ó … ÜŠ ª Ù8ˆ­ Ö7‡³?3]]3í22]]/]3í210]]]]#!5!3!Ÿ“þX¨“¨`þT¬’¬þT’¸þúÛ N¹ÿà· H —–¸ÿÀ@ H€ @ P °     ¸ÿÀ@&)H @ H ¨› /ýä/++]qr3+ýí10+%#>5#5 {-1XÛ¨5WKB A„AÛ[ÐOp!@@p»ŸÏ//]qí//]105![ôР »~Û.@ –@P°àð @ H›/í/+]qrí10353»ÃÛÛÿì9Ì3@y‰ H) €¸ÿð´??/8Í]810]+]3›žþiàú Pÿì#–'p@PY%i%F!V!f!VfYiv†y ‰   y‰v†n@ )€n?  s#s?í?í/]íÜ]í10^]]]]]]]]]]]]#".54>324.#"32>#M…´fg²ƒKK„´je±„L·(NqHLtO()OrIGrO+ÁËþë«JJªÌÕ¦CC¦þéը߅78…ß§¢Þ‡;;‡Þœ ^@ €  n/¸ÿð@HDTdHt?í2?33+/3]+/^]3/]/]í2/]1035!5%3!œgþÂM¦W™<ãªåû™g –(¡@Muu…zŠe%V%)!Y!i!i##u…'n@@&*H@*€nt&„&& ¸ÿÀ@&H&Ž\l|  s&t?í9?í3]]]9/+]33]/íÜ]q+í210]]]]]]]]]]]35>54.#"'>32!g3“¢Ÿ€O$D_:6_J/¸ Bt£ki¤q<3Upz|mVßu³‘||ˆV<[>54&#"'>32?y³sƒ³t: º+JlJˆ›Egy3fb3n[;…ƒw“ µ P{žYvªl3"HoNU~R)…a˜i7Ak‰I8\B$†„N_5œ7^Iqƒzo]Š[-;eˆM>lV> ;Xp/7 u@Pš™ˆ…•vv†–@ H[ k {  opà0Pàs ??39/3í2/^]qr33í22]/+3]q10]]]]]#!533!qªýh…½Æþþ—ò?þÁ?Œ¶üLŽw$% ýìRÿì,µ@V f † UeZjU+e+U*e*&¸ÿØ@YH $™$‰$Ù$D!# H# n@/Ÿ.€$%n! nÐ ?  s(($t!ss ƒ g   ?3]]]í?í9/í/]qí3/3í22Ü]qrí9+10_q_qr]]+]]]]]#".'732>54.#"#!!>32@~»{o¥rC¶ (EeHFrQ,*NqH-LA5°/!ýƒ0ci¨v@Ëj°F4[zF(K;#+TzOAmO,%ö™þA%5@u¢hÿì–$8¯@0ŒzŠYiZjzTdT#d#t#T"d"t"5E…22¸ÿð@- H„%5Euon@/%Ÿ%%%:€/n  ¸ÿÀ@&H *u 4s™4s?í?3]í9/í2/+]í2Ü]qí2/í10]]]+]]]]]]]]]#".54>32.#">324.#"32>;sªo{¸z=E‚»vH~gN¬{QJxT-1²s`œo=·$HjF1dQ3(KjBAgH&Íj±G^±¤¼¾`CnP[QF‹ÒŒ[_>u§pIvS-AjLN‡d:-Uzi D@-z Š i nP   _ @`€ t ??í2/]q3/]q9/í10]] #47!5! j²€G¼Pˆ´eý £ï¢þÕþÑþÁ´©E9.“™Yÿì–)=Q¿@„u(…(u!…!u…u…u…zŠzŠz zŠzŠzŠu…UEeEUKeKZAjA4n*n$O n@>>>/>Ÿ>>>S€HnÐ  $Cu99M/uMu?í?í9/í99/qíÜ]qrí99//q99íí10]]]]]]]]]]]]]]]#".54>75.54>324.#"32>4.#"32>9u¶||µw9/Oe6;]?!9p¦ms©o6!?]==hL,Þ>dIGb?:fPUg7#DsVOoE FrQRpD‰Z—n>>m—YMxW5 >Wj;Jƒc9:c„J:jW=  5WxL5X?##?X5*XH..HXý£3_I--Ja4AkM**Mm`ÿì–$8¾@i©'£ • ¥ ª™t#„#t „ ” zŠšzŠš{‹›Z(j(Yi H6%n/?O¿ 0@°: o /n ¸ÿÀ@ &H4s_o*s"s  ?3]í?í9/]í2/+]í3/íÜ^]qrí310]+]]]]]]]]]]]]#".'732>7#".54>324.#"32>G„½vQ‚fH¬w[IyU0I]l7`›l;?x¯oëòÄ%IkFAhH'#FhE2gS5ݼþå¼^!FpOEŠÐŒ/J3E|¯km°{Bþ¤¯NŠf;.UzKGzY3"Fk»~:6@$–@Pàð @ Hœœ?í/í/+]qr3í2105353»ÃÃÃkÏÏü•Ïϸþú: Y¹ÿà@ H —– ¸ÿÀ@ H€ @ P °     ¸ÿÀ@&)H @ H œ¨œ /ýä?í/++]qr3+3ýí310+%#>5#553 {-1XÃÏœ5WKB A„AÏœÏÏešHªj¹ÿØ@H(H(H‰¸ÿØ@3H† Pp ?0p€?oŸÏ/]33Í]Í]/]/]310]+]+++5 eãü¦Z;Í¢šþ’þ‘™dXGìF@1@` pÐß ­/_oß­PÐ/]]íÞ]í/]]3/]q3105!5!dãüãX””þ””ešHªj¹ÿØ@H(H(H‰¸ÿØ@3H† Pp 0p€??oŸÏ/]Í]Í]33/]3/]10]+]+++75 5eZü¦ãš™onšþ^ÍT'–%)‰@Du$…$u#…#ZjZZzŠZ z Š :J H °)À))–&&FF @°¸ÿÀ@&,H!_  'œ&L_!?í3]/ýÆ]9/+]í/í9/íq3/í10]]]]]]]#>54.#"'>3253'%>ORO?'¯'>NPM<%*MmCŒ¤¸ Cy³zr²{@ýÃGlUC<:DS7EhP?99FX;;\? Œz T•pA8g”ûÉÉ¡þånÌ]re@ÿzŠu…u…y/‰/t&„&f&cFVEfE{‹IJ8Z8j8;fR?6?F?R@&@6@F@ƒ%5E%5E…9   H\f\†\P:`:::5:E:‰9]9 99 }44 4K4 *hÔ%)Ó p"„HH 1PP  RÒ@_1o11Ÿ11t€=ÒRR RR,ÕkÖcÖ$/?O 0@M6ÖY•GGBÖM/í3]?í99//]]3íí3/í/]íÜ]qí99//]r9]22í2í10]]]]]]]]]]+]]]]]]]]]]]]]]]]]]]]]]#".5467##".54>3237332>54.#"32>7#"$&54>$324.#"32>7>nCv¥a8O2E]uGT}Q(G„¹r<`I6'œt+&>kO-S¡îœ†ã¸‹^0V¥óži¶˜x,72‡¦Äo¾þÙËi?vª×ÿÉ$¿\ý¢"?Y8V‚W-_cEx`F óï¬`/@&+ -YE+:gSxÝ©f0C( þTx10.QŽÀpÞ¢\@t¡ÀÛsî«`!09p?4!sΩ‹Ü´€FvÈþø›2Tf„G$PR@Îfv†fv†iy‰iy‰sƒe|ŒjzŠ9Yiu…6VfZHUG%5æö*: éù *: éù 0 %5æö¯¿P°0`Àð/_v  ?2?3]9/3í2]]q/]3]qq3/]q3]qq9=/33]qq]qq999910]]]]]]]]]]]]]]]]!!#3 .'!¡ý~¢Æ?Ù6ý®´œþdú(RC-.DR(þ1¨ê!.›@l›«“ … “-u-…-z$Š$š$  % &«Ÿk{‹ Z@ H)Z@"/"¯""0€)Z@(_)_)_?í?í9/qí9/^]í2Ü]qí9/+í9]]]10]]]]]]]]#!!24&#!!2>4.#!!2>êT޼hýÄu¸€C!CeCUƒX.þþ¿ATtH Q1\PþœsI{Y2k—_,'TZ;hU= :ZwBrbþB!=Vý¾C^<þ7#"$&546$32.x¹}@E»uR‡mV!œ&p—¿v«þÿ­V[¯¤á.GµDf‰úP”ÐÓ˜T+NkANOˆd9mà Ÿ¥ »e°­<2[F*¨e d@F©{¬+;{©+;{{™yZ@/  €@Z@__?í?í/^]í]Üqí10]]]]]]]]]#!!24.#!!2>ej¸û‘ýñÒ£ÆoÀR”Î{þñ:o½ŠNϰþóµ]Q©þü´Ë‚=û±HŽÔ¨þ Mµ ¸ÿÀ@% H  Z@ _ _ _?í?í9/qí]/^]í23/+99//103!!!!!¨-ü’2üΗœþ<šþœ¨‘ i¹ÿÀ¶ H¸ÿÀ@: H Z@0 _ï?oŸ¯Ïß@H_??í9/+^]qí]/^]í23/+9/+10!!#!güî¿éåýôžýÅœgÿì –-¹@‚†+j+B%R%UVVUz Š Y i jjI%Y%5{ ‹ @  $\@!!/€ /`/€/[¯¿ !_ð"""_)_0 @  à  ?3/]qí?í9/]í/]]]í]Ì]9/í2/]10]]]]]]]]]]]]]]46$32.#"32>75!5!#"$&gY±­‚Äd#¶Ih‰X€½|=B‚ÁSŒqVþ[U/ž¼k²þö±YÇ¥ »e.V{M64U¨? š@g«ŠšŠšªfƒ“d­k{‹YV › $  jú      Z@ ?3?39/^]í223/]839/]93q310]]]]]]]]]]]]]!#33 Rý͸¿¿§áý¨¨¨Œýäý>Âýœüã¨/8@(0 @`€ ðZ@_?í?/^]í/]q1033!¨¿Èûœ¨,,@ ˜)— H ¸ÿð³ H ¸ÿð@H(   H* !%H* H* H¸ÿà³!%H¸ÿà³H¸ÿà@ÿ H $$,\*$4Ô‹›.‹.t.;.Ë.´. .Ï«.4. ...ô.Ð.Ä.°.t.„.¤.`.T.@.4...—ð.´.Ä.ä. .t.”.P.D.0..$.ô.à.´.Ô..„.p.4.D.d. ..ô.Ð.t.„.¤.Ä.`.4.T...gt.”.´.Ä.ä.P..$.D..4.D.d.„.´.Ô.ô.¤.Ä.ô.‹..4.T.t.7@Sä.Ë.$.D.t.”.´. .Ô.ô.».d.„.K..4.û.¤.Ä.ä.€.@.P.p.?.. .\@¸ÿÀ@%H*K$ $?3]?33+3/^]í2]]]_]]]qqqqqrrrr^]]]qrrr^]]]]]]]qqqqqqqqqrrrrrrrr^]]]]]]]]]]]qqqqq^]]]qqqÜ^]]]q2í9=/3310+++++++]+++]]!46767#.'&'#3>73V þ”†þ ªûwpõ¬3j,3032+a'ü@À(-/5987/g'üTü/?B;Ñú¨ Ĺ ÿà@' +H6 F  +H)9I !H H– ¦ ) ¸ÿð³!H¸ÿà@5Hšª&\DT”à0@pÀÐ@@ÀÐà¸ÿÀ@H \@¸ÿÀ@+H  @+H ?33+?33+/^]í2+]q/]_]q3í10]_]++]]++]+]+!#3&'.53:ýªÞú¬°10)[#üXûH11*c-œúaÿì×–'l@J[%% %R!!!T[fh [@)€ )€)[¯ ¿     _#_?í?í/]]]í]Üqí10]]]]]]]]]]]]#"$&546$324.#"32>×_´þü¥®þú®X\²©¨±\ÃA¼{~¾?A½{„¿{;Ç¥þòÀhmà Ÿ¥ »ef¼þö£ДPP”ÐÓ™UV™Ô¨êu@S©“›« *  % Z@€@@Z@_/O_Ïÿ@ H_ ??í9/+^]qí/]í2]qÜí10]]]]]#!#!24&#!!26ê=y¶yþb¿Q}º|>À¤¤þ…ƒ¥›Ù\ŸuDýÛ=oa†‹ýÔ’aþ}×–$8¢@ql|Œhhe"WU1Z'Z-l|ŒZ(Z(,U,6Z662U22 [@%%:€/[¯¿  :€:*_ 4_ _/í?3í?í]/]]]íÜqí992/10]]]]]]]]]]]]]]]]3267#".'.546$324.#"32>×M‘Ó†5DS3@&[1V€aFžïŸP\²©¨±\ÃA¼{~¾?A½{„¿{;Ç•÷ºu@Z9† 3_ŠWsÁ˜¥ »ef¼þö£ДPP”ÐÓ™UV™Ô¨hÒ@>© Ššª”u…®|ŒJZj r‚’c@3%¸ÿp@WIp€TdB#3Z 0@` @   Z@_/_o_?2?í9/]í2/^]í2]/]39/í9310]_]]]+_]]]]_]]_]]]]]]]]!!#!24.#!!2>Œþ’þI¿—x¹~B'T‚[ø,TxLþ;ÍRxM%Iý·7h–^C‚lNý¡ì@^?ýø)Hb]ÿìø–?â@n–>D>¦;†6„1—(©! !!+!›!Y©‹‹–„:`6iv*Z))Z@°A€ Z@H4Z@Hxˆ˜;4¸ÿð@/Hw4‡4—4:44/_o*Y*K***$_` R D  ?3]]]í?3]]]]í99]]+]]+/^]í3/+íÜ]í2/í10]]]]]]]]]]]]]]]]]# $'732>54.'.54>32.#"øEÛ–þùþÚ(¹:c’fUŽf9?rž`;wm`F(QÄrƒº€M¼5V{Sb…Q#?lŽPAvgL+…Y–m=¸®%7ZA$<_BEV8& +:QkFd\*)RyP!3P6#53ÛtÐ\¿9f‹SR’n?¾] ×>ƒÉŠük•^+,`›odü‘ψB Më@µJZjEUeŒ:Zjzƒ5Ueut„ Œ{*: éù%5æö *:èø4T 0`Àð%5æö¯¿ P0`Àð/y  ?3]?3]]q/]3]qq/]q_qq3]q_q9=/33]qq]qq10]]]]]]]]]]]!#367>73ÆýÁɆ   „Éü -Y#)'%)#X0à †.W@Iy,u{‹It „ F zŠIYiu…GWgŽ-[-k-{-dtU H ¸ÿà@ÿ HƒuDTd6ŒzK[k H*: éù % 5  æ ö  *: éù%5æö*: éù%5æö'{'t„''-*-:--è-ø--Û.Ï.».¯.›..{.o.[.O.O..¯..@H .0.. .åõ¶ÆÖ8xˆ˜¸ @@ÿ&Hw0—0×060F0V00'0070g0w0§0·0Ç0ç0÷0&000ÉÇ0×0ç0x0˜0¨0¸0i0(080X000è0Ù0¨0È0™0Š0X0h0I07000ç0È0§000(0H0ˆ0™Ç0X0h0ˆ0˜0¨0I0(0 00Ø0è0Ë0š0ª0º0‹00À|H90*00 0ù0ê0Ù0Ê0¸0‰0™0©0x0i0:0J0Z0)00 0hý0ì0Ý0Ì0@ÿ½0«0œ0‹0|0k0\0K0<0+00 0ü0ë0Ü0Ë0¼0«0œ000m0_0M0/0?000ý0ï0Ý0Ï0½0¯000m0}0[0M0;0-00 08û0í0Û0Í0»0­0›00{0m0K0[090+00 0ù0ë0Ý0Ë0½0«00‹0}0k0]0K0=0+00_00Ÿ0¿0ß0ÿ00DT-'@{‹ H?33+]3?3]^]]_qq_qqqqqqqqqqqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]qqqqqqqq_qqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]qqqq+qqqqrrrrr^]]]]qqqqqqqqqrrrrrr^]]]qqqq/+^]3_]]q/^]]+]_qqqqqqqqqq3]q_q9=///]]33]qq]qq33]qq]qq33]qq]qq10+]]]]]]]++]]]]]]]]]]]]]]]!#.'&'#367>732>73çäô   öäþaÇý õ·õùÇ&h/79:70f&üü?|1:4EC><7mü“7;>CFEhy4.+ w@ÿ\I;& K[)9DT&6 )Q E 3   ]L+; RC&6 Û Ä «  „ ` T 0 $  ô Ð Ä   ” p d @ 4   Ìà Ô ° ¤ € t P D   $ T „ ´ ä  4 d ” Ä ô œ4 d ” Ä ô   K { « Û ‹ » ë   4 D jT d „ ”@œ ´ Ä ä ô ; $  ô Û Ä « ” { d 0 $  ô Ð Ä   ” p d @ 4   9à Ô ° ¤ €  D t $ T „ ´ ä T d ” ô @  0      À ð  ¸ÿÀ@H¯     ¸ÿÀµ H ¸ÿð@) àð¯¿Ïr4DT ?2?39]]/]]q83/+]]]]+]8399//923]_]]qrrrrrr^]]]]]]]]]]]qqqqqqqqqqrrrr^]]qrr^]qrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqq10^]]_]]]]]]]]]]]]]]]]]]]! # 3 3 XþYþPÓþÓˆ}Óþ hý˜Ü¥ý×)ýbý-)S@  H¸ÿè@ÿ Hi©6FZ&V–væ9I™ © É V  9  Y ‰ ù  Êù æ   ¹ É Æ Y y © 6 ) 9 ¹ é  ™ù Æ Ö ² ¤ – ‚ t V f B $ 4   ô æ Ä Ô ¦ ¶ ’ „ v b T 6 F $   ò Ð à Ä   ° ” p d @  $ 4  iä ô Ð @¶¤ ´ Ä € t P ` D    ô à Ä Ô ° T d t ” ¤ 0 @ $  Ä ô    $ D T t „ 9à „ ¤ Ô p  $ 4 T d ä ô À ´    4 T „ Ô ä » ¤ p 0 `  / ;K{??39]3]]_]]]]qqqqqrrrr^]]]qqqqqqqqrrrrrrrrr^]]]]]]]]]_]qqqqqqqqqqqqqrrrrrrrrrrrr^]]qqqrrr^]]qqq/^]]]qý9Î^]]2+Mæ210+_^]]+]]#3 3 ¾ýâÒ­«ÒHý¸H9ýaŸA£ z@#dt„m}[)9Ir‚Td¸ÿð@ H ¸ÿÀ@ H@ H ¸ÿÀ@ H__?í2?í22+/+]33/+]3310+]]]]]])5!5!!£ûžZüïêü¦‰Vœ‹û¦’þW)Ì1@0àñ?¿ õõ?í?í/]]qíÍ]q210!#3’—ééþWuùÿì9ÌG@(xˆ H IF * €¸ÿð·??/]8Í]810]]]+]3—þiž›àú þW§Ì1@?ïñ@PÀÐàõõ?í?í/]qýÍ]q21053#5!éé—þWsø‹ ¡·óµH¸ÿè³H¸ÿè@/Hv†Hy‰6Ffv†æ&FVf¸ÿÀ³0AH¸ÿÀ@9H9Iiy‰ )Yi @H†9&6Föæ¸ÿÀ¶H"8ðÔä°d„”¤@P$4äô«»t„”K4 ëûÐİ„”¤`p@P"/2/?3]]^]_]]]]]]qqqqqqrrrrrr^]_]+]]+]+qqqq+rrrrrrr^]]]]]]]]]qqqqqqqqqrrrrrrrrr^]]]]]qqqrr^]]]]qqqqr/^]]qqq+q+qr^]Í+^]qr33Í++]qr10_]+]+++ #3þËþ΢pËr¡yý‡àý ÿáþiŠþë#@`€ Ð`€ðº/í//]q105!©þi‚‚j±ä/@u…@€@•€/?ï/]í/]Í]10] 53´þ¶ÏÙ±þáWÿìsN2A¡@2y=‰=y ‰ ( H + H%%F@. o8888C€G¸ÿÀ@H?G0CÀC CC¸ÿÀ@ #H!Q(9Q 3_/P.3P?í2?í3/]q9/í?í+]q/]í3/+íÜ]22í2/10]+]+]]"&54>?54.#"'>323267#".'#'2>=ž£¤Qƒ¨Wó:W;4T>&¼ 8g›nÌÎ*;"C&3I.E\u#VU*ÅBwZ5_¬–k‰N;C^:'C3@kN+»±þ.PQp7Q64T; ‡?bt5Y2ZIX`„ÿìÌ3’@ i1y1y#¸ÿà@ H†–IYIY†–¸ÿà@? HG@   5€*F0ð°5?5p555ÿ5À5à5%P /P?í2???í2]]qqrr/^]í22Ü]í10+]]]]+]]!"&'##>533>324.#"32>þr{£3®´2¥zÍÁ½>`EGmI&&IlFB`@"ýÊYc80" +32.#"@iM`¶ hl C|^9V—Íxm§}U32WvDZj3gœVÿìïÌ3{@WU"e"Z2j29I6 F  y‰v†F@*ï5€ Gp555ÿ5À5à5 /P%P?í2?í2??]]qq/]íÜ]22í10]]]]]]%#"!234.453#.532>54.#"52¥zÍÁŽ{¤2´¬ýÚ>`EGmI&&JkFB`@®hZ6Zb +/* £û'H<+ %05pp g0.g¦xsŸb+.f£WÿìN%k@.Z#j#ZjUeI G@'€%G0'À'Ð''¸ÿÀ@#HP%% PP?í?í9/í9/+q/]í2Ü]qí2/í10]]]3267#"4>32'.#"#IrPuž=f™lðûL„°dˆ·o/º‡-cT:÷Ug9^H--[I/˜Ó„;X›ÒzŠ«Jb<Ê¡@   3 C  ¸ÿà@j HF/O_Ÿ?¯¿ßï;_¿Ÿ@VdH@',H 0`¯ßï@/P P??3í2?í]]]q++qr^]q/^]3í22/^]310+^]##5354>32.#"3i´˜˜;fQ E-(3 Ó·üI·ƒz;eK+‰)<'aƒVþWïK1EÙ@Hz1Š1v†e>U e Z:j:&6&)! y‰v† /F@2"0ßG€F¸ÿÀ@QH=##".54>3234>734.#"32>$]f@µ{d=dF&;UpHg“]++a›os©.«ß,1Pg6EcA@bD6gR2þW&Gb<KQ"KxV®)K:#EŠÍ‡‚БMia>7( +32#4.#"#3=FTd>h…Mµ0XF@gI(´´7M28eŒTý/®EhE#.TxKý‚Ìþ~!B8'‰=Ìs@ F0¸ÿÀ@*H ÿ à ß ° À Ÿ p €   ð ß  ¸ÿÀ@"%HO  S?í??]q+qqrrrrrrrr9/+^]3í210533‰´´´ ¬¬úà:ûÆÿÎþW=Ì3@— H( HF  @?Û@ÒÕHÐà@P_oÿ àðO ?¯¿Ïï°ÀÐ?O_ ¿ÏoïÐ?oŸ¯ÿ¸ÿÀ@TORHß °/?O=@58Hp€°ÿ@#&HOÿp€ÀÐàP S?í?í?]]]qq+qrr+^]]]]+qrrr^]]qqqqr^]]]qrrr+^]]]9/^]33/í210++53#"&'532>53‰´6]H"A $ &1 ´ ¬¬úZ>jN-‹+C.¥ŠÌ û@T|zvV f † – ‹›Yiyt „ ” D  * t  T t ” t ” ´ Ô ä ô 0  ¸ÿÀ@i H F0ð ?  ? _ ÿ   ? _  9 @SVH` €   À Ð ß  ` €     0 @ €   À à ð  ????9^]qqr+^]qr/^]í2/+_]]q833/]83_r9310]]]]]]]]!#33 0þ’„´´ÛÓþIÎîmþÌüa þ/ý—Š>Ìo@4FÀÐ0ðàðß°ÀŸp€ð߸ÿÀ@"%HOÿp€ÀÐà??]]]q+qqrrrrrr/^]qrí1033Š´Ìú4ˆ#N;¹*ÿà³ H ¸ÿà@ÿ H";F .FÙ/ù/¶/)/Y/‰//¦/¶/Ö/æ/‰/v/Y///F// FÆ   6 æ ö  û=É=Ù=é=»=™=‹=i=y=[=I=+=;=ù=ë=Ù=Ë=½=™=‹=i=[=)=9== =Êë=û=i=‰=™=¹=É=[=M=)=9==ù=ë=É=Ù=»=™=‹=}=+=K=[=k===Ë=ë=¯=¿=‹==+=K=[=k== =šÿ=ë=@ÿß=»=¯=‹=›==[=k=O=;=$= =ë=ß=»=¯=›===d=K=?=+===ë=ß={=‹=«=»=o=;== =j»=Ë=ë=¯=‹==[=O==û=ß=ï=»=Ë=¯=d=”==+=K==ô=‹=«=Û==k=4===9»=Û=û= =t=”=+=K=[== =Ë=ë=û=¤==K=[={=ô=Ð=`== =À=O=0=/=@="5P(P/ ?22??í2?í2^]]]]]_]]qqqrrrrrr^]]]]]]]qqqqqqqrrrrrrr^]]]]]]]qqqqqqqqqqqrrrrrrrrrrrr^]]]]]]]qqq_qqqqqqqrrrrrr^]]]]]]]]]]]]qqqqqqqqq/^]qí2/^]]]]]qqqqí9/í910++!4.#"#4.'33>323>32#4.#"/L79\A#³ª8Ka@{3294U?@gI(´ª>RjFZ‚T'®OjA-U}QýS"KC0,9;/L5,\‘dý/VÿìN"t@;y ‰ t„v†y‰– ¦      G@$€0$$¸ÿÀ@#Hß$GP P?í?í/]í]+qÜ]í10^]]]]]]]]]#".5!24.#"32>úîq²{Aå~·u8½'KlDEoN),Mi>EpN*þäþêDŒÓ0FŒÒŒ~¤b')c¤{~¥b('b¦„þWM&:”@i8y8i*y*†$–$$¸ÿà@ HIYIY†–¸ÿà@? HG@ ''<€1F0ð°<?<p<<<ÿ<À<à<,P"6P?í2???í2]]qqrr/^]í22Ü]í10+]]]+]]]#"&'##4.'33>324.#"32>(]™pt®.´®@Re?p™](½;bJ73#46767#4.#"32>äÎÀÅÉCgQ=­´?Rg)KkBEb==aFv `)3i¡nl h3%a©ˆˆN>@(0! FÀ0àð(H ???3Í+/^]qí23/]1034.'33>32.#"Žª+:P9( 0>W7>"GB:;>9>[;¥8c‰QýÌ9ÿì¶K7½@Ut.„.ok%6*4 $I##H@ 0 °9€ I @H ,HO_ `9À9€99¸ÿÀ@*'*H?99,)P $$ð$$$ P` p €  ?3/]qí?3/]qí99]]+]q/]qí3/+íÜ]qí2/í10]]]]]]]]#".'732>54.'.54632.#"¶;p£i^—rMŸ€:aF'.RuFA€g@ÓʳÓ¢ 0DU.zt+MlA+ZUK8!+LwQ+@iLWQ'A01?**EfM”›~‹*9#JK,9' #/BXÿð*,{@W(iy‰( i y ‰ ‹ Hl|œ¬ Ho F  @€P ?  P?í?Í]3í2]/^]q33í2/]10+]+]]q]q%#"5#53733#3267*)U8Ø}„5xÈÈ3?1 õÒƒòòƒýUN?…ÿìë:%y@E–!*!:!F@/ ¿  Ÿ ÿ  '€Fß$ï$$$0$ð$$°'À'Ð'°'ð'ÿ'p''¸ÿÀ@ HP ?2??í2+]]qr/^]qíÜ]qrí310]]32>53#.5##".5:4U?@gI(´ª>RjFZ‚T':ýROjA-U}Qsü­"KC0,9;/L5,\eÑù:[@79I™6F†–:Jšiy‰5E•gw‡ H¸ÿð@> H +{DT„”ÄÔÛDT„”ĸÿð@ÿ [*  K[‹›ËÛÿÄÔ „”`DT ÇàÄÔ DT„”DT„”ÄÔÛÄ›„[D— K[‹›ËÛ›ËÛ„`DT àÄÔ „”`DTgDT„”ÄÔÛÄ›„[DÛÄ K@c[‹›7K[‹›ËÛ? àÄÔ „”`DT ÄÔ „”`P/ ?3?3^]]]_]]]]qqqqqqqqrrrr^]]]qqqqqqqqr^]]]]]]qqqqqqr^]]]]]]]]qqqrrrr^]]]]]]]]qr/^]83/^]]]]qrr839=/3310++]_]q]]q]q]q!#3>73eÕþwÀîö¿:ý@?D??B?ÂÿýÌ:*±@$å:)J)z)Š)š)5Eu…•6F6¸ÿð@ H9I9 H6F¸ÿð@ H6 F  ¸ÿð@3 H9I H9I H #(#X###)**¸ÿÀ@I/2HI*4*&*ù*Æ*æ*¤*–*y*6*F*f**ô*¶*æ*„*”*f*v*9*&****¸ÿð@ÿ Yiy Æ,æ,ö,¤,–,y,f,T,6,F,,ô,æ,Ä,¶,™,†,t,f,9,,$,,Êù,–,¶,Æ,æ,i,6,F, ,,æ,¹,V,f,†,9,+,,,ä,Ö,Ä,¶,¢,”,†,r,d,V,4,D,",,,™ö,Â,Ò,´,¦,„,v,T,d,B,4,,&,,â,ò,Ô,Æ,¤,’,„,f,v,T,6,F,$,,,ô,@Õæ,Ä,²,¤,f,†,–,D,T,6,,,iö,â,Ô,–,¶,Æ,t,„,6,F,f,$,,,ô,¶,æ,”,¤,†,i,V,D,,6,ä,Ö,Ä,¦,¶,‰,r,`,,$,T,8¤,Ä,Ô,ô,€,t,K,0,,$,û,Ä, ,”,{,4,D,d,,ð,ä,Ë,d,„,”,´,?,,,¸ÿà@(HB4")#( H-#( H-#?3]+]+?3]]]+^]_]]]]]qqqqqqqrrrrrr^]]_]]]]]]qqqqqqqqrrrrrrrr^]]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrrr^]]]]]]]]]]]]]]qqqqqqqrrrrr^]]]]]]]]]]]qqqqqqqq/^]83/^]]]]]]]]qqqqqqqrrr+839=///qr33333310+_q+q+q+q+]q+]q]q]qq!#.'&'#367>7367>73–Ñ­ ²ÐþѲ· ÄÁ½¿°ºP&,/-,&RýJ:ý!C %'&$@çýB"#&$Cßê: Ö@H”†y‚’vy7 w  zxˆ˜‡—  ¸ÿð@;   ) 9   Ö æ ö Ä – ¦ ¶ „  & F f † – ¦ Æ æ  ¸ÿÀµH ¸ÿð@  9  ¸ÿ€@tßéHv d V D 6 $   æ ö Ò À ² „ ” ¤ v d V D 6 $   Çö ä Ö Ä ¶ ¤  F V † – ¦ Æ Ö æ – Æ  ¸ÿÀ@»·ÀH„ V f v D & 6  —& 6 f v ¦ ¶ Æ æ ö æ „ v D T d 6 $   ö ä Ö Ä ¶ ¤ v † – d   & F V g F V † – Æ Ö æ ™ Ù d V D 6 $   Ö æ ö Ä  & 6 F 7f ¦ ¶ æ ö  ¸ÿÀ@6=BH9 "   ô À Ð à ´ €   t ` T @ 4   ¸ÿÀ@"H    P p €  ?3?393^]_]+qqqqqqqqqqr_rr+r^]]]qqqqqqqqr^]]]]]]]]]qqqqqqqqr^]]]]]+]qrrrrrr^]]]]]]]]]]]]]qqqqqqqq+/^]r83/+^]qqqqrr8399//8892310]]_]]]]]]]]]]]]! # 3 3 !þÝþÛÂþ‘Ç Éþ‘†¼þD,þ[¥ýôýÒþWü:Ï@;““™–zŠši H’†rVf’¸ÿð@$ H™†YF¸ÿð@$!!&!6!F!f!v!†!¦!¶!Æ!æ!ö! Çæ!ö!!¸ÿÀ@ÿÙéHÄ!¦!¶!„!!&!6!F!f!v!!&!6!F!f!v!†!¦!¶!Æ!æ!ö! !!&!F!V!f!†!¦!Æ!æ!ö! —ô!à!Â!Ò!´! !‚!’!t!`!B!R!4! !!!ä!ô!Â!Ò!¤!´!‚!’!d!t!B!R!$!4!!!ä!ô!Â!Ò!¤!´!‚!’!d!t!V!B!$!4!!!gä!ô!Ö!Â!¤!´!–!‚!d!t!V!B!$!4!!!ä!ô!Ö!@¦Â! !°!„!”!`!p!D!T! !0!!!à!ð!Ä!Ô! !°!„!”!`!p!D!T! !0!!!7à!Ä!Ô! !„!”!`!D!T! !!!à!Ä!Ô! !„!”!`!! !0!P!P!€!!À!/!!!  P?í?3333^]]]q_qqqqqrrrrrrrr^]]]]]]]]qqqqqq_qqqrrrrrrrrrrrr^]]]]]]]]]]qqqqqqqqrrrrrrrrrrrr^]qrrrr+r^]q/83/^]]]]]]8399=//3310+_]]]]]+]]]]]]]]]!#"&'5326?3>73\&ObxN": 0Oˆ3þSÀä  Ô¾bo;‡v+5ýªZZH APRj1¶:  @N­‹Yi’¢t„FVf({$¤´Ôä ;[ @'7H@H ¸ÿÀ@(\dHÀ ´   ” € t ` T @ 4 D d „  ¸ÿÀ@ IRH   ?D d „ ¤  $ D d  ¸ÿÀ³3>H ¸ÿÀ@'Hà  P p  ¸ÿÀ@ HPP?í2?í2+^]_]++qr^]]]+]qqqqqqqqq+/++^]33/^]q33_q10]]]]]]35!5!!1•ý“8ýj»‰&‹‰üÚ‹"þWˆÌ-`@A H H-!(ð ?@! õ/ o  O ß ï / O o  õ+õ?í?í9/]qrí9/]]q33í22Í210++".54.'5>546;#";AcB"7P33P7…ƒ‡?[M4G)+G3M[?þW)LlDi?X88X>j˜klþœ2T@,  ,AT3þ›jm·þN]ÌÏ@« Öæö¸ÿ€³âåH¸ÿÀ@ ÞáHÚ¸ÿ€³ÖÙH¸ÿÀ@ÒÕH´Ä¢p€¸ÿÀ@ÇÊHðÔä°À¸ÿÀ@+»¾H0@P$ðÄÔ䀠$¤¸ÿÀ³¨«H¸ÿ€³ £H¸ÿÀ@œŸHp€ä¸ÿÀ@ ‘”H°ÀиÿÀ@…ˆH0$¸ÿÀ@z}H€$n¸ÿÀ@ ruHÀT¸ÿÀ¶fiH¸ÿÀ@ [^HP`¸ÿÀ@ORHËÛ °¸ÿÀ@ DGH>¸ÿÀ@8=HÏ`p ° àð¸ÿÀ@H@H@p€//?^]]++qrrrr+^]+_]]+q+r+rr+^]]+qqq+q+qr+++^]]]]qq+qqqr+r_rr++^]++]]9/^]í103·¦þN~ø‚"þW‡Ì-b¹(ÿà³ H¸ÿà@7 H, &ð 0ÀÐ õ/oOßï/Oo-õ,õ?í?í9/]qrí9/]q33ý22Í210++2654>75.54&+532+5^[O3G+*F4O[<„ƒ…7Q44Q7"BcA„þØmje3TA,  ,@T2dlk˜þ–>X88X?þ—DlL)\)P' š@ZŠ)90 H 0 H ¸ÿг H¸ÿÐ@ H p  ­@ ¸ÿÀ´&323267LE‘IX&A<82„Q(PMK%233E{4 ;=D),-  &.  2*•òþ¹¸:@…[¦¶–i¹FV9@H¶ÆIYi6  y ‰ ™ É F  9 ù ¶ i y © &  ÌÙ é – I Y y  ¹ É † t V f D  & 6  ¸ÿÀ@¨«H´ † – ¦  ¸ÿÀ@Ÿ¢H$   œ¶ Æ Ö ö  ¸ÿ@@“–Hf – ¦ ¶  ¸ÿÀ@‰Hb r ‚ @ P " 2   ¸ÿ@¶u|H€  ¸ÿ@@ nsH  l ¸ÿ@@>ekH´ Ä Ô – ¦ „ v R b $ 4 D   ö Â Ò    ° d t „  ¸ÿ€@GKHÔ ä ô   °  ¸ÿÀ@=;@H  7´ ä ô € T d t   ð Ä Ô ä T d ¤ Ô ä ô  ¸ÿÀ@H@  œ/]?ýÎ^]_]+]qqrrrrr^]]+]]+qq_qqrrrrrrr+^]+]+qqqq+qr+r^]]+]]+qqqqqqrrrr^]]]]]qqq/^]]]]+qqqíq3/í103##5 ”ÄÆÂ­ü Éɇÿáú%i±?°/°3°Í°2}°Í°/°%3°Í°&/°Ö°Ͱ°ܱ22°ͱ22°° ܰ"2° Ͱ!2° °'Ö±µ !"$9°°90167#5&'&576753.'¦$ & –¶·?S|Óe[yf´|ÞY ¹^9>ÌNÆNÚ"« ÓZ¨¨žŽñx››³7?ZW :P–2Ò@SF6F%5$' o',n#'n_  O_o2o  0Pp°Ð0Àà¸ÿÀ@@H& Q#¯?oŸ¯Ïß@%*H@ H,s,t2v2†22?3]í2?3í9/++^]q3í2/+]qrí/]9/q3í2í9/í3910]]]#!5>=#534>32.#"!!!2>7P 9YsCýFYVºº0c˜gF{cG® '5A$rp˜þh,?(ã&C5%7PuM%š. y\“f7:V994$s}þà~8j\G*C0qás#7™@wJZj,<JZj,<E U e # 3 EUe#3J"Z"j"-"="EUe#3EUe#3JZj-=.°$°Ïß/9)°3° /íÜí]/]]íÜí10]]]]]]]]]]]]]]]]467'7>327'#"&''7.732>54.#"‰)%dhc6IG~6ah`%+,&dfe6~GH€4iff%)š,Mf:9fM,,Mf9:fM,¬G6dge'+*&ai`6GG€5die%)*&iif6I:fL,,Lf::fL--Lfÿþv¹@†—§˜¨IF›«JjzŠ”¤Eeu…O @€\  @ €  Q Q/ Ÿ ¯  @)-H     ¯??39/^]q33Þ]+q2í2í2/^]33ý229Ì]2Ì]210]]]]]]]]!!!!#!5!7!5!3 3ÐAþþ²þƒ}þ@þ[ÇswÇÅ}šþÑ/š}¼ýy‡·þN]ÌÝ@«  Ö æ ö   ¸ÿ€³âåH ¸ÿÀ@ ÞáH  Ú ¸ÿ€³ÖÙH ¸ÿÀ@ÒÕH´ Ä ¢ p €  ¸ÿÀ@ÇÊH ð Ô ä ° À  ¸ÿÀ@+»¾H0 @ P   $ ð Ä Ô ä €     $ ¤ ¸ÿÀ³¨«H ¸ÿ€³ £H ¸ÿÀ@œŸHp € ä  ¸ÿÀ@ ‘”H° À Ð  ¸ÿÀ@…ˆH0  $   ¸ÿÀ@z}H€   $ n ¸ÿÀ@ ruHÀ T  ¸ÿÀ¶fiH  ¸ÿÀ@ [^HP `  ¸ÿÀ@ORHË Û   °  ¸ÿÀ@ DGH  > ¸ÿÀ@8=HÏ ` p   °     à ð  ¸ÿÀ@!H @H@ p €   / ?/99//^]]++qrrrr+^]+_]]+q+r+rr+^]]+qqq+q+qr+++^]]]]qq+qqqr+r_rr++^]++]]9/^]3í21033·¦¦¦Â üöûŒ üõsÿTÌMaO@u/…/zŠdU+UkU-QmQ-9m9}99U`u`…`S>s>ƒ>SZsZƒZyP‰PoPZP-Pt„6F*I%*%-+$$ LLIK"I7KK7K7NFAII NN N@NNN¸ÿÀ³!HN¸ÿÀ@HN-I,,XIA A°AA¸ÿÀ@D"&HAÙ7Ë7¼7˜7õæ•ySjSÚS›Säô¦w‡hS]72Q-' Q?2í/3í9]]]]]]qq]]]]]]]/+]í3/í/++]qí2í9999//ríí10]]]]]]]]]]]]]]]]]]]]]]]2.#"#".'732>54.'.54>7.5464.'>LOŠlI¡.DT.}2Sm;D‹pF7R61O7:p¤k]šuO¡ 6Nd9:fL-9_{AAƒhA ;T5*K9!Óá5Xq=:Y<1Rl<6]D'Ì?bE-:" OG-@. .IjL-WI7 3@Q3IuS,@hM7C% (A/6H3$.IiJ-SG5.@P0‹›üË0E3#!4E'.B0"/F-ÃZ{Á²…¸ÿÀ³H¸ÿÀ@ƒ H…@H@H‘;- 9ýëÛÉ«»™€,0H+ëû¿Ïß«Ÿ{‹o[O;/?¯¿@H@H/++]_qqqqqqqqqqrr+_rrrrrrr^]]]3í2/++íÜ++í1053!53·£ýÓ¥ø¸¸¸ÿðÅ–1[õ@oŠQ II*I EE*EL<9/I/6(F(6$F$9IŠZšZ5QEQ:=…4•46.F.6)F)9#I#9I2ÄQ=_GoGG=G=Ã0@ @¸ÿÀ@DH&Ão<7ÉBWÉLRLBBBBBBŸBÿBLLLpL€LLðLBLBL!È+È?í?í99//]q]q3íí3/qí/+]qí99//]3í10]]]]]]]]]]]]q]]q#".54>324.#"32>%32>7#".54>32.#"Å4^ƒ¡¹dc¹ …^44^„¡¸d–Åq\-RtŒ¡W‚ä«cc«ä‚W¡ŒtR-ü‰!CdC1K8's:RoKe•b00a’bKpP7r &7H/Ec@Ãd¹¡ƒ^44^ƒ¡¹dd¸¡„^4rÄþù–V¡‹sR-c«ä‚ƒå«b-QsŒ¡YHxV0-7#+Q?&@rž^ao;$;K'!2&.Sv‹ý˜2AË@-( H.( H( H H¸ÿØ@ H3'' â/ Ô88¸ÿÀ@H8d8t8„8P88¸ÿÀ@ H8ã?ã@&HÀCC¸ÿÀ@3 H9 99ä˜ H   #33ä** PäÞ?í3/]3/í]29/]]3+]í]]+]/+í3/í/+_]]]+q33í2/]10+++++".54>?54.#"'>323267#".'#'2>=5V>!3Vq>²'8#CQ •+KlGDmM*#  *)9&&„30P9 Š)J7 :‹8R4E\8<.<#;L /R>#<_BþÌ:2h'3MFo"7G%A 4+8AS ¬q@Tj z Š j z Š jzŠjzŠìëì_  @ `   ìëì°_ `€ ï /o/]3ä2/]qqííí/]]qííí10]]]]%53 !53 vþ®R¨þ®Týƒþ°P§þ±Qm?sþŒþ‘m?sþŒþ‘d´Gò3@ß ªàŸP¸ÿÀ@ H­³?Ìí/+]]]í/]]10%!5!¶ü®ã´¬’ýÂÿðÅ–1?Hð·==$=:¸ÿà@^ H9/I/6(F(6$F$9I= H6.F.6)F)9#I#9IEE3>>E?E5Ä6@Ä;;2??6?6?Ã0@ @¸ÿÀ@<H&Ão226>4ÉE DDDÉ7666ß777p76E77E6!È+È?í?í9///]q]í]í23//qí/+]qí99//833/íí293]10]]]]+]]]]+]#".54>324.#"32>##!24&+326Å4^ƒ¡¹dc¹ …^44^„¡¸d–Åq\-RtŒ¡W‚ä«cc«ä‚W¡ŒtR-þRÇ¡3Ž—hUÝŸ_Qª¶PTÃd¹¡ƒ^44^ƒ¡¹dd¸¡„^4rÄþù–V¡‹sR-c«ä‚ƒå«b-QsŒ¡þµPþ°?~of{þ¢PEHþÓUÿï¬| ´Œ/í//10!5!|ûs¬^z\¸–'B¹ÿè³ H ¸ÿè@! H H H¬¬   #¯¯?íÜí/]íÜí10++++#".54>324.#"32>¸-Ni;;hN..Nh;;iN-m0A&%A00A%&A0y;hM--Mh;54&#"'>32!+XdgR4GJDX….LkDAgG%6Sf_N»3g=`QHIP1>KID3W@%!dVKIJ*q'‚5–@ffV f Y"i"*¸ÿè@P H H0-á--á ` ` à"á### á¿@%H1ä i"H"X""ä(Þ äG  Ý?3]í?í3]]9/í9/+]í3/qí/]qí2/í9/910++]]]]#".'732654.+532>54&#"'>32‚›ŽWtI$ˆ XUMS%8C=9=2 JGDT‡2Of;EhF#VZ4K0t€'@Q+ CEHL-6 m 5(3!tpÙqP…`52_ŠW3ùÝ#ùݾ-X…YT…]2f»¾~š&@–°›@&H/+]í/^]í1053»Ã¾ÜÜwþNã~@ H HFV¸ÿè³ H¸ÿà@> H 0ƒƒ/oï@ H Œ P`p°À/]í/9/+Í/]Ý^]qrí9/3í]210++]++#"&'532>54&#*73ãAhK-1%)8#=HAk'^^ý)C0b %(¶dQP3} K@, 0`  à 0o Üäß?í2?33/3/]3/]/]í2/]10]535733PÓÊÒ{×3klŠx‰ýk‹Ó˜#‚¹ ÿè³ H ¸ÿà@+ H  H  Hã$4d”´ÄÔô€¸ÿÀ@& Hã@!Hï%p%€%/%ä Pä Þ?í3/]í]]]/+í/+]_]]qí10++++#"&54>324.#"32>Ó°¯¨±+WƒX]ƒT'•2H00K33F+1K4¼Ëɾ[‘e55d‘\SnABnRTnBBnS ¬…@deu…e u … eu…eu… ì ìë ï p € Ð ? o    ììëp€°°Ð?  ï/o/]3ä2/]]]qýíí/]]]qqrýíí10]]]]%#5 53#5 53ΨRþ°¦RüݪRþ°¨Ootþ?þ“otþ?ÿÿ8N&yè'ù“¸ýÏ@¿ p `   ?55]]]]5ÿÿ8u&yè'ùròýÏ/@o/¿ p `   3@ H?5+]]]]5]]5ÿÿIN' '“¸ýÏs.!@p`S@ H?55+]]]5ƒþ¤V:%)Ÿ@py‰z#Š#z$Š$Td:JzŠ H °'À''–((F_@733267#".#5ƒ%>ORO?'¯'>NPM<%*MmCŒ¤¸ Cy³zr²{@qÃ2GlUC<:DS7EhP?99FX;;\? Œz T•pA8g“dÉÉÿÿRð&$šN´&¸ÿá´%+5+5ÿÿRð&$›Û@ &L%+5+5ÿÿRþ&$œ`@ &%+5+5ÿÿR&$Ÿ^@ &,%+5+5ÿÿR²&$žl@ &%+55+55ÿÿRû&$P‰ˆ@ 8%+55?55¨ˆ@VtrVfsƒUem\)    Z_ _ _ _?í??í29/í9/í/33í23/399/]99//q10]]]]]]]]]!!#!!!!!#!ÉýÜÆÇ®¹ý »ýE ü!—ÙÞœþdœþ<šþœî#2:3&þ3ÿÿhþNy–&&xþ ¶:0(%+5ÿÿ¨þð&(š?´ &¸ÿª´  %+5+5ÿÿ¨þð&(›ß@  &(  %+5+5ÿÿ¨þþ&(œw´ &¸ÿï´ %+5+5ÿÿ¨þ²&(žy¶ &¸ÿê´ %+55+55ÿÿ ±ð&,šŸ´&¸ÿÁ´%+5+5ÿÿŽ6ð&,›F@ &E%+5+5ÿÿÿÒhþ&,œÒ@ & %+5+5ÿÿ4²&,žÚ@ &%+55+55e!p@Eu [ ‹ [‹ZŠ[  Z@#€Z___?í?í9/q3í2/33/í2Üqí9/10]]]]]]]3!2#!#%4.#!!!!2>šÒ£Æoj¸û‘ýñš—R”Î{þñ–þj:o½ŠN!`Q©þü´°þóµ]‡HË‚=þ9šþHŽÔÿÿ¨ &1Ÿ¡@ & +%+5+5ÿÿaÿì×ð&2š¶´(&¸ÿØ´), %+5+5ÿÿaÿì×ð&2›%@ (&%(+ %+5+5ÿÿaÿì×þ&2œÕ@ )&.( %+5+5ÿÿaÿì×&2ŸÁ´(&¸ÿõ´1? %+5+5ÿÿaÿìײ&2ž×¶(&¸ÿÿ´,* %+55+55Žás ¹ÿè³H¸ÿè@H H H¸ÿè³H¸ÿè@HHH¸ÿè@HH H¸ÿè@HÔä´ÄÔ /q/]]q10++++++++++++ 7   Žbþ h^^iþ¢`fþŸþœJb`gþŸ_iþ¤þ iaþGÿËôº'3Ä@Y,%T!e‹{‹lZi  „ t„cU2[2r+‚+T+&T&U%ŒJZzd k ,([@5€ 5([¯¿ +#/_#_ ?3í?3í99/]]]í]Üqí9910]]]]]]]]]]]]]]]]]]]]]]]#"&'#7&546$32734&'32>%.#"×_´þü¥ÎQx¾ÈXV\²©}ÏRyÀÉUWÃ11ý;;–]„¿{;ü23Ã;—\~¾?Ç¥þòÀh:6‘ña  ¥ »e86’ò^þý p¸Hü«,/V™Ô}q¾KU*.P”Ðÿÿžÿì)ð&8š´&¸ÿè´%+5+5ÿÿžÿì)ð&8›í@ &%%+5+5ÿÿžÿì)þ&8œ˜@ & %+5+5ÿÿžÿì)²&8žž¶&¸ÿþ´%+55+55ÿÿ-)ð&<›Ð@  &A %+5+5¨ê_@?–t„{‹Z0ÿ @ Z@__    ??99//íí/^]í22/]]qí10]]]#!#3!24&#!!2>ê;y¶{þb¿¿’}º|>À¤¤þ…ƒRyO&ßXŸxGþ×ü54.#"#4>32)Wˆ^P”7CJN%\b6Q_Q6!1:1!!?Z9DkI'´?x®nf›i5!3:3!7R_R7'BsU1¤ VO8M>9IbI3I:04?+%>-#MzXüv­p6.Pm>=ZE5/0&;9@UrÿÿWÿìsä&DC¼´B&¸ÿ•´CF$%+5+5ÿÿWÿìsä&DtT@ B& BE$%+5+5ÿÿWÿìsÓ&DKÚ´C&¸ÿÀ´HB$%+5+5ÿÿWÿìs½&DRõ´B&¸ÿà´KY$%+5+5ÿÿWÿìs{&Dië¶B&¸ÿÊ´FD$%+55+55ÿÿWÿìss&DP¶G&¸ÿÈ´LB$%+55+55BÿìÂN>OXû@`†6z${:u…eDuD…D|VjV~QjQeu)/),( H 5XF!OOO_OOOOP I =G@P/P?PPPZ€,G-¸ÿÀ@H--GG@ H>PPP5¸ÿ¸@+I5SP8?Q!!J2,+,,,'P2JPPï €  ?3/]]í?í2?í3/]]9/í?í2+9/í/+í3/+íÜ]qí2/í9/]3í29910]+]]]]]]]]]]]]3267# #"&54>?54.#"'>32>32%32>5%.#"È"FmNuž=f™lþ¿fJf‰]§©&C[ku<ð9X=6X@'¼ :iŸp€¬1?±jˆ·o/üPÃ(QLB1d]ZS(ö‡-`Q6÷Rˆb7^H--[I/3]G*¬–GlN3 ;C^:'C3@kN+FEJAX›Òz3I3Wa?bt5Ä«JbÿÿWþNÊN&Fx ¶(0( %+5ÿÿWÿìä&HCÝ´&&¸ÿä´'*%+5+5ÿÿWÿìä&Htp@ &&T&)%+5+5ÿÿWÿìÓ&HKõ@ '&,&%+5+5ÿÿWÿì{&Hiø@ &&*(%+55+55ÿÿ ²ä&ñC ´&¸ÿ´%+5+5ÿÿ‡/ä&ñt?@ &?%+5+5ÿÿÿÓiÓ&ñKÓ@ & %+5+5ÿÿ5{&ñiÛ@ &%+55+55Vÿì'ê'9¾@^d3d8k*k0 %5E22#G(@ (@H(( ((;€2G-P P  ¸ÿÀ@ HR$4D  5P?í?99//]]]+]3í3/9/]íÌ]q9/9+9í9/]910]]]]]]]".54>32.'57.'3%4.#"32>6}µv84tº…Gu++sLþÓÚ8xBÑ-S*2ÓQX/9x¼°!GqPQsI!‘QvK$I„¹ok¶†K V°E…r^-N#3„p\J°ÈßyzÄŠJõ^‰Z,-\‰[¾²,Z‹ÿÿŒò½&QRõ@ &&/=$%+5+5ÿÿVÿìä&RCß´#&¸ÿä´$'%+5+5ÿÿVÿìä&Rtg@ #&I#&%+5+5ÿÿVÿìÓ&RKð@ $&)#%+5+5ÿÿVÿì½&RR÷@ #& ,:%+5+5ÿÿVÿì{&Riú@ #&'%%+55+55Aß$u K@0 «€ _ ?_o ®@­®OŸ³?Þ]íýÞ]í/]/]]]9/3í210535!53Þ¨ý»ãýº¨¾··þ¢’’þ··,ÿÚ´\"-¡@]u!…!u…z&Š&z,Š,–BMDK &#G@ÏŸ¯ÿ/€#G   @ ð  / /ð/à/ß// //¸ÿÀ@ H%)PP?3í?3í99+]]]q/^]qíÜ]qí9910]]]]]]]]]#"&'#7.5!2734&'32>%.#"XúîaœEpN*ý³â%hBEoN)þäþê02tÖD¶t0.-iÉE¹wDm,ýÎ1''b¦~‚U1-$)c¤ÿÿ‹ÿìñä&XCì´&&¸ÿì´'*$%+5+5ÿÿ‹ÿìñä&XtW@ &&5&)$%+5+5ÿÿ‹ÿìñÓ&XKï´'&¸ÿü´,&$%+5+5ÿÿ‹ÿìñ{&Xií¶&&¸ÿó´*($%+55+55ÿÿþWüä&\t@  &6 #%+5+5ŠþWÌ"6m@Lf4v4i&y&IYF V )‰™&†–G@ ##8€-!F""0"ð""!2P(P ??í2?í2?/^]í22Ü]í10]]]]]]33>32#"&'##4.#"32>Š´@Re?p™]((]™pt®.´Ö;bJ54.#"52¥zÍÁŽ{¤2þÔ,´„„¬ýÚ>`EGmI&&JkFB`@®hZ6Zb +/* ƒ““ƒü)'H<+ %05pp g0.g¦xsŸb+.f£ÿÿ¨þ¡&(MzN´ &¸ÿí´ %+5+5ÿÿWÿìS&HMõ@ &&'&%+5+5ÿÿ¨þó&(¡‰´ &¸ÿë´ %+5+5ÿÿWÿìæ&HN@ &&+7%+5+5ÿÿ¨þñ&(OÉ%´ &¸ÿì´  %+5+5ÿÿWÿìÌ&HOD ¶&(%+5ÿÿ¨þUþ&(QP ¹ÿ´ %+5ÿÿWþUN&HQ} ¹þò´22 %+5ÿÿ¨þþ&(o´ &¸ÿç´ %+5+5ÿÿWÿìÓ&HLê´&&¸ÿþ´(.%+5+5ÿÿgÿì þ&*œÛ@ /&"4.#%+5+5ÿÿVþWïÓ&JKØ@ G&LF)%+5+5ÿÿgÿì ó&*¡ö@ .&'3;#%+5+5ÿÿVþWïæ&JNù@ F&KW)%+5+5ÿÿgÿì ñ&*O5%@ .&'.0#%+5+5ÿÿVþWïÌ&JO- ¶FH)%+5ÿÿgþN –&*’N ¶.2.#%+5ÿÿVþWï &J™8´O&¸ÿü´FJ)%+5+5ÿÿ¨ þ&+œ™@  &  %+5+5ÿÿŽî>&Kœò@´#&¸ÿÿ´(" %+5+5¹¦@H ZZ ;8¤›DôëD”à0pÐ  °À¸ÿÀ@$H/_ P`_@ Ð ?2?39/]qíÜ]22í22]+]q/^]_]qqqrrr^]]33í22/^]33í2210!!##5353!533#5!fý¿šš¿ÿº™™ºýýsšææææšûÿ-ÔÔ îÌ)–¹ÿè@B H! F@P Ÿ ÿ  +€ $FÀ0àð°+À+Ð+°+ð+ÿ+p++¸ÿÀ@H#Q  P¸ÿÀ´ H?+í2?3?9/3í2+]]qr/^]q33í22Ü]qí910^]+>32#4.#"##5353!!=FTd>h…Mµ0XF@gI(´„„´,þÔY7M28eŒTýW†EhE#.TxKýª¶ƒ““ƒ”!B8'ÿÿÿ¸…&,ŸÏ@ & %+5+5ÿÿÿ¸…½&ñRÏ@ & %+5+5ÿÿ 1¡&,MÿÙN@ &%+5+5ÿÿ 1S&ñMÙ@ &%+5+5ÿÿÿÒló&,¡ê@ & %+5+5ÿÿÿÒlæ&ñNõ@ & %+5+5ÿÿ\þUº&,Q ¶%+5ÿÿþU}Ì&LQÏ@ %+5]ÿÿ½|ñ&,O'%@ &%+5+5Âv:‰@F$ 4 å¸ÿÀ@7áäHðä°ÀЄ”¤@4 Ôäôt„`¸ÿÀ@ÁÄHàÄÔ°$4¸ÿÀ·¶¹H¯¸ÿÀ³«®H¸ÿÀ¶¡§H€¸ÿÀ@&–œHÐdt¤´Ä ´Äôu¸ÿÀ³y|H¸ÿÀ³nqH¸ÿÀ@cfHà´ÄÔ0$¸ÿÀ·CFH >¸ÿÀ@ 8;HËÛ¸ÿÀ@*-0H+ÄÔäk{@ 0¿Ï @¸ÿÀ@ H??^]+]]q_qqqr+r+^]+qqqq+++^]qqqq+r++^]+]]]]+qqqqrrrrrrr+^]]9/^]í1033´:ûÆÿÿªÿìI&,í-áÿÿ‰þWÌ&LMÆ@o0]55]]]55ÿÿ ÿìÍþ&-œ7@ &¾%+5+5ÿ™þW/Ó”@–¦˜¨ H( H¤¸ÿÀ@1 Hû;@ H$F   $ D  Û¸ÿÀ@ ßãH@ÒÕH¸ÿÀ@3ÍÑH@P_oïÿ 0@ àðO ¯¿Ï¸ÿÀ@9“–Hï°ÀÐ_ /?¿ÏoïÐ?oŸ¯ÿ¸ÿÀ@eORHß °/?O=@58Hp€°ÿ@#&HOÿp€ÀÐàŽ@”€/?ï P?í?/]3/ýí]]]qq+qrr+^]]]]+qrrr^]]qqqq+r^]]]qqrr+++^]_]9/^]3/í/]+]qÌ+]10++_]]"&'532>53#'##53M"A $ &1 ´6]šiÛèhêÌþW‹+C.¥û@>jN-n©©ÿÿ¨þN?&.’ݹÿÍ´  %+5ÿÿŠþNÌ&N’N¹ÿë´  %+5Š: ¦@H{tV f {‹›YiC :* ›zŠ,  p €  P  Ð ð  ¸ÿÀ@( H F0ð€ À à ?  ?2?39]]/^]í2/+]q839/]893310]]]]]]]]]]]!#33 0þ’„´´ÛÓþIÎîlþ~:ýó þ/ý—ÿÿ¨/ð&/›­´&¸ÿ^´ %+5+5ÿÿ[>&O›N@ &K%+5+5ÿÿ¨þN/&/’…¹ÿý´ %+5ÿÿ~þNGÌ&O’ÿ¹ÿÿ´%+5ÿÿ¨/&/˜@ Š %+5?5ÿÿŠiÌ&O˜$KA@@H@H@H¸ÿÀ³H¸ÿÀ@ H@ H ¸ ´%+5?5++++++ÿÿ¨/&/OÕý ¶_%+5ÿÿŠ’Ì&OOBý¹T´%+5/ w@1y‰dt„V†V† Z  @`€Ðð ¸ÿà³H ¸ÿà@H    _?í?9/]Í]9++/]q/3í210qrqr]]!!573%hþÿÈüy””¿•þœUžUÉý¥”ºÌ f@*'' F @ ÿ p € À Ð  ¸ÿà@H H O??9/]Í9++]]]9/^]33í2210qq35737Šzz´||DžDýXHŸGýzÿÿ¨ ð&1›@ &I%+5+5ÿÿŒòä&Qt„@ &&a&)$%+5+5ÿÿ¨þN &1’ü¹ÿü´%+5ÿÿŒþNòN&Q’[ ¶*&$%+5ÿÿ¨ þ&1“´&¸ÿú´%+5+5ÿÿŒòÓ&QLò´&&¸ÿþ´(.$%+5+5ÿÿÿþP&Qb ÿ¥ÿì4•7¢@š5•¥ƒ)“)£)0¸ÿè³ H/¸ÿØ@[ H*6:6š6ª6Ÿ¯3'Z@3Z@Pp °0PðàŸ¯0'_-! _?2/í???í2/^]]]qrí/]í29/]310]++]]]".'732>54.#"#4.'33>32­8`O?%d;@N) 'QW^£yF¿¸"g‚™V|±p5V˜(6s-A:k™_Blšb.>i‹Mü…D%\ZL?EE=eF'@…Ì‹þ¥‚Ð’NŒþWòN5‡@y4‰4Z4j4+4;4K4.¸ÿè@J H..1F@  ` Ð  ¯  7€%F °ÀÐ @àð%P+P?í???í2/^]qrí2Ü]qqrí9/10]+]]]"&'532>54.#"#4.'33>32"A $ &1 4U?@gI(´ª>RjFZ‚T'6]þW‹+C.OjA-U}QýS"KC0,9;/L5,\‘dü©>jN-ÿÿaÿìס&2MÖN@ (&)( %+5+5ÿÿVÿìS&RMô@ #&$#%+5+5ÿÿaÿì×ó&2¡ç@ (&-5 %+5+5ÿÿVÿìæ&RN@ #&(4%+5+5ÿÿaÿì×ñ&2 â@ (&](1 %+55+55ÿÿVÿì"ä&RS @ #&g#,%+55+55aÿö¦Œ1ª@w‰ f i V0Y*T„//T/ ++[+Z" 0"/"O"?"_""Ÿ"Ï"ï""@&H" -[    3___(__?í?í?í?í9/í]/]]í/]/+]q99//]í29910]]]]]]]]!#"$&546$32!!!!!%267."#"ç399©þý¯Y^²¤:94’üÝçýLûo L %%}»}?@~ºj¿ Ÿ¥·bœþ<šþœ‘WJŽÎƒÑ”PVÿì2N';D¾@ƒ„fvaUZBjBl=Z=E:U:e:E4U4e4J0Z0j0J*Z*j*I &G@32%4.#"32>%.#".#IrPuž=f™l‰Æ=?ɉqµDýòuCÈwˆ·o/ü?*MnDErQ-/Ql>ErQ,‡-cT:÷Ug9^H--[I/[\]ZDŒÓ±^SX›Òz'~¤b')c¤{~¥b('b¦á«Jbÿÿ¨hð&5›á´&¸ÿõ´"%+5+5ÿÿˆ¦ä&Ut¶@  &J #%+5+5ÿÿ¨þNh&5’¹ÿá´#%+5ÿÿþNˆN&U’¹ÿ^´$ %+5ÿÿ¨hþ&5f´&¸ÿ©´!'%+5+5ÿÿ8ÎÓ&UL8´ &¸ÿû´"(%+5+5ÿÿ]ÿìø-&6têI@ @&[@C%+5+5ÿÿ9ÿì¶ä&Vt9@ 8&]8; %+5+5ÿÿ]ÿìø&6KrG@ A&F@%+5+5ÿÿ9ÿì¶Ó&VK¬@ 9&>8 %+5+5ÿÿ]þNø–&6x¦ ¶(H@%+5ÿÿ9þN¶K&VxÚ ¶@8 %+5ÿÿ]ÿìøþ&6s@ @&BH%+5+5ÿÿ9ÿì¶Ó&VL­@ 8&:@ %+5+5ÿÿ.þN´'x[7ÿÿþN*,&xGWÿÿ.´þ&7!´&¸ÿû´ %+5+5ÿÿÿðÌ&W˜ÌK±¸ˆ´%+55.´e@>     ¯ ¿ /  @H Z   _ _  ??9/3í2í2/]3ý2Ì+]q9+Mä9_^]10!!#!5!!5!Ðþç¾þéþ†åþ<šýy‡šÄœœÿð*,Œ@[(((( Hœ ¬  ( H oF    € / PP¿ÏP ?í?Î39/]3í2í2]]/^]q33í2/]333310+]+qqqq3267#"5#53#53733#3P3?1)U8Ø}}}„5xÈÈÈøN?… õƒ0ƒòòƒþЃÿÿžÿì)&8Ÿ”@ &#1%+5+5ÿÿ…ÿìë½&XRö@ && /=$%+5+5ÿÿžÿì)œ&8MŸI@ &%+5+5ÿÿ…ÿìëS&XMð´&&¸ÿþ´'&$%+5+5ÿÿžÿì)ó&8¡®@ &'%+5+5ÿÿ…ÿìëæ&XN ´&&¸ÿý´+7$%+5+5ÿÿžÿì)>&8P¿Ë@ &$%+55+55ÿÿ…ÿìës&XP@ +&0&$%+55+55ÿÿžÿì)ñ&8 @ &Q#%+55+55ÿÿ…ÿìä&XS@ &&d&/$%+55+55ÿÿžþU)&8Q (¹þgµ''%3¸ÿÀ³H3¸ÿÀ³H3¸ÿÀ²H++++5ÿÿ…þU:&XQW ¹ÿâ´22%+5ÿÿ †þ&:œy´0&¸ÿý´5/.%+5+5ÿÿÿýÌÓ&ZK”´,&¸ÿû´1+*%+5+5ÿÿ-)þ&<œ[´ &¸ÿû´ %+5+5ÿÿþWüÓ&\K¶@ !&& %+5+5ÿÿ-)²&<žh@  & %+55+55ÿÿA£ð&=› @  &J %+5+5ÿÿ1¶ä&]t5@  &] %+5+5ÿÿA£ñ&=O|%@  & %+5+5ÿÿ1¶Ì&]Oý ¶ %+5ÿÿA£þ&=8@  & %+5+5ÿÿ1¶Ó&]Lœ´ &¸ÿô´ %+5+5ŠÊ}¹ÿس H¸ÿà@8 Ho  F0ðÿàß°ÀŸp€ð߸ÿÀ@"%HOpP??í]]q+qqrrrrrrrr/^]í2/]10++!#4>32.#">´;fQ E-(3 ´;eK+‰)<'ÀþNî”@k…zŠ‹Yiyƒ U e u 6 &&"2r‚%5ÔäôP&6F  _Ÿ P  Q¯ //]í9/3í2/q333qqq/10]]]]]]]]]]].#"3###737>32¤>.! ÓÕþ´þ˜— (GmQ R#  (@-‰ƒúÓ-ƒ˜;fL+ R>'=C$@z@Š@fv†Vf¸ÿè@· H H H  & '  (‚DB„BB>2‚¯>¿>Ï>/ Ÿ>>  ‹Zjz 0 EPE°E0E`EEÀEðE/E„ U e u  >>-p€9@Ÿ@¯@¿@@@ H@ '&&  €9?999 /3//]]]39/3Í2/+]9/]í3//3]]]]q3/]q3]]939///]q]q]íÍ]í‡ÀÀ‡ÀÀ310]+++]]]#!#&'.54>32.'!4.#"32>573ž&!áý~¢Æ$!&&BX22XB&ž´ƒ$11$$ 1$÷ÙÏþÊp-O ûDsþ¹ O--O;"";Oýþ$J<))>I$þ_w,!!,,# #,#µ®ÿÿWÿìs>&D'PÿUtcZ#@e&jm$%¸ÿÔ´LB$%+55+5+55ÿÿ¨ð&†›ä´&¸ ´%+5+5ÿÿBÿìÂä&¦t¯@ Y&IY\=%+5+5ÿÿGÿËôð&˜›K@ 4&I47 %+5+5ÿÿ,ÿÚ´ä&¸t²@ .&^.1%+5+5ÿÿ]þNø–'’Ù6ÿÿ9þN¶K'’)Vÿÿ.þN´'’‹7ÿÿþN*,&’sW±–Ó B@v † xˆ€¸ÿÀ@ H¿Ž@”€/?ï/]3ýí/]Ì+]10]]#'##53–iÛèhêÌÅ©©±–Ó B@v†xˆ€¸ÿÀ@ H@¿”€Ž/?ï/]íí2/]Ì+]10]]#53373¶ÌêhèÛi±©©3ÔXSQ@;äô¤[k4D HŽ@!H/?¯¿@H@H/++]_q+í+/]]]/]q10!5!XýÛ%ÔÿݱwæI@3……O¯ßï@@73)JtT2u'8H**G8&u 2St±3Up=+;$$;*=pU3œ PÌ@ †@HS?í/+í1053œ´ ¬¬3s'Y¹ÿè@ H  H H¸ÿè@* H‚@À‚_  #/?OŸ¿ï/]íÜ]í/]íÜí10++++#".54>324.#"32>&BX22XB&&BX22XB&l$11$$11$‚2XB&&BX22XA&&AX21$$11&&1PþU®L@7 H  H H „_¿ @ H  P`p°À/]qí/+/Í]qí210+++#"&54>733267®G(ij"05…4+1-:þp fU/O=* -;F'*0 ÿé±¶½M¹ÿè@¶ H  H))9Yi@åèH@ÙÜH Щ¹É› 9¹ÉÙ@ÃÆH›«‰{I‰¹@«¯H6ž™}o-=M íý€ˆ‹H‰™[k{À‚H ùëÉÙ«»™&fv†n¸ÿ@@`emH”p€Rb@"2äôÖİ¢€Rbr$4DöÒâÀ’¢²dt„¸ÿÀ@ <@H;¸ÿ€@95:H¤´dt„0@P$ÐऴÄp€”¤ä¸ÿÀ@H€Tdt@ H¸ÿ€@ $'H”¤¸ÿ€@!HD0 Ðà¸ÿÀ@+ H @ÿ@H€/?ï/]2íÝ+]qí3//Ì]+]q_qq+q++]]+]qqqrrrrr+_^]+]]]]]qqqqqqqqqrrrrrr+^]]]]]]]q+qq+qrrrrrr^]+]qqqq+qrrr^]++]q10++".#"#>3232673ì*TNG76 [-J;,TNE67\+J±%-%>9-_N2%-%?8,_N3±ä o@R¤ f šªb¢bšª Ÿß@?O¯¿Ï@)H@H•€/?ï/]2í2/++]ÍÜ^]qÍ10]]]]]]53353ÙÏþ¶ýÙÏþ¶±þêþêÍÂá@@+ H) *+@€„”p @`/]_]]Í/Í]10_]]+53ÍEÏÉÂ!$%þà°‹A S@5 H *//À Ð  À Ð    À?/]]33/Íí2/Í]/Í]9/qÍ]10]+53%53!53úE»µþØ–B–°!p%þ”¬¬¬¬ÿÿRƒ&$Tÿlÿ|^³¸ÿ µ%¸ÿÀ³$$H¸ÿÀ³H¸ÿÀ³H¸ÿÀ³H¸ÿÀ³H¸ÿÀ³H¸ÿÀ@ H@ H?5+++++++++]5»¾~𠳆¸ÿ€@ åéHö¸ÿ€@!ÞáH–¦t„VfD&6Ó¸ÿ€@ÏÒHÆÖ´–¦t„¸ÿÀ@$ÃÇHÖæö”¤´v†Td¸ÿÀ@"®µH¤´ÄFVv†–4&¡¸ÿÀ³ H¸ÿÀ@%˜›Hdt6FV$ôÖæ²Â¸ÿ€@‡ŠHVf$4DÔäô¸ÿÀ@w|HRb 0@p¸ÿ€@ goHDT¸ÿÀ³cfH¸ÿ€³\_H¸ÿÀ³W[H¸ÿ€@QVH$4Dä°ÀиÿÀ@CFH0$<¸ÿÀ@ 8;H»€¸ÿÀ@)-0H Ðà¤´Ä 0🯸ÿÀµ H›/í+]]]q_qqqr+rr+^]]]+]]q++++r+^]]_]+]qqq+qqqrrrr++^]]]]]+qqqqqr+rrrr+^]]]]]]+]q+/í1053»Ã¾ÜÜÿÿÿõîƒ'(ðTÿ(ÿ|1@ ¸ÿq@%п//]]]]5+]]5?5ÿÿÿò ƒ'+íTÿ%ÿ|_¹ÿÀ³H¸ÿÀ³H¸ÿÀ³H¸ÿÀ³H¸ÿÀ@ H¸ÿq@%Ï¿o/]]]]5+]]5?5+++++ÿÿÿèUƒ',ÙTÿÿ|\¹ ÿÀ³H ¸ÿÀ@ H @ H @ H¸ÿf@%€o_O//]]]]]]]5+]]5?5++++ÿÿÿ»ÿìÓ–&2üTþîÿ|'@ *À((¸ÿ^@ (( %/]55+]]5?5ÿÿA«ƒ'<‚Tÿtÿ|À@@ééH@ååH@ããH@ââH¸ÿÀ³ààH¸ÿÀ@ÞÞH@ÜÜH@ÛÛH@ØØH¸ÿÀ³××H¸ÿÀ@ÓÓH@ÏÏH@ÎÎH@ÍÍH¸ÿÀ³ÌÌH¸ÿÀ@ÊÊH@ÇÇH@ººH@¸¸H¸ÿÀ³··H¸ÿÀ@¶¶H@³³H@±±H¸ÿÀ@¬¬H@¦¦H@¤¤H@££H¸ÿÀ@¡¡H@œœH€™™H@˜˜H@——H¸ÿÀ³••H¸ÿ€³””H¸ÿ€³““H¸ÿÀ³’’H¸ÿ€³‘‘H¸ÿÀ³H¸ÿ€³H¸ÿ€³ŒŒH¸ÿÀ³‹‹H¸ÿ€³ŠŠH¸ÿÀ³‰‰H¸ÿÀ³ˆˆH¸ÿÀ³‡‡H¸ÿ€³††H¸ÿÀ³……H¸ÿ€³ƒƒH¸ÿÀ³‚‚H¸ÿ³H¸ÿ³€€H¸þÀ³H¸ÿ³~~H¸ÿ³}}H¸ÿ@³||H¸ÿ@³{{H¸ÿ@³zzH¸ÿ³yyH¸þÀ³xxH¸ÿ³wwH¸ÿ³vvH¸ÿ@³uuH¸ÿ³ttH¸ÿ@³ssH¸ÿ³rrH¸ÿ@³qqH¸ÿ@³ppH¸ÿ@³ooH¸ÿ€³nnH¸ÿ@³mmH¸ÿ€³llH¸ÿ³kkH¸ÿ@³jjH¸ÿ³iiH¸ÿ@³hhH¸ÿ@³ggH¸ÿ@³ffH¸ÿ€³eeH¸ÿ@³ddH¸ÿ@³ccH¸ÿ³bbH¸ÿ@³aaH¸ÿ@³``H¸ÿ@³__H¸ÿ@³^^H¸ÿ@³]]H¸ÿ€³\\H¸ÿ@³[[H¸ÿ€³ZZH¸ÿ@³YYH¸ÿ€³XXH¸ÿ@³WWH¸ÿ@³VVH¸ÿ@³UUH¸ÿ@³TTH¸ÿ@³SSH¸ÿ€³RRH¸ÿÀ³QQH¸ÿ€³PPH¸ÿ€³OOH¸ÿ@³NNH¸ÿ@³MMH¸ÿ@³LLH¸ÿ€³KKH¸ÿ€³JJH¸ÿ€³IIH¸ÿ@³HHH¸ÿ€³GGH¸ÿÀ³FFH¸ÿ€³EEH¸ÿÀ³DDH¸ÿÀ³CCH¸ÿ€³BBH¸ÿ@³AAH¸ÿ€³@@H¸ÿ€³??H¸ÿ€³>>H¸ÿÀ³==H¸ÿÀ³<@::55%Ÿ_߯Ÿ]]]]qqq5+]]5?5+ÿÿÿ°A&†U“<@ @ããH@ââH¸ÿÀ³ßßH¸ÿÀ³ÜÜH¸ÿÀ@ÛÛH@ÕÕH@ÔÔH@ÓÓH¸ÿÀ³ÏÏH¸ÿÀ³ÎÎH¸ÿÀ@ÍÍH@ÈÈH@ÇÇH@ÆÆH¸ÿÀ@ÀÀH@¶¶H@±±H¸ÿÀ³¯¯H¸ÿÀ@®®H@¨¨H@§§H@¤¤H¸ÿÀ³¡¡H¸ÿÀ@  H@››H@ššH@™™H¸ÿÀ³˜˜H¸ÿÀ@——H@H@„„H@ƒƒH¸ÿÀ@ H@wwH¸ÿÀ@ssH@nnH@mmH¸ÿÀ@jjH@eeH@ddH@``H¸ÿÀ³^^H¸ÿÀ@]]H@WWH@VVH@UUH¸ÿÀ³TTH¸ÿÀ@ OOH@JJH¸ÿÀ@==H@88H@77H@66H@33H¸ÿÀ³22H¸ÿÀ³11H¸ÿÀ@00H@**H@))H@((H¸ÿÀ³$$H¸ÿÀ³##H¸ÿÀ@""H@H@H@H¸ÿÀ³H¸ÿÀ³H¸ÿÀ@H@ H@H¸ÿÀ@ H&¸ÿÜ´ %+555+555++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ÿÿR$ÿÿ¨ê%¨/‚8@(Z@0P @`€ _??í/^]q/]í10!#/ý8¿‚œû=°@jzŠeu…YV H¸ÿè@@ H„Ffv‹Iiy _¯ÏßÿO0€¸ÿÀ@H0/_ H™  ?3]+?í2]]/+]3/]]]]qqq39=/3310]]]]++]]]]1073!%.'>Ùþû#þ®þ­ôû œ^(RE01FR(ü¤ÿÿ¨þ(ÿÿA£=ÿÿ¨ +aÿì×–'+³@‚i fYV VZU *+ %%Z%!!U! +*[;Ïïïÿ°o0 @P [¯ ¿     +_((#_#_€- -]]?í?í9/í/]]]í/^]qqqqqrr^]í9910^]]]]]]]]]]]#"$&546$324.#"32>%!!×_´þü¥®þú®X\²©¨±\ÃA¼{~¾?A½{„¿{;üâKýµÇ¥þòÀhmà Ÿ¥ »ef¼þö£ДPP”ÐÓ™UV™ÔРÿÿ½|,ÿÿ¨?. N‚Ê@ t„{‹ ¸ÿè¶H6  ¸ÿð@ H HH9o0/%5æö*: éù % 5  æ ö  ¯¿*: éù 0o0v†?2?3]/]]q2]qq/]3]qq9=/3]qq3]qq]]]]10]+++]+]]%#.'&'#3NÉþ|   þzÉ?Æà/Y#)%')#Y-ü ÿÿ¨0ÿÿ¨ 1ZÙ K@1R _¯¿0 @p  _ __?í?í9/í/]q3/]q39910q!!!5!5}9ûÇ\ûäü·œû·œœ…ššÿÿaÿì×–2¨ O@(Z@Z@o¿ €    ° À  ¸ÿÀ@ H_?2?í+]qÌ/]í/^]í10!!#!aý¿xàû úÿÿ¨ê3l¡ ¼@‡©i t „ ¤ ”¤Wg‘Td’ ¢ t „ F V f 9¹ùg¨gd'¯Ð   0 P ` €  F  ¯¿ _  _?í2?9í2/]]]33/3qq/^]]99//]qq3qqqqr10]]]]]]]]q]35 5!!!lý÷çüðÊþm¢Cû¡œþC|ýðœÿÿ.´7ÿÿ-)<uÿõî‹(3´¹ÿð³ H¸ÿð³ H¸ÿð³ H¸ÿð@H H)Z {«Zt¤#Z/$Dt¤ô5D55„5¤5Ä5ô5p5`55¸ÿÀ@ H#.`  "1`  ??99//3í23í2+]_]]qq/]q33ý22Ü]íÜ]í10+++++#5#".54>;53324&+32>%;#"î@ƒÅ…S¹S…Ń@C…ɇH¹G‡Ê…CÀ¹·08\ˆY+ü+Yˆ\84¶¶ài¼TããT¼iq¹ƒH¶¶Hƒ¹u»´ý5bŒXXŒb5ê´ÿÿ.+;‘#Ë@ZjUeZjZjJE Zd„”#Z Zk‹›Ûd„Û4Dd„”´Ä%$%4%D%„%Ä%Ô%ä%ô% %„%”%`%p%T%@%%¸ÿÀ@ H"`ï??339/]3í2+_]]]]]]q/^]]qq3Ü]qíý2Ü]qí10_]]]]]]!#".53;332>53+ûS…ɆC¿/]‹\8¹8_Œ[-¿D†É„S«T޽hÏþ-P‰d9Iü·9d‰PÓþ1h½ŽTþUW£–9á@[e$e111 H    Ht„66v68v8t7„767** )50( `(p((oŸ(("[P55¸ÿÀ@EH¿5Ï5055[Oà_Ïß oŸ 0_; '0*_)_?í?3í2]/^]]]qqrýÄ/]]+rí99//]]33Ä10]]]]]]]]+]]+]]]]267>;!5>54.#"!532.54>ý—ñ¨Z;mc*'!Gôý³`‹Y*=t©lmªt=*Y‹`ý³ôG!'*cm;Z¨ñ–V¢ê“j¿§Š6œà3~ŸUtµ|AA|µtUŸ~3àœ6Ч¿j“ê¢Vÿÿ4²&,žÚ@ &%+55+55-)² r@  H¸ÿè@ÿ H … …@ i©6FZ&V–væ9I™©ÉV 9Y‰ùÊùæ ¹ÉÆYy©6)9¹é ™ùÆÖ²¤–‚tVfB$4ôæÄÔ¦¶’„vbT6F$òÐàÄ °”pd@$4i@ÊäôФ´Ä€tP`D ôàÄÔ°Tdt”¤0@$Äô$DTt„9à„¤Ôp$4TdäôÀ´4T„Ô令p0`/ ‘ _  @ H ;K{??39]3/+]3í2]]_]]]]qqqqqrrrr^]]]qqqqqqqqrrrrrrrrr^]]]]]]]]]_]qqqqqqqqqqqqqrrrrrrrrrrrr^]]qqqrrr^]]qqq/^]]]qý9Î^]]2+Mæ2/íÜí10+_^]]+]]#3 3%53!53 ¾ýàͲ°Íýù£ýÓ¥Hý¸H9ýaŸy¸¸¸¸ÿÿVÿìe&~T!@ <&73#.'32>7.#"KAWoFÍÁÙÑEpV? ¼.'$·  ýÄ;]B6dR= -GfFB`@í8^E&'E]68?A/€‹‹:g¯n'BA:1p g04k lVšsD.f£ŽþWIÌ >¹@D•š{‹z<Š<jzŠfvJ2Z2j2%eu…“%0H400@0`00¸ÿÀ@:H0404H@0+@+ + +°+À++@€! F00P11&9P !&P ?3í2??í9/í9/^]í2Ü]qí99//+]qí910]]]]]]]]]]#"&'##463232>54.#5>54.#"I5o­xf 8´äâc˜f5#=Q.9r[8üùGQW+HnI&&Q€Yq9W73#>7Àõï¿þz¿0:ý]?C?>C?¥ûû-o|„AƒÕ[VÿìÌ2œ@Qsƒjv.†.j.ZjZjU e r‚&€r3C22G@.//)4€ G))/P¸ÿà@HHoZ.0P$?í?99]]++í2/]íÌ]q9/993í2/10]]]]]]]]]]]]4.'32>".'#".54>75!`1ELI†f<#IoMQpEþÿ *-) <6fO1@{´sr´}BI©`þÁÝ×U‘sVQr’[Lƒ`76_ƒ¿þ¼7t†Ÿan¶ƒHD·sp°‡a!Sw„FÿìjN9³@1Œ%…5$E$7"*% H **F000##@%0H¸ÿÀ³H¸ÿÀ@B H;5G?O_@%+H€;;_;0P//O/_/¯/ß/ï/¿/Ï///'P$ P ?3í?3í9/]qí9]q/+]íÆ+++2/99//9í10]+]]]]]]%2>7#".54>75.54>32.#"3"È6`O?i Tj‚N`\-*H`63U="2_ˆWv¿C€/}K[`7aƒKH‹mB4Jr08d'G5 .TtE:_E*(@V3>jM,VcXGDUJ9F% ‡ (PE-E.VþŸ`Ì8Ñ@u©&œ¬•7¥7­'|'Œ'œ'usd$„$”$¤$‹›«9,œ¬,<Ld6„6¤6&6V6ð///G!(22 O¿@!H @2/P¸ÿð@H‡—Ú!©!¹!É!ˆ!˜!!0/?9]]]]+3í2/^]+]qÍ2/3/í9/q10]]]]]]]]]]]]]]'>54.'.54>75#!5!+Jd96oZ: ~  $B^9*YRI61Uq‡@ "$" þ§‚>ƒ{lQ/{@O1"9XD"D>38 !&'"-! $2JdCS°°¯¦›DƒF¦¬«¦jþXîN#d¹ ÿè@. H#F@PŸÿ%€ FÀ   0 à ð  ð%ÿ%p%%¸ÿÀ@H#P ???í2?+]]q/^]qí2Ü]qí10+4.#"#4&'33>3294U?@gI(´ª  >RjFZ‚T'þXVOjA-U}QýSDy*01//L5,\‘dû‡jÿì Ë%Â@l™©–¦Š…Š… |$Œ$sƒUe|ŒJZjsƒEUe     !G@ïÿ@-0H'€ G ¸ÿÀ·#H0''¸ÿÀ@#Hß'P P P?í?í9/í]+q/+]í2Ü+qí310^]]]]]]]]]]]]]]]]]#".5322>7!"!. ðäl«v>éèy¯p6þ*>dI*ýÝ,G^B>cH*#(EaÝþƒþŒ\ºÀuy]¼þçüØ4€Ø¤¤×4Ù3~Ô¡¡Ô~3‰:  @Ò FÏß Ð _o àðo ÍÏßï`Ï@P¯ßï`pšÿÐà?Ÿ¯pß?OjŸßï`pïÿ€Ð?`7Ïÿ °/?°ÀÐo à???^]]]qqrrr^]]qqqrrr^]]]]qqrrr^]]]qqrr^]]]qq9/^]qí2103.53Ç´ 5@F!Nü© @<4Š: ž@r” ¤ f v † ¬‹›iyV – ¦ — § T F† ÷       @   à  F0ð€ À à ?  ?2?39]]/^]í2/^]q839/893q310]]]]]]]]]!#33 0þ’„´´ÛÓþIÎîmþ:ýó þ/ý—îÌ!<@e•Љ‰™Œœsƒ“Œœjz’ „ e u fv–~lT”eu…V’€T¸ÿà@; H’Tdt]m•I–Šeu&V*:JzŠ  !¸ÿð@E!??_Ÿ¿ßÿßÿÀ_Ÿ@#0#`# #°# !P ?í?399]/^]]]]qr83/839/9910]]]]]]]]]]+]]]_]]]]]_]]_]]_]]]]]]]]]]]]'.#"'>32#.'#Ï$*-9( #H 7WIC$«¾Ïþÿ»ÅcIiC‚ $Qƒ_û‹A8;8<>7ýÁŠþw:)l@7 (HZj#F"_"Ÿ"¯"ÿ""" ""+F0ð`+€++¸ÿÀ@H)"P ?3í2/?3?+]/^]í2Ü^]]q2í10]+!.5##"&'##332>53^8EV9Rx ¶¶;bJCdC!µ.;;3O5@: ?þ‹Ãý|EtU/4[~Kiü¯"LC1²:#@O‚’¢™©ƒ“£Wgw H F@[ k { [ Û ë ´ Ä   ; [ k  €¸ÿð@ÿ  K[‹›ËÛÿÄÔ „”`DT ÇàÄÔ DT„”DT„”ÄÔÛÄ›„[D— K[‹›ËÛ›ËÛ„`DT àÄÔ „”`DTgDT„”ÄÔÛÄ›„[DÛÄ K[‹›@]7K[‹›ËÛ? àÄÔ „”`DT ÄÔ „”`P/ ?3?3^]]]_]]]]qqqqqqqqrrrr^]]]qqqqqqqqr^]]]]]]qqqqqqr^]]]]]]]]qqqrrrr^]]]]]]]]qr/83Ü^]]qrí239=/+3310]_]]]#3654&'3²?jŒMªþz½7Ž|±NcÚÝÖ^:ü`¹VœQw--qVþŸjÌJ@}zGŠGe!u!…!i'U2S,9nB~BŽBB*B , ( H II,IlI|IŒI _%O%p%€%%_o%4?F   ???O?o???¯?¿?Ï? Ÿ?¯?ÿ??¸ÿÀ@ H?*G%P *¸ÿð@ H—*H˜4*9 $$$9P?í22/9/]9]+]+99í9/]í/+]q99//]íÍ22/]r3/]qr910]+]]]]]]]]]4>75.54>75+5!'>54.'.V3n¯}DvW32Oa/ DPLJzMpD@]@( ƒ} ";ZC?Q1ƒ 6YT@O1"9XD"D>38 !&'"-! $2JdÿÿVÿìNROÿì+:0s@#5 u … (H(H.P ` . #F@oP¸ÿÀ@& H2€2/2 HO_oÏ"P(P?í??í22/22]í2]Ü+]qí22]/10++]".5!#>="5>3!#32>7f;R4þn$¼' 'OE5 +36%ê #E;^BÔHƒûäÃJLÅâ÷}P ‹ ƒýS,8  „þW;O/@@zeujzj-z-K[k}kJZG@ 1€&Fß0011¸ÿÀ@#Hß1`1€1 P+P?í??í]]+q/^]qí2Ü]í10]]]]]]]]#".'##4>324.#"32>;?s¡b>bPB´54.'.54>32.F6XC1  L|\5r_= ~  #Da?Bq^H2.Kn”aDcI6t*19Á1Phlj*D`H9%;YD"D>38 !&',$(3D]zQ/‚ŒˆlB",w$VÿìÑ:/„@^… z Š ƒ.e.u.d*t*„*|!Œ!Z!j!&l&|&J&Z&oG@¿ @1€(G  #P+P?í?í2/]íÜ]qíÄ^]10]]]]]]]]]]#".54>3!#".'4.'#"32>0={·{{º|?V™Õ~9¥ #+,7+½"-YSk=—“NuL&ëp¼‡LJ‹ÊÒŠBƒ*csƒNJ„tc*2i nÏÎ4a‹ÿì:#c@2# ƒ  H - F" """$%O%Ð%Ÿ%%%¸ÿÀ@ HP#P ?í2?í+]]]q9/]ýÌ]33/10]+]"5>3!!32>7#".5'OE5 +36DþÐ #E+;R4· ‹ ƒýS,8  ;^BÔ…ÿìþ:q@>†…•jzV)G@/Ÿ !€ F  0 ð  ð!ÿ!p!!¸ÿÀ@ H! P?í?3]+]]q/^]íÜ]qrí210]]]]]#".5332>54.'3þ5q°{m h3µu†IhA!(¼( ;‰ÚšR2k¦t—ýc’”2lªxD“‹x)(q†•UþWÚR#-‚@e"e!u!…!JZEU-¸ÿÀ³ H¸ÿà@6 H @PG $Gà+H@@/P'P+P??3í2?í3/íq/]3ý2ÜqíÜí2/]10]++]]]]#.54>746324&#">ÚJ„¸nªrµ}C1gŸmE`<“—šžT…\1½WPDL¢•5—׌Gþi—HŠÏf¼–gˆMrPÕÉDÁÔLÇyÁÓŒý¹ÚþXP@3©™Šš®{‹›T­Œœ{Zj)9 H¸ÿð@c H¢ƒ“tEUe&6¦™'7GeuV'7;[{›»ÛÛûD ¸ÿð·$ ¸ÿÐ@)HF5‹}K[k? P?3?í?9]]_]]]]+]]/833//^]]q833/3910]]]_]]]]]]]]++]]]]]]]]]]]%#.#"'>323 #þ³¼¸ª,(* "> 0F<;$Ž»þ–¾ïýi9W6R7ƒ >fKþÙýGüׇþW,<€@Zy Hy‰™y   Hy ‰ ™ FFH Ð€!°!à!o! !ÿ!P!€!!À!P ??3í2?33/]]qqq/^]3ý2ÜíÜí10]+]]+]%>53#.533.W|P%¶;|Á†ª†À|;µ&O|WªwIy[†ý|z¬n5þk•5n¬z„ýzZyI ÅSÿìëO?°@S™!©!™©wz:Š: %%*%š%ª% *šªI==(. . 3G@€°A€3G?((A0AðAA¸ÿÀ@ #H¯AßAA A@A#>>8P#. P-?3í2?3í29/9]]+]qr/]íÜ^]]í99//9/í910]]]]]]32>54.'7#".'##".54>732>=3srfAW5=aCmŸg15e”_DhM44MiC_”e51gŸmD`>4VA3R9¦Á­8f‘ZR–yT‹p¡Âe€È‰H$Dc@@cD$H‰È€e¡p‹Ty–RZ‘f8-T{NüÿÿÿÍú{&†i ¶&¸ÿÙ´ %+55+55ÿÿ…ÿìþ{&’iò¶ &¸ÿô´$" %+55+55ÿÿVÿì&RT)@ #&F#&%+5+5ÿÿ…ÿìþ&’Tü@  & # %+5+5ÿÿSÿìë&–Tÿ@ @&7@C(%+5+5ÿÿ¨þ²&(žy™¹ÿÀ³ééH¸ÿÀ³ææH¸ÿÀ³ããH¸ÿÀ³ààH¸ÿÀ³ÝÝH¸ÿÀ³ÚÚH¸ÿÀ³××H¸ÿÀ³ÔÔH¸ÿÀ³ÑÑH¸ÿÀ³ÎÎH¸ÿÀ³ËËH¸ÿÀ³ÈÈH¸ÿÀ³ÅÅH¸ÿÀ@ H &¸ÿê´ %+55+55++++++++++++++.ÿìO-…@ ›«e%u%…%¸ÿà@G H H* : $4 *'Z-¯((( Z°à*_+&!_(+(_??3/]í??9/3í2í2/^]í/]]Ìý2Ì9/10]]++]]>32#".'7326=4&#"#!5!Ð!m‚5âÙ)V…\5XK@o)08!TP3{xi!¾þ†åþ  »¼Ö]‘d5 .{!eoÛwz ý 圜ÿÿ¨/ð&a›q@ &! %+5+5hÿìy–*Ú@œœ¬œ¬œ'¬'Š'œ)¬)Š)‰u u ¥ ¦I‰F † % 5 *:D,[t„ËÛD+%ëdt¤Ô@0_¯ "O&&&_" _ 0@p€ÀÐ?3/]qí?í3/]9/qí/^]_]]q3/]]]qí29/]10_]]]]]]]]]]]]]]"!!32>7#"$&546$32.o­|I Žýr M€°mZlOœ(l”¿{«þÿ­V[¯¤á.GµDf‰úD~²nšp¹„H2Ri7MOˆd9mà Ÿ¥ »e°­<2[F*ÿÿ]ÿìø–6ÿÿ½|,ÿÿ4²&,žÚ@ &%+55+55ÿÿ ÿìh-ÿð &/×@b9¦§ ¢ … • : šª ­ y t/„/”/{(‹(›(e ­ H+{‹›*zZ0'''' $ 4  ¸ÿø@HI$4¸ÿø@'H I ¯¿!,Z+_!!__,_?í?í?í9/í/í2/]3q+qq+q/^]qí10]]+]]]]]]]]]]]]]#!!#"&'532>7!!24&#!!26 =y¶yý·þ`1+1À¤¤þ™o¤œW–p@áþ¬þõljU%˜>k©î¡þý¬:i“\yþˆ¨«n@t„”{‹›&6Z°¸ÿÀ@+ H Z  @  Z__   _?í??39/í3/í/^]3í2/^]í2/+]í10]]]#!!#3!3!24&#!!26«=y¶yýßý¿¿>¿V}º|>À¤¤þÁG¤œW–p@ýsý¬Tý¬:i“\yþˆ./ƒ@ ›«eu…¸ÿà@L H%5E Z¯  0  Z0ÀаÀаðÿp ° _ _ ?2?í29/3í2]]qr/^]í/]]ÌýÌ310]+]]!4&#"#!5!!>32q€…5tnb#¾þ³ýï$bpv8åÖ?zm ý 圜þ  »²ý­ÿÿ¨ð&´›¬@ &% %+5+5ÿÿ7ÿì:&½—^J@ &'%+5+5¨þh ^@@ \ Z0@ŸÏ@Z@  € à   _/?í3?3/]]q/^]í/]]qqí9/í10!3!3!†þ"¿÷ºþ"þh˜ûáúþhÿÿR$¨ÖŽ@Ft„”{‹›™& ZßP€ÿÀŸ @ Z@0¸ÿÀ@#Hß_@   Ð   __?í?í9/]qí]+q/^]í2/]]]]qqqí2/10]]]]#!!!!24&#!!26Ö=y¶yý·žý!~}º|>À¤¤þ™o¤œW–p@œþH:i“\yþˆÿÿ¨ê%ÿÿ¨/‚aþhEÂ@_– ––†sƒ“€rfU e Zja‘S5E\Z¿Ï _Ÿ$4¸ÿø@ H$4¸ÿø@H \/__/3?í22?í]/í3+q+q/^]]]]í2/í10]]]]]]]]_]_]]]]]]%3#!#3>7!!–¯´ü2´)B7,CÔºþ‰1(.6  ýȘþh83еäþûAþ†Ý²‰3ÿÿ¨þ(G)H@)…u…ucl|Œl|Œe u … !(H¸ÿØ@#H:J)5Eu'0H(8H ¸ÿÐ@ H' 7 G ¸ÿà³H¸ÿð@I H H H" (Z) ) 4)t)Ä)ä))!  @ Hä › « D t  +  ¸ÿð@3«»D+t+„+ä+/++"'`¯/ )!?33?339/]q3í29933]_]]/]83/]]]]+83/]q39/933í29/93310++++]+]+]_]]]++]]]]]]]".'#&'3332>73###R-0.þUÞý0ƒþåÈÍBZLQ9¿9QLZBÍÈþåƒ0ýÞþU.0-¿… ýU#½šþÏc{Dký•D{c1þf½#üù« ý{Cÿìp•<@3Š!†|Œpp`eu…„"e"u"| Z j ;K!¸ÿè@z H+3Z.@%H..8Z‹$›$«$_o$$pOoÿ 0¯¿@ -H@ H3_¯ )#@ H##_) _ 0p€Ð¸ÿÀ¶ H?2/+]qí?í3/+9/qí9/++]/]]]]qq99//]_]qí2/+í910_]+]]]]]]]_]]_]]]".'732>54&+532654.#"'>32mv°‚^$¥B[yPMzU-ÀÊGGµ­'HhAMrS8²!`„¨il¬x@(Ih?CuW3E„À2[€OM7bK,%Ed@…v”w{7V;(DZ1=RW-5`ˆSDkP7 2RsI_œq>¨{@¬Šš“£…¸ÿè@A H  H \)  @ P à  Ÿ ¯  0  ¦\/   ?22/?33/]/^]í2q/]]]q3qí10++]]]]333#46767¨¬îÞªýüd3b'.(®ú¨'Y&,,ûZÿÿ¨:&²—’J@ &! %+5+5¨—@hT t „ T‹zYiŒ H:d t „ P 5 E    ` €  Z    Ï ï /  / `/ ?2?39/]í29]/]q83/]í29/]893310]]]]+]]]]]]32>73###¨¿9QLZBÍÈþåƒ0ýÞþU.0-¿ý•D{c1þf½#üù« ý{ÿð™°@#–“u…U•‘sƒUe‘¸ÿØ@. H%5jzŠZ @à_$4¸ÿø@HI$4¸ÿø@H I €__ ?í?í?]/3q+qq+q/^]]]qí10]]]+]]]]]]]]!#"&'532>7!#ßþ^1+1k©î¡þúÿÿ¨0ÿÿ¨ +ÿÿaÿì×–2ÿÿ¦nþX¹ ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ³H ¸ÿÀ· H @ H++++++++++ÿÿ¨ê3ÿÿhÿìy–&ÿÿ.´77ÿìµ@oÙ‹Zjz)Ue…FÖƒdtVy€„ƒTdFÆÖqVf:J  ?Oo¸ÿð@ _?í2?3/99/8]22/8]39910]]]]]]]]]]]]]]]]]]]]]]#".'732>?3 3Þ/QZmK B@:Q#S0%:59&1ýÃÚÁ€Í>X€R( %4ZDYºüðvÿõŸ‹(3@\FVfIYi;3;5+&+5'&')ZZ#Z.àO  5p5Ð5à5O55$/`  "1`  ??99//3í23í2]]]q/]]]33ý22ÜíÜí10]]]]]]]]+#5#".54>;53324&+32>%;#"Ÿ@ƒÅ…(¿(…Ń@C…ɇ¿‡Ê…CÀ¹· \ˆY+üW+Yˆ\ ¶¶ài¼TããT¼iq¹ƒH¶¶Hƒ¹u»´ý5bŒXXŒb5ê´ÿÿ.+;¨þhÅ J@/\ Z¯@pZ@ à   _/?í2/?3/]/^]í/]]qí2/í10%#!3!3Å´û—¿õº ýȘûáû ®†@F¤( H H*:JZ0@Ïpo@ ZÏ   @   ¸ÿÀ@H_/  ?3/?9/]3í2+]q/^]]í/]]]]qqq3í10]++]#".5332>73#ð$^ks8r¦l4¾‚†5nh\#¾¾ü /\‰YRýÂ{l ôú¨­ r@LZ Z$ äÛ”{dZDäë Ä » „ p @   _?í2/?33]]_]]]]]/^]í/]]]]]qqí9/í1033!3!3¨¿éºéºûáûáú¨þh/}@T„”´{T\Z Z ; K [ { ‹ › Ë Û û Ï Ÿ € o   Z   _/?í2/2/?33/]í/^]]]]_]]q9/íí2/í]]]10%#!3!3!3/´ú-¿ÓºÒº ýȘûáûáû.ëd@Dt„”{‹›™&@Z/°Ÿ @Z  _ __ ?í?í9/í/]ý2Ì/^]]]qí]10]]]]!2#!!5!4&#!!26¸B}º|>=y¶yýóþ5Šs¤¤þÕ3¤œ-:i“ZW–p@åœüyþˆ¨mŒ@Lt„”{‹›™ & ZŸÏß@PpZàŸ @ Z@€¸ÿÀ@ H_ _?í3/?3/9/í+]/^]í2/]]]qí/]]í10]]]]#!3!24&#!!263Ö=y¶yý·¿~}º|>À¤¤þ™o¤œ˜¿W–p@ý¬:i“\yþˆþáú¨Ök@Lt„”{‹›™ & Z °Ÿ @` Z¯@€_ _?í?9/í]]/^]í2/]]]qí10]]]]#!3!24&#!!26Ö=y¶yý·¿~}º|>À¤¤þ™o¥›W–p@ý¬:i“`yƒþƒiÿìy–*Î@Qsƒsƒesƒesƒee e ‡jZ!Š!  Z  (($$&[ #p##°##@##¸ÿÀ@? H#P`¯¿ #_&¯&&& _ 0@p€ÀÐO_ ?í3/]?3/]qí9/qí/]]q3/+]]]qí39/10]]]]]]]]]]]]]]"'6$32#".'732>7!5!.ÉX‰fEµG.᤯[V¬þÿ«v½•q)œQmŒWm°€M ýrŽ I|­ú*F[2<­°e»þö¥ŸþôÃm6cˆSN7iS2H„¹pšn²~D¨ÿì³–.¨@?¥…Šyv#v'JŠ:z5"u"*,:,z,%(5(u( 0[  °¸ÿÀ@6 H Z  @  %[0 p  _ _P°à  *_?í??9/^]]qí?í/]3í/^]í2/+]qí]10]]]]]]]]]]]#".'!#3!>324.#"32>³Zªõ›œï¥ZþÙ¿¿* c¦è’Ÿõ§WÃ3!#!3!!"`[‚T'B~¹x—¿þIþ’%MwSÍþ;LxT,_Nl‚C^–h7úIý·ì9bH)?^ÿÿWÿìsNDxÿì?Þ8ž@E‰,z-Š-fv†TT [Z#z#Š#Z/j/Š/{.‹.I.i.**G@Ð:€0:€::¸ÿÀ@ #H4 G ¸ÿÀ@#H4P*0)@)ð))P?í/]q39/í2/+]í9+]qÜ]qí2/10]]]]]]]]]]4.#"32>2#".54>7>7>‚'IhAErQ,,Mi>EpN*óÞÒúîq²{A:€Î“9d[V+V¡[N|^C,Ca~ör—[%'\–pr–Y$$X—þûþúþ÷þýFœú´ÀÁs  ¡ !2Il•e7aH)Žç:$/•@ *%*¸ÿè@! H‹ ›  &,GG@/Ÿ 1€@11¸ÿÀ@2#H1?1ï1&FÀ0àð $Q&Ÿ&¯&&&%PP?í?í9/qí9/^]qí2]+qÜ]qí9/í9]10+]]]2#!32>54.+32>54&#4LpD#hQ5Q:% #=Z=NuN':üK,C/2F,ÂþÀ'=+RLޝ:6@#@'H0FÀ0àðP??í/^]qí3/]+10!#¯þ“´:ƒüI:þhˆ:Ÿ@A† f"r‚""‰"yfv""b$DTI ¸ÿÀ@*H F@o @€ I PP  /3?í22?í/33í33Ü]]í2/+í10]]]]]]]]]]]]]]]]!!#!#3>7!3BþÎ100ñF£üÒ£w::9„’·±þùˆ2ýå˜þh2Ü;ßüIÿÿWÿìNHS:'a@X¥¥«"¤¬š£ • ZjzUeuJ!š!ª!E•¥*:% 5 "ª &F'¥  ' ¸ÿð@1 ''!  ÿ   Ÿ P ?  Ï € _  0  ¸ÿð@@/Ÿ?Ÿßÿ)ÿ) )o)Ÿ)P)?) )Ï)€))O)_)0)"¸ÿð@% H%PO_O '!?33?339/^]q3í299+33]]]]qqqqqqr/]qr83/]]]]qqqqqqr839/39/8933]í29/893]310]]]]]]]]]]]]]]"&'#.'3332>?3###SAþêÈaB-ؼ”0A40´04A0”¼Ø-BaÈþêA´Ý þPUBEïM\2Úþ&2\Mïþ»BUý°ñ þ#1ÿì^N7¯@55&&%&ƒ--F((3G I@¸ÿÀ@V$H      9€9I@ H-PŸ¯#àðP#P`p€ï ?2/]]qí?í3/]q9/qí9/+í]Ì]]q99//]+íí2/í9q10]]"&'732654.#52>54&#"'>32ʧÅ-Ÿ~g`q7\x@@rV1c]#F<*¢ >a€NUŠb5,GX-8dK+1e˜},NV^[;N-‰&C4JV!7*Db?*Lh?9X=$)C]:EwW1Žê:º@ éùäô ëû¸ÿÀ@k7#<óŬþÀ:ý°MRJeûÆ”9<9ü—:ÿÿŽêð&Ò—ê@ &!%+5+5ŠŠ:Ê@u…•9y‰™ ¸ÿÐ@{ H… • x… • /OI8 y‰™G 6   F0ð9I  O0/ P?O?ÿ?2/?3/9/^]qí2/8]]]]]qr3q/]í29/89qq3]3qq]10]]]+]]32>?3###Š´04A0”¼Ø-BaÈþêA´:þ&2\Mïþ»BUý°ñ þ# ÿì:º@*‚tUe‚u&fr‚dV†¸ÿð@= Ht HF@Àаð@`p °Àƒ6¸ÿð@H×ç€  PP ??í?í/]3]]+3q3]]qrÜ]í10+]]+]]]]]]]]]]]!!#"&'532>7!hþ‰*,3G^A0 &#3(!"&η¸þáØ•]**^•Ø·ûÆŽó:@‰™† – k{d t ¸ÿà@z7!#4>7™þ¼®Ü% #Ü ­·<=9ý,:ýk?—HH—?•ûÆÔ<@<ŽÝ: ‹@0F@O9/oÿ¿Ÿÿ € À Ð à À €  ¸ÿÀ@1H FÀ   0 à ð  P°ÀŸ¯¿? ?2?39/^]qrí/]qí2+]qrÜ]qr^]2í10!3#!#Bç´´þ´:þ6ÊûÆíþ:ÿÿVÿìNRŽÇ:m@PF@O9/oÿ¿Ÿÿ € À Ð à À € ° À Ð / FÀ0àðP?3?í/^]qí]]qrÜ]qr^]í10#!#Ç´þ/´:ûÆ·üI:ÿÿ„þWMSÿÿWÿìÊNF#‡:H@+ßF   _ 0 @ / P?í2?]]]]9/^]íÌ]+Mä10!!#!#dþ¨´þ¨:ƒüI·ÿÿþWü:\VþW>Ì5J_å@ ]]­]NHH¸ÿè³H9¸ÿè¶HmR3¸ÿà@K H/  H 6G@ KG$D”¤U' HA&$Dd„´ä4aa¸ÿÀ@4#HÛaTada„a”a@a a0aaa&-PFP1[;P ??3í2?3í2?]]]_]]]+q/^]q33í22Ü]í+Môí10_^]+]+]+++]#"&'##467##"3234.533>3232>754.#"4.#"32>>&VŒeiž*ª.•oº³¹´p•-ª.reŒV&úÕ8U<<^A""@^=9V9n4X@5\F(#A\54&+ ÍÒ4h›gþgþ¸üÊE`;t…Ëp“ŸJvR,·ƒþ6þ1G.^WŽ2: i¹ÿà³ H¸ÿà@: HG F@Ÿ¯€ F @  Q¯ ¿ Ï   O    Q ?í3?39/^]qí/]í2Ü]í9/í10++2#!332>54&+3&ÍÒ4h›gþg´ÊE`;t…Ë<´p“ŸJvR,:þ6þ1G.^Wþ :ûÆŽ×: „¹ÿà³ H¸ÿà@V HG@°€//¯?_Ÿ¿Ïßÿ@#'H F Ð  @ ð  Q¯ ¿ Ï   O   Q ?í?9/^]qí/]qí2+]qrÜ]í10++2#!332>54&+8ÍÒ4h›gþU´ÜE`;t…Ýp“ŸJvR,:þ6þ1G.^W7ÿì¾N(ª@Wv"vkk  G@    *€FFß@ H P Ÿ ¯  P$ `p€ÀиÿÀ@"H$/ß@ HP?í3/+]?3/+]í9/qí/+qrí3/íÜ]q2í9/]10]]]]]732>7!5!.#"'>32#".7¶…dIgD"þc"CgImv¹ Bi‘]Zª†Q3r¶‚c—j=; lh5a‡RƒZ…X,i[DtT05€Ø£xÍ—V6\zŽÿìªN'€@Uy%‰%t!„!v†y‰–¦G G@ )€ FÀ   0 à ð  P P/  #P?í??9/]í?í/^]qí2Ü]í9/^]3í10]]]]]#".'##33!24.#"32>ªëßf¡sAÞ´´ß!¤í×½#Ca=?cF%'F^8>dF&þäþê>€Àƒþ:þ6Þþèþè~¤b')c¤{~¥b('b¦Ç: @Du… H (+Hßï %H4+)0 H  HG  F@¯ ï  €¸ÿð@[kQ/Q  ?3?í9/]í2/]83Ü]qí39/93í10++]]q+q++] #.5463!##";þÅËXƒvØÏ°´ê‚xk|ýÊþ6×£z•–ûÆÊñ\]^]ÿÿWÿì{&Hiø@ &&*(%+55+55 þWîÌ9¢@ ª1 H¸ÿè@V H$$9F@P-Ÿ--;€ 9FÀ0àð°;À;Ð;°;ð;ÿ;p; ;°;9(P!3P Q¸ÿÀ¶ H??+9/3í2í2?í?]]qr/^]q33í22Ü]qí9/10^]++]3#5353!!3>32#"&'532>54.#"Ž„„´,þÔFTd>h…M6]H"A $ &1 0XF@gI(¶ƒ““ƒ”!B8'7M28eŒTüÑ>jN-‹+C.ñEhE#.TxKýªÿÿŽÈä&ÍtØ@ &U %+5+5WÿìÞN(«@qtt‰‰/*?$F#F$ $$@$`$€$ $À$à$$GPŸ¯ P /ß@ H  P## #`#p#€#À#Ð##¸ÿÀ¶"H##?2/+]í?3/+]í9/qí/]í2/^]qí3/í9/]]10]]]]".54>32.#"!!32674‚¶r3Q†ªZ]‘iB ¹vmIgC"œþc#DgJd…¶ =j—V—Íx£Ø€50TtD[i,X…ZƒR‡a5gm Cz\6ÿÿ9ÿì¶KVÿÿ‰=Ì&ñÇOíÔµ @88H ¸ÿÀ@ 77H @66H ¸ÿÀ³55H ¸ÿÀ@ 44H @22H ¸ÿÀ³11H ¸ÿÀ@ 00H @**H ¸ÿÀ³))H ¸ÿÀ@ ((H @&&H ¸ÿÀ³%%H ¸ÿÀ³$$H ¸ÿÀ³##H ¸ÿÀ@""H @H @ H¸ÿÀ³11H¸ÿÀ@ ()H@H¸ÿÀ¶H€¸ÿÀ@ H%+5+]++++55++++++++++++++++++ÿÿÿø%{&ñi˶&¸ÿó´%+55+55ÿÿÿÎþW=ÌM ÿìì:"-*@R£”u…j9Hƒ“£uj 9  H£ W g w  Hm H¢u…•6F¸ÿà³ H¸ÿà@ H"#F@  G°))¸ÿÀ@  H)/P//¸ÿÀ@]#Hÿ/0/m  ? ÿ é » Ë Û £ •  ? ÿ j ) £ 5   -Q¯"¿"Ï"""O""" P P#Q ?í?í?í9/^]qí/3]]qq]q]]]]]qq]]+qÜ+]í9/]í210++]]]+q+]]+qq]]+qq]]]2#!!#"&'532>7!32>54&+MÍÒ4h›gþ>þe*,3G^A0 &#3(!"&òòE`;t…óp“ŸJvR,·¸þáØ•]**^•Ø·þ6þ1G.^WŽ,:…¹ÿà³ H¸ÿà@ HF G@°!€P!!¸ÿÀ@2#Hÿ!F @Q P¯¿ÏOQ ?2?í?9/^]qí3/í/]í2]+qÜ]í9/3í210++32#!!#3!32>54&+©äÍÒ4h›gþfþN´´²µÊE`;t…Ë:þ6“ŸJvR,íþ:þ6ÊüE1G.^W îÌ)¹ÿè@U H! F@P Ÿ ÿ  +€# FÀ0àð°+À+Ð+°+ð+ÿ+p+ +°+#Q  P¸ÿÀ´ H?+í2?3?9/3í2]]qr/^]q33í22Ü]qí910^]+>32#4.#"##5353!!=FTd>h…Mµ0XF@gI(´„„´,þÔY7M28eŒTýW†EhE#.TxKýª¶ƒ““ƒ”!B8'ÿÿŠŠä&Ôt?@ &Q%+5+5ÿÿþWüð&\—·@  & %-%+5+5ŽþhÝ: }@Y I O & F@O9/oÿ¿Ÿÿ €FÀ0àð° À Ð ° ð p   ° À  P/í3?3/]qr/^]qíÜ]qr^]í9/^]í1033!3!#Ž´ç´þª£:üI·ûÆþh˜¨º7@%Z@Fÿ@€°Ð_??3í/^]]í/]í103!#´ý­¿›ýÉû€Ž Ì8@$I0 FÀ0àðP??í?/^]qí3/]í10!#!3!B´Ù£þ8:’ýëÿÿ †ð&:šA´/&¸ÿ¸´03.%+5+5ÿÿÿýÌä&ZCH´+&¸ÿ¢´,/*%+5+5ÿÿ †ð&:›÷@ /&K/2.%+5+5ÿÿÿýÌä&Zt&@ +&]+.*%+5+5ÿÿ †²&:ž†@ /&31.%+55+55ÿÿÿýÌ{&Zi¡@ +&/-*%+55+55ÿÿ-)ð&<š"´ &¸ÿµ´ %+5+5ÿÿþWüä&\Ci´ &¸ÿ§´!$%+5+5[ÐOp°/°ͰͰ/°Ü°Ͱ°Ö015![ôР [ÐOp°/°ͰͰ/°Ü°Ͱ°Ö015![ôР ÃrL+@º?O/?o¯ß@&+H/+]qí//105!rɉÃL+@º?O/?o¯ß@&+H/+]qí//105!ɉÃL+@º?O/?o¯ß@&+H/+]qí//105!ɉÿÿÿáþNŠÿ©&BåB¾¸H /@ H@ H – —¸ÿÀ@  H œ©?ôí/+íí2+10+54>733 y-2Y¸’4VKB A„AøH 4¹ÿà· H —–¸ÿÀ´ H ¸ÿÀ@  H œ© ?äí/+3+ýí10+#>5#53H {-1XÃð5VKB A„?ÅþúHà 3¹ÿà· H —–¸ÿÀ´ H ¸ÿÀ@  H © œ /ýä/+3+ýí10+%#>5#53H {-1XÃ35WKB A„AÃ~¸G /@ H@ H–— ¸ÿÀ@  H ©œ ?íä/+íí2+10+##.=AX1-{ Å?„A BKV5‘K¸_ Y@: H H@ H– @ H – —€— Ÿ¯ œ ©?3ä2/í2]/íÜ^]]íí2+í2+10++54>733!54>733— z-1Xýò y-2Y¸’4VKB A„AÃ’4VKB A„AÃK¸_ k¹ÿà³ H¸ÿà@ H— – —–¸ÿÀ@ H€    ¸ÿÀ@ H?Ÿ¯ œ© ?3ä2/í2]/]3+Ü^]]2+ýíýí10++#>5#53#>5#53_ y-1XÂþµ {-1XÃð5VKB A„AÑ5VKB A„AÃKþú_à h¹ÿà³ H¸ÿà@ H— – —–¸ÿÀ@ H€    ¸ÿÀ@ HŸ¯© œ /3í2/ä2/]/3+Ü^]]2+ýíýí10++%#>5#53#>5#53_ y-1XÂþµ {-1XÃ35WKB A„AÃ5WKB A„AÊÿvêÌ @@% À ¼À/o¯  Á ÂÁÂ/?öíôí/]qí33/í22/í10#53%‰sþ `×aèûŽr¤xþˆ¤ˆÿséÌV@2 ½   ¾½ Á Á ÂÁÂÁÂ?öíôí/öíôí/]3/33í2í2/í21053%%%%#5ñþ˜h¯iþ—hþ˜¯þ—iè¤xþˆ¤þ¶þ¹¤þˆx¤GQ‘|¼I¹ÿè³ H ¸ÿè@' H H H€?¿  0/]Í]]/]Í]]10++++#".54>32|-Lf:9cK++Kc9:fL-ª:fM,,Mf:9dJ++JdêÛ V@=– –0`€ Ðð0@`ÀÐð–/¿ ›/33í22/]]í/^]qí9/í10!53!53!53(Âü·ÀüµÃÛÛÛÛÛÛ7ÿõÈ+?Sg{Ù@ v†y‰f¸ÿà@ H` H\ HV¸ÿà³ H>¸ÿè@ H8 H4 H.¸ÿà³ H¸ÿà@ H H  H¸ÿà@  HJ´;µ1¸ÿð@ƒv y 1´f@&@¶@Æ@Ö@@@r´cµY´ihh&hÉhùh‹hvhYhFh)hhéh–hÆhyhkhVh9hhh&h h´ µ"´ )IYy‰™"@-1H¸ÿÀ@ÿHÙ}Æ}©}›}y}k}]}I};}-} }}û}í}Ù}Ë}½}›}}}}i}[}M}6})} }}Ìé}ù}Ö}»}­}‰}™}{}f}K}=} }Û}û}Í}™}©}k}‹}]}9}+}} }í}ý}¹}É}Ù}{}«}Y} };}K}›ù}ë}Ö}»}™}{}‹}f};}K} }}ö}Ù}Í}©}¹}›}i}y}]}9}I}+}}ù}í}É}@ù»}™}{}f}I}6} }}iù}ë}Ý}©}–}y}k}I};}} }ý}Ù}Ë}©}›}}y}[}k}9}}+}ù}ë}©}É}–}y}k}9}&} }8ù}æ}É}¶}™}‹}Y}F})}}ù}ë}É}»}­}”}{}d}K}?}}}ä}Ë}°} }}p}_}@}}}m¶T·w¶^E¶,·O¶6'¶·¶???íôí?íôí?íôí^]]]]]]]_]]]qqqqqqq_qqqqqrrrrrrrrrr^]]]]]]]]]qqqqqqqqqqrrrrrrrrrrr^]]]]]]]]]]qqqqqqqqqqrrrrrrrrr^]]]]]qqqqqqqqqrrrrrrrrrr^]]]]]]]]]]]]]qqqqqqqqqqq/++^]íôí/^]]]]]]]qqqqqqqrrýôí9/]qí99//^]]8833ôí10++++++++++++_]]!#3%2#".54>4.#"32>2#".54>4.#"32>2#".54>4.#"32>0›šü˜?lP..QnÒ%7#&:''8%"6'?lP..QnÒ%7#&:''8%"6'ý?lP..QnÒ%7#&:''8%"6' !S‹jfŒV&%VŒgj‹S!þ—Ib:;aIGa;;aþï!S‹jfŒV&%VŒgj‹S!þ—Ib:;aIGa;;a°!S‹jfŒV&%VŒgj‹S!þ—Ib:;aIGa;;aUzY(@ H H–/0?Í/]Ý]í10++3U@ÄžzýùÿÿUz¯&V ´`]5XQ¬H@7jzŠjzŠìëìO_0@`p ï/o/]ä/]qííí10]]%53 ¨þ°P§þ±Qm?sþŒþ‘YR¬B@0eu…eu…ììëp€°Ðoï/o/]ä/]]qýíí10]]%#5 53¨Rþ°¦Qotþ?ÿÿ¹G&È@ //]55]55ÿÀßëT ³/Í//10!5!ëüÕ+ßuþ`b-¶o¸ÿð@ï@ H@ H??/++]8/]810!#3þô”q‘eƒ!o¹ÿØ@ H à$  !à$Ôää ‹û¸ÿÀ@& HK[@H@H/?/_]]]++]3/Ì]+]2í2/]í/]í210+4.#"#4.533>32 /#HU€w&1@*naŽ.=%d^þ”ÿ.("# . lyþO.j@E  0Ppà \  Q   _?O? _ ??í9/^]]qíÜ]q2í2/33í22/]q99//10!!!!##53!g¯ýQ’þn´¯¯{æþ$Õþéé›:P–:Ý@Q…:•:%5(,0 o4n+'0n O_o:o  0Pp°Ð0Àà¸ÿÀ@FH*Q. Q+¯  @*-H   'o/_oŸßï4#s)4t%:::?3]]í2?3]í9/]q3Þ]+]2í2í2/+^]qrí/]9/33í22í9/í339910]]#!5>=#535#5354>32.#"!!!!!2>7P 9YsCýFYVºººº0c˜gF{cG® '5A$rp˜þh˜þh,?(ã&C5%7PuM%š. yŒ‚\“f7:V994$s}ŠŒ8j\G*C0žÿìg/bÁ@G†u[…[[IkI‹IDmD[DiRiP}[k}[kT9d969F9%a5aEaL H1¸ÿà@^ H H -RIQQ0HAF'K%)H" 9I8f888YHK_?K_KïKK@'Hï_KK@APA`AAAA¸ÿÀ@ HAF d¸ÿÀ³[_Hd¸ÿÀ³PXHd¸ÿÀ³FJHd¸ÿÀ³;>Hd¸ÿÀ³05Hd¸ÿÀ@ HOd_dodd¸ÿÀ³ HY¸ÿø@GHAHYAN54.'.54632.#"º=y¶y‚µ+}º|>¶¤¤iq¥›{#J0i]ho5n)7(è·ªKy\=ŸcX(D1">W41`M/¨¡¥¡-6› 9P00dR4Ù\ŸuDýÛ=oa†‹ýÔ’üº {zŃòòƒþbNIbx6X@=: () 5O;pwit& U$ 6WÿìV–=è¹ÿë@DIj&:+J+z+Š+$;4;D;t;„;.779-3n%n$$n@`€ °°Ð¸ÿÀ@^H0Q9Q6Ÿ@'/H€-/?/?¯Ï/¯(sØ%|%Œ%%*%%ssƒ% ?3]]í?3]]]í9/]qr3Ü]+q2í2í2/+]qí3/í/3/Äí229/Ä10]]]+%267#".'#73.5467#73>32.#"!!!!³dx¹ ?g“ax±yE «(x (I{­sa“g? ¹yjDjO2 ¾(þcÄ(þl *Mr~d[DvW2M‹Àr.5z½‚C2WvD[d'W‰c/%QŠd9EÿôÐŒ+OÀ@v†y‰…/B¸ÿè@  H< H¸ÿè³ H ¸ÿè@ H H HJ´II4´5²?¸ÿð@>,´?@ H?"´ ²´ P`Ðàð&441¶:¸M¶JD¶¸'¶?íôí???3íôí3]/]ýôí/+í99//88ôí3/í3310++++++]]]#".54>32#34.#"32>3267#".54>32.#"Ð3WtBBsU10VuDBsU2û;›š•+?(*@,+?)'?,ú›/K6E^ -MoH^„R&;a|ADjL0 SKlW²}«i--h«~…®g))g®ýÉü1cƒN !Nƒb_€O""O€|K|Z2RW 6cL-Ey¤`‚­g*(F^7 HU¤ÿì~•'7¹@ Š 5(H¸ÿè³H¸ÿè@CH H H( (`(p(€(À((((333Ÿ##À Ð à  ¸ÿÀ³"&H ¸ÿÀ@ H O93- "-/Í?9/Í9/99Í99]/++]Æ3Í]2^]3/]]qÍ2/310]]+++++]%2673#"&=5>74>324.#">±3DExmo B"#B;bH4O5,OnB *s( '1M6NhmšŸ›¯ IK;lS1*NoEc´˜v&ô9S64U=!$=Q.þ!hƒ—¼.#7;ô@| H=„ r E U e  & !!%!  /=:I$I9.I À$ $°$/$$$ I0@P )¸ÿÀ³$H¸ÿÀ@H 3À9Ð99¸ÿÀ@#,H98 @$H @H 8?3++/Ý+]ÞÍ?33++?Í/]qí22/]]]99//]]í33íí2]10]]]]]]]]]]+]!#3&'.53#"&54>324.#"32>5!&ý0 ÊØ¢6°¯¨±+WƒX]ƒT'Ÿ/E-.G00C).H2þ{¦,,&Y'üXûR(.'b3œú²¼Ëɾ[‘e55d‘\Qk@@kPRl??lý ’’¼z'/”@ Hˆ ¸ÿè@HYiy% H¸ÿð@I H,)Ä*Ä@à@//**@*P**'Ä%o¯Ïßï(,Ê * *P*€**%-?33Ì]2í2/]3í/]Ì]9/]í2ýÌ10++]+]+5#.'&'#367>53##5!›æl£€¾ß ¨¸û(†ÿŠz©Â ýË@&,7 ýÉýÍ 3)"üù˜ýh˜ool¸–9Ý@_e$e111 H    Ht„66v68v8t7„767** )50(  (`(p((/oŸ(("[55¸ÿÀ@AH¿5Ï55055[?O¿ÏßoŸïÿ0 '0*_)_?í?3í2/^]]qýÄ/]]+rí99//]]33Ä10]]]]]]]]+]]+]]]]267>;!5>54.#"!532.54>—ñ¨Z;mc*'!Gôý³`‹Y*=t©lmªt=*Y‹`ý³ôG!'*cm;Z¨ñ–V¢ê“j¿§Š6œà3~ŸUtµ|AA|µtUŸ~3àœ6Ч¿j“ê¢VXÿÞ|H -R@2Z @ !°!_!P!`!p!!/€ /-Ð--' ?2]]Í?Í9/Í/Í]2]Ü]qqÍ210]".54>32!32>7.#"k‚ƆE_˜½_pÂŽQüÅ@NX.Kt]L#H$TmË;M\53WJ<"]Ìo“Õ‹BO’Ò‚þœ-#73!;H:‚RR‚:H;Ý)"bADp*$*pDAb"VÿÃð@ @ €/ÍÌ299/Í105>73.'#Õ"bADp*$*pDAb"V ;H:‚RR‚:H;ü#¢d^D@  €/Í/ÝÌ29910.'3#>7!5;H:‚RR‚:H;ü#"bADp*$*pDAb"VÿÃð@ @ €/ÝÌ299/Í10%>7#.'53+"bADp*$*pDAb"V¢;H:‚RR‚:H;Ý¢d^D$@€@ €/Í/Ì299ÝÌ29910#.'5>73!.'3#>7;H:‚RR‚:H;þ;H:‚RR‚:H;)"bADp*$*pDAb""bADp*$*pDAb"ÿÃð&@@€@ €/Ì299ÝÌ299/Í105>73.'>7#.'5Õ"bADp*$*pDAb""bADp*$*pDAb" ;H:‚RR‚:H;ý;H:‚RR‚:H;ÿHð#(@#  /Ì299ÝÞÍÌ299/3Í210!!5>73.'>7#.'5àþ Å"bADp*$*pDAb""bADp*$*pDAb"hPX;H:‚RR‚:H;ý;H:‚RR‚:H;8ÿåºÅ/EÞ@]œ¬šªz!Š!DHUe•¥ŒJZzJ8Z8C8 H:C* : J %-5-•-¥- '0'''©0ù0(00F@`¸ÿÀ@@H@ HG€323>54&#"7>32.#"32>º  `‚¢a]N#/If„S*M@2‚;:7$*tCqš^)Ó$3@$5VC1 *A,BlS8ª.hjj0€ÎM?kŠK<†h?0C*:"ÄÑ “'X•Ãþ“*J7 3Tntt05[C&c¡Íáô@JZjEUe87H¸ÿè@Hf'GWi(HX ;ôk›»ë4T //¯¿ßÿ p?:¯Ïßÿ@`_Ÿ¿ß Pp_ H™  ?3]+?í2]]qrr^]qqr/^]3/_^]]]]qq39=/3310]]]]++]]_]]73!%.'Ùþû#þ®þ­ôû œ^(RE01FR(ü¤ëþN¬6@$ZO¯¿ÏZ  ÀÐ_/2?í/]qqí/]í10!#!ôü¶¿ÁþN‘ùo3øÍšþN0 ª@ †–£  ¸ÿÀ@ H£r‚d5EU¸ÿð@J H)9 HŸ¯HIÏ  @    Ï@ _ _/í9?99í9]/^]]33//3/]]99//]+]310+]+]]]]_]+]]5 5!! !š{ý•Bü²Hý¨¢þNm0,j˜ýüù˜e`Hò @ Pp ­³?í/]/]105!eã`’’3ÿòbT¹¹ÿè@‡H 9I o¯Ïï/Oo_/Oo ¯ 0 P p o  0 ð  / O 9ï ° Ð  ¯ Ï ï p / O o ¯ ¯³/3?9/]í]qqrr^]]qqrr/^]3/]/]q89=/]3310^]+##5!3njþå¶ò®uýN‡WË]×#3Cr@K‰25CEC  !'4/ /@/p//<$à77*ïAA'4?  @H P  /]3Ü]+q29Í]2Í]2/Í/]Í910]]]]]]#"&'#".54>32>32%"32>54..#"326],RsFa¨F KTZ.EsS.,RtG^¨CKT^3ErQ-þ³Fw83wM+G33Gþ]3wN+F10G/FxNNj>…•?fH'7dYQŽh<‡”>fI(7e¨~‚€€(F^66\E'ú€€(F^63]E)~˜`Ç ³/Í/Í103!!˜^jû8Çû—^ÿþª#@K[K[ /Í/3/Í/Í10]]4>32#4.#"Dz§bc©{Fg5_‚NN‚^4tÀŠLLŠÀtþb›l98lœdþÿžþN”ã#@ ""*"% Ú%É%š%ª%º%%¸@¢áäHL%/%?% %Ü%@ÓÙH%@ÍÑH†%%)%9% %û%é%%@¼¿Hk%{%‹%]%K%)%9%% %ù%%€ª±Hm%%€¤¨H %£%€œ¢H½%y%™%©%K%[%k%%ÀŒ“H›%«%»%}%%k%]%&%6%F%ä%Ö%´%Ä%%p%¸ÿÀ@nwzH%@ekHÛ%v%¦% %%)%é%%@ORH%€JNH%)% %û%Ù%é%«%»%Ë%™%%€54>32.#"$$K>#3B'2Z}K"K=$3B'2Y|þN “%@T0¼^†V( ” (AT,ûB^†V)8P,ô!C@$ H HA HB0 H=0 H*¸ÿг H0¸ÿÐ@ H H 0 H0 H ¸ÿè³ H¸ÿг H¸ÿгH¸ÿÐ@) H?0P@`€ ð- @ H /E;­@-¸ÿÀ´#@)(­1 1011­@ ¸ÿÀ´'323267"&'.#"5>323267(E‘IAk-&A<82„Q(PMK%233E{4 ;=D(E‘IAk-&A<82„Q(PMK%233E{4 ;=Dö+ !%/  3+•þZ,  &.  2*“ A7$¢@l5: < *      dtP0 `o  _ o  ­ ­/_oß P Ð   /]]3Þ]22í2í22/]q3/]q_qq39‡ÀÀÀÀ‡ÀÀÀÀ10_]]]]##5!!5!3!!!À˜‘—í7¾þ =š˜þ¢¿Xþß!”l”$þÜ”þ””dôGP 1@ ­ ­?­?/]í/]í9/í/33/33105!5!5!dãüãüã¼””ý8””d””?$Ï {¹ÿØ@H(H(H‰¸ÿØ@?H† 0P @`€ @ H­O_@P€P€/]33Í]Í]/í/+3//]q310]+]+++5 5!Aãü¦ZüãwÍ‹šþ¨þ¨™ì‘‘A$Ï y¹ÿØ@H(H(H‰¸ÿØ@>H† 0P @`€ @ H­@P€O_P€/]Í]Í]33/í/+3/]q310]+]+++75 55!AZü¦ãüãì™XXšþuÍý‰‘‘7 #@i y iy/Í/Í/ÍÝÍ10]]3 %! ÍÍü¶úþƒþƒ{ýúý…RªþVd´Gò·ª­/í///í107!!dãü®´>’þT"ýšÒª¶  H ¸´ //ÍÍ/íÌ10+#47632#"'.'&#"µ“TR€?K3% !$ ýšVÄ{{?0(4 ''#iýšµª ¹ÿà´ H ¸´//ÍÍ/ýÌ10+3#".54>3232765"“Z(g>2%!%ªø¨Í}86'"%)jÿö%µ¶´¸±ü?í33105! ¿%‘‘Øý“iH»´þú??öí103#Ø‘‘HöKý“µ¶"²º³þ¸±ü?í?öí310!!#(ýi‘¶‘ûnÿöý“¶"»µþ¸±ü?í?3öí105!# (‘%‘úÝ’%µH"²½³üú??íöí3103!!‘—üØHûn‘ÿö%H"»µú¸±ü?í?3ôí105!3 —‘%‘’úÝý“µH'³ º³þ¸³üú??í?öí23103!!#‘—ýi‘Hûn‘ûnÿöý“H'±º·þú¸±ü?í??3ôí3105!3# —‘‘%‘’öK’ÿöý“µ¶(² º¶þ¸±ü?í2?3öí3105!!# ¿ýi‘%‘‘ûn’ÿö%µH(² º¶ú¸±ü?í3?3ôí3105!3! —‘—%‘’ûn‘ÿöý“µH 3³ » @ þú ¸²ü?3í2??3ö2í23105!3!!# —‘—ýi‘%‘’ûn‘ûn’ÿöqµj%· ¸²ý¸±û?í?í3233105!5! ¿úA¿Ù‘‘þ˜‘‘Ùý“ÒH*A ¶þú?2?3öíôí103#3#Ù‘‘h‘‘HöK µöKý“µj 1µ º³ þ¸²ý¸±û?í?í?öí23310!!!!#(ýi—ýi‘j‘בü"Ùý“µ¶ 3² ¿  ² ¸´ üþ?3?í2ôíöí310!###µþ‘ב¶‘ûn’ûn#Ùý“µj ?´ A   µý þ¸±û?í?3?íöíôí3310!!#!!#ÙÜüµ‘htþ‘j‘úºo‘ü"ÿöý“j 1± º·  þ¸²û ¸±ý?í?í?33ôí3105!5!5!# —ýi(‘q‘בú)Þÿöý“Ò¶ 4A   · þ¸±ü?í2?33ôíöí105!### ܑב%‘úÝ’ûn’ÿöý“Òj ?´ A   µ ýþ¸±û?í?3?íôíöí3310#!5#!5!Ò‘üµt‘þtjú)F‘ú)Þ‘qµH 1µ ½  ²ý¸³ûú??í?íöí233103!!!!‘—ýi—üØHü"‘בÙ%µH 4² A    µüú?3?3íöíôí3103!!33A‘ãü$‘×Hûn‘#ûnÙqµH ?´  A    ²û¸´ýú?2?í?íöíôí33103!!3!!Ù‘Kü$h‘ãýŒHúº‘×ü"‘ÿöqH 2¼ ·  ú¸²û ¸±ý?í?í?33ô2í105!5!5!3 —ýi—‘q‘בÞú)ÿö%ÒH 4A  ·  ú¸±ü?í3?33ôíôí10!5!333Òü$ã‘ב%‘’ûn’ÿöqÒH ?A   µ  ¸µ ûú¸±ý?í?3?í33ôíôí10!5!3!3!5!Òü$K‘þ‘ýŒãq‘Fû‘‘ý“µH 6¶  º ³ þ ¸²ý¸³ûú??í?í?öí2233103!!!!#‘—ýi—ýi‘Hü"‘בü"Ùý“µH 8² º ² º·  þú¸±ü?í?3?3ôí2öí3103!!#3#A‘ãþ‘þ˜‘‘Hûn‘ûn µöKÙý“µH Iµ A  ² û¸·ý ú þ?3?3?í?íöíô2í23310#3!!#3!!j‘‘×tþ‘‘ãýŒý“ µúº‘ü" µü"‘ÿöý“H 8¹ ² ¸@  þú¸²û ¸±ý?í?í??33ö22í105!5!5!3# —ýi—‘‘q‘בÞöKÞÿöý“ÒH ;A   @ þú¸±ü?í?3?33ö2íôí105!3#3# ã‘‘h‘‘%‘’öK’#öKÿöý“ÒH Iµ  A   µý þ¸´ ûú?3?í?3?íôíö2í233103#3!5!#!5!A‘‘þ˜‘ýŒã‘‘þtHöK µû‘‘ú)Þ‘ÿöý“µj 9´  ºµ  ¸µ ûþ¸±ý?í2??í33öí33105!!#5! ¿ýi‘ýi¿q‘‘ü"Þh‘‘ÿöý“µ¶ :² ¿  @  þ¸±ü?í22?33ôíöí3105!!### ¿þ‘ב%‘‘ûn’ûn’ÿöý“µj J´  ºµ½³û ¸µý þ?3?3í2?íöí33ôí3310#!5!3!!#!5j‘þt×tþ‘túAý“Þ‘‘ü"ב‘ÿöqµH :@   ½ µ ýú¸±û?í3??íôí3333105!3!5! —‘—úA¿Ù‘Þü"‘þ˜‘‘ÿö%µH :² ¿ @ ú ¸±ü?í33?33ôíôí3105!333! ã‘בã%‘’ûn’ûn‘ÿöqµH L@  A   ³ ý ¸µ ûú?3?3í2?íôíôí3333103!!3!5!5!A‘ãýŒþ˜‘ýŒãþ¿Hü"‘oû‘‘þ‘‘ÿöý“µHL¶  ¸²¸@ þú ¸´ û¸² ý?3í2?3í2??33ö22í2233105!5!5!3!!!!# —ýi—‘—ýi—ýi‘q‘בÞü"‘בü"Þÿöý“µHM³ » ²»@  ú  ¸¶ü þ?3?33í22?33ô2í2ö2í23103!!###!5!33A‘ãþ‘בþã‘×Hûn‘ûn’ûn’‘’ûnÿöý“µH ]µ» ¶  »²¸·ûú ¸µ ýþ?3?3í2?3?3í2ö2í233ô2í233103!!#!5!3!!#3!5!A‘ãýŒ×‘þt×tþ‘þ˜‘ýŒãHü"‘úºÞ‘‘ü" µû‘‘m«H¶ú/?3310!!«úU«mÛý“«m¶þ?/3310!!«úU«ý“Úý“«H·úþ??3310!!«úU«ý“ µý“ÖH¶úþ??/310!!Öý*Öý“ µÕý“«H¶úþ??/310!!«ý*Öý“ µ*gýõ«£ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§1µ¡™•‘¥¸¶¤mUE- y¸@ xlTD, xeM5‰¸@ ˆdL4ˆqYA)}¸@ |pX@(|aQ9 ¸@ Œ`P8Œu]=%¸@!€t\<$€xˆ|Œ€€Œ|ˆx„ œ˜”¤¤©iI1!…¸@hH0 „„§‹‡¸´„£gck¸·h d`h_[W¸·T\XTŸSOK¸·HœPLHC?G¸·D@§¢.)'.@D%T%K![!K[DT #/ÍÜÍ/ÍÜÍ10]]]]4>32#".732>54.#"§Fz¤^^¥{GG{¥^^¤zFV9b…LL†c::c†LL…b9d^¥{GG{¥^^¤zFFz¤^L„c99c„LL†c::c†²‰#ú¶ /]Í/Í102#"'&5467>76jnk5R·¶S4lú9R46n9··:m64R9)¬ƒ· /ÍÝÍ/ÍÝÍ103!32>54.#")ƒüEx [[¡xEEx¡[[ xEƒû}A[ xEEx [[¡xEEx¡)¬ƒ+"@" '/ÝÝÎÝÎ/ÝÝÎÝÎ103!4>32#".'32>54.#")ƒüQ:c…KK…c::c…KK…c:MEx [[¡xEEx¡[[ xEƒû}AK…c::c…KK…c::c…K[ xEEx [[¡xEEx¡s…cu"· /ÍÜÍ/ÍÜÍ10#"'.5476324'&#"3276c%%%V3eK#%HJfgGJL33FF3331HH13}5V%#%H%V5fHJJGgF3333FE6116±ÿåy¬!-9D“@] $ t $t+{+{D"(?4.(.(.1%+7+>:h:Y:G:::b¹^0Hþ²³³²þ€×[²²[×€Ù™šš™ÙØ™šš™W .. -- .. --þ¿‰‰#º_[Ñÿ噬)4`@7*/$'!04h4Y4K4=442-_oO-_--- /Ì99//]^]Î3]]]]33Î2/Í99//Î3Î310#"'&54676324&#"326%4&#"326327'#"'™´³ýý³´ZZ²þþ²ZZý. -- .Ó, // ,ý®0^¹b>L‘“LHþ²³³²þ€×[²²[× -- .. -- ..þÜ[_º#‰‰Fÿs;3F‹¹/ÿð@ H4.4$w##¸ÿð@M H H;;  H;/4#4;B ß p ?   9+>€Ðà0/43?3O33/^]ÍÜ]]]]Í/ÍÜ]]]]Í10]]]]+]]++]]]+373#'#5.''7.'#5367'7>7"327654'.‰B 965º-¸-,××,(¸1¶7:"B?n0¼+¶(.×× P´(½9p6Eu0bb0uE‹`cc1u;Ù  ¶-¸;q9>€_¸1¶(,=20dˆ‰b2/aaЉc02ÚP&/b@>+ï+ÿ++"à"ð""P'ð''€@%(H /Í+Ü^]2Íqr/]3Í2/ÍqrÜ]Íqr9/3Í210.'&547>32!!#!5!"327654&'&Ü7Z#GS,e>SW;=>B.*PlzS++VSzmQR ¦FþúF‘;G,+G>>=T,G;Qú¯AQF@(1A;NN?  33FF;A1?J7€77B??/^]Ì]ÍÜ]Í99/ÍrÜ]Ì]Ír9910.'.'.547>323267632#"'.'#"'&547632"327654'&ÿ6%( ? .@$    íTVWvvWTTUzGSšZ>==@XY<>><      "O-@" '*R*îQm}VXTTuuWV+ >=X[===>ZW>>;Ï/(@& 0 ` p  "@ H"O_/]//+3/]/10#"'!727>'#"'&547>7>76 (_E#%?BXc$&£‰üè}V+B,-„SZB?N9En&8Ï6_,+i?~BCF_?B¿“WVc %%1E[wK`_B?[J;*U/;q9S<ÇK/@9M?4=C /)//99//]923/]Î10)7>7>7654&5#"&'&547632.'.547>3267>32#"&'.'Fü¶Tl)@4:Z+X-;a)OII]P3N(a„2+C.=Ÿ#!K2dmy;*&StsOP"4&sN&(PNmVb(%)LtvSP<3=-Q}.-L'fÿéZy'&@) @ P p €  ///]Î10^]].'.'.'.547632>32b*gL8E+%DFfbN/"ŽX2U#F)N7>-qEEt/'xSEj( #&b<^Q2€P;`ÇN¥]]5(–o]ŸH: 9‡Pwc; kM”Ä;!0@! @O_o€! //ÍÌ]9/9/ÍÜ]ÍÍ2103#>54&'&'#"&547632éL™3:0./9@%%Hl9:Q0*ýÚ%#Jj9:;b&J5-L9<ð²þg•u˜vÌ#d³C  ¸ÿà@; H#F/ Ï  O o  O_Fo"SP P ?3?3í2?í?í?/]]í2/]/]q3í210+]##5354>32.#"3533i´˜˜;fQ E-(3 Ó†´´´·üI·ƒz;eK+‰)<'aƒi¬¬úà:ûÆwÌZ³C  ¸ÿà@5 HF/ÏOoO_FoP P?3?3í2?í?/]]í2/]/]qí10+]##5354>32.#"33i´˜˜;fQ E-(3 Ó‡´·üI·ƒz;eK+‰)<'aƒüIÌú4wþNãÿªK¹ÿè³ H¸ÿà@( Hƒ_Œ?O Œ P`p/]í/]í/Ý]qí9/10++#"&'532>54&#*732ãAhK-1%)8#=H>4T< ý)C0b %(`)?ÿÿó¾¶šw8@ o_]]]5þNHÿž K¹ÿÀ³ H¸ÿÀ@ H—– ’ ` °À¸ÿÀ@ !H   /]Ì+]qí/3ýí10++#>5#53H,(u-1XÃÁWk/0V.œ3– l@JV V y‰¯¿@32|&IlFBeJ, …'6$GVQK3M!úþr[6CgE$CAhJ(!;Q0/$U]QU%Ôqõ!'Gf+4x6@!௠¿  `¿Ïÿ` å Üß??í2/]]q3/]9/í10#4>7!5!x@jM+…/Pk<þ4Ma°°»lf¼³¯Xq-(‚Ž'QйDÿè³ H@¸ÿè@R H/ H+ HL7G âH===âà2¿22âFGGG(â ` ` àL8ä# äBÞ#ä-Ý?í?í]]9/í99/]qí2/qí/]]í3/qí99]10++++4.#"32>4.#"32>7#".54>75.54>32ß 5)'5 6-06 #=1-;$$=..="Ž#IqMMqJ#/= $7&#FhDHiE!&8$$?.©0""0/''0þ›4()5#;**<6[B%%BZ6.H4 %4@#-O;"#@)u … u… I ¿ ï  I@ € Ž/?ï/]íÍ2/íÜ]í10]]".'332673ToQ ¤h]]h¤ Q°9[s9g``g9s[9|E $@—– ’P` ° ?Ì]qí/3ýí10#>5#53E,(u-1XÃWu/0`.§‚»K /@ –— ’_o¯¿P  ?   /]qÍ]qí/íí21046733#‚,(u-1XÃ%Wu/0`.§júð0@u…€@@@H€_@ H/+]Í+/Í]]10]%53 þÊÏÙúÙâHúðð4@"zŠ@€@O@H€_@ H/+]Í+/]Í]10]573HÙÏþÊúâÙú–þ A@v † xˆ€¸ÿÀ@ HŽ@@H€_@ H/+]3Ý+í/Ì+]10]]#'##573–iÛèhêÌ‹‹ðú–þ A@v†xˆ€¸ÿÀ@ H@@H€Ž_@ H/+]íÍ+2/Ì+]10]]#'53373¶ÌêhèÛiúï‹‹-úZ²#@……‘_@ H/+]3í2/íÜí1053!53·£ýÓ¥ú¸¸¸¸ÿéú¶DµYi¸ÿè@" H  H@ @€_@ H/+]2íÝí3/Ì]]10++]".#"#>3232673ì*TNG76 [-J;,TNE67\+Jú%-%>9-_N2%-%?8,_N3 úñ X@<šªšªf bb Ÿß@@ H@H€_@ H/+]2Í+2/+ÍÜ^]qÍ10]]]]]5733573 ÅÏþÊýÅÏþÊúãÚãÚÿèú‚ó7@  d @ @H€ _@ H/+]ÍÍ+2/Ì^]10^]]".'3326734JtT2um[[ku 2Stú)EZ15<=41ZE)VŒ H$ÿ7ÿÛ<ÿÛVÿ_ÿbÿiÿqÿÛrÿÛxÿÛÿh$ÿ$7ÿh$9ÿh$:ÿ´$<ÿh$YÿÛ$ZÿÛ$\ÿÛ$ ÿh)ÿ)ÿ)$ÿ/ÿ´/7ÿh/9ÿh/:ÿh/<ÿh/\ÿ´/ ÿ3ÿÛ3þø3þø3$ÿh57ÿÛ59ÿÛ5:ÿÛ5<ÿÛ7ÿÛ7ÿ7ÿ7ÿ7ÿ7ÿ7$ÿh72ÿÛ7Dÿ7Fÿ7Hÿ7Lÿ´7Rÿ7Uÿ´7Vÿ7Xÿ´7Zÿ7\ÿ9ÿD9ÿ9ÿD9ÿ´9ÿ´9$ÿh9Dÿh9Hÿ9LÿÛ9Rÿ9Uÿ´9Xÿ´9\ÿ´:ÿ:ÿÛ:ÿ:ÿÛ:ÿÛ:$ÿ´:Dÿ´:HÿÛ:RÿÛ:UÿÛ:XÿÛ:\ÿî<ÿÛ<þø<ÿD<þø<ÿ<ÿ{<$ÿh<Dÿh<HÿD<Lÿ´<RÿD<Sÿh<TÿD<Xÿ<YÿIIÿÛI %UÿUÿU LYÿhYÿhZÿZÿ\ÿh\ÿhVfÿÕVmÿÕVqÿhVrÿhVsÿÅVxÿhV€ÿÛVŠÿÛV”ÿÛ[rÿ¾\^ª\_ÿh\bÿh\fÿ\iÿh\mÿ\sÿ\vÿž\{ÿh\|ÿ´\~ÿF\„ÿh\†ÿ´\‡ÿh\‰ÿh\ŒÿF\ÿF\“ÿF\—b\™ÿF]rÿÑ]xÿÑ_ÿ_fÿÕ_mÿÕ_qÿh_rÿh_sÿÅ_xÿh_€ÿÛ_ŠÿÛ_”ÿÛ_ ÿhaÿaÿa^¤a_ÿDabÿDaiÿDa†ÿ¨a—XbÿbfÿÕbmÿÕbqÿ‰brÿhbxÿhf_ÿÛfbÿÛfiÿÛfrÿ¾fxÿ¾hfÿÁhmÿÁhsÿhyÿçh~ÿçhÿçhƒÿçh…ÿçh‹ÿçhŒÿçhÿçh“ÿçh–ÿçh™ÿçh›ÿçiÿifÿÕimÿÕiqÿhirÿhixÿhm_ÿÛmbÿÕmiÿÛmrÿ¾mxÿ¾oÿÛoþúoþúo_ÿhobÿhoiÿhpÿžp‘ÿžqÿÛqÿqÿqÿqÿq^¼q_ÿhqbÿhqfÿÛqiÿhqmÿÛqsÿÛqvÿÛqyÿqzÿq}ÿNq~ÿq€ÿNq‚ÿq„ÿjq†ÿ´q‰ÿjqŠÿqŒÿqÿq’ÿPq“ÿq”ÿq•ÿjq—¼q˜ÿNq™ÿqšÿNrÿÛrþúrÿFrþúrÿrÿr^¼r_ÿhrbÿhrfÿriÿhrmÿrsÿrvÿžr{ÿhr|ÿ´r~ÿFr€ÿžr„ÿhr†ÿ´r‡ÿhr‰ÿhrŒÿFrÿFr“ÿFr—yr™ÿFs_ÿÅsrÿ¾sxÿ¾uyÿ²u~ÿ²uÿ²u…ÿÙuŒÿ²uÿ²u“ÿ²u–ÿ²u™ÿ²u›ÿ²vrÿÑvxÿÑxÿÛx^ªx_ÿhxbÿhxfÿxiÿhxmÿxsÿxvÿžx{ÿhx|ÿ´x~ÿFx„ÿhx†ÿ´x‡ÿhx‰ÿhxŒÿFxÿFx“ÿFx—bx™ÿFˆÿÙÿã‘ÿã”ÿɃyÿwƒ{ÿÛƒ~ÿwƒ€ÿªƒÿ´ƒ„ÿÛƒ…ÿžƒ†ÿÛƒ‡ÿÛƒŠÿªƒŒÿwƒÿªƒÿwƒ‘ÿªƒ“ÿwƒ–ÿwƒ™ÿwƒ›ÿw…ˆÿÙ‡yÿç‡~ÿç‡ÿ燃ÿ燅ÿ燋ÿ燌ÿç‡ÿç‡ÿ燓ÿ燖ÿ燙ÿ燛ÿçˆyÿáˆ~ÿáˆÿላÿሌÿáˆÿшÿሒÿψ“ÿÛˆ–ÿሙÿሚÿψ›ÿá‹yÿÉ‹~ÿÉ‹ÿÉ‹ƒÿÉ‹‹ÿÉ‹ŒÿÉ‹ÿÉ‹ÿÉ‹“ÿÉ‹™ÿÉŒˆÿÙŒÿ㌑ÿ㌔ÿÉyÿã~ÿãƒÿãŒÿãÿãÿã“ÿã–ÿã›ÿ㎈ÿÙŽÿ㎑ÿã‘yÿã‘~ÿã‘ÿ㑃ÿ㑌ÿã‘ÿã‘ÿã‘“ÿã‘–ÿã‘›ÿ㓈ÿÙ“ÿã“‘ÿã“”ÿÉ”yÿÉ”~ÿÉ”ÿÉ”ƒÿÉ”ŒÿÉ”ÿÉ”ÿÉ”“ÿÉ”–ÿÉ”™ÿÉ”›ÿÉ–ˆÿÙ–ÿã–‘ÿã–”ÿÉ™ˆÿÙ™ÿ㙑ÿã™”ÿÉ›ˆÿÙ›ÿ㛑ÿã›”ÿÉžÿžÿžlÿwž{ÿwžÿÓ¤ ÿ`¥ ÿwª®Dª±ÿ骵-ª¸ÿÓª¹ÿ骻ÿÓª¼ÿ`ª½ÿ¦ª¾ÿ¼ªÁÿ`ªÇÿӪʪÜÿÓªÝÿéªÞªç-ª ÿ«ªÿÓ«±ÿ髸ÿé«»ÿ髼ÿ¤«½ÿÑ«¾ÿé«¿ÿÓ«Áÿ¤«Äÿ¼«Çÿé«Éÿé«Õÿé«ÝÿÓ¬ªÿ¼¬®ÿÓ¬°ÿÓ¬±ÿ¼¬µÿ鬸ÿ¼¬»ÿ¼¬¼ÿw¬½ÿ¼¬¾ÿ¼¬¿ÿ¦¬Áÿ¤¬Äÿ¬Éÿ¼¬Îÿé¬Öÿé¬Üÿ¼¬Ýÿé¬ßÿé¬áÿ¼¬éÿé­ÿ­ÿ­lÿw­{ÿw­ªÿw­®ÿw­±ÿÓ­µÿ­¶ÿÑ­¸ÿ­»ÿ¤­Éÿ¼­Êÿ­Ìÿ­Îÿw­Ïÿw­Òÿ­Õÿ­Öÿ­×ÿ­Øÿw­Úÿ­Ýÿw­åÿ­æÿ­èÿ­éÿw­ÿÓ®½®¾ÿÓ®Áÿº®ÑD®Ø®Ý-¯±ÿÓ¯Ûÿé°±ÿé°¸ÿÓ°»ÿé°¼°½-°Ä-°Ê°Ïÿç°Øÿé°Ýÿé±µÿ鱸ÿé±»ÿé±¼ÿÓ±½ÿé±¾ÿé±ÁÿÓ±Éÿé´±ÿé´¸ÿé´»ÿé´½´¾ÿºµ¾ÿéµËµÝ¶¾ÿé¶Áÿé¶Ê¶Ï¶Ø¶Û¶Ý¶áÿé¶ç¸ªÿÓ¸®ÿÓ¸°ÿÓ¸µÿ鸽ÿÓ¸¿ÿ¤¸ÁÿÓ¸ÉÿÓ¸ÎÿÓ¸Õÿé¸ßÿéºþ}ºþ}ºÿÓºÿÓº{ÿºªÿwº®ÿwº°ÿ麱ÿÓºµÿº¶ÿ麸ÿÓº»ÿ麼ÿ¤º½ÿÓº¾ÿ麿ÿ¤ºÉÿÓºÊÿ¼ºÎÿ`ºÏÿ¦ºØÿ¦ºçÿÓºéÿ¼»ªÿÓ»®ÿÓ»±ÿ黵ÿ¼»¶ÿ黸ÿÓ»¼ÿ¼»½ÿ¼»¿ÿ»Áÿ¼»Äÿº»Çÿé»Ê»Ð-»áÿé¼ÿ¼ÿ¼lÿ¦¼{ÿ¦¼ªÿ¼¼®ÿ¼¼°¼±ÿé¼µÿÓ¼¸ÿ¤¼¾ÿ¼¼ÉÿÓ¼Êÿ¤¼Ìÿ¦¼Ïÿ¼Òÿ¦¼Ôÿ¦¼Õÿ¤¼Öÿ¦¼Øÿ`¼Ùÿ¦¼Úÿ¼Ûÿ¼Ýÿ¼ßÿ¦¼ãÿ¦¼åÿ¦¼æÿ¦¼èÿ¦¼éÿ¼ÿÓ½þð½þð½ÿÓ½ÿÓ½lÿ¦½{ÿ¤½ªÿw½®ÿ¤½±ÿÓ½µÿ¼½¸ÿ¼½¾ÿ¼½ÇÿÓ½ÉÿÓ½ËÿÓ½Ìÿ½Íÿ¤½Îÿ`½Ïÿw½Ðÿ¼½Ñÿ½Òÿ¤½Óÿ¼½Ôÿ¤½Õÿw½Öÿ¤½×ÿ¤½Øÿw½Ùÿ¤½Úÿ¤½Ûÿw½ßÿ¤½àÿ¤½âÿ¤½ãÿ¤½èÿ¤½éÿw½ÿ龪ÿÓ¾®ÿ¼¾µÿ¼¾¼ÿ¾½ÿ¤¾ÁÿÓ¾Éÿº¾Õÿ¼¿±ÿÓ¿¸ÿ¼¿»ÿ¼¿¾ÿ¼¿Çÿº¿Øÿé¿ÝÿÓÀ¸ÿÓÀÊ-ÃÊÃÝ-ÄÉÿ¼Ä ÿwƪÿÓÆ®ÿÓÆ°ÿ¼Æ±ÿ鯵ÿºÆ¶ÿÓÆ¸ÿÓÆ»ÿÓÆ¼ÿ3Æ¿ÿ¤ÆÁÿ`ÆÇÿéÆÉÿ¤Æ ÿ`Ç®ÿ¼Ç°ÿçDZÿéǵÿ¼Ç¿ÿºÇÉÿÓÇÎÿ¼ÇÐÇÕÿ¼ÇÖÿéÇéÿéȪÿ¼È®ÿ¦È°ÿÓȵÿ¤È¸ÿéÈ»ÿéȼÿÈ¿ÿ¤ÈÁÿ¼ÈÎÿ¤ÈÕÿ¤ÈÖÿéÊÑÿéÊÜÿÓÊÝÿéÊáÿÓËÊÿÑËÎÿ¤ËÏÿéËÐÿéËÑÿÓËÕÿ¤ËÖÿÓËÛÿéËÝÿÓËÞÿéËßÿ¼Ëáÿ¼Ëäÿ¼ËçÿéËéÿÓÌÊÿéÌËÿéÌÎÿéÌÏÿéÌÐÿéÌÑÿéÌÕÿÑÌÖÿéÌØÿéÌÛÿéÌÜÿÓÌÝÿÓÌÞÿéÌáÿ¤Ìäÿ¼ÌéÿéÍÿÍÿÍÊÿÓÍÎÿ¤ÍÏÿÓÍÑÿéÍÕÿÓÍØÿÓÍÛÿÓÍéÿéÎäÿÓÎçÏËÿéÏÎÿÓÏÐÿéÏÑÿÓÏÕÿ¼ÏÜÿ¼ÏÝÿéÏßÿÓÏáÿ¼ÐËÐÝÐáÿéÐä-ÑËÿéÑÎÿÓÑÏÿéÑÑÿéÑÕÿéÑØÿéÑÛÿéÑÝÿéÑÞÿéÑáÿ¼ÑäÿÓÔÊ-ÔË-ÔÏÔÑÔÕÔØÔÛÔÜÔÝÔçÕØÕáÿÓÖËÿéÖÑÿéÖÝØÎÿÓØÐÿéØÑÿéØÕÿÓØÜÿÓØÝÿéØßÿéØáÿÓÚÎÿÑÚÑÿéÚÕÿºÚÜÿÓÚÝÿéÚßÿéÚáÿÓÚéÿéÛÐÛØÛáÿéÛçÜÿÜÿÜÊÿéÜÎÿ¼ÜÏÿéÜÐDÜÕÿÓÜØÿéÜÛÿéÜÝÝÿ3Ýÿ3Ý{ÝÊÿéÝËÝÎÿ¼ÝÏÿéÝÐÝÕÿÓÝÖÿéÝØÿçÝÚÿéÝÛÿéÝÞÿéÝçÿéÝéÿéÞËÿéÞÎÿÓÞÕÿÓÞÜÿÓÞÝÿéÞáÿÓÞéÿéßÊÿéßËÿéßÏÿéßÑÿéߨÿéßÛÿéßÜÿéßÞÿéßáÿÓàÏÿéàÑÿéàØÿéàÛÿéãÏÿéãØÿéãÝæÜÿ`æáÿwçÎÿÓçÏçÑÿéçÕÿÓçØçÜÿÓçßÿéçéÿéèÎÿÓèÐÿéèÕÿÓèÖÿéèÜÿÓèßÿéèáÿÓöÿ3öÿ3øÿøÿøÿÓøÿÓølÿ`ø{ÿ`øÿÓÿÛ ÿ´ VÿÛ  ÿÛÿ`¦ÿ`¼ÿ`Áÿ¼Äÿ¼V^¾=]›Ö +z0Õ  Q .Ì û+Ó ¼  M 4e ¶ æ   ô: (« ê 8 \n þû V{Copyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.Copyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.Liberation SansLiberation SansRegularRegularAscender - Liberation SansAscender - Liberation SansLiberation SansLiberation SansVersion 1.02Version 1.02LiberationSansLiberationSansLiberation is a trademark of Red Hat, Inc. registered in U.S. Patent and Trademark Office and certain other jurisdictions.Liberation is a trademark of Red Hat, Inc. registered in U.S. Patent and Trademark Office and certain other jurisdictions.Ascender CorporationAscender CorporationSteve MattesonSteve Mattesonhttp://www.ascendercorp.com/http://www.ascendercorp.com/http://www.ascendercorp.com/typedesigners.htmlhttp://www.ascendercorp.com/typedesigners.htmlUse of this Liberation font software is subject to the license agreement under which you accepted the Liberation font software.Use of this Liberation font software is subject to the license agreement under which you accepted the Liberation font software.http://www.ascendercorp.com/liberation.htmlhttp://www.ascendercorp.com/liberation.htmlÿ'–¢  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a£„…½–膎‹©¤ŠÚƒ“ˆÞ žªõôö¢­ÉÇ®bcdËeÈÊÏÌÍÎéfÓÐѯgð‘ÖÔÕhëí‰jikmln oqprsutvwêxzy{}|¸¡~€ìîº    ýþÿ !"øù#$%&'()*+,-./012ú×3456789:;<=>?@AâãBCDEFGHIJKLMNOP°±QRSTUVWXYZûüäå[\]^_`abcdefghijklmnop»qrstæçu¦vwxyz{|}~Øá€ÛÜÝàÙß‚ƒ„…†‡ˆ‰Š‹Œލ‘’“”•–—˜™š›œžŸ ¡Ÿ¢£¤¥¦§¨©ª«¬­®¯°±²³—´µ¶›·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,²³-.¶·Ä/´µÅ‚‡«Æ01¾¿2345÷6789:;Œ<=>?@ABCDEFGH˜Iš™ï¥’JKœ§L”•MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰¹Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­uni00A0uni00ADuni037Euni00B2uni00B3uni00B5uni2219uni00B9AmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflex Tcommaaccent tcommaaccentTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongs Aringacute aringacuteAEacuteaeacute Oslashacute oslashacute Scommaaccent scommaaccentuni021Auni021Buni02C9tonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammaEpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsi IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdanuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonos afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061 afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109 afii10110 afii10193 afii10050 afii10098WgravewgraveWacutewacute Wdieresis wdieresisYgraveygraveuni2010uni2011 afii00208 underscoredbl quotereversedminutesecond exclamdbluni203Euni2215uni207FlirapesetaEuro afii61248 afii61289 afii61352uni2126 estimated oneeighth threeeighths fiveeighths seveneighths arrowleftarrowup arrowright arrowdown arrowboth arrowupdn arrowupdnbseuni2206 orthogonal intersection equivalencehouse revlogicalnot integraltp integralbtSF100000SF110000SF010000SF030000SF020000SF040000SF080000SF090000SF060000SF070000SF050000SF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000upblockdnblockblocklfblockrtblockltshadeshadedkshade filledboxH22073H18543H18551 filledrecttriaguptriagrttriagdntriaglfcircleH18533 invbullet invcircle openbullet smileface invsmilefacesunfemalemalespadeclubheartdiamond musicalnotemusicalnotedbluniFB01uniFB02uniF005middotuniF004uni2074uni2075uni2077uni2078glyph571glyph572glyph573glyph574glyph575glyph576glyph577glyph578glyph579glyph580glyph581ÿÿ¡ LNDFLTcyrl$grek.latn8ÿÿÿÿÿÿÿÿ TbDFLTcyrl&grek2latn>ÿÿÿÿÿÿÿÿkernpiÜ 2@^p‚Ì4r|Š”ŠžÄÊ&Tv¦äþ.8¾,:dºÌRˆº²Øæºººº>TZ`¦à6¨ÂÌö  . < b ò 0 ® H j ˆ ’ œ ¦ à  @ R Ò ü  , > l –   ® Ð ò.pŽ´ÆÔÞ(FLZ $ÿ7ÿÛ<ÿÛVÿ_ÿbÿiÿqÿÛrÿÛxÿÛÿh ÿ7ÿh9ÿh:ÿ´<ÿhYÿÛZÿÛ\ÿÛ ÿhÿÿ$ÿÿ´7ÿh9ÿh:ÿh<ÿh\ÿ´ ÿÿÛþøþø$ÿh7ÿÛ9ÿÛ:ÿÛ<ÿÛÿÛÿÿÿÿÿ$ÿh2ÿÛDÿFÿHÿLÿ´RÿUÿ´VÿXÿ´Zÿ\ÿ ÿDÿÿDÿ´ÿ´$ÿhDÿhHÿLÿÛRÿUÿ´Xÿ´\ÿ´ ÿÿÛÿÿÛÿÛ$ÿ´Dÿ´HÿÛRÿÛUÿÛXÿÛ\ÿîÿÛþøÿDþøÿÿ{$ÿhDÿhHÿDLÿ´RÿDSÿhTÿDXÿYÿIÿÛ %ÿÿ Lÿhÿhÿÿ fÿÕmÿÕqÿhrÿhsÿÅxÿh€ÿÛŠÿÛ”ÿÛrÿ¾^ª_ÿhbÿhfÿiÿhmÿsÿvÿž{ÿh|ÿ´~ÿF„ÿh†ÿ´‡ÿh‰ÿhŒÿFÿF“ÿF—b™ÿFrÿÑxÿÑ ÿfÿÕmÿÕqÿhrÿhsÿÅxÿh€ÿÛŠÿÛ”ÿÛ ÿhÿÿ^¤_ÿDbÿDiÿD†ÿ¨—XÿfÿÕmÿÕqÿ‰rÿhxÿh_ÿÛbÿÛiÿÛrÿ¾xÿ¾fÿÁmÿÁsÿyÿç~ÿçÿçƒÿç…ÿç‹ÿçŒÿçÿç“ÿç–ÿç™ÿç›ÿçÿfÿÕmÿÕqÿhrÿhxÿh_ÿÛbÿÕiÿÛrÿ¾xÿ¾ÿÛþúþú_ÿhbÿhiÿhÿž‘ÿž!ÿÛÿÿÿÿ^¼_ÿhbÿhfÿÛiÿhmÿÛsÿÛvÿÛyÿzÿ}ÿN~ÿ€ÿN‚ÿ„ÿj†ÿ´‰ÿjŠÿŒÿÿ’ÿP“ÿ”ÿ•ÿj—¼˜ÿN™ÿšÿNÿÛþúÿFþúÿÿ^¼_ÿhbÿhfÿiÿhmÿsÿvÿž{ÿh|ÿ´~ÿF€ÿž„ÿh†ÿ´‡ÿh‰ÿhŒÿFÿF“ÿF—y™ÿF_ÿÅrÿ¾xÿ¾ yÿ²~ÿ²ÿ²…ÿÙŒÿ²ÿ²“ÿ²–ÿ²™ÿ²›ÿ²ÿÛ^ª_ÿhbÿhfÿiÿhmÿsÿvÿž{ÿh|ÿ´~ÿF„ÿh†ÿ´‡ÿh‰ÿhŒÿFÿF“ÿF—b™ÿFˆÿÙÿã‘ÿã”ÿÉyÿw{ÿÛ~ÿw€ÿªÿ´„ÿÛ…ÿž†ÿÛ‡ÿÛŠÿªŒÿwÿªÿw‘ÿª“ÿw–ÿw™ÿw›ÿwˆÿÙ yÿç~ÿçÿçƒÿç…ÿç‹ÿçŒÿçÿçÿç“ÿç–ÿç™ÿç›ÿç yÿá~ÿáÿá‹ÿáŒÿáÿÑÿá’ÿÏ“ÿÛ–ÿá™ÿášÿÏ›ÿá yÿÉ~ÿÉÿɃÿÉ‹ÿÉŒÿÉÿÉÿÉ“ÿÉ™ÿÉ yÿã~ÿãƒÿãŒÿãÿãÿã“ÿã–ÿã›ÿãˆÿÙÿã‘ÿã yÿã~ÿãÿãƒÿãŒÿãÿãÿã“ÿã–ÿã›ÿã yÿÉ~ÿÉÿɃÿÉŒÿÉÿÉÿÉ“ÿÉ–ÿÉ™ÿÉ›ÿÉÿÿlÿw{ÿwÿÓ ÿ` ÿw®D±ÿéµ-¸ÿÓ¹ÿé»ÿÓ¼ÿ`½ÿ¦¾ÿ¼Áÿ`ÇÿÓÊÜÿÓÝÿéÞç- ÿªÿÓ±ÿé¸ÿé»ÿé¼ÿ¤½ÿѾÿé¿ÿÓÁÿ¤Äÿ¼ÇÿéÉÿéÕÿéÝÿÓªÿ¼®ÿÓ°ÿÓ±ÿ¼µÿé¸ÿ¼»ÿ¼¼ÿw½ÿ¼¾ÿ¼¿ÿ¦Áÿ¤ÄÿÉÿ¼ÎÿéÖÿéÜÿ¼Ýÿéßÿéáÿ¼éÿéÿÿlÿw{ÿwªÿw®ÿw±ÿÓµÿ¶ÿѸÿ»ÿ¤Éÿ¼ÊÿÌÿÎÿwÏÿwÒÿÕÿÖÿ×ÿØÿwÚÿÝÿwåÿæÿèÿéÿwÿÓ½¾ÿÓÁÿºÑDØÝ-±ÿÓÛÿé ±ÿé¸ÿÓ»ÿé¼½-Ä-ÊÏÿçØÿéÝÿéµÿé¸ÿé»ÿé¼ÿÓ½ÿé¾ÿéÁÿÓÉÿé±ÿé¸ÿé»ÿé½¾ÿº¾ÿéËÝ ¾ÿéÁÿéÊÏØÛÝáÿéç ªÿÓ®ÿÓ°ÿÓµÿé½ÿÓ¿ÿ¤ÁÿÓÉÿÓÎÿÓÕÿéßÿéþ}þ}ÿÓÿÓ{ÿªÿw®ÿw°ÿé±ÿÓµÿ¶ÿé¸ÿÓ»ÿé¼ÿ¤½ÿÓ¾ÿé¿ÿ¤ÉÿÓÊÿ¼Îÿ`Ïÿ¦Øÿ¦çÿÓéÿ¼ªÿÓ®ÿÓ±ÿéµÿ¼¶ÿé¸ÿÓ¼ÿ¼½ÿ¼¿ÿÁÿ¼ÄÿºÇÿéÊÐ-áÿéÿÿlÿ¦{ÿ¦ªÿ¼®ÿ¼°±ÿéµÿÓ¸ÿ¤¾ÿ¼ÉÿÓÊÿ¤Ìÿ¦ÏÿÒÿ¦Ôÿ¦Õÿ¤Öÿ¦Øÿ`Ùÿ¦ÚÿÛÿÝÿßÿ¦ãÿ¦åÿ¦æÿ¦èÿ¦éÿÿÓ&þðþðÿÓÿÓlÿ¦{ÿ¤ªÿw®ÿ¤±ÿÓµÿ¼¸ÿ¼¾ÿ¼ÇÿÓÉÿÓËÿÓÌÿÍÿ¤Îÿ`ÏÿwÐÿ¼ÑÿÒÿ¤Óÿ¼Ôÿ¤ÕÿwÖÿ¤×ÿ¤ØÿwÙÿ¤Úÿ¤Ûÿwßÿ¤àÿ¤âÿ¤ãÿ¤èÿ¤éÿwÿéªÿÓ®ÿ¼µÿ¼¼ÿ½ÿ¤ÁÿÓÉÿºÕÿ¼±ÿÓ¸ÿ¼»ÿ¼¾ÿ¼ÇÿºØÿéÝÿÓ¸ÿÓÊ-ÊÝ-Éÿ¼ ÿwªÿÓ®ÿÓ°ÿ¼±ÿéµÿº¶ÿÓ¸ÿÓ»ÿÓ¼ÿ3¿ÿ¤Áÿ`ÇÿéÉÿ¤ ÿ` ®ÿ¼°ÿç±ÿéµÿ¼¿ÿºÉÿÓÎÿ¼ÐÕÿ¼Öÿééÿé ªÿ¼®ÿ¦°ÿÓµÿ¤¸ÿé»ÿé¼ÿ¿ÿ¤Áÿ¼Îÿ¤Õÿ¤ÖÿéÑÿéÜÿÓÝÿéáÿÓÊÿÑÎÿ¤ÏÿéÐÿéÑÿÓÕÿ¤ÖÿÓÛÿéÝÿÓÞÿéßÿ¼áÿ¼äÿ¼çÿééÿÓÊÿéËÿéÎÿéÏÿéÐÿéÑÿéÕÿÑÖÿéØÿéÛÿéÜÿÓÝÿÓÞÿéáÿ¤äÿ¼éÿé ÿÿÊÿÓÎÿ¤ÏÿÓÑÿéÕÿÓØÿÓÛÿÓéÿéäÿÓç ËÿéÎÿÓÐÿéÑÿÓÕÿ¼Üÿ¼ÝÿéßÿÓáÿ¼ËÝáÿéä- ËÿéÎÿÓÏÿéÑÿéÕÿéØÿéÛÿéÝÿéÞÿéáÿ¼äÿÓ Ê-Ë-ÏÑÕØÛÜÝçØáÿÓËÿéÑÿéÝÎÿÓÐÿéÑÿéÕÿÓÜÿÓÝÿéßÿéáÿÓÎÿÑÑÿéÕÿºÜÿÓÝÿéßÿéáÿÓéÿéÐØáÿéç ÿÿÊÿéÎÿ¼ÏÿéÐDÕÿÓØÿéÛÿéÝÿ3ÿ3{ÊÿéËÎÿ¼ÏÿéÐÕÿÓÖÿéØÿçÚÿéÛÿéÞÿéçÿééÿéËÿéÎÿÓÕÿÓÜÿÓÝÿéáÿÓéÿé ÊÿéËÿéÏÿéÑÿéØÿéÛÿéÜÿéÞÿéáÿÓÏÿéÑÿéØÿéÛÿéÏÿéØÿéÝÜÿ`áÿwÎÿÓÏÑÿéÕÿÓØÜÿÓßÿééÿéÎÿÓÐÿéÕÿÓÖÿéÜÿÓßÿéáÿÓÿ3ÿ3ÿÿÿÓÿÓlÿ`{ÿ`ÿÓÿÛÿ´VÿÛ ÿÛÿ`¦ÿ`¼ÿ`Áÿ¼Äÿ¼i$)/3579:<IUYZ\V[\]_abfhimopqrsuvxƒ…‡ˆ‹ŒŽ‘“”–™›ž¤¥ª«¬­®¯°±´µ¶¸º»¼½¾¿ÀÃÄÆÇÈÊËÌÍÎÏÐÑÔÕÖØÚÛÜÝÞßàãæçèöø ÆÔ.™¿ÿ€È TÐgosa-core-2.7.4/html/themes/default/fonts/LiberationSans-BoldItalic.ttf0000644000175000017500000040645411376667572025106 0ustar cajuscajus0FFTMMü‡; GDEFÏý¬ GPOSàÁC,þòGSUB“<‚KýÌPOS/2øFˆ¸`cmap f¢ ”cvt ]Íd„BfpgmsÓ#°˜gasp ýœglyf¦®ìn% §Dheadö¬å<6hheaôut$hmtx® ¸¿ zkernXò`2ÌäJloca˜4x XFmaxpÆ’˜ namee)ãià0Êpost–%¸èüžprepî„ q Ì E~_<õÈ a&È a&þTý“ =>þNC +þTýý d›¢RT~/Z]鼚3š3ZÑf   ¯Pxû1ASC!!ûÓþQ3>²`Ÿß×: ìDª9ªOËÛsAsÿõpÇ1çÆªJªÿLX¬}9ÿìª89.9ÿ´sUs!sÿàssÿÞss_sss0ªYª¬|¬{¬|ã¸Í–ÇÿÖÇ$ÇdÇ$V$ã$9dÇ$9$sÇ$ã$ª$Ç$9dV$9dÇ$Vã‘ÇwV«–Vÿ¢V¬ãÿЪÿÊ9oªÿR¬Usÿˆª!s ã#s?ã:s?ªJãÿùã#9#9ÿ$s#9##ã#ã?ãÿÓã;#sªVãUsn9csÿ¦sÿ«ÿÝ=¿ÿe¬vªsLsÿÍsHs'=ÀsÿÖª‡å>öhsH¬Kå>kÿï3½dWªGª`ªÿœÿÑsj9~ªXªbìfs&¬b¬b¬nãÇÿÖÇÿÖÇÿÖÇÿÖÇÿÖÇÿÖÿŸÇQV$V$V$V$9$9$9$9$ÇÇ$9d9d9d9d9d¬~9#ÇwÇwÇwÇwV¬V$ã#s s s s s s *s?s?s?s?s?9#9#99#ã:ã#ã?ã?ã?ã?ã?dEã*ãUãUãUãUsÿ«ãÿÒsÿ½ÇÿÖs ÇÿÖs ÇÿÖs Çds?Çds?Çds?Çds?Ç$ë:Çã:V$s?V$s?V$s?V$s?V$s?9dãÿù9dãÿù9dãÿù9dãÿùÇ$ã#Ç$ã#9$9ÿñ9$9#9$9#9ÿé9ÿÛ9$9#B$s#s9ÿ$Ç$s#s#ã$9#ã$9ÿðã$+#ã$Õ#ãÿí9Ç$ã#Ç$ã#Ç$ã#«É$ã#9dã?9dã?9dã?g:Ç$#Ç$ÿîÇ$#VsVsVsVs㑪Kã‘ÕV㑪ÇwãUÇwãUÇwãUÇwãUÇwãUÇwãU–9cV¬sÿ«VãÿÐÿÝãÿÐÿÝãÿÐÿÝ9#sÚÇÿÖs ÿŸ*9#ã*Vs㑪VªLª“ª§ªªJªãªjªDª:ª™ªÿÆÇÿÖª·Õ™?™É™Á9qÆÇÿ°9$ÇÿÖÇ$á$_ÿÀV$ãÿÐÇ$9d9$Ç$Vÿ£ª$Ç$Bÿø9d¾$V$¹ÿÑã‘V¬”`Vÿ¢¡ª?ÿà9$Vö9Ôã%9C»fö9÷ÿÔslâ7Ôï1ã%vl9C‡%sÿ¤ÓÿÑsi™1ã?²CØÿÑBLO@E9»f¡@ŸÿL/b­79C»fã?»f­7V$‘é$ÀdV9$9$sÁÿ…V%Ô‘ú$k7Á#ÇÿÖª$Ç$é$ÇÿoV$kÿª$Á$Á$ë$ÿ…ª$Ç$9dÁ$V$Çdã‘k7?NVÿ¢Õ$ª±Õ$é$Õ•$ª$À*V#ÕÿÔs ô]Õ'Eò<s?äÿ¤ ãUãU$úÿ®ë#Õ#ã?ã#ãÿÓs?#sÿ«?sÿ¦+UªjU{U¨MÕ&À&jë#¶ÿ£s?ã#Á#?s9#9#9ÿ$Áÿ®?%ã#$sÿ«ãUš$¼#–9c–9c–9cV¬sÿ«ª8ª8s,ÿíÿíkÿˆ9½9½9ÿî9þ½½ÿösÕs2ÍZ…HëÃÕêIª!ÕOªÿïVþT+\sÿÖsÿÍÕ;sƒ!$ +*¹%]Íb¬‚¬–¬“¬²¢¢¢ô?å+–à´¤¬}d|´QÕ˜Ç1ÿdDd;«ddWdWÕ¬dÕ"Õ«ÿöØ««ÿö««ÿö««ÿö«ÿö«ÿö«ÿö«ÿö«Ù««Ù«Ù«ÿö«ÿö«ÿö««Ù«Ù«ÿö«ÿö«ÿö««Ù«Ù«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«««««Õ«g«ÕÕ{ÕÖmÖmëžë‘ëžë‘ô+Õ§Õ²Õ)Õ)Ös+±kÑUFÚQ@;@<ÀfBÄãJãJª]ª½ªPªFªUª¨ª]ªÇXÇ@ª-¦—¶o:øÜ€B~’ÿÇÉÝ~ŠŒ¡Î O\_‘…ó    " & 0 3 : < > D  ¤ § ¬!!!!"!&!.!^!•!¨"""""""")"+"H"a"e###!%%% %%%%%$%,%4%<%l%€%„%ˆ%Œ%“%¡%¬%²%º%¼%Ä%Ë%Ï%Ù%æ&<&@&B&`&c&f&kððûÿÿ  ’úÆÉØ~„ŒŽ£Q^€ò    & 0 2 9 < > D  £ § ¬!!!!"!&!.![!!¨"""""""")"+"H"`"d### %%% %%%%%$%,%4%<%P%€%„%ˆ%Œ%% %ª%²%º%¼%Ä%Ê%Ï%Ø%æ&:&@&B&`&c&e&jððûÿÿÿãÿ®ÿGÿ/þ…þ„þvü ýÐýÏýÎýÍý›ýšý™ý˜ýhãzãáòáñáðáïáìáãáâáÝáÜáÛáÖáœáyáwásááá áàþà÷àËàšàˆà/à,à$à#ààààßóßÜßÚß>ß1ß"ÝDÝCÝ:Ý7Ý4Ý1Ý.Ý'Ý ÝÝÜÿÜìÜéÜæÜãÜàÜÔÜÌÜÇÜÀܸܿܳܰܨܜÜIÜFÜEÜ(Ü&Ü%Ü"‹À bcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?w6   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a„…‡‰‘–œ¡ ¢¤£¥§©¨ª«­¬®¯±³²´¶µº¹»¼pcdhvŸnj#ti<†˜7q>?fu143:kzv¦¸bm6@;2l{€ƒ•   ·}¿8Žw ‚Š‹ˆŽŒ“”’š›™ñKRoNOPxSQL@EYXUTSRQPONMLKJIHGFEDCBA@?>=<;:9876510/.-,('&%$#"! ,E#F` °&`°&#HH-,E#F#a °&a°&#HH-,E#F`° a °F`°&#HH-,E#F#a° ` °&a° a°&#HH-,E#F`°@a °f`°&#HH-,E#F#a°@` °&a°@a°&#HH-, <<-, E# °ÍD# ¸ZQX# °D#Y °íQX# °MD#Y °&QX# ° D#Y!!-, EhD °` E°FvhŠE`D-,± C#Ce -,± C#C -,°(#p±(>°(#p±(E:± -, E°%Ead°PQXED!!Y-,I°#D-, E°C`D-,°C°Ce -, i°@a°‹ ±,ÀŠŒ¸b`+ d#da\X°aY-,ŠEŠŠ‡°+°)#D°)zä-,Ee°,#DE°+#D-,KRXED!!Y-,KQXED!!Y-,°%# Šõ°`#íì-,°%# Šõ°a#íì-,°%õíì-,F#F`ŠŠF# FŠ`Ša¸ÿ€b# #б ŠpE` °PX°a¸ÿº‹°FŒY°`h:-, E°%FRK°Q[X°%F ha°%°%?#!8!Y-, E°%FPX°%F ha°%°%?#!8!Y-,°C°C -,!! d#d‹¸@b-,!°€QX d#d‹¸ b²@/+Y°`-,!°ÀQX d#d‹¸Ub²€/+Y°`-, d#d‹¸@b`#!-,KSXа%Id#Ei°@‹a°€b° aj°#D#°ö!#Š 9/Y-,KSX °%Idi °&°%Id#a°€b° aj°#D°&°öа#D°ö°#D°íа& 9# 9//Y-,E#E`#E`#E`#vh°€b -,°H+-, E°TX°@D E°@aD!!Y-,E±0/E#Ea`°`iD-,KQX°/#p°#B!!Y-,KQX °%EiSXD!!Y!!Y-,E°C°`c°`iD-,°/ED-,E# EŠ`D-,E#E`D-,K#QX¹3ÿà±4 ³34YDD-,°CX°&EŠXdf°`d° `f X!°@Y°aY#XeY°)#D#°)à!!!!!Y-,°CTXKS#KQZX8!!Y!!!!Y-,°CX°%Ed° `f X!°@Y°a#XeY°)#D°%°% XY°%°% F°%#B<°%°%°%°% F°%°`#B< XY°%°%°)à°) EeD°%°%°)à°%°% XY°%°%CH°%°%°%°%°`CH!Y!!!!!!!-,°% F°%#B°%°%EH!!!!-,°% °%°%CH!!!-,E# E °P X#e#Y#h °@PX!°@Y#XeYŠ`D-,KS#KQZX EŠ`D!!Y-,KTX EŠ`D!!Y-,KS#KQZX8!!Y-,°!KTX8!!Y-,°CTX°F+!!!!Y-,°CTX°G+!!!Y-,°CTX°H+!!!!Y-,°CTX°I+!!!Y-, Š#KSŠKQZX#8!!Y-,°%I°SX °@8!Y-,F#F`#Fa#  FŠa¸ÿ€bб@@ŠpE`h:-, Š#IdŠ#SX<!Y-,KRX}zY-,°KKTB-,±B±#ˆQ±@ˆSZX¹ ˆTX²C`BY±$ˆQX¹ @ˆTX²C`B±$ˆTX² C`BKKRX²C`BY¹@€ˆTX²C`BY¹@€c¸ˆTX²C`BY¹@c¸ˆTX²C`BY¹@c¸ˆTX²@C`BYYYYY-,Eh#KQX# E d°@PX|YhŠ`YD-,°°%°%°#>°#>± ° #eB° #B°#?°#?± °#eB°#B°-,zŠE#õ-¿P/¯@2Ðý¿ýýoû@û€õí@ëæä åä=âàáà=ß=ÝUÞ=Uݸ²</A  @ÿÀ@FÜÿÈÃÿ0þGºOd¹`ÿ¸´¸@ ·µ µ@µ`´p´€´²_²±<¸@ÿ®2°ªÿ/³?³O³³@³&)F¯/¯?¯Ÿ¯¯@¯FŸ®­ªÿ«ª5ªP&ž›'›%œ›%›`›€›ð›ŸKÿ””‰‰“&’‘&Œ&ŽŒ&_oÿ@FŒ…G2Ÿƒmÿ€ÿvP&uP&tP&sP&/y?yOyqopGoGU3U3Uÿ§m)mlÿaP&`_2_P&cGbéb bF)b9bIb^G][ÿ\[3[G2@AU2UU2Uo?–Y_S@S(,F@S"F@SFRQ(QOPOO)OYOiO¸³Guº…@=PN M°MÀMMGLG2KG2JGÿIIGHG2G2UU2UUÿ¸²¸@=@ 0p?_/Ooßÿ?_ïo_€¸±TS++K¸ÿRK°P[°ˆ°%S°ˆ°@QZ°ˆ°UZ[X±ŽY…BK°2SX°`YK°dSX°@YK°€SX°±BYststust+++++++t++t++++tss+st++++++sssu++++++++s+t+++++ss+++++++s++++++s+s+tu++++ss+st++++++t+st+st+++sssss++++t+++su+++++++sssssssssssÌÌ}y:wÿìÿ²ÿìÿìþW'áÿéÁÓº°ÏÌ ,"-äôÆëÙmßÑŵ•¨æˆ¤B¹€ý?Û]%ª€uü\1à”à”Dàs®Õç—ôËNÑp´¯p‹¢¶ÿö²¼Š`ð¾Hj¶ý“‘g‘aÙAþoþh˜ÃòÕ«S}ϾD©Ÿ,,,,†´`.T`æ(V æ  0 Z Ä  ¦ Œ  Š Ä ` ê0ŠÒ TÊÒVìPºbúpìTè&>àP²HÀD€Š>Ô<’Øþ – Î ä þ!Ø"‚"þ#¨$&$ˆ%^%ì&H&À'@'”(t))v*2*ð+X,,€-<-®.Œ/D/Ì0&0Ä1¬2Z2¼3&3Æ4b4Î5\6D6ú77ì8”8ö99Þ9ô:^:è;0;®;Ê<–<þ=@=„=Î>.>”>Æ>ò??š?²?Ð?ê@@$@@@Ì@æ@þAA.AHA^AvAŒA¦B.BFB^BvBŽB¦BÀCCÀCØCðDD"D:DžE2EHE`ExEEªEÄF®FÄFÚFòG G$GPTPjP‚P˜P®PÄPÚPðQQHQjQ–Q®R0RHR`RäRüSS,SDS\S€S–S°T TdT|T”T¬TÄTÜTôUUæV–V®VÆVÞVöWW*WÎX¨XÀXØXðYY Y6YNYfY~Y–Y¬YÂYÚYòYþZ Z"Z8Z’[[6[N[f[~[–[®[È[â[ü\\,\@\X\p\ˆ\ \º\Ò\ê]]]2]J]’^^,^V^n^†^ž^¶^Â^Î^Ú^æ_ _._D_€_˜_ì`&`t`¦`ÄaaaaHava¦aÒaüb4bNbVb^b¤c ccc$c c¨c°ddd&dddldÄdÌe(e0e8eòeúfÚgjg„gžg¶gÎgægþhh¸iriâjfjîkdllŒlîmfmÜn’nöošo¢pRpäqXqÈrVrÊs¨tzu@vvv6vNvfv~v˜w(w@wªw²wºwÔwÜxvyyv|L|d|ð|ø}^}f}°~J~R,°€(€@€Æ,4“¬”D”¶•4•Ò–j–„—V—ž˜"˜*˜d˜|˜„™0™Ð™Ø™ðššÐ›"›f›~›–›®›Æ›à›úœœ(œDœ`œ¦Zr†ŸŸRŸ–Ÿâ r¡¡|¡Ò¢`££ì¦’¦¶¦Î§§D§l§‚§¨¨¨v©6«Ú¬l­&­Þ®ä¯t°°n°°°æ±±Z±ˆ±¶±ä²²Z²¢²ò³|³Â³è´4´N´€µ2µJµ‚µÔ·@¸^¸Ž¸â¹8¹f¹€¹¶¹ôº º&ºHºjºŒº®ºÔºú» »F»x»ž»È»ö¼&¼`¼Ž¼¾¼ø½&½V½½¾½î¾(¾\¾’¾Ö¿ ¿B¿ˆ¿¾¿òÀ8ÀnÀ¢ÀêÁ2Á|ÁØÁð Â8ÂPÄhÆDÈÈÈ2ÈNÈvȄȒȠȮȼÈòÉDÉxɪÉüÊRËË‚Ì2̬ÍDͤÎ*Î~θÏÏzÏ ÏÚÐÐHÐjÐØÑHÑxÑüÒ(ÒJÒjÒ„Ò¢ÒÆÒêÒôÓBÓnÓ¢DdU.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!D þ$˜þhUú«DÍO‡„@) RRŸ 0@P`€¸ÿÀ@,HlmXð à Ð À ° €  ]]]]]]]+??ýÎ0//]q+]q/+<‡++ÄÀÀ+‡ÄÄ10#!!§æ &ýÈ4 4ª×úþòÛ‚à/@o°o€ p ]]?3Í2/]qýÖ]í10#!#!`ÛHýÖÛH‚ÿþÿApsç@*     R¸@ R  ¸@L    @ H! Ð    ®  ® ¯ Ï ÿ O¯Ï  ± /3?399//]q]q33í2233í22/]]33Ä+2299//Á‡+‡+ć+‡+Ä10‡ÀÀÀÀ‡ÀÀÀÀ‡ÀÀÀÀ‡ÀÀÀÀ]]3##!##53#533!33!!«E×öRœPþÍP™O›¼FÏîT™R3TœT¤ýoH5F^þ´•þƒ}þƒ}•L”þþ”þ´Lÿõÿh…ð1:EÇ@~00A H@ H$;%656E6%555E5+2!,-56 A@ r¿)9† 2o'&/&&G;o @-56t,Au !?33/3í2?33/3í29/3ÖíÖ]2Þí9/]3]]]]q‡+}ÄÀÀÀÀÀÀ‡ÀÀÀÀÀÀ]]]]++10]#7".'%3.54>372.#4&'2>"8LÒ†!p R’oE`[IMˆf;-Nhu};nYˆ_4þû *1C\•k:þòX_I2]G*þr'9%C3R9Úo¦p;­¯-X€R*XY„?[xLLxZ?'~‚.Pm>9,=%þŸ>Wt‰MQþ–-E+! K3Epÿñä.H]a5@ÿ`^a^¸_`_`^_a_a_4Q´Aµ4,´µ"´'4´¸[È['[[c%¶ ·I¶/·T¶<_¶`fc'c—cc·cWc6cucWcGc6cçcÆcµc¦cÇc'ccc[cKc"32>7654&2#".5467>"32>7654&#3"?pU1 cw|5>lO. _ry4:3+ ,*:5-2`?pU1 cw|5>lO. _ry4:3+ ,*:5-2ü Å>Ç IvU%]0~ ["$MxT%[.ƒ W—9gT5Y%IE9fPmMJAþ| IvU%]0~ ["$MxT%[.ƒ W—9gT5Y%IE9fPmMJAý%1ÿìB‰;O_ @µ6I*DfCB BA A; ;3 3<L  +   33/X?XOXKAJE4A''"*FFSSXPIP  XI!"-a aKJ/?O¯fSUS[A¶Y'A44!97.54>32>73267#"&'#"&2>7.'>54&#"1@rœ\ 8l hK|Y0Lª] )3!Iq0»>GO*(]39'!?+[–@F[{TÉÖ¼"B<4"<3((P>'1FØ ?lN,C:'E3bWŒpV 2;A!R‹f9 A`@UeP&*RQS,NµjS8okc+"Ë <9."Á -cc`+.@V9+G1g,E .8H0363NÆ‚ð@*6Fv†öä&6FfvVfv–æ¸ÿÀ@$'HoFVv–ÆÖæ ¸ÿÀ@ÿHF6&ôæÖƶ¦–†vfVF4$ÊöæÆ¶¤–†vfVF6&öäÔÆ¶¦–†vfV&öæÖ¦–†fVD6&šæÒÄ´¤”†tdTD4$ôäÔÄ´¤@딄vdTD4$òàÐÀ°¤”€p`P@0$iðàÔİ ”€p`TD4$ôäÐÀ° „tdTD4$ðàÐÄ´¤”dTD4$9ðàÐÀ rrrrr_^]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]_]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]qqqqqqqqqqqqqqrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqq?Í/+^]í+]qqqr10#!¡ÛI‚ÿJþWjÌ=@'   H   Ð   ??/]]ýÆ2]]9/3]10]]!&547jþþþöHKþíIKA‚ÃÌöý«þ—ÃþžœœlɳL- oÿLþWnÌ¥@ÿ +@.1Hÿ/?Ÿ¿ÏŸ¯ß   HT ôäÔÄ”„tdÎÄ´¤tdTDôä„D4$ôäÔÄ„tdžôä´”„4$ëĤ‹tdË´¤k$ jô䔄K4$뤔@4‹d4+Ë´¤k;$ :ô¿_rr^]]]]]]]]qqqqqqqqqrrrrrrr^]]]]]]qqqqqqqqrrrrrrr^]]]]]]]]qqqqqqrrrrrrrr^]]]]]]]]]]q??/^]íÆ2_^]]9/3]q_q+r10$4.'! ´ &8$ KVAƒÃ‚þWüdrO¯±ªJ•þ¢À·þ¬þËþðrX‡m3@!  € `   À ?Í/]]qÍ]10]]]7''7'73>ëDúº¸’•º¾úDï×ohÅ=Õyüü{Ó=Åh}¡€± a@< _Ÿ¯  ª@ 0€P à­ ²?3í2Æ]q+æ9/_^]3í2Æ^]+æ10#!5!3!îâþqâ’9þh˜à˜þhàÿìþÊ1S@  Ÿ   ¸ÿÀ@H   › XYX€]+/íÄ]10//]+/+<‡+}ÄÆ]2910%#>7#![ $.7 ¹#@4$;!BCn]N##NRR(18™o#@P€/?O¹/í/]Æ]107!8//™ôô.Š17@ Ÿ¸ÿÀ@HœXYX+?í0//]+/+<‡+}Ä103!.;!;1þÏÿ´ÿ×íÌ4@°??Æ/Á‡+Á‡}Ä10]3LKîý¹)õú Uÿì_–58@#   o&&71o/s)s?í?í/]íÔ]í10]]]]2#".5467>2>7>54&#"ÔSj>L]jtz>^’e4N_mty¨7[L>IO54.#"%>32! %0z†‹ƒsU2+<#'D9,þöR|©nq¢j22Vq„{j&Ž,ÃS‰td\W]e;(7!*G5;QZ11Z€PN„rd\Y\c8çÿì\–;K@,))!::+!o6oÿ= ,+:s;;1s&s?í?í9/í/3Æ2Ô]íÜí9/910]]2>54&#"%>32#".'%32>54&+7/iW9MP[xþõ^‚¥cf o:0]†V?fH'DƒÂ~|µx?#9O18S7lpk,=0WGHSZ^4^‡V)/YQL~]: /LhBWŸyG6a…O&2C) 8M-]]ãÿÞP w@H Rq0 /t€X+?3?339/33í2/]33/Ä]]q/+<‡++ÄÀÀÀ‡ÀÀ10]!!7!3>7!j6þô6ý€)Ír²¼*þÈ !#þX…þâÏ”üoÒÞ273 +10ýäÿì‹,t@ #o.+fv†W¸ÿð@-Hv†æöUe,(sss?í?í9/í/3]Î2]]]q+qq2Æ]2/]í10]]!!>32#".'%32>54.#"!<O+ý®W1>N0N‡d9N”׉p¤qA 0H3CeC!3E(Ab'þîçþ² 6j›ewÆŽO5]€K-*?*,Mf9:T6.-_ÿì~–"4g@D   +oo*6'#o0tßïP`&s &s?í?í9/]]qí/]í2]Ö]2]Ö]í10]]]]]".54>32.#">3232>54.#"k£o9_«ðEˆpM þöJBsª'5£gO‚]3MŽÉþßb[3V>#0A&-XE+Eƒ¼wÌYüŽJ}_)IFæèHY1_‹[oȘZÁi|(MoG4L1"CfÃ2@ @ o @H s?í?/+2/íÆ]2]]10!!67!¼,Tœ‹ydMþÖ#‰»çýßf¸³´ÄÚ¶3 Žÿìp•'9Ma@< & "5-- oIo--O5o#?o@ H :u((Du0u?í?í9/í99/+]íÔíÔ]íÔí99]]10]]]]2#".54>75.54>2>54&#""32>54.ÃeŸn;+QvJ3U<"F‹Ð‹w°s8Ci<\_Eƒ½<32#".'%32>4.#"32>7>1CLY6Rƒ[1QÈx_ uB &€£¿fU’pJTN,[UI@/A(6ZA%/B'&K@0 %8&9gVqÄ‘S>y°rDIL"¼þö¨M(S|T0KR'e¯ì*I7(OtK-G12P;,YB \@Ÿ€ ¸ÿÀ@ HœœXYX€ ]+??íí0//]+]/+<‡+}ÄÀÀ‡ÀÀ10!!ë7 7þN7 7ðþæýþçþÃB j@$   Ÿ ¸ÿÀ@ H  ›œXYX+?í/íÆ]10//]+]/+<‡+}ÄÀÀ‡ÀÀÆ]2910! #>7#!ë7 7… $.8 ¸#@4$7 ðþæýRCn]N##NRR(|}Íh@8R°R°?_ /]]]3/]39=/33/3ÖÔÁ‡+Á‡+ÄÁ‡+‡+Ä10 |ü¿AB‡äþ»þ¼ã{#~)L@7 ßïÿ­ß?O@H­0p @`p À/]qí/+]qí/]3Æ2105!5!{ûýJßßýÙÝÝ|}Íh@8R°R°_ ?/]2/]]]39=/33/ÄÆ2Á‡+Á‡+ÄÁ‡+‡+Ä1075 5|@üÀ}ãDEäþyþ¾¸¹–%)f@8()R&'(')Ÿ&'&')'&H&&!G+ + +' ! '&_XYX+?í?ýÎ99/3/]qÔí9/Ôí/+<Á‡+Á‡+Ä10]2!>7>54&#"%>!éh«zCAiƒC"<.þõ 3I`:E[6`enŽþö\йþÃ4!4–/Z„VVƒhR%*0:'FgQD$+B=>'?S]d(Xc6újþò–þÚwÌ_xÏ@9 P72 2 lÓ#'Ó `"! p   T/HHTÓ///zzz¿zÏzßzz¸ÿÀ@H H;ÓT T*o×e×" B4×[B×M°z zzzoz_zOz?z/zzzF^]]]]]]]]qqq/í?í99//^]Äí3í2/^]í+]r3/]í9/99//]333í2í10^]]]]#".5467##".54>3237332>54.#"32>7#".54>$324.#"32>7>wLƒ¯c*G2F[m;_L D€ºvf‚ 'œu/;oX5R ìš…൉]/"Ei޵nV “‡=><Š¢¼n‚ܱ†Z-?w«Ù’Ë)Á]ýy8N07\H6#ad0_TE óï¬`+A+&,VC*DnŠEsܬi]Q˜þO|%2*Lˆ¼p~ØžZ?rž½ÖrW£ŽvT/*9 z"@19g®Èk‹Ü´€FvÈþø—/O9 )F]jp5r„.YƒT+*&ÿÖ3µ@w¬¼ÌJZjH*:  R ]R c”   +  _ p@ ðO@п]]qr]]qqq?3?29/í10Æ]/]9/]]‡+‡+ć+‡+ćÀÀ‡ÀÀ10]+]q!!!!.5!7ýçÃþÚ\îþK Ô‹hþ˜ú -/) 1<@þr${#.œ@e [*[o0.$##$$[0@P¯ ._$_#_lmX 0ð0À0 0p000@0Ð0]r]]]]]q+?í?í9/í910//]q/+<‡+}ćÀÀÔ]q]íÔí910]]!2#!!2>54.#!!2>54&#!6Hƒ¿~=.UxIGlI%e«äý?Ê&W{M#!?];þÓ¼H_Œ[-ˆšþ¶,TyMIsU9 8Qe9}¦c)I0K4,;#ü52T@Z`dÿìß–+G@-  ""!- -@-[`'__@-`-P-à-]qqr?í?í/]qíqÖ2]Æ2]1032>7#".54>32.#"‘*S{RN€gOã+x¢Ð„ç–I4c¸Ý‰ÇŠRþî 1LjD~ÁƒC=T†^2*H]3uLˆe;\Ÿ×{|à¿›l;@lŽNG,SA'[¥æ$y@S [ o¯P` \   0 @ P   ¯  __ lmX@¿]r+?í?í/]q//+<‡+}ÄqÔ]]q]qí10]]2#!32>54.+Þ£ÿ°]=m—³Êiý¾AætÆR8i˜`°L—á–…ß³‡[.ûcJÓŠb‘`0$‰ s@   ¸ÿÀ@1H  \0@P¯_ _ _lmX+?í?í9/í//]q/+<‡+}ÄÆ+]9/3‡ÀÀ10]3!!!!!$T,üÓEð,ýHV-äþžäþä$ v@'\0@P¯¸ÿÀ@!H _/@1H_lmX P ]q+?í?9/+]í10Ö+Ä//]q/+<‡+}ćÀÀ10]!!!!0Uœ,ýdeþÚÚ,þLäýûädÿíú–-©@-"-^)*))*)))¸ÿÀ³H)¸ÿÀ³H)¸ÿÀ@6 H ))@H/++*[`   )$*a--$_$_lmX+?í?í9/9í9/]qí/9/Æ]+2]2_]+++F·.(*)). +</+<+H‡+}Ä10_]]]%#".546$32.#"32>?!7!xC ·m¢ñŸNvÛ8ÁƒÈ[þæ 1NnIņE)X‹a>pbQ.þª'f¯.I1[ Ý‚¼8à{@lNN.VB'\¢Þ‚MŠi="äÐ$ê ¯@h   R \   0@ R\0@P¯` lmX@ P ]r+?2?39/3í2/]q3/+<Á‡+Á‡+ćÀÀÄq2//+<Á‡+Á‡+ÄÀÀ10]]!!!!!!¼výŽvþÚ'mrmþî\ý¤ýÏ1ú$\Ø@dt”@°¸ÿÀ@D&,H_Ÿ àð@P`\`p0@P°à¸ÿÀ@9&-HP` lmX° €p@0<° rr^]]]]]]]]]+??/^]]]+]qr//+<Á‡+Á‡}Ä]]]qq+q_rr10_]3!$'þîúÿì–y@@0À\O 0@0 _ _lmX+?í?í99/33/]q]/F·( +</+<+H‡+}Ä]10]]".'%32>7!7!àiœnC !1E.2B, þç,?ÁLx©8g”\:1S<"&?S-âçü&m¥p9$C é@h H‹   RR^    \0@P¯¯     ¸ÿð@+H„ lmX€  @  à Ð P ]]]qrqq+?3?29]+Ö]2Æ]/]q//+<Á‡+Á‡}ćÀÀ9]‡++Ä+‡ÄÄ10]]]]]+]!!!! ãþÓeþÜ'‚øqýÑ€{ýûýý˜üç$kX@6 \0@P¯_lmXP]+?í?//]q/+<‡+Á‡}ÄqÆ10]3!!$'åô-ûcä$Î0ˆ@V-..#""6Ff–#(%(."(µ(((/00^0‰™&f¦æ¸ÿÀ@ÿH2^ ! !! F V f  ‰ ¹  !( ! "./!lmXi2)2Ö2›2;2»2™2‰2Y2I2;2™2t2V2F2ö2æ2É2¹2«2v2f2I2É2f2)22P2@222$222ä2Ð2Â2²2¤2–2t2d2P2B242&22Éò2à2Ò2Ä2¶2‚2t2b2T2F262&222ò2ä2Ô2Æ2¶2¢2@ÿ”2†2r2d2V2F2$222ô2æ2Ö2²2¤2–2„2v2f2V2B242&222™ô2æ2Ä2¶2’2„2v2T2F262"222ä2Ô2Æ2¶2¤2–2d2V2F242&22ô2ä2Ö2´2¦2„2t2f2V2D26222iô2æ2Æ2©2’2„2v2V2"222é2Ö2Æ2²2¤2–2i2V242&22@3ù2æ2Ä2´2¦2‰2y2R2@202229ð2Ð2À2¯2rrrr^]]]_]_]]]]]]]]qqqqqqqqqqqrrrrrrrrrrr^]]]]]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrrrrr^]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrrr^]]]]]]]]]]]]]qqqqqq^]]]]qqqqqqqqrrrr]]]]]]qqqrr+?3?29//]q/+<‡+}ÄÄ+]q//+<Á‡+}Ä9]_]33‡ÀÀ‡ÀÀ]10]]]]]]]!>767#.'&'!!67>7!¶¬  $! þdÒ^¬þú‹X-’‰þît7q/74NIB?9üÐ35>BJR=;640ü‰üì]-4773,[ú$êð@–        R  R^{‹›ëû 0@ÐÐO^  0@P¯ , #    lmX€@P]rq+?3?29]]//]q/+<‡+}ÄÄ]]q_qq/F·( +</+<+H‡+}Ä+‡ÄÄ+‡ÄÄ10_]]]]]!!!67>7!tþŠ®þú^y ®þîk+*$S#ü„û‹'+%[.uúdÿì–1J@2[o-¯--- -P-`---3"[`%_ _@3 3`3qqq?í?í/]qíÔ]q]qí102#".5467>$"32>7>54. ”ê£V Ðþñ¡™êŸQ ŠÎ•k¨{R´¡l¨|Q0X–Q—Ö…1i0š÷®^WÚƒ.`1–ö¯_é@x¯o%K"¸¹Az­l$R]Š].$Yh@@[  \   0 @ P   ¯   _ _lmX@/]]+?í?9/í10//]q/+<‡+}ćÀÀÔ]í10]2#!!!2654.#!R|Á…EQ”Ðþ‡bþÚ¢!››$B[7þú:nœbr¶DþýRt„7O3dþp–*Bj@C # [#[o>¯>>> >P>`>>>D3[`###6_ a+_@D D`Dqqq?í/í?3í10/]qíÔ]q]qí9/]ýÆ9910232>7#".'.5467>$"32>7>54. ”ê£V s¨Ù‚[Y((&-[1oœf6 vµ{> ŠÎ•k¨{R´¡l¨|Q0X–Q—Ö…1i0‡ß©mbXà 8gXe—Äs.`1–ö¯_é@x¯o%K"¸¹Az­l$R]Š].$¹‚@O\ [`Ð \0@P¯__lmX @ rq+?í?39/í2910//]q/+<‡+}ćÀÀÔ]ýÔ9‡+}Ä10!!!!2 2>54.#!òæþ¦gþÙ‹‡Ày8Co’Oþ0ClM*&BX2þ”QýêBo’P^“j@ ý¹ü8U:4I-þ`ÿìA–=\@<66\9%%0$$$?€?-\/?O-(a _?r?í?í99/]3]ÖíqÖ]q2]Þí10]]]".'%32>54.'.54>32.#"X‡ÌQ! ,JjHL[3&KoJ^¥{HZ›ÑwÊRþà“vBcC"-OnB3kdXB&P¢ö0a`16P5/L8/B0&>_‰d_“d31Y}LCZk.@&-=,"!-=UoIi¤r<‘sL@-¶¶\¯ P_lmXp  qq+?í2?10//]q]/+<‡+}Ä10]]!!7!æþÙæþ9,¶,ûcääwÿìñ!¼@_  \@ÏO#\Ðà¯@#H _ lmXP#]+?333?í9999//+]]/F·"(" +</+<+H‡+}ÄÄ]qqF·"(" +</+<+H‡+}Ä10]]]%2>7!#".54>7!°Oz[<¨'«n§ã’ÎŽL”'™ (IeÓ"N~\dü‘ŽÏ‡B;r©m785üÖ"_+6Q6«å§@ #3#¸ÿس#&H¸ÿØ@]HR ^R ]{ ‹ +    /?O¿Ðà O ?¿_]]q]qq?3?3310Æ]]/]9/]]q‡+‡+ć+‡+Ä10++]q)!67>7!áþ­ã1r-Ñ4üw-^'.*)-&_/‰–.È@€&!$ $  R RR-'-^...'[k! Td@.R\0@/?O¿¿...0''- O0?0/0_0]]]]?33?29/39Æ]]/]]Å]Á‡++Ä29/]]33Å]2‡+‡+Ä+‡Ä+‡Ä10]]]])4.5!!67>7!67>7!¡þ¢ þ¤þY$  N< 0N#, GZ`$;831,üÑüÑ0w6>?JF@>9 ü*\(/-9<3z9.ÿ¢¼ ì@Ÿ          & 6 )9)9&6R  b  R^ 0@ À /  / ? O     ° Ÿ _ ]]]q?2?3/]Æ]]qÖ]Æ]‡+‡+ć+‡+Ä10]]]]‡ÀÀ‡ÀÀ‡ÀÀ‡ÀÀ]]]]]]!! !!Ü5à’9ý¨oþÍýþ9þÆŒþ)×ý[ý$ýìà¬ðœ@eRbR^O_o¯Ï  \0P`€ÐlmXp ` Ð ]]]+?3?910/]//+<‡+}Ä]]3/]2/‡++ć++Ä10!! !DpþÚpþŽ$ÚCBý¾B?ý£]ÿÐ# z@yHv¸ÿð@Hb ¸ÿÀ@+ H €/? O €__?í9?í9/]Ä]3]Ö]]]Æ+3‡+‡}Ä10+]]+])7!7!!:û–(Ÿýi-ö(ü^ÑÉçÍü3ÿÊþWZÌ_@M0@P¸ÿÀ@ HõõlmX+?í?í/]+q/F·( +</+<+H‡+}Ä10]!!!6r%þìþ×%þWu¾ú¿oÿ×Í-@°??Æ/Á‡+Á‡}Ä103!²î·)öú ÿRþWâÌ@ÿ i  û 9 I Y é ™ ©  @!$H  V f v  M™©¹Æ õõlmXY 9 )   é Ù Ë » © ™ ‹ { i Y I ; +   Éù é Ù É ¹ © ™ y i Y )   ù é Ù Ë » © ™ ‰ { i Y I 9   ù é ¹ © ™ i @ÿY 9 )   ™ù é ß É ½ ­   } m _ M = -   û ë Û É ¹ « › ‹ { k Y K ; +   ý ï ß Ï » « Ÿ  { k [ O ? /   ië Û Ë » ¯ Ÿ   o [ K ? /   û ë ß Ï ¿ ‹ { k [ K ; +   Û Ï @,» « › ‹  o _   9ÿ ï Ï ¿ ¯ rrrrr^]]_]]]]]]]]]qqqqqqqqqqqqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]_]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrr^]]]]]]]]]]]]]]]qqqqq+?í?í/^]]/F·( +</+<+H‡+}Ä^]+]qqrr10_]]]7!!7!®%)þê%þþW¿ø¾ø‹U§B@& @p€€`°]]]?3Ä29/q33Íq2Íq210 #!Âþºþ¼ã‡B‰ðýüÿˆÿ!ÿTµ»/í10Æ/105!x™úNN!ŸîÞ´Œ/í/Í10 7!TþÍß+þà ÿì7N@OÓ@`  %555E5 AO455KOOOOOßOOOOO OOQ/Q()EG/?O¯((/(_(o(((#Q.OJ ”A¤AA¸ÿà@ HA54.JO?>54&#"%>323267#32>7)*V-dl"FUjGNsL&-Nix‚?¿D;>7- þùHt¡jÏÁGþ¢u‡(5GE< TE!5T;2Sl9QvT5 $-B>90ClM*’•V(þŸ' P\T'9$6[C#ÿì¨Ì&>›@b77Gß< <<À<P<< <°<<@ @,$   K Oÿ,'4O$'OXYXÐ@q+?í?99í9??/]//+<Á‡+Á‡}ćÀÀÀÀqÔ]qrqí10]]]]2#"&'#!>7!#3>"32>7>54&WQ~U- X}¡d}œ  þñ öT 8³4`P? 5J-3QA3 GN2\ƒQ0p:ŽË‚=h^;4% +32.#"Sl S{©ot¬q8 M_ntw9kœi7þäQQ8S@3Z­ig2O‚\2>qœ^(^-o£sI):cƒIZe%QY--)yq:ÿëÌ'=@f 11  0"!"!K""!"ß"""? ?p?€?;G Ð à / ? O   "0(3O(OXYXP?]+?í?99í9??/]]í/]qÄ]q/+<Á‡+Á‡}ÄÀÀÀ]10]]]%#".5467>323>7!!4>7'2>7>54&#"í$LUd ^^/VH: L /D-8dŠQ-h?ŽË‚=6H)P>¢û=t6 ,2 !Q‰h,M!xm O…e3S&js?ÿì:N#/o@N $/ G'''P'`'' 'Ð''1/GÐà/?OQ//*RQV f   $  ?3]]í?í9/í/]]í2Ô]q]ýÌ2]10]]32>7#".54>32'>54&#"f][*B4'õLnškn©s;W›Öp¤l4 ìcP"LG9Ü,jq->$J@iJ(>r¢d¤þ¯[32.#"3®þ讞%ž 5]ˆ`-Q$  C< Õ%|ü„|¾qDlJ' µ@AU¾ÿùþWÀM:Rº@j @@  ***>066K///ßÀT TpT€TðT0KGÐà/?O6/ >NC*$NPCO$0/$ QXYXPT]+?í??3í/í999992/]]íÆ2/]qÄ]q/F·S(/S +</+<+H‡+}ÄÀÀÀ]10]]".'%32>7>767##".5467323>7!>54.#"32>¯išj= ^P:V?+ ?SlHOW/ 3ñÐ9gR;   ¥R‡Ä 5I*3SA2 YT,\RAþW%HiEB=AeE=(L:#6`†P1p?5M2>9) ,=K(üµl£m7Í#L9S8K_2b%g`'U…#Ì'@`''RKßÀ) )$%%R%K&'&''&'O&&&ÿ&&'& &$%%P XYX+?í?339939?3//]//+<‡++ćÀÀqÄ]q/+<‡+Á‡+Ä10]]]3>32!>54&#"!YO IZoE˜šþév MK/^Q= vþæÌþk10.*J8 ’Š.-)ýsS..) ?B(Ji@ý¢Ì#\̇@TKP ðOÿSXYX ¯ € / ð Ð     qqqqq]]]q+?í2??3/]q//+<Á‡+Á‡}ÄÀÀ‡ÀÀ10]7!!))ýðÒÓýÏÏû:ûÆÿ$þW\̘@QKOOÿ@-H PSXYX ¯€/Рqq]]]q+?3í2?í?399/+]q/F·( +</+<+H‡+}ÄÀÀ‡ÀÀ3/10]]7!"&'732>7!((ý–2V$ ! "0" ßì 5TuýÏÏùZ ¼&>.vûFAlP,#ÈÌ Â@|     R RK    KOÿ  Ÿ   0 P ` p   XYX€ O / ]]]+??2?9Ö]Æ]83/]//+<Á‡+Á‡}ćÀÀ9]‡++Ä+‡ÄÄ10]]]]!!!! ؼŒUþè §ÑBþ'ñKþZÌü®ÀþZýl#\ÌŠ@Y ` KP` °¿ XYXðàРC°r^]^]]]]]]+??//^]q/+<Á‡+Á‡}Ä^]]]q10^]3!# þßÌú4#ÈM@@ ?  677K898998988+K€#K P?¿ï 9+#67(78P0(XYXðB`BÏBoBOB BB°B0B°B BB0BB?^]]^]]]qq^]]]]]qq+?3í2?3?399//^]q/+<Á‡+}ćÀÀ3//q/+<‡+}ćÀ3///+<‡+}Ä10^]]]"!>54#"!>7!3>32>32!>=&*-QA/ wþé{~.PB/ vþæ¦  AM_<| FTgAŠ“ €þéz|(KiAý¡{%&! y)KkAý¤S"KC0,9;/L5wq2T?#’Š$Z&ýss%%$y#M+œ@\''*+R*+K+ßÀ- -RKOÿ P"XYX+?2?9?í9//]//+<Á‡+Á‡+ćÀqÄ]q/+<Á‡+Á‡+Ä10]]!>54&#"!>7!3>32âv LL/^Q= vþæ¦  IZoE˜šS..) ?B(Ji@ý¢S"KC0,9;*J8 ’Š.-)ýs?ÿì¡M-Z@@))GßP / /ð/!G Ð à / ? O  O&OXYXÐ/P/]q+?í?í/]]í]qÔ]qí10]]#".54>324.#"32>7>¡b®îŒk®|C]ªìŽv´y>þÚ6M0,ZQC 8L--XPB «£þû¶a;q£h›ü²a8l›xB^;Bzd0U$Hb>Ayf4WÿÓþW¡N?º@3  "GßP A:?.21122\3433433ÿ33@$H 3033¸ÿÀ@1H334.?* 439O O*93XYX A€ApAÐAPA]q]]q+????íí999910//]+]+]F·@(433@ +</+<+H‡+}ćÀÀÀÀÔ]qí10]"32>7>54&%>32#"&'#!>7!Ø4`P? 5J-3SB3 MþÁ#JVd7!!>7##".5467>322>7>54&#"‚ ìþçU $LWeS[5[K9 '=‡71( Ž€û<°!N-/E.7aˆQ-m?Ì‚<0L5ý%!Q‰h,L!pvN…g4Y&1O8#zNi@ARKOÿP`€!PXYX¯!/!_!]]]+?í??9910Æ]/]//+<‡++ćÀÀ10.#"!>7!3>32L4'{›#eþç¡   "CIS2 U ®´ýþ>#FB;<>9>[;ÿì-K9º@†8%%  G*(((O'¿'''P'';;P; ;@;0GÏßï %  ¯0V0f0Ue0+Q("Q @;0; ;Ð;°;P;]]qrrr?3í?3í99]q]q/]3]Ö]í]rÖ]]2]]Þí10]]]]]]]]]#"&'732>54.'.54>32.#"èC»xÉè)û $:S81Q;!7U9O…`6Kƒ°f]•lE ûbU+K7 &D^7FyZ3NY…X,Ž•$$5#!4$ ) 2MmLZ}O$DnQE> .# + .IjVÿðð8Ž@#   K  O   ¸ÿÀ@# H  O OXYX€!ß!]]+??3í2í99Í2//+]F· (  +</+<+H‡+}ÄÀ‡ÀÀ10]]%#".5467#73733#32670%^5;`D% f”%¢‰°0Ê#Íh/&1# 8U8-U¾þþ¾ýé9*)Uÿí¿:+ó@‰+ $$KO¿ÏßÿPÀ?O -- -p- -Ð-ð-K+*+*+**+*Ï*ÿ*O***ÿ** ***"+ P"XYX+??í?3999//]]qr/F·,(+**, +</+<+HÁ‡+}Ä]qrÄ]]]qqrF·,(, +</+<+H‡+Á‡}ÄÀ10]]]32>7!!4>7##"&54>7v LL/_Q< v¦ þôHZpE˜š:ý­..(?B(Ji@^ü­"KC0,9;*J8 ’Š.-* nÐ:¢@ 4DT”¸ÿà@` HR MR L  $ ¤  /¯P`€ÀÐ p`Pа]]]qqqrq?3?3310Æ]q/]q9/]‡+‡+ć+‡+Ä10+]q)!>7!nþ°°!G !"<.:ý£HHDDHF`c¦:)+@+)(y(‰(y'‰' Û@HJZ #  ¸ÿà³H¸ÿÀ@Hu…R 0@f R"¸@  R¸@D  R("(M))) RMd""F"i,<f"))¸ÿÀ@(H)+" ()@+ ++?+ +]]]]q?3?29Æ+]/9]]]]]]]]‡+‡+ć+‡+ć+‡+ć+‡+Ä10]]]]++]]]+]]]]]]).'&5!!67>7!67>7!·þ×+!þÒþ×E    &-*    ”P#)++)#Q ýn:ý„CD""C|ý„B"$$"B|ÿ¦¸: /@q      jt$Ä{›+ %H$e{+Ët”$¸ÿà@` %H)R MR N?O¯p  O O  `   P @ 0  `   0  ]qrrr]]qr?3?2Ö]]qÆ]/]Ƈ+‡+ć+‡+Ä]+qr]qrq]+qr]qrq10‡ÀÀ‡ÀÀ‡ÀÀ‡ÀÀ]]]]!! !! Ôºþ¹þÓüþé$­(4þ&þ2þ¥[ýóýÓÿ«þWÈ:%™@fÌu…1AQ‘%5E RL R$$M%%%$P%/%%'@''à'P'P%$ P?í/33?333/]]qrÆ]]9/]‡+‡+ć+‡+Ä]]qqq10]]#"&'732>?!>7!:8eo‚T4S&&1&A><Ô#G",9Wˆ_2 Ä.K70"þ 4CJC4 3AHB5 õÿÝ: ‚@ZUZ4Dô·Ç† ;Kû¸È‰M P ` p `p€OOPP?í9?í9/]qÄ]3]ÖÆ3‡+‡}Ä]]]q]]]q10]]#7!7!!#&þ ()'ýv7(ǨËÉý\ÍþW®Ì:@F   #12"2 "22M218#") )õ8õõlmX+?í?í9/í999999999//]F·;(; +</+<+H‡+}ÄÀÀ‡ÀÀ10]]]".5467654.'7>7>;#";„;_B$=2G,&5ZF1 C§šÂ%L-?+ < 1ET,$;,AB8P%þW:S3:4#!*<%À6U>R’”¾3M3þÊ2S?*  "1@' þ²-54¿¿þWÅ̳@ÿ«;K[ ËÛë¤T4»”T”K;ôäkD«d $Ë”„td ÌôäÔÄ´dT4$Û”„t;+œôäÔ›‹d4»„D ´¤[Kkô«”€tdTD ûÐÄ@>´¤”ôÄ´{dTD$;ëÛİ r_rrrr^]]]]]]]]]]qqqqqqqqrrrrrrrrr^]]]]]qqqqrrrrrrr^]]]]]]]]qqqqrrrrrrr^]]]]]]]qqq^]]]qqqqrrrrr]]]qqr??9/qrí10!¿þWuø‹ÿeþWÍ=§@[  4 4&%M%5%%5%%%¯%¿%% %P%5%%&54+< =+õ=õ<õ=lmXÐ?]+?í?í9/í999999999//]]F·>(5%%> +</+<+H‡+}ÄÀÀ‡ÀÀ]10]]]]2+732>7>?.5467>54&+7;_B$=2G,&5ZF1 C7UvMÂ%L-?+ < 1ET,$;,AB8P%Í:S3;þÌ"+;&À6V>þ¯JnJ%¾3M362T?*  "2@' M-54¿v„Hf@?   ­ ­  ­­0ð@ ~ðB^]q^]^]]]qq/íÔí9/9/ííÆ/^]]10]"&'.#"5>323267yK‘KBm.'C=:3ˆTP™J6n0D€4 =?F*  Õ&.,2*Ûþ¹L:¦@ RRŸ¸ÿÀ@=H@#)HlmX@  ð À   0   à Ð ° ]]]qqq]]]qq+?/ýÎ0//+]q+F·( +</+<+H‡++ÄÀÀ+‡ÄÄ10]]!3÷5 5ýýÞæž,þòûÕü+Lÿáb%»±?°3°&/°Ö°Ͱ°'Ö°6¹>ÕóÔ °.°À¹ ù°À°±°À°À°° À°À°°À°À°°À°%À² Š Š#9°9°9°9²9° 9°%9°9@  %..........@  %............°@0167#7&'&54776?3&'ω;$@/ýc1eþš ¢ ª[U@¢€¾¢–TM þäGZÅ/P¶s5ª3%ž2þ¸§®rk©iJ€d š¡e[‡~+ÿÍ––,ª@U ""!$% %  %%q   ,:J.%($ ! $ v! (t/ uXYX+?í2]]?í29/3í29999Ö]2]Æ2/3//F·-( - +</+<+H‡+}ÄÀÀ‡ÀÀ9/10]]#!7>?#73>32.#"!!!267P*ä«ý6'^r» ²3Clœkc‘b5õSG%:, 5!þâxY˜_wk³¸Í&…i{ª_“e50Sm<0TI.K8þôª~k"ZfHªH¬"64@-ª#ª@`ÿ (ª2ª /íÔí+/_^]]qíôí10467'7>327'#"&''7.732>54.#"•…ƒ0p<+L9!!9L++L9!!9L'À@o   RbR^¯q    Ï   w  w   lmX+?3?99//]33í23í2//]/+<Á‡+}Ä3/]2/‡++ć++ćÀÀ‡ÀÀ‡À‡À10]!!!!!7!7!7!7!!!þ® Rþ®.þð.þ°Q þ¯àš†&³’¢“ìì“¢’Îý¬TÀþWÆÌ¥@ÿ« {‹›ëû» T Ô 4 ä d D   4 ë ¤ ” „  ä ` D  $   Ë ” „ t d   Ìô ä Ô Ä ´   d T 4 $ Û ” „ t ; +   œô ä Ô › ‹ d 4 » „ D  ´ ¤ [ K  kô « „ T D  ä Ô Ä ´ @/¤ ” 4 $  ô Ä ´ „ D $   ;°   r_r^]]]]]]]]qqqqqqqqqrrrrrr^]]]]]qqqqrrrrrrr^]]]]]]]]qqqqrrrrrrr^]]]]]]]qqq^]]]]qqqqqr^]]]]qqr??99//9/]qrí3210!!ÀþúàìýûwíýÿÖÿ|“I[o@BG G& & M@EW1o/WWo] oE MMo;(R6J@6,v# v?í/í993333/Öí]ÔíÖ]Þí]Ôí9910]]]]]]2.#"#".'732>54.'.54>7.54>>54.ÎWšsFô pSqs/IZ+Af?#A\9?EIŠÇg¤wG ôtj3cO10Smÿðä–/Y§@& 77 33 JÄ5?U5U5Ã&Ã@ 0`p¸ÿÀ@FH/O_ T@EOÉ0EÉ:00::0:0:È+È[o[O[?[/[_[]]]]]]?í?í99//]]íí99+/_^]+]qíôí99//Æí10^]]#".54>324.#"32>".54>32.#"32>7ä4^ƒ¡¹dc¹ …^44^„¡¸d–Åqp`¦ÞT›ˆnP+`¥Ý~Þ¦`ýªh˜d00b•dNtS9œ />):T58T9)@0!  9TtÃd¹¡ƒ^44^ƒ¡¹dd¸¡„^4rÄþù–~Ý¥`,Oo‡›TÞ¦``¦ÞþÙ?qœ\`šk:%?S.).%'He>>hK**3/+UD)h± Š;H@++  <3â ¸ÿÀ@5H ,â@â% H %%% 8;C+=;==å)C丳 å)Þ?í?3í9/]í]339]+/]]íÔí9/+í9910]]]#"&5467##".54>?654&#"'>323267'32>7:BG-7F.2K2@e~>{ ,&($«”Ї} /  ïbMX3&.-& Å 4.  "7&!6F&N_4$*($Xg]b8å  Ú963/#;,H‹Rªs@M * * ë ë O  ë  ëëOëЯÏP`? í  À/]3ä2/]]]]]íÝ]í9/íÔ]íÝ]í9/í10]]%73!73ÒÀCïþ·¼ýNÀCïþ·¼‹iGo)þ’þŸ'iGo)þ’þŸ'KN@@ Hª­²?íÄÖí/+10%!5!nüݬàýt>ÿðä–/=FÄ@ :: 1<Ä9=0)00== ==¸ÿÀ@ H4=4=Ã&Ã@ 0`p¸ÿÀ@?H/O_ =4<2ÉCBÉ54C55C4È+ÈHoHOH?H/H_H]]]]]]?í?í9///íí23+/_^]+]qíôí99//+]3]Öíí29310^]#".54>324.#"32>##!24&+326ä4^ƒ¡¹dc¹ …^44^„¡¸d–Åqp`¦ÞT›ˆnP+`¥Ý~Þ¦`þE²u²J™˜`NÕÛKE…BCÃd¹¡ƒ^44^ƒ¡¹dd¸¡„^4rÄþù–~Ý¥`,Oo‡›TÞ¦``¦Þþå9þÇ/q^vþ°;9<öGÿï¬| µ’/íÆ/10!5!|ûs¬^½>‘']@@    ¬¬@   € ° À à ð  #¬@À¬€)]?íÜí+/_^]qíôí10^]]]]#".54>324.#"32>>3WuBBuW22WuBBuW3ž,;##<--<##;,VBsU11UsBCsU00UsC#=--=#"=..=WZö Ö@  O_Ÿ¯  ª  ­@ PpÐ ­ ¯ooO/ O¯oOoO/ïO/9ïϯrrr^]]]]qqqqqrrrr^]]]^]]]]]qq/3í2Æ^]+æ?í9/_^]3í2Æ^]+æ3210#!5!3!5!Èàþo‘à’ûýÃþ«UßTþ¬ßý=ßßG¸Ö’ -@Òâòá"åÝ äÞ?í?íÔí/3]Ä2Ä107>54&#"'>32!G$_c`K.,#$?¢Š{?\>2M`\N]¸x9R?56?+'(9"c[3D'32#".'7326ð(D<>L)**;£6L`9v„.E,@N-RuGJe?µ22.A“!~2-',*48I-YZ >1! M?3S; "8G$035ÿŸÞ·Œ/í/Í]107!ÿ÷þˆŸ +þìÿÑþWs:4÷@C& %'((K%&%%&%%o%%?%O%%%%À%&%6Kÿ@$H¸ÿÀ³H¸ÿÀ@: H  %(. P '&XYX@6ð6€6`6O6/66Ð6]q]]]]]q+?3?3?3ýÄ999//]+++]F·5(5 +</+<+H‡+}ćÀÀÄ/]]qF·5(&%%5 +</+<+H‡+}ÄÀ10]]".5<7##"&'#!!32>7!3267k1@%*jQ;MIþè#v:C+I:) p“   &c$5"  Wa1)þ„ãý£!<MX-QsFBý )Á jþøRŒ@\Å   ÅÊ °`@ °p p9àr^]]]qqqqqrrrrrr^]]q?í2/39/Ô^]í/^]9/]í10###".54>3!ϜÛQ…`52_ŠXuòúúú¾-X†XT…]2~ÙDg@8ŸP`pp€o¿ÏßÿœXYX+/í0//]qrqrF·( +</+<+H‡+}Ä10]!~; ;1þÏXþW7@! H†0  ’P]//í99/Ô]í9+10]"&'732654&#*73Â7)QJ4: b0FW¨þWu#* «SABaqbµ‘… c@1    àåÜåÝXYX+?í2?í3/]/F· ( +</+<+H‡+}ÄÀ10]]]73?33b¸[ÂʯtªµyÔlzuý©yf±<Š+?@" á   á-$帳åÞ?í?íÔ]]í/]]í10]]#".54>324.#"32>7><@p™ZFqP,=m˜[™ Ë"-72) ",30+vi¨u?(KlDd¢r>“+:$ 'I=6.>%$KC 7&‹0ªy@T % %Pp€À/ ë ë @  ë  ëë@ë 0@`/?O í  À/]2ä2/]qíÝ]í9/íÔ]íÝ]í9/í]]10]]#77!#77¦Àþ½ïI¼²Àþ½ïI¼ªþ—Gþ‘)na'þ—Gþ‘)na'ÿÿb…&y'”“4ýK?@ o_¸K@  %° o ¸ñ@  %?55+]]5+55]]]5ÿÿbD…&y'”rnýI6@ o_¸ƒ@ & %o ¸ñ·  %?5+]5+5]]]5ÿÿn’&s'”“4ýK/@¿55O5?555---:?55]]5]]]]]5þ¤:%)u@6H&()R)Ÿ&'&&'''&&!G*' !+ '(&)_XYX +]+/í?3ý2Î99Æ2/Öí9/F·*(&''* +</+<+H‡++ÄÔí10]]".54>7>7!3267!êh«zCAiƒC#;. 3I`:E[6`enŽ \й=4þß4þ¤/Z„VVƒhR%)0:'FgQD$+B=>'?S]d(Xc6–þòÿÿÿÖ3&$š]´&¸ÿ°´%+5+5ÿÿÿÖ3&$›ç@& `È%+]]]5+5ÿÿÿÖ3+&$œ}@&O%+]5+5ÿÿÿÖC&$R»[@&/  0%+]5+5ÿÿÿÖ3Õ&$iØK&@&_¸5´%+]]]55+55ÿÿÿÖ3&$P½”@8¿O%+]]55?55ÿŸ3µ@ARc   \ /?O¸ÿÀ@$H_ _   __lmX+?í22?33í9/9/íí32Æ+]/]]9/9/Æ//+<‡+}ÄÀÀ‡ÀÀ3Á‡+‡+ÄÀÀ10]!!!!!!!!#!EFþ>òþÈÅÏ-ýCE+ýIæ,üâ=%+) þó\hþ˜ãþÝþ…㨠8C?þoÿÿQþWÌ–&&íx]·0//¸ÿˆ´/B!%+]]55ÿÿ$‰&(šÿ@  &6 %+5+5ÿÿ$‰&(›µ´ &¸´ %+5+5ÿÿ$‰+&(œ[@  & %+5+5ÿÿ$‰Õ&(i«K@  &¶%+55+55ÿÿ$t&,š…@ &S%+5+5ÿÿ$f&,›1´&¸´%+5+5ÿÿ$N+&,œÃ@ &› %+5+5ÿÿ$LÕ&,iK@ &±%+55+55#œ@k  # #\   0 @ P   ¯  [ o¯P`%_OŸ/¯ßÿ_ #_lmX+?í?í9/]qr3í2Ô]]q]qí//]q/+<‡+}ÄÀÀ‡ÀÀ10]2#!#73!!32>54.+Þ£ÿ°]=m—³Êiý¾s€*t²e,þGætÆR8i˜`°L—á–…ß³‡[.RÛTý¬Ûþ’JÓŠb‘`0ÿÿ$ê&1RÜ[@ &»/%+5+5ÿÿdÿì&2š@ 2&O36%+5+5ÿÿdÿì&2›D´2&¸+´25%+5+5ÿÿdÿì+&2œš@ 3&u82%+5+5ÿÿdÿì&2R[@ 2&¨=M%+5+5ÿÿdÿìÕ&2iK@ 2&¦64%+55+55~¨~ª y¹ÿè@!H#3C !H, < L ¸ÿè@8!H#3C!H,<Lp @`pÀ  Àð¸ÿÀ´ H²?+]q/]q10]+]+]+]+ 7   ~dþ ž``žþ `žþ þœFf`œþ¢`žþžþ¢ bþš#ÿËzº!.;…@ ,24"-1/*¸ÿÀ@H H  [o/¯/// /P/`///=*[` -1/*,24"4_"_?í?íÄ2Æ299/]qíÔ]q]qíÆ2Æ+2910273#"&'#7.5467>$"&4'32>7> xÆNƒËß=? Ðþñ¡p¹IsÏÍEG ŠÎ•k¨{R'»WÌýPO|l¨|Q–53ŒïI½r1i0š÷®^.-|ÜNÍ{.`1–ö¯_é@x¯o%K"yQìFþŽdKý4Az­l$Rÿÿwÿìñ&8šB@ "&#&%+5+5ÿÿwÿìñ&8›@ "&ñ"%%+5+5ÿÿwÿìñ+&8œ@ #&c("%+5+5ÿÿwÿìñÕ&8iÑK@ "&~&$%+55+55ÿÿ¬ð&<›·@  &Ž %+5+5$.k@> [\0@P¯__lmX+??99//íí//]q/+<‡+Á‡}ćÀÀÀÀÔí10])!32#!7!2654.#!KþÙ',ö|Á…EQ”Ðþ†,!››$B[7þúá:nœbr¶Dãt„7O3#ÿì£Ì?|@L32 H6(H//?H( ((A>??K?Oÿ%Q>9PXYX+??9í9?í/]//+<Á‡+}ÄÔ]í99//íÔí10]]]]36$32#"&'732654.54>54&#"#È2ëYf7+?K?+%8B8%:k”Zqš6D26=#PS$7?7$+BKB+IF6YE1ÅíÜ'JkDEeJ834"$3/1D^ET‡_3º  TH-=2.:O9:SB8>J35<>cGüÿÿ ÿì7Þ&DCh@ P&OQT@%+5+5ÿÿ ÿì7Þ&Dt´P&¸´PS@%+5+5ÿÿ ÿì7ù&DKç@ Q&…VP@%+5+5ÿÿ ÿìTÄ&DRÌ@ P&‘[k@%+5+5ÿÿ ÿì7Š&DiØ@ P&™TR@%+55+55ÿÿ ÿì7•&DPâ)@ U&¢ZP@%+55+55*ÿì×NET`Ê@‡ ! ;; BGX;$``€F& **XX XÐXXXPX`XXbÐb_b23JG/?O¯22/22@H22-%`FQ``O8[-Q=8OO  $  Q?3í3]í?3ýÄ9/ýÅÄ9/+]/]íÄ2]]Ä]]]q9/3]33Ä]2]9ýÌ210]]]]]32>7#"&'#".54>;7>54&#"%>32632%#"32>7%>54&#"][*B4'õLnšk™Ã..hpw=NsL&-Nix‚?¿D;>7- þùHt¡jr‘)ŒÊp¤l4 ü(¡q€$1GE<cP"LG9Ü,jq->$J@iJ(shHV/2Sl9QwU6 $-B>90ClM*?2q32.'7"32>54&•/kD%$I ' ‘,D.R£ñŸv°u:O˜ÛC>6B+þë!’GqP*1M7CsT/j.](1m°69x„”T¨þìÄlBt[}ИT  Gˆ9o³þ3:iV)P?'CuŸ[U`ÿÿ#¯Ä&QR'@ ,&µ7G%%+5+5ÿÿ?ÿì¡Þ&RC@ .&&/2 %+5+5ÿÿ?ÿì¡Þ&Rtl´.&¸´.1 %+5+5ÿÿ?ÿì¡ù&RK@ /&k4. %+5+5ÿÿ?ÿì¡Ä&RR @ .&‚9I %+5+5ÿÿ?ÿ졊&Ri"@ .&“20 %+55+55EªHª ]@B?o?OoŸ¯ß ª0`0@` Ðïÿ ­ ­­²?ÖíýÖí9/]3Ä]qý2Ä]q10535!53Îîý‰ý†îÁééþxààþqéé*ÿÚÊ\'6@[22',##,+Gß(P(( ((88@8Ð8P8p8à8ð8GÐà/?O+,/  /O O ?Æí?Äí99/]]í]qrÔ]qí910]]]]7.54>3273#"'.#"%4&'32>7>*ƒ68]ªìŽRˆ7<½†]b®îŒŠj:}ÇF*,ZQC þD>#-XPB &˜8˜a›ü²aEœi¬£þû¶a1CÕ2+Bzd0UÃýüAyf4WÿÿUÿí¿Þ&XC‰@ ,&-0%%+5+5ÿÿUÿí¿Þ&Xt]@ ,&Û,/%%+5+5ÿÿUÿí¿ù&XK%@ -&Z2,%%+5+5ÿÿUÿí¿Š&Xi@ ,&t0.%%+55+55ÿÿÿ«þWÈÞ&\t@ &&Þ&)%%+5+5ÿÒþW¡Ì;´@>:$$&GßP =28;;89:;:8\9:9:8999ÿ99@$H 909P9`99¸ÿÀ@$H9:9 2.O! O.:9!XYX=P=]r+????íí999//]+]+]F·<(:99< +</+<+HÁ‡+Á‡}ćÀÀÀÔ]qí10]]"32>7>54&%3>32#"&'#!!Ø4`P? 5J-3SB3 MþÝ #JVd323>?!7!7!3#!4>7'2>7654&#"í$LUd^^-SH9 L /D-6`…N,d=‰Ã};4E'[Ezª‹‹ªüP=t6 ,2 MƒcU=sgK`1N%emÿÿ$‰©&(M§N@  &¯ %+5+5ÿÿ?ÿì:[&HMÖ@ 0&x13 %+5+5ÿÿ$‰&(¡–@  &¿%+5+5ÿÿ?ÿìCâ&HNà@ 0&£5D %+5+5ÿÿ$‰Ú&(O”@  &¨ %+5+5ÿÿ?ÿì:Ì&HOÝ ¶‹02 %+5ÿÿ$þW‰&(QE·–"%+55ÿÿ?þl:N&HQO´5¸ÿœ´5F %+]55ÿÿ$‰+&(ƒ@  &¶%+5+5ÿÿ?ÿìRù&HLØ@ 0&¢28 %+5+5ÿÿdÿíú+&*œ¦@ /&4. %+5+5ÿÿÿùþWÀù&JK@ T&gYS0%+5+5ÿÿdÿíú&*¡ÿ@ .&Ð3= %+5+5ÿÿÿùþWÀâ&JNõ@ S&˜Xg0%+5+5ÿÿdÿíúÚ&*Oã@ .&Ÿ.0 %+5+5ÿÿÿùþWÀÌ&JO ¶˜SU0%+5ÿÿdþ9ú–&*’´9'¸ÿ¿´4: %+5+5ÿÿÿùþWÀI&J™@ \&ƒ]W0%+5+5ÿÿ$ê+&+œ“@  &¤  %+5+5ÿÿ#®z&Kœ#O@ )&ã.(&%+5+5$?Ï@€  \   0@   \  0@P¯ `a    lmXP]+?3?299//]3í2í32//]q/+<‡+}ÄÀÀ‡ÀÀÀÀÄq//+<‡+}ÄÀÀÀÀ‡ÀÀ10]]]!!!#737!!7!3# 7!¼výŽvþÚÊ{!{&'&r&&{!{Ëw&ýŽ&\ý¤ªÂªûëPÅÅ#…Ì/½@x+ RKßÀ1 ()).+*)R)K*/*//*/O***ÿ**+@H+R...@H../(# )*#P 0@XYX 1q+?]í?39999?39/+]3í+2//]//+<‡++ÄÀÀ‡ÀÀÀÀÄ]q/+<‡++Ä10]]!!3>32!>54&#"!#737Y9!þÆ IZoE˜šwþén MK/^Q= nþæâ‰!‰Ì‹ªˆ10.*J8 ’Š.-)ý›+..) ?B(Ji@ýÊ—ª‹ÿÿ$‰&,ŸÖ@ &§%+5+5ÿÿÿñ5Ä&ñR­@ &z%+5+5ÿÿ$©&,MN@ &¡%+5+5ÿÿ#Þ[&ñMÈ@ &Ž%+5+5ÿÿ$c&,¡@ &À %+5+5ÿÿ#(â&ñNÅ@ &¬ %+5+5ÿÿÿéþW\&,Qÿ±¸ÿg´ %+55ÿÿÿÛþW\Ì&LQÿq±¸ÿY´ %+55ÿÿ$•Ú&,O @ &´%+5+5#:c@AKP ðOÿXYX ¯€/ðР0qqqqq]]]q+??10/]q//+<‡+}Ä10]3!#ÒÓ:ûÆÿÿ$ÿìf&,-Ð'@ÿ o  ï¯o_]]]]q5]]5ÿÿ#þW•Ì&LM9>¹!ÿÀ@(&&H!@ H!@ H_ðï¯?]]]]]]qq55+++ÿÿÿì+&-œw´&¸8´ %+5+5ÿ$þWóùš@U À/?Ÿ K  O ÿ  @-H   PXYX ¯€/Рqq]]]q+?3Í9?í?399/+]q/F·(   +</+<+H‡+}Ä3/]qÌ]10]]"&'732>7!#'##7362V$ ! "0" ßì 5TuÜ–¦ø©@åþW ¼&>.vûFAlP,dÀÀ>ÿÿ$þ9C&.’„´'¸ÿ9´ %+5+5ÿÿ#þ9ÈÌ&N’ý´'¸ÿp´ %+5+5#È: Ì@f  + &)  RK    KOÿ  Ÿ   0  ¸ÿÀ@H  XYXO ]+??2?9Ö+]Æ]83/]//+<Á‡+Á‡}ćÀÀ9]‡+}Ä+‡ÄÄ10]]]]]]]]!!!! ؼŒUþèÒXÐBþ'ñKþZ:þ@ÀþZýlÿÿ$k&/›­@ &Š %+5+5ÿÿ#g_&O›2O´&¸´%+5+5ÿÿ$þ9k&/’>´'¸ÿß´ %+5+5ÿÿÿðþ9\Ì&O’ ´'¸ÿI´ %+5+5ÿÿ$r&/˜æ´/ ¸´ %+]55ÿÿ#ÔÌ&O˜HK-@@ H? / ¸ú´ %+]]5?5+]5ÿÿ$k&/O†ýޱ¸)´%+55ÿÿ#ªÌ&OOý޶¸É´%+55]5ÿík t@E     \0@P¯   _lmX+??í99//9//]q/+<‡+Á‡}ÄÀÀ‡ÀÀÆ10]3?!%!$]”,”ˆ'mP+þ°Mô-â@áA½ýϕߕþsä€Ì y@J KP àðOÿ   XYX¯ / ð q]]+??99//9//]q/+<Á‡+Á‡}ÄÀÀ‡ÀÀ10!?!7ÇŒþèl‰)ŠŠl*Íý31E×EÄýØJÕÿÿ$ê&1›ç´&¸´%+5+5ÿÿ#Þ&Qtk´,&¸´,/%%+5+5ÿÿ$þ9ê&1’ˆ´'¸ÿi´ %+5+5ÿÿ#þ9M&Q’ ´7'¸ÿœ´28%%+5+5ÿÿ$ê+&1Ä@ &Ç%+5+5ÿÿ#ù&QL@ ,&¿.4%%+5+5ÿÿU'QÈ ÿK1¶ :¸ÿÀ³H:¸ÿÀ¶ H7¸ý²´28%%+5?5++]55$ÿì°•?Ý@~==!!899\ 0ÐàOA'-\ ! !! 0 @ P   ¯  !982 !- 2'& _ _2lmX@A A`Aqqq+?í??í?399999//]q/+<Á‡+}ćÀÀÄ/]]q_qF·@(@ +</+<+H‡+}Ä9/10_]]]".'732>7>54&#"!>7!3>32LJx^F÷!'1/@0$8 uxLsP ®þÚÓ" ,k|RÅÊC(6Ki#?U3u+!%Q‚] ,/.V`2Up>ü…D%\ZL?EE>dF'µ·0a þ¦Y™}`A"#þWM;°@\91677K  À  =$(KOÿ 76(.P.P$#.XYX =q+??3?íí?9999999//]/+<Á‡+}ćÀÀÄ]/F·<(  < +</+<+H‡+}Ä10]]]]"&'732>7>54&#"!>7!3>32‰2V$ ! "/" ƒ LL/^Q= vþæ¦  IZoE˜š— 6TuþW ¼&>...) ?B(Ji@ý¢S"KC0,9;*J8 ’Š.-)üóAlP,ÿÿdÿì©&2MßN@ 2&€35%+5+5ÿÿ?ÿì¡[&RM@ .&u/1 %+5+5ÿÿdÿì&2¡è@ 2&ª7A%+5+5ÿÿ?ÿì¡â&RN @ .&°3B %+5+5ÿÿdÿì&2 H¶2&¸´2;%+55+55ÿÿ?ÿìÞ&RS9@ .&Õ.7 %+55+55gÿö3Œ 4§@.$\$%$$%$$?$_$%$$0[P    ¸ÿÀ@'H6_$!__%*__lmXO606]]+??íí2?í?í29/íÆ+]/]]qí9//qF·5(%$$5 +</+<+H‡+}ćÀÀ9/310!#".547>$323!!!!!%267.#"•4::—â—K“ן'H6"µ,ýeE^+ý¢IÄ-û–4`´')'Öþû, 0W{T™×ƒ[d–ó«\ãþÝþ‰çÞ ŸíÛ+W'WT):ÿì_N3R^©@vII<<--( ($^^H44V 0GVV VÐVàVVVVPV`VV`ð`AGÐà/?OQ^^F#YR+9R#FQ  $  ?33]ýÄ?íÔí9/í/]]í]Ô]]]qýÌ29/í2]99]]]10]]]32>7#"&'#".54>32>32%4.#"32>767>7>%>54&#"‹][*B4'õLnšk~·9%`nx>k®|C]ªìŽ@jYL"KÂrp¤l4 ü/6M0,ZQC 7M--XOBæcP"LG9Ü,jq->$J@iJ(OI):$;q£h›ü²a#5$FHAyf#*kb;eOÿÿ$¹&5›Í´&¸´" %+5+5ÿÿ#ÇÞ&Ut¶@  &ï #%+5+5ÿÿ$þ9¹&5’•´*'¸ÿ´%+ %+5+5ÿÿÿîþ9zN&U’ž´+'¸þ¸´&,%+5+5ÿÿ$¹+&5[@ &v!' %+5+5ÿÿ#ßù&ULe@  &"(%+5+5ÿÿÿìA&6›´´>&¸,´>A$%+5+5ÿÿÿì1Þ&Vt ´:&¸´:='%+5+5ÿÿÿìA+&6œ+@ ?&–D>$%+5+5ÿÿÿì-ù&VKÆ@ ;&c@:'%+5+5ÿÿþWA–&6x±¸ÿ°´AT9%+55ÿÿþW-K&Vx’±¸ÿ°´=P%+55ÿÿÿìA+&6^@ >&»@F$%+5+5ÿÿÿìEù&VLË@ :&¯@ &? / Î %+]]5+5ÿÿÿÝ#ù&]L©@  &À %+5+5#.ÌJ@, /KOQXYX+?í?/99//]/+<‡+}Ä]10]]>32.#"! 5]ˆ`-Q$  C< ãþè«DlJ' µ@AûqÚþW9Ì|@=  q` uv XYX+?í??3í299//]]F·( +</+<+HÁ‡+}ÄÀÀ‡ÀÀ10]] !#737>32.#"3ôþþþèž%ž 5]ˆ`-Q$  C< Õ%|úÛ%¾qDlJ' µ@AU¾ÿÿÿÖx=&$'P¾“›C-3@!===8=B%¿O%+]]55+5?55]]5ÿÿ ÿ쯲&D'PÞ›z¢0@ŸxxxxU&x}ZP%¢ZP@%+55+5+55]]]5ÿÿÿŸ3&†›ä´&¸ ´%+5+5ÿÿ*ÿì×Þ&¦tƒ´a&¸ ´adB%+5+5ÿÿ#ÿËz&˜›@ <&ð“Ÿzù @   À`/Í]29/Ì]10#73373=åÅ–®ð©Ÿ=ÁÁ§³[´/í/Í10!7!ñý¶!N³¨Ÿcâ'@ ƒ@À ƒ@€/íÍ2/íÜí10]".5467332>73ÖJtQ*£-; $C9, ¤?_„Ÿ,Mh<  *>))>+IwU.JýŒÌ¶…S?í10/í107!J))ýÏÏãpßl'4@"   ‡‰‡ ‘”#‘/íôí/íôí10]]]]#".54>324.#"32>ß(E]44]E((E]44]E("/.""./"n5]E''E]54]E((E]4-""-/""/jþWå !@  † “/í//íÄ10]]".54>7332672(I7 1A$¤ 6',#2%OþW,C.,L@47<<&& DŸˆÄ:@‚@p€¸@ ‚  /2ýÔí3/íÜ]í10]]]".#"#>3232>73p,QKD% ˆ $?bI-SJB% ‡ $?aŸ&/& --fX:&/& .-fX::ŸßÞ %@  @ HŒ/í32/Ý]Ô+Í]107!!7!:  þŒ  þŒŸ +þì +þ왟ä@ @€/Í/Í10]7!™~þëŸ!$%þàÿƦÍU 9@ @ H „ ¸ÿÀ@ H„ @€/Í9/í23/ÍÔí+Ôí+1073%73!73¹ˆíþÿþš,Ç,L,È,¦!Ž%þv)ÞÞÞÞÿÿÿÖ3‚&$Tüž³¸þÓ´%+5?5ÿÿ·D‘úÿÿ™‚'({Tž9¶ ¸ý @ %`Oÿï ]]]]qqq5+]5?5ÿÿ™b‚'+xTžB¹ÿÀ@H@ H0  ¸üÝ@  %P ÿO]]qq5+]]5?5++ÿÿ™í‚',‘TžE@ @ H¸þ‹@%Pï°¯o_?]]]]]]qq5+]5?5+ÿÿ9ÿ쟖'2ˆT ž;¶42¸ÿM@22%ðàßÏ ]]]]]]]55+]5?5ÿÿÆ ‚'<T-ž:@    ¸ü @ %¿o]]]]]q5+]]5?5ÿÿÿ°G–&v3TÿÿžS³<¸ýF@3:=)%:@.H/::ß:Ï:¯:Ÿ:::o:_:O:?:::]]]]]]]]]]]qq+5+5?5ÿÿ$+U&†U^@& %+555+555ÿÿÿÖ3$ÿÿ${%$2f@4/?\0@P¯_lmX+??í/]q/F·( +</+<+HÁ‡+}ÄÆ]10]!!2,ý*åþÙäûd€ÿÀƒ@X&6F,<LR \R ^   ¯  `?/]]?3?í29Æ/]]]99]]]‡+‡+ć+‡+Ä10]]'!%.5ÈYö,úè#‚ $-þrâŸûbâôº)QE12FR(ýHÿÿ$‰(ÿÿÿÐ#=ÿÿ$ê+dÿì–5Q@31&[` [o1¯111 1P1`1117_)__?í?í9/íÔ]q]qí/]qí99//10!!2#".5467>$"32>7>54.,K,ýµ ”ê£V Ðþñ¡™êŸQ ŠÎ•k¨{R´¡l¨|Q0X;ä?Q—Ö…1i0š÷®^WÚƒ.`1–ö¯_é@x¯o%K"¸¹Az­l$R]Š].ÿÿ$\,ÿÿ$C.ÿ£Ü‚„@V,<,(#&H(HR]R  ^ H/?O/]]??23310Æ]]/]]9/+‡+‡+ć+‡+Ä10++]q%!.'&'!!ÜþÙu -þ2þÃ+u,^'.+*.'^-ü‹ÿÿ$Î0ÿÿ$ê1ÿøe ?@&@P` /    _ __?í?í9/í/]Ô]ÆÖ]ÖÆ]10!!!7!7,9,ûÇ£-û‚-W,ü·,äüGääWääÿÿdÿì–2$àƒ@TR\R\0@P¯ 0@ `lmXP  ]]+??2í0Äq/]q3/+<‡++Ä3//+<‡++Ä10]]!!!!±ãý˜ãþÛ«þîûsúÿÿ$Y3ÿÑÚ |@b b  ¸ÿÀ@* H /?/?¿ _ _?í2?í29/]2/]2Ö]Æ+9/33‡+‡}ć+‡}Ä10#7 7!!!/2!þ¦)ç,ýG+þ  -ûû³Øäþ‹†þBäÿÿ‘s7ÿÿ¬ð<`ÿõv‹ *7Ó@++[# #P#Ð# #0#P#`##°#À#Ð###1[//?o¿Ï )**+7 * *^  *   0 P  P ° à  7a) +almXP9]+?Ý2í2?Ý2í2//]qqF·8( 8 +</+<+HÁ‡+Á‡}ÄÀÀÀÀ‡ÀÀÀÀ3/]qí3/]qí10]32>54.#7#".54>;7!32+#";/6R†`5:V8ýæ&Lg©zC`°ûšECu±x=Z¬ùŸQ&@.P‡b77S8Býq4e’]:aE'ûÙÇBzªi™å˜LžžH~«cŽàœSÇ'._“f7aH)ÿÿÿ¢¼;ªì(<@¸&& )!) && "##^ ! !  0   °  0 P ` p  !  ^   / ? O  Ÿ  ^ @0P`à*) ! _  !" lmX`*P**]]]+?3?9/3í29909/]qr//+<‡+}Ä3//]qqF·)(  ) +</+<+H‡+}Ä3//]]qF·)(! ) +</+<+H‡+}ćÀÀ‡ÀÀ]]]]10]]!#".547!;!32>7!#ÈSþéS~¸y;RT‚}””&LvW:ZZX•Ü«þU«:k˜_FN¦þL   jgùý FpPÓþ1ƒCÿà–9t@J 87'"/ 5[P;"[ 5°55))Ð)à))0' *_)_?í?3í22222/]Ô]íÔ]]]]ýÄ9999]10]]]]]267>;!>54.#"!732.546$˜ñ¦X7}Ë”-(#Já,ý‰?_”f52\ƒRX¦€M$7!!.=##".5467>"32>7>54.dJtT5 ""  NLD  þê "M_uKT‚X. e‰©e-M?1’)RMD*CM%D]8BE>/ŒœŸBe–va0=>:5_G*6f“].r6ŽÄy5Â#Q†c2U$Õ0_Ž] ?kN+ÿÔþW³Ì <Ã@ 4444%H/H:P:`::¸ÿÀ@,H:>€>%$$K  ÿ  @$H 0 P `  ¸ÿÀ@H  4O55$%!*O!OXYX+/?í?9í999/í9?3//+]+]F·=( = +</+<+H‡+}ćÀÀ]Ô+]íÔí9/]910]]6$32#"&'#!"32>54.#7>54&ë-ï[—m<1Qj96\E'E„¾zd¡6 ;þæ-a€“5=D"=gK*%HiD(DjK'Qóçò.VwJS‚^: 8Rj@k±F8&9\5þת†Šý#GkH/Q:!Æ%7!!>7l N  E1ý­ :61þÞ._-:ýÁT]YIG?{ûü7ou~F†ÖX7ÿíåÌ4l@I--33!G0 11+O_oÿO6P6ð6GÐ+à+/+?+O++++14O 02O&?í?99í2/]]í]Ä]]]q9/993ýÆ]10]%2>54.'".'#".54>77!-JoK&$2%TSL;# 8NX )-) )D1Z£á‡q²{@\Ïr÷$G±;g‹P:aRH!#3F_}P=^A!]þÊ6gnwE„ÎKBuŸ\†ÅŽ_8Ÿ¾ÿìçM9m@E   1/1?1O1117Ð##;°;7G,H/?O¯12R$'11'RO ?í?í9/9í99/]Ôíí]Ö]Î9/]910]]]%267#".54>?.54>32.#"3"ÎY•E€.brˆS\’f60UwG'D4?s£dEucQÀ#gB"A1.Ql?E‰mCOªO=—+B.0TrBCeG) '9J,IoJ%3Q:T?81$'6"¯!F?;K1þn@Ì6P@6% %H0.P`/?85H/'?'O'''¯'¿''4/5Q6/?í22/]íÄÖ]]2Ö]í10]]]'>54.'.54>?#!7@"J¥¡“pC;W97gP0-;#™ 'F_8>nR0>k£¯T !#! þÉ%̽@’›£¢žJ'3&(:Q;1aYO a%)-)!,FeIZ´°ª •C½%þWM)»@k  KPà 0P`ÀÐ+"K0Oÿ"'P'XYX+?3?3?39?9í999///]q/+<‡+}ćÀÀÄ]qrqF·*(* +</+<+H‡+}Ä10]]!>54&#"!64'!3>32ÑþéÈ LL/^Q= tþæ¥ IZoE˜š1.-)ûÊü..) ?B(Ji@ý¢SDy*01/*J8 ’lÿìLÌ#/v@T('   )*H--P-`--Ð-à--1O1HP`ÐàO))Q $Q?í?í9/í/]í]Ô]í910]]]]]]]]]2#".54672>7!"!>54&ß¹´%o”¼rR„^3I$*MD;þ… $2â*LD9z MÌéß@¤[¾þì²U;x³x:“Pvoú×-mºA…/CZ7p+k³ˆ;{.~oC :ˆ@< 0 Ðð¯€/ K  O o  ÿ  @$'Hð  ¸ÿÀ@H  XYX+??99/+q+]q/F·(   +</+<+H‡+Á‡}Ä]]]q10%!.5467!`*þÔ ¥§‘V;E'>Nü©0%Ò: ´@n    RK    KOÿ  O  P ` €    XYX/ ]+?3?29Ö]]Æ83/]//+<Á‡+Á‡}ćÀÀ9]‡+}Ä+‡ÄÄ10]]]]!!!! ñ¾°EþçÓfù.þ*·qþº:ý÷ þ2ý”ÿ¤î!|@QK I! RK!!!F%•O##   /?OP?2?í0/]]3]]Ö]9]]33‡+‡+ÄÀ]]]]10]]).5!'.#"'>32îþä/ +12þ÷þΦ #. 2!f9QoK.ÎKRLQXVþSüIE\7 À +\ŽbÿÑþX¹:*æ@Y##$%"#$#%K"#""#""""O""P""À"",¯,p,# Kÿ@$H 0P`¸ÿÀ@H" % #P XYX+??í???3999/+]+]/F·+(+ +</+<+HÁ‡+}ćÀÀ/]]Ä]q]qF·+(#""+ +</+<+H‡+Á‡}ÄÀ10]]!>7##"&'#!!32>7!ã9‰V9OIþè#vAM2YI6p£  ,56ci0*þ…âý£!<LY-QsFBü¸"IC6i_:{@: G_oP`P`p°Ð RK’¸ÿÈ@ HOÐ?3?33/]q3+]Á‡+}Ä+‡Ä]qrÔ]qí10%>54&'!!!éN}W/ " -OlŠGþõ³ï_¬¬µg#:8"T§¦£ž›J:1þp÷ÌF‚@V ;; 0, ,  ?93. $HP``HH90E@EEH/.?.O...¯.¿..4 O EQF /?í29/í9/]íÔ]ÖíÖ]Ö]í9/9910]]]]]]]]'>54.'.54>75.54>?+7÷$Q‘nA/Ne7%gµ†N5U>2bM0-:™-!;R29oY7DŒÓ;fJ*6Zs< EQLL&̹ 5P:.:$¿ )JsU'7)"%:U?0^XP"`)D)!-" +FiLX¦‰d!8O2?"7>3!#32>7#".5467r;?C"þá"GD>'K?1',56s%éo.-  498>[;k||‚Úº JL£¸Ô}„ Æ ¾ýÍ!2,· #?X5A)ÿÑþW™O+›@9 GP'' '°''--Kÿ@$H 0P`¸ÿÀ@H"O OXYX+?í?99í99?3/]+]+]/F·,(, +</+<+H‡+}ćÀÀ]Ô]í10]]2#"&'#!>"32>54.ÍgªyBKŒÆ{jˆ/SþÚÃUˆÁs6V@-2&sBChH%2DO>w°r‰î°eGB7 þWîvÀ‰KÂ.W}Oþæ6>L€¨[GgB Lþn=O5P@6 4- -%H`€7p7HP/`////?/O//* O?í/99/]]í]Ö]Öí10]]]]2.#"'>54.'.54>ç|¨2¢&0:":fTB-8^F8u_=-0('>ZD3^UJ a ")/(!6MgGE§«¡}L@ÿì:3J@3,,HP%% %/%?%%55051Gà/?O)O  O?í?í/]]í]Ô]]ýÄ10]]".5467>3!#".''2>54&'#"s¯v<  ‘Êõ…J%† -67"Lœì€YyJ GFƒlOk>p a$T(Äw4¾DLT.~ߦaÀH³lFs/#O_#?x†9ÿìœ:(@_  +(K(((*'J'*J*JK'(''(''''' '@'P'`'à'(''(O(O XYX@* ***]]]]+?í2?í99//]]F·)(('') +</+<+H‡+}Ä]]]]]10]]]"7>3!!32>7#".54677'OE5'+25…%þím.-  498>[;k| Æ ¾ýÍ!2,· #?X5A)fÿìd:'r@9  H))?)K'&''&&&'O&&&&&&'P'XYX+?22?í99/]]/F·(('&&( +</+<+H‡+}Ä]Ô]í10]]32>54&'!#".54>7tRV>\B) =`…­lcœm:v:ý¿!RN^2Wt„ŒCl–-2‘Xgʶ›q@+X†\))% U@þWcR#3@µ,#))!!!P5?5/H)%H°À)  ! * ))+)F)V)<)!+!F!V!7>">54.Rƒ[1Y©õOîNZ™o>M‘Ó†AiK(^[h&Éš/& heŠT$ &P7fY¬þñ»eþi•Bu¥gæ¨k³Y„¨^vŠÆÌ®8W?ýë [‘½l/Q;"ÿLþWÎP$!@>  à t Ä  ¸ÿà@!H{› %Hï{Ë Ht”¸ÿà@\%H[T  RM R N  &!?O  ! Ð  &  P@&Ÿ&]]?í?3?399Æ]/]ÆÆ]]9]‡+‡+ć+‡+Ä]]+r+]rq+r+]rq‡ÀÀ‡ÀÀ‡ÀÀ‡ÀÀ10]]]]]]]]2>7!!!'.#"7>16RDóLb8 bþW <"@‰!!  K0@KPÏ " "M!!! 0P`pÀÐ $#  O"!XYX`$]+?3Æ2?3?í2399999/]/F·#(!# +</+<+H‡+}ÄÀÀ‡ÀÀÄ]]/F·#(# +</+<+H‡+}ÄÄ]/F·#(# +</+<+H‡+}Ä10]]]%>7!!$467!!FMjI-vyW’×™OþýOþC ep1P:â° GqQ`ý}´t8þk•y*c/ý¹7-M8!‹7ÿìhOG¿@$88/ /”¤”G¤G*F*E&EGEFGF¸@HEFEFEEE E@E EEE=GP IF=GÐ1à1/1?1O1111EFFBO!,7Q66XYX+?3í2?3í29/9/]]í/Ô]í9]]F·H(FEEH +</+<+HÁ‡+Á‡}Ä9]]]]10]]]32>7>54&'7#".'##".54>7326?!Ç "2!5P:)Y^6hžj6b†¥^FgI. I]sEX‡]0S¡ì™ Œ§# #7&Sm1íH%%B2.V|N$C fоV}™R'O&€¾~>%Eb>>cE$9mŸe‰ðºw¸½›*M#0P9 ž‹âÿÿCŠ&†iÉ@ &‚ %+55+55ÿÿfÿìdŠ&’iò@ (&n,*!%+55+55ÿÿ?ÿì¡ä&RTñ@ .&Ü.1 %+5+5ÿÿfÿìdä&’TÃ@ (&¹(+!%+5+5ÿÿ7ÿìhä&–Tß@ H&ëHK1%+5+5ÿÿ$‰Õ&(i«K@  &¶%+55+55‘ÿì±5~@K¶5¶4/ [@&&&&7.///\0101/10¯0 0P010.)_3_01_3lmX+?í2??í9/í22//]q]/+<Á‡+}ćÀÀÔ]]í9/10]]]>32#".'732>7>54&#"!!7!A'g{ŒKÃÐ KwªzIu\Fá"-:&.@.  s|6mf[#þÙæþ9,¶,þ°$•œ396²n2-C*£'!A`@@GI  ýkääÿÿ$5&­›q@ & %+5+5dÿìß–/H@) **+1[`_%_ %_?í?í9/í/]qí2Æ2]9/Æ2]10]".54>32.#"!!32>7Çç–I4c¸Ý‰ÇŠRþî 1LjD^œyW-ýí*S{RN€gOã+x¢Ð\Ÿ×{|à¿›l;@lŽNG,SA'4`ˆUäT†^2*H]3uLˆe;ÿÿÿìA–6ÿÿ$\,ÿÿ$LÕ&,iK@ &±%+55+55ÿÿÿì–-ÿ…ÿðr&1š@[ \#$##$$# &1'%%''\   -/?O[---3%$  #$'_ 1_&&$` `$lmX+?í?í9/í?í9933Ô]]í/]q9///+<‡+}ćÀÀ99‡+}Ä10]2#!!#"&'732>7! !2>54&#!}n¸…JTŸäý0áþ¢t6ZUTaqH$>0$ *-2?N2ŸŠmx‡EoN*|‰þžP2b^o­u=þ¤ ø¹O" ÷8b›Ú“ÙýÏý–5O5Y[%!¬@g! \   O  @H  \0@P¯[#! `_  lmX+?3?33í9/33í22Ô]]í//]q/+<‡+}ćÀÀ9/+]//+<‡+}ÄÀÀ‡ÀÀ10]2#!!!!!! !2>54&#!n¸…JTŸäýuþ-vþÚ'mÓm'mx8EoN*|‰þíP2b^o­u=\ý¤ýÏ1ýÏý–5O5Y[‘Zp@C¶¶[!\¯ P_  _lmX+?í2?39/í22//]q]/+<‡+}ćÄÄÔ]í10]]]]>32!>54&#"!!7!!A(Ybl;ÃÌ QþäP hrU«EƒþÙæþ9,¶,þ8^»» V$þ_žD!X^ ý_ääÿÿ$`&´›¬¹!ÿ€³ÞÞH!¸ÿÀ³ÝÝH!¸ÿ€³ÜÜH!¸ÿÀ³ÛÛH!¸ÿ€³ÚÚH!¸ÿ€³ÙÙH!¸ÿÀ³ØØH!¸ÿ€³××H!¸ÿÀ³ÖÖH!¸ÿ€³ÕÕH!¸ÿ€³ÔÔH!¸ÿÀ³ÓÓH!¸ÿ€³ÒÒH!¸ÿ€³ÑÑH!¸ÿÀ³ÐÐH!¸ÿ€³ÏÏH!¸ÿÀ³ÎÎH!¸ÿ€³ÍÍH!¸ÿ€³ÌÌH!¸ÿÀ³ËËH!¸ÿ€³ÊÊH!¸ÿÀ³ÉÉH!¸ÿÀ³ÈÈH!¸ÿ€³ÇÇH!¸ÿÀ³ÆÆH!¸ÿ€³ÅÅH!¸ÿ€³ÄÄH!¸ÿÀ³ÃÃH!¸ÿ€³ÂÂH!¸ÿÀ³ÁÁH!¸ÿÀ³ÀÀH!¸ÿ€³¿¿H!¸ÿÀ³¾¾H!¸ÿ€³½½H!¸ÿÀ³¼¼H!¸ÿÀ³»»H!¸ÿ€³ººH!¸ÿÀ³¹¹H!¸ÿÀ³¸¸H!¸ÿÀ³··H!¸ÿÀ³¶¶H!¸ÿ€³µµH!¸ÿÀ³´´H!¸ÿÀ³³³H!¸ÿ€³²²H!¸ÿÀ³±±H!¸ÿÀ³°°H!¸ÿÀ³¯¯H!¸ÿÀ³®®H!¸ÿ€³­­H!¸ÿÀ³¬¬H!¸ÿÀ³««H!¸ÿÀ³ªªH!¸ÿÀ³©©H!¸ÿ€³¨¨H!¸ÿÀ³§§H!¸ÿÀ³¦¦H!¸ÿ€³¥¥H!¸ÿÀ³¤¤H!¸ÿÀ³££H!¸ÿÀ³¢¢H!¸ÿÀ³¡¡H!¸ÿ€³  H!¸ÿÀ³ŸŸH!¸ÿÀ³žžH!¸ÿÀ³H!¸ÿÀ³œœH!¸ÿÀ³››H!¸ÿÀ³ššH!¸ÿÀ³™™H!¸ÿ€³˜˜H!¸ÿÀ³——H!¸ÿÀ³––H!¸ÿÀ³••H!¸ÿÀ³””H!¸ÿÀ³““H!¸ÿÀ³’’H!¸ÿÀ³‘‘H!¸ÿÀ³H!¸ÿÀ³H!¸ÿÀ³ŽŽH!¸ÿÀ³H!¸ÿÀ³ŒŒH!¸ÿÀ³‹‹H!¸ÿÀ³ŠŠH!¸ÿÀ³‰‰H!¸ÿÀ³ˆˆH!¸ÿÀ³‡‡H!¸ÿÀ³††H!¸ÿÀ³……H!¸ÿÀ³„„H!¸ÿÀ³‚‚H!¸ÿÀ³H!¸ÿÀ³€€H!¸ÿÀ³H!¸ÿÀ³~~H!¸ÿÀ³}}H!¸ÿÀ³||H!¸ÿÀ³{{H!¸ÿÀ³zzH!¸ÿÀ³yyH!¸ÿÀ³xxH!¸ÿÀ³wwH!¸ÿÀ³uuH!¸ÿÀ³ttH!¸ÿÀ³ssH!¸ÿÀ³rrH!¸ÿÀ³qqH!¸ÿÀ³ppH!¸ÿÀ³ooH!¸ÿÀ³mmH!¸ÿÀ³llH!¸ÿÀ³kkH!¸ÿÀ³jjH!¸ÿÀ³hhH!¸ÿÀ³ggH!¸ÿÀ³eeH!¸ÿÀ³ddH!¸ÿÀ³ccH!¸ÿÀ³bbH!¸ÿÀ³``H!¸ÿÀ³__H!¸ÿÀ³]]H!¸ÿÀ³[[H!¸ÿÀ³ZZH!¸ÿÀ³XXH!¸ÿÀ³WWH!¸ÿÀ³VVH!¸ÿÀ³UUH!¸ÿÀ³SSH!¸ÿÀ³RRH!¸ÿÀ³PPH!¸ÿÀ³NNH!¸ÿÀ³MMH!¸ÿÀ³KKH!¸ÿÀ³JJH!¸ÿÀ³HHH!¸ÿÀ³FFH!¸ÿÀ³EEH!¸ÿÀ³CCH!¸ÿÀ³@@H!¸ÿÀ³>>H!¸ÿÀ³;;H!¸ÿÀ³88H!¸ÿÀ³66H!¸ÿÀ³33H!¸ÿÀ³..H!¸ÿÀ³++H!¸ÿÀ³))H!¸ÿÀ³&&H!¸ÿÀ³!!H!¸ÿÀ³H!¸ÿÀ³H!¸ÿÀ³H!¸ÿÀ@ H!@ H&¸´ %+5+5++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ÿÿ7ÿìíG&½—ÝJ@ &y'%+5+5#þhâ Û@r c   \ P Ðà \@P¯` lmXP  ]]+?3/?3í2//]q/+<‡+}ÄÄ]q/F· ( +</+<+H‡+}Ä9/]/F· ( +</+<+HÁ‡+}Ä10]]!!!!!®Oþ&'âiâþîþ'Oþh˜ûsúþhÿÿÿÖ3$$Zm@D   [0\   0 @ P   ¯  __ _ lmX+?í?í9/í/]q//+<‡+}ćÀÀ]Ô]]ýÄ10]2#!!! !2>54&#!en¸…JTŸäý0#,ýAx‡EoN*|‰þžP2b^o­u=ãþ²ý–5O5Y[ÿÿ${%$5l@8P`/?\0@P¯_lmX+??í/]q/F·( +</+<+HÁ‡+}Ä3/]]10]!!5,ý'åþÙäûd€ÿoþh’Ò@|  ô  ^\ 0P`p ``lmXO]+?3í2/3?í2299/]3Ä]/F·( +</+<+H‡+}Ä39]3‡+}Ä]]]]qq10]]]]%3#!#3>7!!°¹úOüxOù›.^\T$”þ³þúMHNT,ôýt˜þhŒ> ºÍk½ûs™ê^À³ >ÿÿ$‰(ÿªÆ-@² )9I%5E•¥&6F'&&^%$%%$bc  b  $',/%%%-  €?O,----^¯0  $' ,a %&- lmX/]+?3?29/3í2999//]q]/+<‡+}ÄÀÀ‡ÀÀ3/]]Æ93/]Æ9]]‡+}ć+}ć+}ć+}Ä]]]10]!"&'!.'!3!2>7!!#·v@þ*þÅX  ¬"}!4//tt5DY>ÿ6þ¼>90/þÎà %('v]ý† 0?H$—þ¼Vk<Wý©?jODþi$G=- üô€ ý£ÿìø•:c@:16[,[<!!!"!_'1 _' _?í?9/í99í9/]3]]Æ2]]Ô]íÌ9/í910".'%32>54&+732>54&#"%>32M~¼†W 5MfD;gK+‘—;-;J{Z2h_x 0ÿ'o•¿vq¯v=0[Q7_F(H“à8fW[:]A#3S;R`ã4U=IYwoKaŒ[,3Z|IP}\<1Mg?b¢s@$äœ@(   R R ^    P Ð  ¸ÿÀ@3H  ^0@P¯   lmX+?22?339//]q/+<Á‡+}Ä/Ä+]/+<Á‡+}Ä+‡ÄÄ+‡ÄÄ10]3!!!>767$Ÿ  9Lþîþú¢ üÌüÍ2b'.*Fú?(X&,,ûÃÿÿ$äG&²—J@ &²# %+5+5$`¬@lRb  R\  0@  Ð?\0@P¯  a lmX+?222?3339/9í9//]q/+<‡+}ćÀÀ]]Ö]Ö]9‡++ć++Ä10]!2>7!!#!5't9H^? 4þ±"A9.>þÇð $('vþÛý©?gNIþW*H7& ý€ ý£ÿ…ÿð¢n@?^\ 0@ @ H  `` lmX+?í?3í299?//+Äq93/+<Á‡+}ć+}Ä10!#"&'732>7!!Vþit6ZUTaqH$>0$ *-2?N2Ÿ¸þîþäþ¤ ø¹O" ÷8b›Ú“Ùúÿÿ$Î0ÿÿ$ê+ÿÿdÿì–2$ä~@L\\0@P¯ 0@ `lmXP ]+?3?2í2Äq///]q/+<Á‡+}Ä/+<Á‡+}Ä10]]!!!!µãý”ãþÛ¯þîûsúÿÿ$Y3ÿÿdÿìß–&ÿÿ‘s77ÿìí¢@l£ 0R^Rc O/?O¿ÏP`  `?í?333999/]]Æ]]]Ö]9‡++ć++ćÀ10]]]]]#"&'732>?! ! 9ip‚SJw-v"E'#??@$þ‰)®5>UT*, æ.K7%¤ýX¨Nÿõ8‹ *7Ë@y++[ # #0#@#`# #°#À#à###1[/?O¿Ï )**+7 * *^  *  @ P ` € À Ð ð    7a) +almX`9]+?Ý2í2?Ý2í2//]]F·8( 8 +</+<+HÁ‡+Á‡}ÄÀÀÀÀ‡ÀÀÀÀ3/]í3/]qí10]32>54.#7#".54>;7!32+#"; R†`5:V8ýü&6g©zC`°ûš/-u±x=Z¬ùŸ;&@P‡b77S8,ýq4e’]:aE'ûÙÇBzªi™å˜LžžH~«cŽàœSÇ'._“f7aH)ÿÿÿ¢¼;$þh³ ¨@:   \\°àð¸ÿÀ@% H 0@P¯ `lmX+?3/?í22//]qÄ+]q//+<‡+}ÄF· ( +</+<+H‡+}Ä310]]]!!!!3Oûº'â9ââÃþh˜ûsûsýt±Í @R  \ 0\   ¯   _  lmX+?3?9/3í299//]F·(   +</+<+H‡+}ÄÄqq//+<Á‡+}ÄÀÀ]]10]!#"&5467!3267!”k*`kt?Ï× QPv}\¹K‚'þî#û N$¡þbAba ¡ú$ø ó@I    \   \ÿ 0à0p ¸ÿÀ@;$H\0@P¯`  lmX0  ]]+?3?2í2//]q/+<‡+}ÄÆ/+]q]qF· ( +</+<+H‡+}Ä+æ/F· (  +</+<+H‡+}Ä10_^]]]3!!!!!$âÀââÀâþîûsûsú$þhÈÿ@‘      \    \ÏÿP 0p€à \0@P¯ ` lmX0]]+?3?/í2//]q/+<‡+}ÄÆ/]qr]qF·( +</+<+H‡+}Ä+æ/F·(   +</+<+H‡+}Ä310_^]]]]!!!!!!30Où¥â¨ââ¨âãÄþh˜ûsûsûsýt•…K@)[\   __  _lmX+?í?í9/í///+<‡+}ćÀÀÔ]í102#!!7! !2>54&#!n¸…JTŸäýXåþ9,îmx_EoN*|‰þÆP2b^o­u=äýÏý–5O5Y[$#–@\[ \ 0\0@P¯__lmX+?3?33í9/í//]q/+<‡+}ćÀÀÄ/qq/+<‡+}Ä9/í10]]!! 2#!! !2>54&#!ê'þîüTn¸…JTŸäý0'mx‡EoN*|‰þžúP2b^o­u=ýÏý–5O5Y[$Zh@A  [ \   0 @ P   ¯  _ _  lmX0]+?3?í9/í//]q/+<‡+}ćÀÀÔ]]í10]2#!! !2>54&#!en¸…JTŸäý0'mx‡EoN*|‰þžP2b^o­u=ýÏý–5O5Y[*ÿ쟖-|@S[o   0 P `  /p/(()ð/?O¯¿Ï(#__ #_?í?í9/í99/]]3]]Æ2]]Ô]q]qí39/102#".'%32>7!7!>54&#"'>N”Þ•JoÒþÑÀÁŒ[:QlGbšrMýÑ-"­¢Q`Añ't¢Ô–Q•Ï~¿þ»í†=l”W_"32>7>54.¤ŠÛ˜P ƒÃý–Ú”LàvþÚ'mÖ$…¼î{_•mH `•nH*Op–Q—Ö…1i0š÷®^WÚƒý¤ýτטSé@x¯o%K"¸¹Az­l$R]Š].ÿÔù}@Ic \ 0 [?O¿Ï __  lmX+?222?í9/í29/Ö]í/Äqq/+<‡+}ÄÀÀ9‡+}Ä10#.54>3!!! !"3!,Ü'VH.RœâÜþîþÙhþœþe}þwCrR/7R4”P=[{Lt©p6úýéœ3XC(E3ÿÿ ÿì7ND]ÿì!ÞFV@8 88 +@G HÐHPHðH6HP`6 O;;,+O?í?Í9/í9/]í9]qÔ]qýÆ10]]%2>7>54.#"".547>7>7>32D5`O;5J.5bS=!8M%m²~D$v´þ¬Btjc1-c»i[qWD3#UmŠXj¢o9oŬBrW$@?[;>mW :CdB ÀC„ƃk¼õšU  ë  '<^‰aCgE$9lšaJO„·q2'ÿì¡D(5²@e   5 G$G,P,, ,°,,7p75(444K 0Oÿ4/5!(R55!/R!QXYX+?í?99í9/í999/]q/F·6(6 +</+<+H‡+}ćÀÀ]Ô]qíÔí910]]]]]]#"$'>3232654&+72654&#"¡0Ne50U?%Uš×‚†þüxt^Áyk©u>üÃ/u0Švƒ¾Ñ‰SU)SH8 A@]A( $9O2Z‚U)k{¬l1#B`ý: LU?G¨PI3232>7#".54>7>54.D3J7%éEo£tu¤h/5f–bXR&ij;X@+ëQ|ªoŒµi):p¦lbt=+H 6(0BiI'/Pj$8(8BgH&7Zu>PrS<" $!<ÿì¨Ì0GY@=H 999pP °IPI€IEG$/$?$O$$$?Q,,1OQ?í?í9/í/]]Ä]í]Ô]q2]í10>54.#"'>32#".5>7>322>7>54.#"–4Yt@00,:8?@ŽÞ™P"oÈxu³z>d‡¤Y7gWDþ¶Qh@" 1TA<]F1 j}'Y}N$ «  Oœëœ©™Ø‰>Aw§e@ ·v8'6ý =c|?;+R?&$NyU@:n€ÿÿ?ÿì:NHÿ¤::'g@=+"$"Ë""­"ŸŸŸ' „ÄÔŸ P  P  ¸@  ¸@ "!!¸@3  N  "%%&&''¥&¥&&¸@Y'''Ð''' P€)  ð"  %R»Ë/ '&!   XYX@)]+?3?39/]]3í29/]qqÆÖ]Æ/9/]/+<‡+}Ä]]‡ÀÀ‡ÀÀ99‡+Á‡}ć+}ć+}ć+Á‡}Ä]]]]q]]]]]q10]]]"&'!.'!3>7!!##c7þÈþض%’V,)%\ü\%0D5¹þã*BÔþëš:Wü¿þ6;B6yþÿKV+ Úþ& *UKþ|8<ýÌÊþA ÿìëN9u@L77((/5G 0*H 0@ÀÐ;@;`; R%/ R% Q?í?9/í99í9]/Æ]Ô]qíÄ]9/í910]]]"&'732>54H>54&#"'>32ÀºÞü1D,&C2ˆ}BsV2UG<4) èSu•X\“h7:Xk12U>#A|´ •,%=+%:*QD± #?29: 8+PsI#&E_9EgG&&7!!#!÷[  )2!«þò%!ÒþèŽ Wþæ:þ0 -E1þƒ+ýÈÊþAÿ®ÿìÖ:„@N&&MK?O OO XYX+??í?3í299//]]Ä]/+<Á‡+}Ä99‡+}Ä]]10]]]!!#".'732>7!é®þå=`SNUeA)*% $ $018JaB Ó|¸þêˆP!ºF~É ÅûÆ#Ã:"@V JEy‰Kv†E F  R*:ZšH*:ZšH¸@*PÀÐ  R%5U•¸ÿè@ H% 5 U •  ¸ÿèµH ¸@.Oÿ XYX€ ° ]]+?3?399//]/+<‡+}Ä+]+]+‡ÄÄ]q//+<‡+}Ä+]+]+‡Ä933]10]]]]]]]]]!>7##!>7!úˆþ3Õb ˆöÓl=H*vÓºCIGüC»GF@ýF:ýÏ RUO?W2ûÆ#­: ™@_KOÀ  _ ¯  K   O  ÿ  O  XYX+?333?3339/]q3í2//]//+<‡+}ćÀÀ]Ä]q/+<‡+}ÄÀÀ10]!!!!!TƒTÓþæZþ}ZþæÓ:þT¬ûÆÏþ1:ÿÿ?ÿì¡MR#¿:j@?KÀ KOÿOXYX+?333?3í2//]//+<‡+}ÄÄ]/+<‡+}Ä10]]!!!¿Óþæ®þk®þæÓ:ûÆ|ü„:ÿÿÿÓþW¡NSÿÿ?ÿìUNFÿÿ#ÈMPÿÿÿ«þWÈ:\?þWÔÌ@Vlí@‘ZZ77  /\,\,#I ,K+++ 0P`p Ðð 9GjPjj jjnTGÐà/?O_IAL#/ bAOWLO4,+XYXðn nÐnPn]q]]+?3?3?ÄýÄ?ÄýÄ999/]]íÔ]í9/]]/F·m(+m +</+<+H‡+}ÄÀÀÀ9‡ÀÀÀ10]]]]"&'!>7##".5467>323>733>32%2>7>54&#""32>7>54&êu“sþûT "GQ\7JsN) \z”R>]F2  ûV EP\8KuP) St—ü±/TG7LP/QB2 Cp/SF6 cP-J;- Dh^ý¥°!Q*/E.7aˆQ-m?Ì‚<0L5 =Tbe_K2þA|1G/2\ƒQ;s:ŽË‚=À!Q‰h,L!pvN…g4Y&btß!Pˆh,L!pt N…d3Y&jkÿÿÿ¦¸:[Uþh¿:0÷@ˆ0 ))  !K?OoÀÐ2K0/0/0//0/Ï/ÿ/O///ÿ// //O!/'0 P'XYX`202]]+??í?39999í///]]qr/F·1(0//1 +</+<+HÁ‡+}ÄÄ]q]F·1(1 +</+<+H‡+Á‡}ÄÀÀ310]]]]]32>7!3##4>7##"&54>7v LL/_Q< v1$–tõO¦HZpE˜š:ý­..(?B(Ji@^¢ùº‚+eýª˜,9;*J8 ’Š.-* j€:ª@\  K  KOÀ!@!`!@H  P XYX+?3?39/í2399//+/]Ä]qF· ( +</+<+H‡+}Ä/+<‡+}ÄÀÀ10]]]]32>7!!#".5467ÔGAA!<<@%aÓþçQ!LWd97!32>7!!4>7##"&'#"&5467!ó-QA/ w{~.PB/ v¦ þð AM_<| FTgAŠ“ €z¾(KiA_ý…%&! y)KkA\ü­"KC0,9;/L5wq1U?#’Š$Z&ý$&$yUþh:?\@Ä 33   .123405:.0//K.-..----?-O-Ÿ-- -p-- -`-€-°-à--..! K?O p `ÀKOÿ`p À30O5!-(:(P5 ./XYX€APA]]+?3??2í299í///]q]F·@(@ +</+<+H‡+}Ä3//]q]qF·@(@ +</+<+H‡+}Ä33//]q]qF·@(.--@ +</+<+H‡+}ÄÀÀ310]]]]]]"&'#"&5467!32>7!32>7!3##4>7#î| FTgAŠ“ €z{-QA/ w{~.PB/ v®ºuõPÏ AM_wq1U?#’Š$Z&ý$&$y(KiA_ý…%&! y)KkA\ü„ýª˜,9;/L5Mÿì0:u@8 GÐ!  K   R  O RXYX+?í?í9/í33//F· (  +</+<+H‡+}ćÀÀÔ]í10]]]#"&'!7!3232654&+0M’Ѓ‚ûs©þ–'‚U¿h«zCý277Šzhu°S\‡Y+g¾þMHvþÿ^RHJ&ÿì±:!¿@k     G 0€KÀ#/##!K 0Oÿ!RRXYX+?3?í?329/í///]qF·"(" +</+<+H‡+}ćÀÀ]]Ä]/+<Á‡+}Ä3/]í10]]]!!32#"&'32654&+ÅÓÓü0U¿h«zCM’Ѓ‚ûsÎh277Šzhu°:ûÆ:þMHvW\‡Y+%üo^RHJ&ÿìH:‚@E  GÐOK 0OÿRR XYX+?2?í239/í//]qF·( +</+<+H‡+}ćÀÀÔ]]í10]]32#"&'32654&+U¿h«zCM’Ѓ‚ûsÎh277Šzhu°:þMHvW\‡Y+%üo^RHJÿì*M-t@JG"P"" "°""/0/$(()$/O( ((%OO %Q?í?í9/í9]9]]/]3]Î2]]Ô]qí39/10]]2#".'%32>7!7!>54&#"%>i\£zH9[ƒ®nk¡rC #3?"9T<& þÄ%6XUQoþäU€«M,cžsL£Œk>7`‚L2H/&IhB¾#ffSUGxY2#ÿì©P7“@[3& +G/ ? O  GßP 9KOÿ#OO0OXYX+?í??9/í?í/]//+<Á‡+Á‡}ćÀÀÔ]qí9/]í910]]]]#".5<7#!!3>324.#"32>7>©_¨æ‡g¨xA×ZþæÓTÏm—¾nr®u<þÙ2G,)SK? 3F**RI> ®¤þú·a;q£h  þ1:þTi§t>8l›|B^;Bzd/U$Hb>Ayf3Wÿ£’:Æ@€  eH HeH HNKÀ @ ` G/?O¯R_oRXYX+?3?í9/]í22/]qÖí/]Ä]q/+<Á‡+}ÄÀÀ99]Á‡+}Ä++qq++qq10]] !.54>3!!#";Aþ¢þÀ@6#NÉ{çÓþæU^À6X>")=*гþM× -E[8e„MûƳØ$>/3%ÿÿ?ÿì:Š&Hiô@ 0&™42 %+55+55#þW…Ì?é@‰=5:;R;K  ß  À  A#&-" "RK!!!!Oÿ &@HR#   @H 2"! ;:-2P 202@22PXYX+?í?]í?39999?39/+]3í+2//]//+<‡++ÄÀÀ‡ÀÀÀÀÄ]qF·@(  @ +</+<+H‡++Ä10]]]]]]"&'732>7>54&#"!#737!!!3>32Š2V$ ! "0" z MK/^Q= nþæâ„!„8!þÇ IZoE˜šŽ 5TuþW ¼&>.g..) ?B(Ji@ýÊ—ª‹‹ªˆ10.*J8 ’Š.-)ýAlP,#éÞ T@/ €KO OÿŒOXYX+??íÞí//]Ä]/+<Á‡+}Ä9/Í10!!?!Á%þO®þæÓá÷þˆ:¾ü„:e +þì?ÿì_N.|@R  '',**P`0&,GÐà/?O%)O( !&&!OO ?í?í9/9]]]í9]]]/]]í2Ö]2]Î2]9/10]]%267#".5467>32.#"!!Sv V¬ot¬q8 M_ntw9kŸl;þä[Q2P?06%þË[­ig2O‚\2>qœ^(^-o£sI):cƒIZe@eF¾  xlÿÿÿì-KVÿÿ#VÌ&ñOÊY¹ ÿÀ³((H ¸ÿÀ³&&H ¸ÿÀ³##H ¸ÿÀ³""H ¸ÿÀ³H ¸ÿÀ@ H @H ¸ÿÀ@H @ H“%+5+++++++++ÿÿ#Š&ñiÊ@ &“%+55+55ÿÿÿ$þW\ÌMÿ®ÿìI:(5¶@a  M(&((&(&5))KGÐ1O117O&!(O(5R.(!O).R XYX+?3í2?í?39/íí299//]Ô]]í9/F·6(6 +</+<+H‡+}ćÀÀ99‡+}Ä10]]]]32#"&'!#".'732>732654&+U¿h«zCM’Ѓ‚ûs©þ¬=`SNUeA)*% $ $018JaB§277Šzhu°:þMHvW\‡Y+g¸þêˆP!ºF~É Åüo^RHJ%ÿìÇ:%Â@i  %KKOÿGÐ!O!!'%OR XYX+?2?3?3í29/33í22Ô]]í//]/+<‡+}ćÀÀ9//F·&(& +</+<+H‡+}ćÀÀ‡ÀÀ10]]]32#"&'!!!!32654&+U¿h«zCM’Ѓ‚ûsVþžZþæÓTbSh277Šzhu°:þMHvW\‡Y+ºþ1:þT¬üo^RHJÿÿ#…Ìçÿÿ$aÞ&Ôt?´&¸´ %+5+5ÿÿÿ«þWÈý&\—@ &&‘)5%%+5+5Uþh¿:/ú@‰/ ((€.!KO¿ÏßÿPÀ?O 1K/././../.Ï.ÿ.O...ÿ.. ...!&/ P&XYX+??í?3999/]Í//]]qr/F·0(/..0 +</+<+HÁ‡+}ÄÄ]]]qqrF·0(0 +</+<+H‡+Á‡}ÄÀ9/Í]10]]]#32>7!!4>7##"&54>7‘GõRYv LL/_Q< v¦ þôHZpE˜š8þ `rý­..(?B(Ji@^ü­"KC0,9;*J8 ’Š.-* $,v@; \0@P¯_lmX+??Æí/]q/F·( +</+<+H‡+Á‡}Ä3/]33310]]3!!âPú|ýåþÚ›ýûd€#ÒZ@4 KOÿ_XYX+??Æí/]//+<‡+Á‡}Ä3/]33310]3!!ÕOõtþD­þçÑ:˜ýªü„:ÿÿ–&:šA´/&¸ÿõ´03.%+5+5ÿÿc¦Þ&ZCM´*&¸ÿд+.)%+5+5ÿÿ–&:›à@ /&ª/2.%+5+5ÿÿc¦Þ&Zt&@ *&©*-)%+5+5ÿÿ–Õ&:i’K@ /&31.%+55+55ÿÿc¦Š&ZiÈ@ *&%.,)%+55+55ÿÿ¬ð&<š"´ &¸ÿâ´ %+5+5ÿÿÿ«þWÈÞ&\C:@ &&'*%%+5+58™o°/°ͰͰ/°Ö°Ͱ°Ö017!8//™ôô8™o°/°ͰͰ/°Ö°Ͱ°Ö017!8//™ôô,ÀB‹o@MPÀ/?OÏ º°`@ °p p9àr^]]]qqqqqrrrrrr^]/í/^]qrÆ]107!, ö ÀËËÿíÀ‹K@ñ +;KË º[Û‹K; ;+ûëÛ»«›‹k[K ¿¯Ÿo_O?/ÿïßÏ¿¯Ÿo_O?/ÿïßÏ¿¯Ÿo_O?/9ÿïßÏ¿¯rrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqq_qrrrrrrrrrrrr^]]]]]]]]]]]]qqq^]]]]]qq/í/^]Æ]107!&'ÀËËÿíÀ‹µ»/í10Æ/107!&'ÀËËÿÿÿˆþ!ÿT'BþúB·%+55½?QÀ@ÿ  Ÿ€ ž XYX–V‰vöƆF†FæÖ™fæÖ¶V ¹©9) ËöƆVF ùæÖ™‰ôæÖÄ´¦”„vfVF$™öæÖ¶¦”†vfF6&ôä@ïÖÄ´¦–†vdRB4$öäÔ° „p`PD0 iðàÔÄ´ ”€pdTD4ôäÔĤ”„tdT4 ôäÔİ ”„td@0 9ðÐÀ rrrr^]]]_]]]]]]]]]]]]qqqqqqqqqqqqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]_]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrr^]]]]]]]]]]]]]]]qqqqqqqrrrrrr^]]]]]^]]]]]]qqqqqqrr]]]]qqrrr+?Ö_]í910//]F·( +</+<+H‡+}ÔÆ]29107>733½& $.8 ·#?3$3?ÃCn\O##NRR(þû½?Q j@4  Ÿ  @ P 0 @ À Ð    ž XYX+?ýÆ]10//]]qF· (  +</+<+H‡+}ÄÆ]2910#>7#!+ $.8!¶Fk3¾Cm]N$H¥QÿîþÃQ@  Ÿ   ¸ÿÀ@H O   ž XYX+/íÄ]10//]+/+<‡+}ÄÆ]2910%#>7#!] $.7 ¹#@4%3 BCn]N##NRR(þ?U`@) Ÿ   0    ›XYX+?ýÆ910//]F·(  +</+<+H‡+}Ä2/]q3910##.54?U3*!¶&þü"B‚9/hBH^ý?ÿ¾@YŸ p 0€   Ÿ ž XYX+?Ö]í99332103//F·( +</+<+H‡+}ÔÆ]293//]]qF·( +</+<+H‡+}ÔÆ]29107>733!7>733i& %.9!¶#?3$3ý3& $.8 ·#?3$3?ÃCn\O##NRR(þûÃCn\O##NRR(þû½?ÿÂ@] o Ÿ   Ÿ ï  Ÿ@P0@ÀÐ   ž XYX+?ýÆ]33210//]]qF·( +</+<+H‡+}ÄÆ]293]q//F·(   +</+<+H‡+}ÄÆ]]2910#>7#!#>7#!Ù $/7!¸$@3$3þ, $.8!¶Fk3ÁDo]N$$NQS(ÀDo]N$H¥QÿöþÃ7@1  Ÿ   Ÿ¸ÿÀ@HO   ž XYX+/íÄ]33210//]+/+<‡+}ÄÆ]293///+<‡+}ÄÆ]2910%#>7#!#>7#! $.8 ¸#@3%3þ, $-8!¶#?3$3BCn]N##NRR(ÂCn]N##NRR(Õÿv]Ì q@ R¸@/Ï `€°  P ?/9/3í29/]qq3]]Á‡+Á‡+ÄÀÀ‡ÀÀ10#7!%í뛿þ¯(F-ÿeS(Àû¶JÌxþˆÌ2ÿsd̽@d   R¾ €Ÿ¿Ï   P  PXYX+?/99//3í293í2999//]q]F·( +</+<+HÁ‡+Á‡+ÄÀÀÀÀÀ‡ÀÀÀÀÀ10]]]73%% %%#7!þ§(N5×Uo(þœV"n(þž6×Vþ¥(OVÔÌdþœÌþÊþÍÌþœdÌ3Z}¤É@ÿ @P ` € à ð   /    y &æ¦VF&äÖ¶VÆvfVFÒ–†6&ͦVFäÖÆ¶vf¢æÖ†öͦ’„tdTD6"ôäÖÆ²¦”„vfVD4@$lÔÄ´¦–†dTF6&òàÐÄ´¤€pdP@4$ðàÔ”„td$;ÐÀ° rr_rr^]]]]]]]]]]qqqqqqqqqqqqqq_qrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqrrrrr^]]]]]]]qqqqqrrrr^]]]]]]^]]]]]qq^]]qqqr/Í^]+/_^]q]í10]]]]#".54>32¤/Pk=, øéÚ˼­Ÿ†YK2$9ð仯_rrrr_^]]]]]]]]]_]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrr+rr^]]]]]]+]]]]]]]]+qqqqqqqq+qqqqqqrrr+rrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqrrrrrrrrrrrrr^]]]]]]]]]]]]qqqq^]]]]qqqqqqqrrrrrrr]]]]]]]qqqrr??í??3í2ôíô2í2/]íôíÔ]]ýôíÖíôíÆÆ]]Á‡+Á‡}Ä102#".5467>"32>7654&2#".5467>"32>7654&%2#".5467>"32>7654&#3×2ZD' P_d*2W?$ L[a*.)#  E/*$ '/2ZD' P_d*2W?$ L[a*.)#  E/*$ 't2ZD' P_d*2W?$ L[a*.)#  E/*$ 'ú'Å>Ç‹:_DK&eI>_CI%i€Ey.SB+Hq.R@W>:5ý¶:_DK&eI>_CI%i€Ey.SB+Hq.R@W>:5y:_DK&eI>_CI%i€Ey.SB+Hq.R@W>:5ý±Ãz5(@[0@PPÐ/?Í/]]]qí10!Ã@2žzýùÿÿÃz&é¹ ÿÀ³H ¸ÿÀ²H++I‹‰ªN@4*ëëOëп`/í À/]ä/]]]]]]]íÝ]í9/í10]%73 ÀCïþ·¼‹iGo)þ’þŸ'!‹aª<@'%ëë@ë`/?Oí À/]ä/]qíÝ]í9/í10]#77¡Àþ½ïI¼ªþ—Gþ‘)na'ÿÿO´&-4@#@ Hï ¿  ÿïÏ¿O]]]]]]55]]55+ÿï®»Tµ/í/Æ10!5!»ý4Ì®¦þTY2@âÜ??Æ/Á‡+Á‡}Ä10]+3çÅ>Ç\ %\@4& &   à    %!àŸP'ä /Ô3íÄÔ]q2í2/]q3Á‡+Á‡}Ä2]]]10>54&#"#>533>32ÿJ*+=^D²c¦.8C*ZVO{-'$`[þ¡ÿ.("# . [T.þlÿÖñ„@N    \    0 @ P   ¯   wa almX+?í?99//í3í2//]q/+<Á‡+}ÄÀÀ‡ÀÀÀÀÖ]Ä10]]!!!!!#73!+M}(ýƒ%:þÆ3þä2»(±þtо•þþ•êÐÿÍ––4Ý@u  ! #$$4$$q44444Ÿ444/4440+,:J6$'#41 #w w/ 1't0/ u XYX+?í2]]?í299//]3í2]3í29999Ö2]Æ2/3//]qF·5(445 +</+<+H‡+}ÄÀÀÀÀ‡ÀÀÀÀ9/Ä10]]]#737#737>32.#"!!!!!267#!7>7Þ»¹·µBmkc‘b5õSG%:, þâþáyY˜_wá*ä«ý6']uü•p•t_“e50Sm<0TI.K8|•p•k"Zf'³¸Í&…i;ÿì{,dq @ÿbb GG 33'+k;kky$$NM`32E+*(y'7VpEˆE˜EE@ HEE;eqqy`p;; ;s*)(uee8eHeXexeˆeQxJx(J++(e(e(7x-xqulmX†sFs¶sfs6ssçs·s—swsgsswsgsWs4s%ss¦s—s‡sWsGs&s@ÿsös§s‡ss Ds6s#sssõsçs×sÇs·s¥s–s†susesTsFs6s&sssÊõsäsÕsÆs·s§s•s…susesVsGs6s'sssõsåsÖsÆsµs¦s–sƒsusesVsFs6s'sssösçs¸s–s…susfsWs8s'ssšõsæsÖsÉs©s™sŠsysisZsGs7sssõs@Ëæs×sÇs¶s§sšsŠs{sjsYsHs9s)ss sûsésÈs¸s©s‡sdsUsFs7ssjøs×sÇs˜svsgsUsFs7s'sss÷sÕsÆs¶s§s–s†sWs'sssösçsÆs·s¦s–s‡sws7s&sss:øsÓsÃs²s s_r_r_rrr^]]]]]]]]]]]]qqqqqqqqqqqrrrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqq^]]]]qqqqqqqrrrrrr]]]]]]qqqqrr+?í??í?í99//3Äí2í]qíÍ299Ô^]í//]/+<Á‡+}ćÀÀ99//+]í/]F·r(r +</+<+H‡+}ÄÀ‡ÀÀÆ2Æ23/í_]9910]]]]]#3267#"&547#7+#!23733".'732>54.'.54>32.#"32>54.+›“F&! F*jh I^JÙ•ˆkñ:e¦vA%E‡}/“÷O}Z7Ì PO&A06O4*QA(3`ŠX•¬Ï@@4'4H(*VF-9j˜ú©YHvR-#?Z6F†þ• %ž hW(-‚W`XýÛ/^bJlòòü¿:^D#<6" "7P9?]<y}04 !5N7JmG#ø BgF8N1ÿî½–9{@Q,))(( 4/4?4O44;o!/!?!O!!"w# #(w))))/)#)#)s/s?í?í99//]3í23í2/]íÖ]Æ10]]]]]]]"!!!!3267#".5#73>7#73>32.#"KH@(þÓ 6þÐXLE`óJkZZ£|I ~ †*{œ¶ddˆU(þÿ&2º=uc•:•% }uC=(EpP,1yÌš•9•“Æx20SmXWVYXYV¸WXWXVWYWYW,I´9µ,µ$´,´¿SS[¶ B¶'L¶4W¶Y??í??íÔíÔí99Ô]í/íôÎôí99//Á‡+Á‡}Ä10267#".547>32.#"%2#".5467>"32>7654&#3ÈAO¸=ZwKPuM%\w‡CKlF!¿1;Of 6 ?pU1 cw|5>lO. _ry4:3+ ,*:5-2üÅ>DzSC&@gH&2YzGDKƒ¥^#*Je; ?K’-M MOÀ IvU%]0~ ["$MxT%[.ƒ W—9gT5Y%IE9fPmMJAý%$ÿì*•5D§@U 4400 ##%; oBF< ; 0)(; q(1((1((1(  ( );<610<06- )-u,,t 6vXYX+?í?í9/í99999999//F·E(1((E +</+<+H‡+}ÄÀÀ‡ÀÀÔí]]10]]]]232>73#".546?7>7>">7>54&æMxS,b–Åw"90(?4-’.9GZpFHmJ%#F#%#J!K 9h¡c.!Btš0•%Db<##b™|c,°0<<5P53g_S=#)LlC5b  à  †D„h@©(6þ°,§x  2:* )C5@N$ 3CS  <L\/ / y Ry¸ÿÀ@ H"   R y   ¸ÿÀ@H  7p"p* *0*€***¸ÿÀ@/H*E 73 #".54>324.#"32>7>è!{!û¡ýâ¢ñ$& ŸòþîÖ@p™ZFqP,=m˜[™ Õ *4/& *0.(¦¦=,,&X(üÁûº*.'b23úÈi¨u?(KlDd¢r>“’)7" &E;3,;$#G@5¹@*2{@M  Å@  -2,/-/,Å/-O--Å4 -%+/Ê-0`404P4]]]?3í2/3Þí2/]íÆ+æ9/_^]í2910^]]#367>73#46767#.'&'%##5!_¦ø‹   ó¥ šƒ• þ´ó¢þÓ75-ýT8"''$=þ¸H=#')#7 ¢þ ö‹‹]Ø–9t@K 0(  ((0(@(`(p(€(?O((5[;€;"[5**''*_)_?í?3í22/3/]Öí]Ö]Öí99//]]q3310]]]]267>3!!>54.#"!5!2.54>œú®]/d›m; ý‹WvH 3a[[a3 JwXý„=oe/]®ú–Rœßf±™€3ä5+es„Ježl99lžeJ„se+þËä3€™²fß›RbÿÞ†H"/J@,@ #°#_#P#`#p##1€/Ð//) ?2]]Í?Í9/Í/Í]2Ü]qqÍ210".54>32!32>7.#"u‚ƆE,Lfv€?qÁŽQüÅ@NX.Kt]M"H$SnË;L]53WJ<"]Ìob }]<O’уþœ-# K@.OÐÀ°OZZZZ?555]]]5]]]]]555]]q5ÿÿ²ÿø$'^'–GýL•WS@4Ÿ_O/ŸOßPPPPP?555]]]]5]]]]555]]]]]5¢d^D@  €/Í/ÍÌ29910#.'5>73!;H:‚RR‚:H;Ý)"bADp*$*pDAb"VÿÃð@ @ €/ÍÌ299/Í105>73.'#Õ"bADp*$*pDAb"V ;H:‚RR‚:H;ü#¢d^D@  €/Í/ÝÌ29910.'3#>7!5;H:‚RR‚:H;ü#"bADp*$*pDAb"VÿÃð@ @ €/ÝÌ299/Í10%>7#.'53+"bADp*$*pDAb"V¢;H:‚RR‚:H;Ý¢d^D$@€@ €/Í/Ì299ÝÌ29910#.'5>73!.'3#>7;H:‚RR‚:H;þ;H:‚RR‚:H;)"bADp*$*pDAb""bADp*$*pDAb"ÿÃð&@@€@ €/Ì299ÝÌ299/Í105>73.'>7#.'5Õ"bADp*$*pDAb""bADp*$*pDAb" ;H:‚RR‚:H;ý;H:‚RR‚:H;ÿHð#(@#  /Ì299ÝÞÍÌ299/3Í210!!5>73.'>7#.'5àþ Å"bADp*$*pDAb""bADp*$*pDAb"hPX;H:‚RR‚:H;ý;H:‚RR‚:H;?ÿ综-CY@8+  %%.ªP`E:ª/?O3R?)%% O)?O ?í?í3/9/3í/]íÖ]í29/10]]]]#".54>3236454&#"7>32.#"32>»  Z}¡e^‚Q#,D`}NLzjo974-'kBn—^)þü)2)C5( "2 3WC/‹1iji0u¿‰J@mO;ˆˆ~a:VL,­¾ Í"\šÌþ‹$>-+F\a`(.L6Q†ª+¹C@(   _?í?9/3]]Æ]2]]93]3]1035!.'!+p‘þ ÏDתûVט/aR9:Sa-ýOàþWÞ$@H H/?O`/2?í/]íÔí10!!!ÄýCþÙþþW6ùÊ*øÖ¤þWb _@6c  c    __?í9/í9]99Æ]/]ÆÆ9/‡+‡}ć+‡}Ä105 5!! !¤\ý¸qýýÜKþW ,Ƙãýƒýä}9€@ ïÿ­²?í/]Æ105!}9àà|ÿçäT6@  //9/Í/Æ9]3310]]]]##5!3ê¨þò¸7Ûœºò¦ý…PQØvÄ#3EŸ@""  4'/¸µG>¸@K@ H$9³*C³/ ? O ? O  Ï ß  ðGÀG G€GpG`G@G0GGàGÐG°GG]]]]q]]]]]]]]/]q33í2/33í2/+íÖ]í9910]]]]#"&'#".54>32>32%"32>54..#"326v/VvHg¨AESa8FxV1/VxHg¥ACP_7K|X0þ¥);`GJ…e;p1T>"4`ŠUM†c9o€1T>#4a‰q`e^f5G))H5»/J35H*'G6_˜`Ç ³/Í/Í103!!˜^jû8Çû—^ÿþ­@ 0 ]]/Í/3/Í/Í104>32#4.#"Dz§bc©{Fg5_‚NN‚^4tÀŠLLŠÀtþb›l98lœdþÿþW¾Ï%3@"$$ !H ÐàP P?í?í/]qí10]]]".'532>54>32.#"+*%>$,<$4e–c(W?$,<%3e•þWÙ5H*aWc6 Û 6G'ûWc6DR7<&@ÿ 7)   @ H >8­7)­((#77,­4#­,­ ­  ­­T>>´>”>t>d>D>$>>"$>>Ïä>>ä>Ô>t>T>4>$>>>ô>à>Ô>À>´> >”>€>t>`>T>D>4>$>>>Ÿô>ä>Ô>À>°> >”>€>t>`>T>@>4>$>”>„>t>d>T>D>4>$>>>ô>@…ä>Ô>Ä>´>”>p>d>P>D>0>$>>>oô>ä>Ô>Ä>´>¤>T>4>>ô>Ô>„>d>D>4>$>>>ô>ä>Ô>Ä>´>¤>”>„>d>D>$>>?_^]]]]]]]]]]]]qqqqqqqqqrrrrrrrrr^]]]]]]]]]]]]]]qqqqqqqqqqrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqrr^]]^]]]]]]]^]q/íÔí9/9/ííÔíÔí9/9/ííÆ/+^]]3210_]]"&'&#"5>323267"&'.#"5>323267GK‘K„Y'C=:3ˆTP™J6n0D€4 =?F)H—HBm.'C=:3ˆTS L244D€4 =?Fô)/ !Õ'-,2*Ûþ)  Õ&..2*Û;%f+ò@ÿ    J Z EU +;  @ H­­ D Ä  ë+K[›@HD „ 4 T t „ ´ Ô  kÛ›‹[;»{[Kû»oO//?à Êÿß¿Ÿß¿€`@ÿïŸ_?š_@ @bÿß¿¯Ÿÿß €/jϯoO0pPO/ïßÏO/9аrr^]]]]]]qqqqqqrrrrrr^]]]]]]]qqqqqrrrr^]]]]]]]qqqqqqrrrrrr^]]]qq^]]]qqq_qqqrrr]qqqqqr/]q/+]qÍ]23í23í2Í2Ä2/+399//]33_]]‡ÀÀÀÀ‡ÀÀÀÀ10#7#5!!5!33!!ëÕÛG¦þZ…Óƒüþ—¦#þþÝJßþþßþ¶ÝdôGP +@ ® ®®/]í/í9/í/33/33105!5!5!dãüãüã¼””ý8””d””WY o@< R°R° /­0@/]/9=//í/]33/ÖÄÁ‡+‡+ÄÁ‡+Á‡+Ä3/10 5!WüÀ@ûþwAZãþèþéãþãßßWY s@?R°R°  /­0@/2/]39=/33/í/]Ä3/Æ22/Á‡+Á‡+ÄÁ‡+‡+Ä105 55!W?üÁûþããþ¦þ¿ý‰ßß7 #@i y iy/Í/Í/ÍÝÍ10]]3 %! ÍÍü¶úþƒþƒ{ýúý…RªþVd´Gò·¬®/í///í107!!dãü®´>’þT"ýšÒª¶  H ¸´ //ÍÍ/íÌ10+#47632#"'.'&#"µ“TR€?K3% !$ ýšVÄ{{?0(4 ''#iýšµª ¹ÿà´ H ¸´//ÍÍ/ýÌ10+3#".54>3232765"“Z(g>2%!%ªø¨Í}86'"%)jÿö%µ¶´¸±ü?í33105! ¿%‘‘Øý“iH»´þú??öí103#Ø‘‘HöKý“µ¶"²º³þ¸±ü?í?öí310!!#(ýi‘¶‘ûnÿöý“¶"»µþ¸±ü?í?3öí105!# (‘%‘úÝ’%µH"²½³üú??íöí3103!!‘—üØHûn‘ÿö%H"»µú¸±ü?í?3ôí105!3 —‘%‘’úÝý“µH'³ º³þ¸³üú??í?öí23103!!#‘—ýi‘Hûn‘ûnÿöý“H'±º·þú¸±ü?í??3ôí3105!3# —‘‘%‘’öK’ÿöý“µ¶(² º¶þ¸±ü?í2?3öí3105!!# ¿ýi‘%‘‘ûn’ÿö%µH(² º¶ú¸±ü?í3?3ôí3105!3! —‘—%‘’ûn‘ÿöý“µH 3³ » @ þú ¸²ü?3í2??3ö2í23105!3!!# —‘—ýi‘%‘’ûn‘ûn’ÿöqµj%· ¸²ý¸±û?í?í3233105!5! ¿úA¿Ù‘‘þ˜‘‘Ùý“ÒH*A ¶þú?2?3öíôí103#3#Ù‘‘h‘‘HöK µöKý“µj 1µ º³ þ¸²ý¸±û?í?í?öí23310!!!!#(ýi—ýi‘j‘בü"Ùý“µ¶ 3² ¿  ² ¸´ üþ?3?í2ôíöí310!###µþ‘ב¶‘ûn’ûn#Ùý“µj ?´ A   µý þ¸±û?í?3?íöíôí3310!!#!!#ÙÜüµ‘htþ‘j‘úºo‘ü"ÿöý“j 1± º·  þ¸²û ¸±ý?í?í?33ôí3105!5!5!# —ýi(‘q‘בú)Þÿöý“Ò¶ 4A   · þ¸±ü?í2?33ôíöí105!### ܑב%‘úÝ’ûn’ÿöý“Òj ?´ A   µ ýþ¸±û?í?3?íôíöí3310#!5#!5!Ò‘üµt‘þtjú)F‘ú)Þ‘qµH 1µ ½  ²ý¸³ûú??í?íöí233103!!!!‘—ýi—üØHü"‘בÙ%µH 4² A    µüú?3?3íöíôí3103!!33A‘ãü$‘×Hûn‘#ûnÙqµH ?´  A    ²û¸´ýú?2?í?íöíôí33103!!3!!Ù‘Kü$h‘ãýŒHúº‘×ü"‘ÿöqH 2¼ ·  ú¸²û ¸±ý?í?í?33ô2í105!5!5!3 —ýi—‘q‘בÞú)ÿö%ÒH 4A  ·  ú¸±ü?í3?33ôíôí10!5!333Òü$ã‘ב%‘’ûn’ÿöqÒH ?A   µ  ¸µ ûú¸±ý?í?3?í33ôíôí10!5!3!3!5!Òü$K‘þ‘ýŒãq‘Fû‘‘ý“µH 6¶  º ³ þ ¸²ý¸³ûú??í?í?öí2233103!!!!#‘—ýi—ýi‘Hü"‘בü"Ùý“µH 8² º ² º·  þú¸±ü?í?3?3ôí2öí3103!!#3#A‘ãþ‘þ˜‘‘Hûn‘ûn µöKÙý“µH Iµ A  ² û¸·ý ú þ?3?3?í?íöíô2í23310#3!!#3!!j‘‘×tþ‘‘ãýŒý“ µúº‘ü" µü"‘ÿöý“H 8¹ ² ¸@  þú¸²û ¸±ý?í?í??33ö22í105!5!5!3# —ýi—‘‘q‘בÞöKÞÿöý“ÒH ;A   @ þú¸±ü?í?3?33ö2íôí105!3#3# ã‘‘h‘‘%‘’öK’#öKÿöý“ÒH Iµ  A   µý þ¸´ ûú?3?í?3?íôíö2í233103#3!5!#!5!A‘‘þ˜‘ýŒã‘‘þtHöK µû‘‘ú)Þ‘ÿöý“µj 9´  ºµ  ¸µ ûþ¸±ý?í2??í33öí33105!!#5! ¿ýi‘ýi¿q‘‘ü"Þh‘‘ÿöý“µ¶ :² ¿  @  þ¸±ü?í22?33ôíöí3105!!### ¿þ‘ב%‘‘ûn’ûn’ÿöý“µj J´  ºµ½³û ¸µý þ?3?3í2?íöí33ôí3310#!5!3!!#!5j‘þt×tþ‘túAý“Þ‘‘ü"ב‘ÿöqµH :@   ½ µ ýú¸±û?í3??íôí3333105!3!5! —‘—úA¿Ù‘Þü"‘þ˜‘‘ÿö%µH :² ¿ @ ú ¸±ü?í33?33ôíôí3105!333! ã‘בã%‘’ûn’ûn‘ÿöqµH L@  A   ³ ý ¸µ ûú?3?3í2?íôíôí3333103!!3!5!5!A‘ãýŒþ˜‘ýŒãþ¿Hü"‘oû‘‘þ‘‘ÿöý“µHL¶  ¸²¸@ þú ¸´ û¸² ý?3í2?3í2??33ö22í2233105!5!5!3!!!!# —ýi—‘—ýi—ýi‘q‘בÞü"‘בü"Þÿöý“µHM³ » ²»@  ú  ¸¶ü þ?3?33í22?33ô2í2ö2í23103!!###!5!33A‘ãþ‘בþã‘×Hûn‘ûn’ûn’‘’ûnÿöý“µH ]µ» ¶  »²¸·ûú ¸µ ýþ?3?3í2?3?3í2ö2í233ô2í233103!!#!5!3!!#3!5!A‘ãýŒ×‘þt×tþ‘þ˜‘ýŒãHü"‘úºÞ‘‘ü" µû‘‘m«H¶ú/?3310!!«úU«mÛý“«m¶þ?/3310!!«úU«ý“Úý“«H·úþ??3310!!«úU«ý“ µý“ÖH¶úþ??/310!!Öý*Öý“ µÕý“«H¶úþ??/310!!«ý*Öý“ µ*gýõ«£ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§1µ¡™•‘¥¸¶¤mUE- y¸@ xlTD, xeM5‰¸@ ˆdL4ˆqYA)}¸@ |pX@(|aQ9 ¸@ Œ`P8Œu]=%¸@!€t\<$€xˆ|Œ€€Œ|ˆx„ œ˜”¤¤©iI1!…¸@hH0 „„§‹‡¸´„£gck¸·h d`h_[W¸·T\XTŸSOK¸·HœPLHC?G¸·D@32#".732>54.#"§Fz¤^^¥{GG{¥^^¤zFV9b…LL†c::c†LL…b9d^¥{GG{¥^^¤zFFz¤^L„c99c„LL†c::c†²‰#ú@  /O/]Í/Í102#"'&5467>76jnk5R·¶S4lú9R46n9··:m64R9)¬ƒ· /ÍÝÍ/ÍÝÍ103!32>54.#")ƒüEx [[¡xEEx¡[[ xEƒû}A[ xEEx [[¡xEEx¡)¬ƒ+"@" '/ÝÝÎÝÎ/ÝÝÎÝÎ103!4>32#".'32>54.#")ƒüQ:c…KK…c::c…KK…c:MEx [[¡xEEx¡[[ xEƒû}AK…c::c…KK…c::c…K[ xEEx [[¡xEEx¡s…cu"<@$   @À  @À/ÍÜÍ/]ÍÜÍ10]]]]]#"'.5476324'&#"3276c%%%V3eK#%HJfgGJL33FF3331HH13}5V%#%H%V5fHJJGgF3333FE6116±ÿåy¬!-9D“@] $ t $t+{+{D"(?4.(.(.1%+7+>:h:Y:G:::b¹^0Hþ²³³²þ€×[²²[×€Ù™šš™ÙØ™šš™W .. -- .. --þ¿‰‰#º_[Ñÿ噬)4`@7*/$'!04h4Y4K4=442-_oO-_--- /Ì99//]^]Î3]]]]33Î2/Í99//Î3Î310#"'&54676324&#"326%4&#"326327'#"'™´³ýý³´ZZ²þþ²ZZý. -- .Ó, // ,ý®0^¹b>L‘“LHþ²³³²þ€×[²²[× -- .. -- ..þÜ[_º#‰‰Fÿs;3F‹¹/ÿð@ H4.4$w##¸ÿð@M H H;;  H;/4#4;B ß p ?   9+>€Ðà0/43?3O33/^]ÍÜ]]]]Í/ÍÜ]]]]Í10]]]]+]]++]]]+373#'#5.''7.'#5367'7>7"327654'.‰B 965º-¸-,××,(¸1¶7:"B?n0¼+¶(.×× P´(½9p6Eu0bb0uE‹`cc1u;Ù  ¶-¸;q9>€_¸1¶(,=20dˆ‰b2/aaЉc02ÚP&/b@>+ï+ÿ++"à"ð""P'ð''€@%(H /Í+Ü^]2Íqr/]3Í2/ÍqrÜ]Íqr9/3Í210.'&547>32!!#!5!"327654&'&Ü7Z#GS,e>SW;=>B.*PlzS++VSzmQR ¦FþúF‘;G,+G>>=T,G;Qú¯AQF@(1A;NN?  33FF;A1?J7€77B??/^]Ì]ÍÜ]Í99/ÍrÜ]Ì]Ír9910.'.'.547>323267632#"'.'#"'&547632"327654'&ÿ6%( ? .@$    íTVWvvWTTUzGSšZ>==@XY<>><      "O-@" '*R*îQm}VXTTuuWV+ >=X[===>ZW>>;Ï/(@& 0 ` p  "@ H"O_/]//+3/]/10#"'!727>'#"'&547>7>76 (_E#%?BXc$&£‰üè}V+B,-„SZB?N9En&8Ï6_,+i?~BCF_?B¿“WVc %%1E[wK`_B?[J;*U/;q9S<ÇK/@9M?4=C /)//99//]923/]Î10)7>7>7654&5#"&'&547632.'.547>3267>32#"&'.'Fü¶Tl)@4:Z+X-;a)OII]P3N(a„2+C.=Ÿ#!K2dmy;*&StsOP"4&sN&(PNmVb(%)LtvSP<3=-Q}.-L'fÿéZy'&@) @ P p €  ///]Î10^]].'.'.'.547632>32b*gL8E+%DFfbN/"ŽX2U#F)N7>-qEEt/'xSEj( #&b<^Q2€P;`ÇN¥]]5(–o]ŸH: 9‡Pwc; kM”Ä;!0@! @O_o€! //ÍÌ]9/9/ÍÜ]ÍÍ2103#>54&'&'#"&547632éL™3:0./9@%%Hl9:Q0*ýÚ%#Jj9:;b&J5-L9<ð²þg•u˜ÿÿJÌ&ILª1¹%ÿÀ³H%¸ÿÀ@H%@ H¯¯ €  ]]55]5+++ÿÿJÌ&IOªWµ!@!!H!¸ÿÀ³H!¸ÿÀ@ H!@H!¸ÿÀ³H!¸ÿÀ³H!¸ÿÀ@H!@ H¯¯€]]5]5++++++++]þWÿÆ+@ H †0 ’’/í/í/Ô]í9+10]2#"'732654&#*7>rPX'Sƒ\.6*RF24 ;9:TB5Q7v'& m½D<@ŸœXYX+/í0//F·( +</+<+H‡+}Ä10!½; ;1þÏPþ9€ÿ² · ˆ  ÞýÆ/í10#>7#73h %-‰6Al(õÌ,G=30T&ÏF¶Û† Ž@HàŸßï@ HåÝÜ€X+?3?39/3í29/+]q/F·( +</+<+H‡+}ÄÀÀÀ‡ÀÀ3/3310]#7!7333X·þ¥‹ÛTgÇ ²Ê>BŒŒ”°þK·¿+U¬Ø%o@3  $%@ H% 0@ á'%% H¸ÿð@ H%"ååßåÜ?í?í9/í99+q+qÔí/]Æ]Æ+210]]!!>32#".'732>54&#"#éïþ¦$G61O9+RzN@aC(Á./, 5(<&²Šˆ7Q5?fJ(5F(*+#/82/¨¶&@ á@ ÀÝ å Ü?í2?ÖÍ9/í910#>7!7!ïOwU8ËB`|JþpCO‰ˆ’YS“‹ˆHŠ]¬Ý!1?U@1   -á á;;;á'A5á2å""8åß*åÞ?í?í9/í99/íÔí99//í99í]10]]2#".54>75.54>2>54&#""32654.ßw‡WL4A(QyQEfC!"4A'8-Pn % (*)7 <<032E &^RE^ O>1U>#5I+.A-O82K1þÚ"#&,0}<2#087 ?ý·À “/íÔÆ/Ì10"&'732>7›Ž¹6Á*6B*7VC1pMhƒ €ƒJ*F1#9J&1CnO,XôŒ · ˆ  ?ýÆ/í10#>7#73p %-‰6D l(õï+H=30`.Ï@¼tI ·ˆ  ?íÍ/í10>733#\C1“6D l(õNWu/0`.Ï-úïµ@€/Í/Í10%73]þÐ îËúë+÷ú5@ @€/Í/Í]107%! þ~ú÷+ë¦ú‹+ @ À €/3Í9/Ì]10#'##73‹•®ð©7å———ú}+ @ À€/Í29/Ì]10#73373HåÌ–¶è©ú˜˜ÿÿ¶úkÕi/Koù³:@‚@p€¸@ ‚  /2ýÔí3/íÜ]í10]]]".#"#>3232>73›,QKD% ˆ $?bI-SJB% ‡ $?aù&/& --fX:&/& .-fX::úÁ @ @ H@€/Í32/ÝÔ+Í10?!!57!: ã þ  í þ úø+ìø+ìðc'@ ƒ@Àƒ@€ /íÍ2/íÜí10]".5332673ÖJtQ*¥.>#Nj¤?_„ð,OpD)>)LXEoP+F4 8$ÿ´<ÿÛVÿ´_ÿ´bÿ´iÿ´rÿÛxÿÛÿh$ÿ´$7ÿh$9ÿh$:ÿ$<ÿh$ ÿ)ÿ)ÿ)$ÿ/ÿÛ/7ÿh/9ÿ/:ÿ/<ÿh/ ÿh3ÿ´3þø3þø3$ÿh57ÿÛ5:ÿÛ5<ÿÛ7ÿh7ÿ7ÿh7ÿh7ÿh7$ÿh72ÿÛ7Dÿ´7Fÿ´7Hÿ´7LÿÛ7Rÿ´7UÿÛ7Vÿ´7XÿÛ7Zÿ´7\ÿ´9ÿD9ÿ´9ÿD9ÿ´9ÿ´9$ÿh9Dÿ´9Hÿ´9Lÿ´9Rÿ´9UÿÛ9XÿÛ9\ÿÛ:ÿh:ÿ´:ÿh:ÿ´:ÿ´:$ÿ:DÿÛ:HÿÛ:Lÿî:RÿÛ:UÿÛ:XÿÛ:\ÿÛ<ÿÛ<ÿD<ÿh<ÿD<ÿ<ÿ<$ÿh<Dÿ´<Hÿ´<Lÿ´<Rÿ´<Sÿ´<Tÿ´<Xÿ´<Yÿ´IIÿÛI %UÿUÿU LYÿYÿZÿ´Zÿ´\ÿ´\ÿ´Vÿ´Vfÿ‹Vmÿ‹VqÿDVrÿVsÿ‹VxÿV€ÿÅVŠÿÅV”ÿÅ[rÿ®[xÿ®\^ \_ÿJ\bÿy\iÿ\yÿ´\{ÿ´\|ÿ´\~ÿ´\ÿ´\„ÿ´\†ÿ´\‡ÿ´\‰ÿ´\Œÿ´\ÿ´\“ÿ´\—ƒ\™ÿ´_ÿ´_fÿ‹_mÿ‹_qÿD_rÿ_sÿ‹_xÿ_€ÿÅ_ŠÿÅ_”ÿÅ_ ÿaÿaÿa^ a_ÿNabÿNaiÿNa†ÿÛa—ƒbÿ´bfÿÕbmÿÕbqÿDbrÿbxÿf_ÿÇfrÿ®fxÿ®hfÿmhmÿmhsÿmhyÿÙh~ÿÙhÿÙhƒÿÙh…ÿÙh‹ÿÙhŒÿÙhÿÙh“ÿÙh–ÿÙh™ÿÙh›ÿÙiÿ´ifÿÕimÿÕiqÿDirÿixÿm_ÿÇmrÿ®mxÿ®oþúoþúo_ÿhobÿhoiÿhp‘ÿÏqÿhqÿqÿhqÿhqÿhq^q_ÿhqbÿ¤qfÿÛqiÿ¤qmÿÛqsÿÛqvÿÛqyÿ´qzÿ´q~ÿ´q€ÿÉqÿ´q‚ÿ´q„ÿÛq†ÿÛq‰ÿÛqŠÿ´qŒÿ´qÿ´q’ÿÛq“ÿ´q”ÿ´q•ÿÉq—ƒq˜ÿÛq™ÿ´qšÿÛrÿFrÿhrÿFrÿrÿr^ r_ÿJrbÿyriÿryÿ´r{ÿ´r|ÿ´r~ÿ´r€ÿÕrÿ´r„ÿ´r†ÿ´r‡ÿ´r‰ÿ´rŒÿ´rÿ´r“ÿ´r—ƒr™ÿ´s_ÿÇsrÿ‘sxÿ‘t–ÿºt›ÿºuyÿ×u~ÿ×uÿÇu…ÿÝuŒÿ×uÿ×u“ÿ×u–ÿ×u™ÿ×u›ÿ×vrÿ®vxÿ®x^ x_ÿJxbÿyxiÿxyÿ´x{ÿ´x|ÿ´x~ÿ´xÿ´x„ÿ´x†ÿ´x‡ÿ´x‰ÿ´xŒÿ´xÿ´x“ÿ´x—ƒx™ÿ´€ÿÛÿÝ”ÿǃyÿ#ƒ{ÿ²ƒ~ÿ#ƒ€ÿǃÿ¶ƒ„ÿ²ƒ…ÿÕƒ†ÿ²ƒ‡ÿ²ƒŠÿǃŒÿ#ƒÿǃÿ#ƒ‘ÿǃ“ÿ#ƒ–ÿ#ƒ™ÿ#ƒ›ÿ#‡yÿ²‡~ÿ²‡ÿ²‡ƒÿ²‡…ÿ²‡‹ÿ²‡Œÿ²‡ÿ²‡ÿ²‡“ÿ²‡–ÿ²‡™ÿ²‡›ÿ²ˆyÿãˆ}ÿÙˆ~ÿãˆÿ㈃ÿ㈋ÿ㈌ÿãˆÿãˆÿ㈒ÿÙˆ“ÿ㈖ÿ㈘ÿÙˆ™ÿ㈚ÿÙˆ›ÿã‹yÿÕ‹~ÿÕ‹ÿÕ‹ƒÿÕ‹‹ÿÕ‹ŒÿÕ‹ÿÕ‹ÿÕ‹“ÿÕ‹™ÿÕŒ€ÿÛŒÿÝŒ‘ÿÝŒ”ÿÇ“–›ŽÿÝŽ”ÿÇ‘“‘–‘›“€ÿÛ“ˆÿÇ“ÿÝ“”ÿÇ”yÿã”~ÿã”ÿ㔃ÿ㔌ÿã”ÿã”ÿ㔓ÿã”–ÿã”™ÿã”›ÿã–€ÿÛ–ÿÝ–”ÿÇ™€ÿÛ™ÿÝ™”ÿÇ›€ÿÛ›ÿÝ›”ÿÇžÿ3žÿ3¤ ÿ3¥ ÿ3ª®Lª±ÿ²ªµª¸ÿšª¹ÿͪ»ÿšª¼ÿ1ª½ÿª¾ÿªÁÿšªÇÿšªÊªËÿͪÏÿͪØÿͪÛÿͪÝÿͪÞÿͪ ÿf«ªÿ²«®«°ÿ嫱ÿ嫵«¸ÿå«»ÿ嫼ÿ²«½ÿÍ«¾ÿË«¿ÿå«Áÿå«Äÿš«ÇÿÍ«ÉÿͫիÝÿå«é¬ªÿ²¬°ÿͬ±ÿͬ¸ÿͬ»ÿͬ¼ÿ¬½ÿ¬¾ÿ²¬¿ÿ²¬Äÿ¬ÉÿͬÝÿå¬ßÿå¬áÿ²­ÿ­ÿ­ªÿ˜­®ÿÍ­±ÿå­µÿå­¸ÿå­Éÿå­Êÿå­Ìÿ˜­Îÿå­Ïÿš­Òÿ²­Õÿ²­ÖÿÍ­×ÿÍ­Øÿš­ÚÿÍ­ÝÿÍ­åÿÍ­æÿÍ­èÿÍ­éÿÍ®¾ÿå®Á3®Ñ®Ý3¯±ÿ寵¯Û°±ÿå°¸ÿå°»ÿå°ÁL°Ä°Ê°Ïÿå°Øÿå°Ýÿå±°ÿͱ¸ÿͱ»ÿͱ¼ÿ²±½ÿ²±¾ÿͱÁ3±ÉÿͱÎÿå±Õ´¸ÿå´»ÿå´¼´¾ÿ²´Áf´Ïÿ²´ÑÿÍ´Øÿ²´Ûÿ²´Ýÿå´çÿ͵¾ÿåµÊµÝ¶ÁL¶Ê¶Ý¶áÿ帪ÿ²¸®ÿ帰ÿ²¸µÿ帽ÿ¸¿ÿ͸Á3¸Éÿ͸ָéºÿºÿºÿåºÿåº{ÿͺªÿº®ÿ²º°ÿ²º±ÿ²ºµÿͺ¼ÿ²º½ÿ²º¿ÿ²ºÉÿͺÎÿåºÏÿåºØÿ廪ÿÍ»±ÿÍ»¼ÿ²»½ÿ²»¿ÿå»Á»Äÿš»ÇÿÍ»Ê3»Ð»Ñ»áÿå¼ÿ²¼ÿ²¼ªÿ²¼°3¼¶¼¸ÿå¼¾ÿå¼Ç¼Ìÿ²¼Ïÿ²¼Òÿ²¼ÔÿͼÕÿͼÖÿͼØÿ²¼Ùÿå¼ÚÿͼÛÿ²¼Ýÿͼßÿͼãÿͼåÿ弿ÿå¼èÿå¼éÿå½ÿf½ÿf½ÿͽÿͽªÿf½®ÿ²½±ÿå½µÿ彸ÿå½¾ÿ²½Çÿå½Éÿå½ËÿͽÌÿš½Íÿ²½ÎÿͽÏÿš½Ðÿå½Ñÿ²½Òÿ²½ÓÿͽÔÿͽÕÿ²½Öÿͽ×ÿͽØÿ½ÙÿͽÚÿͽÛÿš½ßÿͽàÿͽâÿͽãÿͽèÿͽéÿ;ªÿ²¾®ÿ;µÿ;¶¾¼ÿ¾½ÿ¾Á3¾Éÿ²¾Õÿ忱¿¸ÿå¿»ÿ忾ÿÍ¿Çÿå¿Øÿ²¿ÝÿåÀÊ3ÃÊ3ÃÝ3ÄÉÿÍÄ ÿ3ƪÿÍÆ°ÿÍÆ±ÿÍÆ¶ÿ寏ÿ²Æ»ÿ²Æ¼ÿ3Æ¿ÿÍÆÁÿ²ÆÇÿ²ÆÉÿ²Æ ÿLÇ®ÿåǰÿÍDZÿÍǵÿÍÇ¿ÿÍÇÉÿ²Èªÿ²È°ÿÍȼÿ˜È¿ÿåÈÁÊÕÊÝÿåÊáÿ²ÊçÿåËÐÿåËÑÿåËÕÿåËÖÿåËÝÿÍËßÿÍËáÿ²Ëäÿ˜ËçÿåÌÊÿåÌËÿÍÌÎÿÍÌÏÿÍÌÐÿåÌÑÿåÌÖÿÍÌØÿÍÌÛÿÍÌÜÿåÌÝÿ²ÌÞÿÍÌáÿšÌäÿÌéÿåÍÿåÍÿåÍÊÿåÍÎÿ²ÍÏÿÍÍÑÿÍÍÖÿÍÍØÿÍÍÛÿÍÍéÿåÎÑÿåÏÊÏËÏÎÏÐÿåÏÕÏØÏÛÏÝÿåÏÞÏßÿåÏáÿÍÐÊÐËÐÝÐáÿåÐäÑËÿåÑÎÿåÑÏÿåÑÑÿåÑÖÿåÑØÿåÑÛÿåÑÝÿ²ÑÞÿåÑáÿšÑäÿšÔÊÔËÔÕ3ÔÝÔáÿåÔçÕËÿåÕÏÿåÕØÿåÕÛÿåÕÝÿåÕÞÿåÕáÿÍÖÑÿåØÊØÐÿåØÝÿÍØßÿÍØáÿšØçÿåÚÐÿåÚÑÿåÚÕÿåÚÖÿåÚÝÿËÚßÿÍÚáÿšÚçÿåÛÐÿåÛÑÿåÛÝÿåÛÞÿåÛßÿåÛáÿ²ÛäÿÍÜÿåÜÿåÜÎÿåÜÏÿåÜÐÿåÜÑÿÍÜÕÿåÜÖÿåÜØÿåÜÛÿåÜÝÿÍÜçÿÍÝÿ²Ýÿ²ÝËÝÐÝÑÝßÝéÞÝÿÍÞáÿ²ßÊÿåßËÿåßÏÿÍßÑÿåߨÿÍßÛÿÍßÞÿÍßáÿÍßçÿåàÊÿåàÏÿ²àÑÿåàØÿ²àÛÿ²àÝÿåãÏÿÍãØÿÍæÜÿÍæáÿ3çËÿåçÏÿåçÐÿåçÑÿåçÖÿÍçØÿåçÛÿåçÞÿåçßÿÍèËÿåèÎÿåèÏÿåèÐÿÍèÕÿåèÖÿåèØÿåèÛÿåèÜÿåèÞÿåèßÿÍèáÿèçÿÍöÿ²öÿ²öÿåöÿåøÿÍøÿÍÿ´ ÿ´ VÿÛ W%  ÿ´ÿ¦ÿ¼ÿÁÿÄÿ3V^¾= e&¿ T•z¥J } Æ .A p+H ¼  M Lq 6æ : 2a ô¯ (  _ 8Œ \ã þp VðCopyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.Copyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.Liberation SansLiberation SansBold ItalicBold ItalicAscender - Liberation Sans Bold ItalicAscender - Liberation Sans Bold ItalicLiberation Sans Bold ItalicLiberation Sans Bold ItalicVersion 1.03Version 1.03LiberationSans-BoldItalicLiberationSans-BoldItalicLiberation is a trademark of Red Hat, Inc. registered in U.S. Patent and Trademark Office and certain other jurisdictions.Liberation is a trademark of Red Hat, Inc. registered in U.S. Patent and Trademark Office and certain other jurisdictions.Ascender CorporationAscender CorporationSteve MattesonSteve Mattesonhttp://www.ascendercorp.com/http://www.ascendercorp.com/http://www.ascendercorp.com/typedesigners.htmlhttp://www.ascendercorp.com/typedesigners.htmlUse of this Liberation font software is subject to the license agreement under which you accepted the Liberation font software.Use of this Liberation font software is subject to the license agreement under which you accepted the Liberation font software.http://www.ascendercorp.com/liberation.htmlhttp://www.ascendercorp.com/liberation.htmlÿôÿ'×¢  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a£„…½–膎‹©¤ŠÚƒ“ˆÞ žªõôö¢­ÉÇ®bcdËeÈÊÏÌÍÎéfÓÐѯgð‘ÖÔÕhëí‰jikmln oqprsutvwêxzy{}|¸¡~€ìîº    ýþÿ !"øù#$%&'()*+,-./012ú×3456789:;<=>?@AâãBCDEFGHIJKLMNOP°±QRSTUVWXYZûüäå[\]^_`abcdefghijklmnop»qrstæçu¦vwxyz{|}~Øá€ÛÜÝàÙß‚ƒ„…†‡ˆ‰Š‹Œލ‘’“”•–—˜™š›œžŸ ¡Ÿ¢£¤¥¦§¨©ª«¬­®¯°±²³—´µ¶›·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,²³-.¶·Ä/´µÅ‚‡«Æ01¾¿2345÷6789:;Œ<=>?@ABCDEFGH˜Iš™ï¥’JKœ§L”•MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰¹Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­uni00A0uni00ADuni037Euni00B2uni00B3uni00B5uni2219uni00B9AmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflex Tcommaaccent tcommaaccentTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongs Aringacute aringacuteAEacuteaeacute Oslashacute oslashacute Scommaaccent scommaaccentuni021Auni021Buni02C9tonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammaEpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsi IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdanuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonos afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061 afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109 afii10110 afii10193 afii10050 afii10098WgravewgraveWacutewacute Wdieresis wdieresisYgraveygraveuni2010uni2011 afii00208 underscoredbl quotereversedminutesecond exclamdbluni203Euni2215uni207FlirapesetaEuro afii61248 afii61289 afii61352uni2126 estimated oneeighth threeeighths fiveeighths seveneighths arrowleftarrowup arrowright arrowdown arrowboth arrowupdn arrowupdnbseuni2206 orthogonal intersection equivalencehouse revlogicalnot integraltp integralbtSF100000SF110000SF010000SF030000SF020000SF040000SF080000SF090000SF060000SF070000SF050000SF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000upblockdnblockblocklfblockrtblockltshadeshadedkshade filledboxH22073H18543H18551 filledrecttriaguptriagrttriagdntriaglfcircleH18533 invbullet invcircle openbullet smileface invsmilefacesunfemalemalespadeclubheartdiamond musicalnotemusicalnotedbluniFB01uniFB02uniF005middot commaaccent foursuperior fivesuperior sevensuperior eightsuperior cyrillicbrevecaroncommaaccentcommaaccentrotategrave.ucacute.uc circumflex.uccaron.uc dieresis.uctilde.uchungarumlaut.ucbreve.uc ÿÿ¡ LNDFLTcyrl$grek.latn8ÿÿÿÿÿÿÿÿ TbDFLTcyrl&grek2latn>ÿÿÿÿÿÿÿÿkern °hÚü*DVdªàT^lvv€ª´þ,NhvNh´ÊÐV¸ÆÐª´úRˆÊô0úúú^hhn¼@ž°¾ä<J\†Ìþ d ò  6 < F P ‚ œ ² Ä ê ( R X † œ Ê ä R   > \ Ž ¬ ¶ Ü ö 0 f x ‚ ˆ š$ÿ´<ÿÛVÿ´_ÿ´bÿ´iÿ´rÿÛxÿÛÿhÿ´7ÿh9ÿh:ÿ<ÿh ÿÿÿ$ÿÿÛ7ÿh9ÿ:ÿ<ÿh ÿhÿ´þøþø$ÿh7ÿÛ:ÿÛ<ÿÛÿhÿÿhÿhÿh$ÿh2ÿÛDÿ´Fÿ´Hÿ´LÿÛRÿ´UÿÛVÿ´XÿÛZÿ´\ÿ´ ÿDÿ´ÿDÿ´ÿ´$ÿhDÿ´Hÿ´Lÿ´Rÿ´UÿÛXÿÛ\ÿÛ ÿhÿ´ÿhÿ´ÿ´$ÿDÿÛHÿÛLÿîRÿÛUÿÛXÿÛ\ÿÛÿÛÿDÿhÿDÿÿ$ÿhDÿ´Hÿ´Lÿ´Rÿ´Sÿ´Tÿ´Xÿ´Yÿ´IÿÛ %ÿÿ Lÿÿÿ´ÿ´ ÿ´fÿ‹mÿ‹qÿDrÿsÿ‹xÿ€ÿÅŠÿÅ”ÿÅrÿ®xÿ®^ _ÿJbÿyiÿyÿ´{ÿ´|ÿ´~ÿ´ÿ´„ÿ´†ÿ´‡ÿ´‰ÿ´Œÿ´ÿ´“ÿ´—ƒ™ÿ´ ÿ´fÿ‹mÿ‹qÿDrÿsÿ‹xÿ€ÿÅŠÿÅ”ÿÅ ÿÿÿ^ _ÿNbÿNiÿN†ÿÛ—ƒÿ´fÿÕmÿÕqÿDrÿxÿ_ÿÇrÿ®xÿ®fÿmmÿmsÿmyÿÙ~ÿÙÿÙƒÿÙ…ÿÙ‹ÿÙŒÿÙÿÙ“ÿÙ–ÿÙ™ÿÙ›ÿÙþúþú_ÿhbÿhiÿh‘ÿÏ!ÿhÿÿhÿhÿh^_ÿhbÿ¤fÿÛiÿ¤mÿÛsÿÛvÿÛyÿ´zÿ´~ÿ´€ÿÉÿ´‚ÿ´„ÿÛ†ÿÛ‰ÿÛŠÿ´Œÿ´ÿ´’ÿÛ“ÿ´”ÿ´•ÿÉ—ƒ˜ÿÛ™ÿ´šÿÛÿFÿhÿFÿÿ^ _ÿJbÿyiÿyÿ´{ÿ´|ÿ´~ÿ´€ÿÕÿ´„ÿ´†ÿ´‡ÿ´‰ÿ´Œÿ´ÿ´“ÿ´—ƒ™ÿ´_ÿÇrÿ‘xÿ‘–ÿº›ÿº yÿ×~ÿ×ÿÇ…ÿÝŒÿ×ÿדÿ×–ÿ×™ÿ×›ÿ×€ÿÛÿÝ”ÿÇyÿ#{ÿ²~ÿ#€ÿÇÿ¶„ÿ²…ÿÕ†ÿ²‡ÿ²ŠÿÇŒÿ#ÿÇÿ#‘ÿÇ“ÿ#–ÿ#™ÿ#›ÿ# yÿ²~ÿ²ÿ²ƒÿ²…ÿ²‹ÿ²Œÿ²ÿ²ÿ²“ÿ²–ÿ²™ÿ²›ÿ²yÿã}ÿÙ~ÿãÿãƒÿã‹ÿãŒÿãÿãÿã’ÿÙ“ÿã–ÿã˜ÿÙ™ÿãšÿÙ›ÿã yÿÕ~ÿÕÿÕƒÿÕ‹ÿÕŒÿÕÿÕÿÕ“ÿÕ™ÿÕ€ÿÛÿÝ‘ÿÝ”ÿÇ“–›ÿÝ”ÿÇ€ÿÛˆÿÇÿÝ”ÿÇ yÿã~ÿãÿãƒÿãŒÿãÿãÿã“ÿã–ÿã™ÿã›ÿãÿ3ÿ3 ÿ3®L±ÿ²µ¸ÿš¹ÿÍ»ÿš¼ÿ1½ÿ¾ÿÁÿšÇÿšÊËÿÍÏÿÍØÿÍÛÿÍÝÿÍÞÿÍ ÿfªÿ²®°ÿå±ÿ嵸ÿå»ÿå¼ÿ²½ÿ;ÿË¿ÿåÁÿåÄÿšÇÿÍÉÿÍÕÝÿåéªÿ²°ÿͱÿ͸ÿÍ»ÿͼÿ½ÿ¾ÿ²¿ÿ²ÄÿÉÿÍÝÿåßÿåáÿ²ÿÿªÿ˜®ÿͱÿåµÿå¸ÿåÉÿåÊÿåÌÿ˜ÎÿåÏÿšÒÿ²Õÿ²ÖÿÍ×ÿÍØÿšÚÿÍÝÿÍåÿÍæÿÍèÿÍéÿ;ÿåÁ3ÑÝ3±ÿåµÛ ±ÿå¸ÿå»ÿåÁLÄÊÏÿåØÿåÝÿå °ÿ͸ÿÍ»ÿͼÿ²½ÿ²¾ÿÍÁ3ÉÿÍÎÿåÕ ¸ÿå»ÿå¼¾ÿ²ÁfÏÿ²ÑÿÍØÿ²Ûÿ²Ýÿåçÿ;ÿåÊÝÁLÊÝáÿå ªÿ²®ÿå°ÿ²µÿå½ÿ¿ÿÍÁ3ÉÿÍÖéÿÿÿåÿå{ÿͪÿ®ÿ²°ÿ²±ÿ²µÿͼÿ²½ÿ²¿ÿ²ÉÿÍÎÿåÏÿåØÿå ªÿͱÿͼÿ²½ÿ²¿ÿåÁÄÿšÇÿÍÊ3ÐÑáÿåÿ²ÿ²ªÿ²°3¶¸ÿå¾ÿåÇÌÿ²Ïÿ²Òÿ²ÔÿÍÕÿÍÖÿÍØÿ²ÙÿåÚÿÍÛÿ²ÝÿÍßÿÍãÿÍåÿåæÿåèÿåéÿå#ÿfÿfÿÍÿͪÿf®ÿ²±ÿåµÿå¸ÿå¾ÿ²ÇÿåÉÿåËÿÍÌÿšÍÿ²ÎÿÍÏÿšÐÿåÑÿ²Òÿ²ÓÿÍÔÿÍÕÿ²ÖÿÍ×ÿÍØÿÙÿÍÚÿÍÛÿšßÿÍàÿÍâÿÍãÿÍèÿÍéÿÍ ªÿ²®ÿ͵ÿͶ¼ÿ½ÿÁ3Éÿ²Õÿ屸ÿå»ÿå¾ÿÍÇÿåØÿ²ÝÿåÊ3Ê3Ý3ÉÿÍ ÿ3 ªÿͰÿͱÿͶÿå¸ÿ²»ÿ²¼ÿ3¿ÿÍÁÿ²Çÿ²Éÿ² ÿL®ÿå°ÿͱÿ͵ÿÍ¿ÿÍÉÿ²ªÿ²°ÿͼÿ˜¿ÿåÁÕÝÿåáÿ²çÿå ÐÿåÑÿåÕÿåÖÿåÝÿÍßÿÍáÿ²äÿ˜çÿåÊÿåËÿÍÎÿÍÏÿÍÐÿåÑÿåÖÿÍØÿÍÛÿÍÜÿåÝÿ²ÞÿÍáÿšäÿéÿå ÿåÿåÊÿåÎÿ²ÏÿÍÑÿÍÖÿÍØÿÍÛÿÍéÿåÑÿå ÊËÎÐÿåÕØÛÝÿåÞßÿåáÿÍÊËÝáÿåä ËÿåÎÿåÏÿåÑÿåÖÿåØÿåÛÿåÝÿ²ÞÿåáÿšäÿšÊËÕ3ÝáÿåçËÿåÏÿåØÿåÛÿåÝÿåÞÿåáÿÍÊÐÿåÝÿÍßÿÍáÿšçÿåÐÿåÑÿåÕÿåÖÿåÝÿËßÿÍáÿšçÿåÐÿåÑÿåÝÿåÞÿåßÿåáÿ²äÿÍ ÿåÿåÎÿåÏÿåÐÿåÑÿÍÕÿåÖÿåØÿåÛÿåÝÿÍçÿÍÿ²ÿ²ËÐÑßéÝÿÍáÿ² ÊÿåËÿåÏÿÍÑÿåØÿÍÛÿÍÞÿÍáÿÍçÿåÊÿåÏÿ²ÑÿåØÿ²Ûÿ²ÝÿåÏÿÍØÿÍÜÿÍáÿ3 ËÿåÏÿåÐÿåÑÿåÖÿÍØÿåÛÿåÞÿåßÿÍ ËÿåÎÿåÏÿåÐÿÍÕÿåÖÿåØÿåÛÿåÜÿåÞÿåßÿÍáÿçÿÍÿ²ÿ²ÿåÿåÿÍÿÍÿ´ÿ´VÿÛW% ÿ´ÿ¦ÿ¼ÿÁÿÄÿ3h$)/3579:<IUYZ\V[\_abfhimopqrstuvxƒ‡ˆ‹ŒŽ‘“”–™›ž¤¥ª«¬­®¯°±´µ¶¸º»¼½¾¿ÀÃÄÆÇÈÊËÌÍÎÏÐÑÔÕÖØÚÛÜÝÞßàãæçèöø ÆÔ.™¿ÿ€È Y!gosa-core-2.7.4/html/themes/default/fonts/LiberationSans-Italic.ttf0000644000175000017500000047311411376667572024302 0ustar cajuscajus0FFTMMü„ãv0GDEFÏeô GPOS¾ÈÓÆfdÌGSUB“<‚KfPOS/2÷†Î¸`cmap f¢  cvt aòP²Ì,fpgmsÓ#°¤gasp eäglyf?„½+„ headõ£Æ<6hhea ìt$hmtxA|Ìõ ˆkern@Ø4ˆ(locaÄá ø Œmaxp¶ ǘ name!yÞþH°‘post–%wQDžprepË«=a¬  Ì‘¼¤H_<õÈ a&È a&ýÓý“€>þNCÀýÓþk€d¢¢RT…/ZM¾¹š3š3ZÑf   ¯Pxû1ASC!ûÓþW3>²`Ÿß×: ìDª99M×»s'sÿô’V!‡Êª`ªÿ9x¬‚9%ªi9P9ÿŒsYs5sÿôs0s s.sssÔs6sF9Q9&¬ƒ¬‚¬ƒsŸÂVÿ›V?ÇqÇ?V?ã?9eÇ?9QÿûV?s?ª?Ç?9oV?9eÇ?V:ã¸Ç™V±±VÿÙVÕãÿØ9ÿÙ9’9ÿWÁ(sÿ`ª‚s.sCsEsE9Ess"Ç!Çÿ"Ç!ª"s"sCsÿÍsEª"9]sVpÇfÿ®ÿŒÿÔ¬Õ¬ÿa¬zª@sžsÿôss-ÕsÿÞª‰å?öYsL¬då?kÿï3ÄdAªª5ª¯œÿÿL9¥ªGª=ìes¬`¬/¬ˆãAVÿ­Vÿ­Vÿ­Vÿ­Vÿ­Vÿ›ÿ¯ÇqV?V?V?V?9Q9Q9Q9QÇ"Ç?9o9o9o9o9o¬¬9ÿÈǙǙǙǙVÕVã"s4s4s4s4s4s4 CsEsEsEsE9Y9Y9:9YsCs"sIsIsIsIsIdRã,sVsVsVsVÿŒsÿÍÿŒVÿ›s.Vÿ›s.Vÿ›s.ÇqCÇqCÇqCÇqCÇ?EÇ"sEV?sEV?sEV?sEV?sEV?sE9es9es9es9esÇ?s"Ç>s"9Q9*9Q9Y9Q9Y9ÿÀÇÿƒ9Q9YÞQ!ÿûÇÿV?""s?Ç!s?Çÿ¼s?@!s?3!sÇÇ?s&Ç?s&Ç?s&ë3É?s"9osC9osC9osCeEÇ?ª"Ç?ªÿËÇ?ª"V:V:V:V:ã¸9ã¸Õ]ã¸9Ç™sVÇ™sVÇ™sVÇ™sVÇ™sVÇ™sV±ÇfVÕÿŒVÕãÿØÿÔãÿØÿÔãÿØÿÉÇ!sVÿ›s.ÿ¯ 9ÿÈã,V:ã¸9QªMªˆªŽª‚ªVªÉªGª5ªªéªÿüVÿ›9¥OLÅIIZÿ÷ìÆ3ÿÿÇ.Vÿ›V??^ÿØV?ãÿØÇ?9e9QV?Vÿ¢ª?Ç?0ÿò9oÌ?V?Ìÿúã¸VÕ²~VÿÙ¥Ð9QVÕF„"q"Ç?fhF’ÿÎorC„"µ=q"WeÇ?"ðÿ£bÿÕc“7sC\[•ÿÎäCÓDþKfh8G^ÿkÒv;CÇ?fhsCfh;CV?¾¸Z?©eV:9Q9Qÿû‡ÿ“Ü?Á¸·?ÿýÊ?Vÿ›5>V?Z?¢ÿCV?Vÿ­é¹?¹?·?|ÿ“ª?Ç?9oÌ?V?Çqã¸ÿý\zVÿÙÑ?cÎ]?b?q¸>5>.?tÿ¥s.€i-'ò,lCsEÿ¶¸ÿósVsVÇ"ƒÿž|"g"sCg"sÿÍCª"ÿŒ¯Eÿ®“Y$‰¤VÏVøBã&5&ï "FÿÐsEs"!÷CÇ!Ç+ÇÿHÿžŸ"s"Ç"ÿŒsVð?·"±Çf±Çf±ÇfVÕÿŒªiªisÿóÿóÿókÿ`ÇÇÇÀÇÿúÇýª”ª‰ªÿ¹sØsDÍaº3€¶Õ¶ªVªMªÿØVýÓë\sÿÑsÿôÀNsƒ–ÿóªT¼%nÍX¬=¬>¬c¬|¢¢¢ô8å–û´Ê¬ƒd3´iÕ˜À1ÿždLdA¬dd?dAÕ¬dÕ"Õ«ÿöØ««ÿö««ÿö««ÿö«ÿö«ÿö«ÿö«ÿö«Ù««Ù«Ù«ÿö«ÿö«ÿö««Ù«Ù«ÿö«ÿö«ÿö««Ù«Ù«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«ÿö«««««Õ«g«ÕÕ{ÕÖmÖmëžë‘ëžë‘ô%Õ§Õ²Õ)Õ)Ös+±kÑUFÚQ@;@<ÀfBÄEEªTªªXª'ªNª£ªKª8ÇøÇZXZ ˜Ã˜ñ‡÷ ­/qH‚øÜ€B~’ÿÇÉÝ~ŠŒ¡Î O\_‘…ó    " & 0 3 : < > D  ¤ § ¬!!!!"!&!.!^!•!¨"""""""")"+"H"a"e###!%%% %%%%%$%,%4%<%l%€%„%ˆ%Œ%“%¡%¬%²%º%¼%Ä%Ë%Ï%Ù%æ&<&@&B&`&c&f&kððûÿÿ  ’úÆÉØ~„ŒŽ£Q^€ò    & 0 2 9 < > D  £ § ¬!!!!"!&!.![!!¨"""""""")"+"H"`"d### %%% %%%%%$%,%4%<%P%€%„%ˆ%Œ%% %ª%²%º%¼%Ä%Ê%Ï%Ø%æ&:&@&B&`&c&e&jððûÿÿÿãÿ®ÿGÿ/þ…þ„þvü ýÐýÏýÎýÍý›ýšý™ý˜ýhãzãáòáñáðáïáìáãáâáÝáÜáÛáÖáœáyáwásááá áàþà÷àËàšàˆà/à,à$à#ààààßóßÜßÚß>ß1ß"ÝDÝCÝ:Ý7Ý4Ý1Ý.Ý'Ý ÝÝÜÿÜìÜéÜæÜãÜàÜÔÜÌÜÇÜÀܸܿܳܰܨܜÜIÜFÜEÜ(Ü&Ü%Ü"‹À bcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,-./0123456789:;<=>?w6   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a„…‡‰‘–œ¡ ¢¤£¥§©¨ª«­¬®¯±³²´¶µº¹»¼pcdhvŸnj#ti<†˜7q>?fu143:kzv¦¸bm6@;2l{€ƒ•   ·}¿8Žw ‚Š‹ˆŽŒ“”’š›™ñKRoNOPxSQL@EYXUTSRQPONMLKJIHGFEDCBA@?>=<;:9876510/.-,('&%$#"! ,E#F` °&`°&#HH-,E#F#a °&a°&#HH-,E#F`° a °F`°&#HH-,E#F#a° ` °&a° a°&#HH-,E#F`°@a °f`°&#HH-,E#F#a°@` °&a°@a°&#HH-, <<-, E# °ÍD# ¸ZQX# °D#Y °íQX# °MD#Y °&QX# ° D#Y!!-, EhD °` E°FvhŠE`D-,± C#Ce -,± C#C -,°(#p±(>°(#p±(E:± -, E°%Ead°PQXED!!Y-,I°#D-, E°C`D-,°C°Ce -, i°@a°‹ ±,ÀŠŒ¸b`+ d#da\X°aY-,ŠEŠŠ‡°+°)#D°)zä-,Ee°,#DE°+#D-,KRXED!!Y-,KQXED!!Y-,°%# Šõ°`#íì-,°%# Šõ°a#íì-,°%õíì-,F#F`ŠŠF# FŠ`Ša¸ÿ€b# #б ŠpE` °PX°a¸ÿº‹°FŒY°`h:-, E°%FRK°Q[X°%F ha°%°%?#!8!Y-, E°%FPX°%F ha°%°%?#!8!Y-,°C°C -,!! d#d‹¸@b-,!°€QX d#d‹¸ b²@/+Y°`-,!°ÀQX d#d‹¸Ub²€/+Y°`-, d#d‹¸@b`#!-,KSXа%Id#Ei°@‹a°€b° aj°#D#°ö!#Š 9/Y-,KSX °%Idi °&°%Id#a°€b° aj°#D°&°öа#D°ö°#D°íа& 9# 9//Y-,E#E`#E`#E`#vh°€b -,°H+-, E°TX°@D E°@aD!!Y-,E±0/E#Ea`°`iD-,KQX°/#p°#B!!Y-,KQX °%EiSXD!!Y!!Y-,E°C°`c°`iD-,°/ED-,E# EŠ`D-,E#E`D-,K#QX¹3ÿà±4 ³34YDD-,°CX°&EŠXdf°`d° `f X!°@Y°aY#XeY°)#D#°)à!!!!!Y-,°CTXKS#KQZX8!!Y!!!!Y-,°CX°%Ed° `f X!°@Y°a#XeY°)#D°%°% XY°%°% F°%#B<°%°%°%°% F°%°`#B< XY°%°%°)à°) EeD°%°%°)à°%°% XY°%°%CH°%°%°%°%°`CH!Y!!!!!!!-,°% F°%#B°%°%EH!!!!-,°% °%°%CH!!!-,E# E °P X#e#Y#h °@PX!°@Y#XeYŠ`D-,KS#KQZX EŠ`D!!Y-,KTX EŠ`D!!Y-,KS#KQZX8!!Y-,°!KTX8!!Y-,°CTX°F+!!!!Y-,°CTX°G+!!!Y-,°CTX°H+!!!!Y-,°CTX°I+!!!Y-, Š#KSŠKQZX#8!!Y-,°%I°SX °@8!Y-,F#F`#Fa#  FŠa¸ÿ€bб@@ŠpE`h:-, Š#IdŠ#SX<!Y-,KRX}zY-,°KKTB-,±B±#ˆQ±@ˆSZX¹ ˆTX²C`BY±$ˆQX¹ @ˆTX²C`B±$ˆTX² C`BKKRX²C`BY¹@€ˆTX²C`BY¹@€c¸ˆTX²C`BY¹@c¸ˆTX²C`BY¹@c¸ˆTX²@C`BYYYYY-,Eh#KQX# E d°@PX|YhŠ`YD-,°°%°%°#>°#>± ° #eB° #B°#?°#?± °#eB°#B°-,zŠE#õ-¿P/¯@•Ðý¿ýýoû@ûõP(òF(ðF+ïŸï/ïoïï¯ïÏïìì@ìPìpì€ì åäãâFâ@âFáàF¿àÏàßà@à36FàFÝ=ßUÞ=UßUÜÿÕÕÿÕÿÕŸÔÓÒ<¿ÂÁP&`¾p¾€¾@¸`¸p¸¸ÿÀ@ ¸2F·?·¸²´#¸@Bµ2³?³ï³ `°p°° °°°€­­ ­°­« ª°ª/©o©©O©Ÿ©ß©  Ÿ+@Ÿ Fº²:@A P°ÀÐÿÀ@ $Fž›$›$œ›$P›˜ZH—–$Жà–¸ÿÀ@W– F•_”o”ϔߔ””””ÿ”“’<@’F@’ F‘_‘Ÿ‘¯‘¿‘ï‘ÿ‘@‘%F °ÀÐàŽF0@€o¾ à ÿÀ @'F Š0Š…„Fmÿ€ÿÏußuïuïuts?sP&и@>rF5qF5@p&,F p0poF5nF5U3U3Uÿ§m)mlÿ`P&_P&KA [› ³16F ¸@1&*F^Z2\F1[ZHZF12UU2Uo?–Y°RÀRÐR¸ÿÀ³R-4F¸ÿÀ@˜R $FïQÿQ@Q58F@Q%(FÏP N)/FN"F MMHMXMØMèMøM˜ML$-FL F˜L¨LKF7IF HF5GF5¯FßFïF€F2UU2UU?_/Ooßÿ?ïo€¸±TS++K¸ÿRK°P[°ˆ°%S°ˆ°@QZ°ˆ°UZ[X±ŽY…BK°2SX°`YK°dSX°@YK°€SX°±BYtstu+++++stu++++s++stu++t++s++sssu+++++++++st+++ss++++++t+++s++st+++s+stst+st+st+++sts+s++s++++su^s++^stssstst^s++s+ss+s+sstu++++++t++^s++^sst+++ssssssssÌÞ}y:wÿìÿìÿìþW´½¯ Ö±¨–‡ˆ~ ¬Ì ¿Ã«¼›¹¯r²©”™€j‘®´[LtdÙj¸¬•Šeö"3íéÃ¥ˆÛÏÉÃ9+áÉ’¨k’·k›òŠ’nÖL‰ ^פ[^‚t^eoˆ¥z€þåÿó ü§ƒˆ–iq¢B©µHj¶ý“‘g‘aÙA¨SE—ãyŒj „“D©XXXXÐTøôÜð 8 à ˆ „ ü T ” Ä ¼ÜTPÀHØdè” ¸¼ü !H"h#H#ü$œ& &Ä'8(()4)œ-„.Ð/à0¤2P3h4Ô5h6Ð7œÀ?œ@<@AB$BLB˜DEdFlGÌHèIÌK L¸MpNPO¬P8TTU`VXWÜY`Z<[\^0_c d|e¸høj`jlmm¤optìvpvÄyy | }À~ Lx‚D‚섇ˆ‡Ü$°ðŽ´‘Ð’Ä“¨“Ô””8•¸•è––H–x–¬–à˜(˜P˜€˜°˜à™™D™t™ ™Ð›(›X›ˆ›¸›èœœLŸ Ÿ<ŸlŸœŸÐ  ø¢€¢°¢à££@£t£¨¥°¥Ø¦¦8¦h¦œ¦È¦ô§ §P©©8©h©˜©È©øª,ªÐ¬l¬œ¬Ì¬ü­0­`®ð¯$¯T¯„¯´¯ä° °4°d°”°Ä°ô±$±L±|±¬±Ü²²³ð´ ´P´€´°´àµµ0µdµ”µÄµô¶$¶T¶„¶´¶Ü··4·d·”¸ØºXº„Â\ÂŒÊdÊÒhÒÒ¸ÒèÓlÓ„ÓœÓÌÔôÕÕDÖœÖÌÖü×$×L×|ר×Ð×øØÌÙ¤ÙÔÚÚ,ÚTÚ„Ú´ÚÜÜlÞÞ4ÞdÞ”ÞÄÞøß,à¸ââÀâðãã@ãpãœãÌãüä,ä\ä„ä¬äÜå å$å<ålå˜æ|ç°çàèè@èpè èÐéé8élé éÈéðê êPê€ê°êäëëDëtëœëÌëüì¼î”îÜï(ïXïˆï¸ïèððð0ðHóõL÷¬ø(ú”ûdþ$ìD„ PÀð P€°äô„dt„” , < L | Œ œ H X  $ °\ <p Ð,dÔ”„è00x°d ¼"#Ø$„&&,'„(ø*8+D,8-h/0l2„3ô4$4X4ˆ4¸4è56à78t8„8”8Ä8Ô:œ;ô=,=\=Œ>¸>È?¸?È?ØA˜A¨C´E@FŒF¼GÜHôIII$I4IDITIdJdKüL M$N<OHPÌQÔS,TUtVÔWäWôYTZ´[ð]P]`_Œ`¸`È`øb8cDe<ff$fØfèføggiŒiœkxlìo4qàstXutv”wìyy8{ {ø}$}4~(~œ~¬€l؃Xƒˆƒ¸…À†˜‡P‡€‡°‡àˆˆDˆxˆ¨ˆØ‰‰H‰œ‰ðŠ8ŠPŒ‘ ‘€‘ä’¤–„šL›œžž|£ü¤P¤h¤ø¥„¥œ¥È¦©Øª¨¬¸¯´±\¶,·œ¹ü»¬½œ¾œ¾Ì¾ü¿,¿\¿¸ÀÀpÀÌÁ\ÁìÂŒÄÄ´ÅÅøÆHÆàÈðÉ ËÐÌtÎüÐÐtÑ,ÑÐÒ,ÒXÒÄÓ@ÓpÓ¤ÓèÔ,ÔpÔ´ÕÕLÕ˜ÕäÖHÖ”Öè×DפØØtØÔÙHÙ¤ÚÚxÚÔÛ4Û¨ÜÜ|ÝÝlÝÜÞhÞÔß<ßÈà4àœá,á¼âPãã8ãhã˜ãÈãøè(ëàï`ï|ï¼ïôðDð`ð|ð˜ð´ðÐñXñüò`òÄóhóìõLöL÷¬ø ùÐúûœüDü¸ýPþ<þTþlÿÿÿ\€p`¼d(èPô” DdU.±/<²í2±Ü<²í2±/<²í2²ü<²í23!%!!D þ$˜þhUú«DÍM%L@ ¶›«¸ÿð@&H›«˜ /˜@ Hp?/ýÎ]/+í3/]]qí10]+]]#373I”¬Äþ((Â(ôúÉÉ»Æ#Y@=–/Ÿ¿  –@oO¿p9npn.À.Ð.@p€.. $o%%¸ÿÀ@GH%%E o @H (?s3)>t>„>9>).%o%%%4s P `   €X+?3//]í2?3//]9]33í2/+í3/+qí9///]q]ííí3/í‡ÀÀÀÀÀÀ‡ÀÀÀÀÀÀ]10]]]]]]]]]]]]]#7.'7.54>?3.'4.'>0GˆÆr ÉÓ£ /IgE`L‡e:T¹drSZ7 œucVG‰lB¹!"32>7654&2#".5467>"32>7654&©¥¢§ûÔ5^G) Zjq/7_F( Xjq0%F>4B<#C>4?h5^G) Zjq/7_F( Xjq0%F>4B<#C>4? IvU%]0~ ["$MxT%[.ƒ WlCxbjHb\Dx_oK`VþT IvU%]0~ ["$MxT%[.ƒ WlCxbjHb\Dx_oK`V!ÿìè‰=Oa@6‹0.Š@€7…5ŠVŠ`…MyF‰F{C;;{:q959U9e9)¸ÿà@, H%% PI",I8A3SF" X@XpXX@""¸ÿÀ@ HX"X"= ¸@7O=Ÿ=¯=Ï=ß=ï===cKH@ H3F8A>S'==>]QÀ''?''>Q?3í22/]qí9/999/+í3/]í2/99//+]]_]9íí10_]]+]]]]]]]]]]]]]]]3267#"&'#".54>7.54>32>7267.'>54.#"à>GS0(e. 3 9&JŠ;RÈ}j™d08m h 6f•^EsR-'D^o{?+4A((F>7ýhY”@+K@3GoM("@\Ç OŠg;+<%4W="¬=}{t3&) ‡ ?;615ggi7.gmp6ýŒ6/5vyw47#73+ "*{9K X*Ã35WKB A„AÛiÐ|p%@/»ŸÏ//]qí/]/]]107!iôР P>Û@ –@ H›/í/+í10373P+Ã+ÛÛÿŒÿìéÌ'¶I¸ÿð@?Oo??/]8/810]3t¿žýDàú Yÿìb–3\@At3„3‡-{(‹(ˆ" [k[k T d o&&&51o/s )s?í?í/]í3/]í10]]]]]]]]]2#".54>7>2>7>54&#"ÜQi= („¥»^SŽg; P`pv|µL€kT wlL€kT w–7r°y?™SËþ÷›>54.#"'>32! 7ˆ”™}^6"=U3m¢%ªRx¡fY–m=;d„’˜Œv(×]’wb[ZfyL3Q9ww%L€]42]PU{ld`dk>™0ÿìa–=Ê@z8Š8r.‚.Z$j$z$Z#j#z#¸ÿÐ@t H%<no!n6?54.#"'6$32#".'732>54.+76$SQJ8"9R6w«"²: »]•i83`ˆUƒ’?}½~r¨sC¤ 3QpIJpK'*Kf<|(?[?,J5zoºµ/YQN^; {WœtDAh>0.[J.)Ie<´>ýs3Ǹ¼Ðý©Ó?þÁ?Œ¶üLŽFýH.ÿìx,½@&y*‰*y‰z%Š%r‚ZjZj  $ ¸ÿð³H¸ÿൠH,¸ÿà@FH H+o,,n####.o@ H,,(sß    sP`t€X+?í?3/]í9/]]3í3//+í3/]3/í9/í3/Í++9++10]]]]]]]!!>32#".'732>54.#"#W!ýƒr6FU1Y–n=GŠÌ…jœmE£ *HkJN€[1)E]3`†4°™þA 5e’]wŠK2XxG+(Q@(,Z‡ZCdB!9,sÿìs–'9†@X†%{3‹3s+ƒ+|Œ:/J/!!%! #n2/222o;(o5sß-s p -s?í?3/]í9/]]3í/í23/]í9/]í10]]]]]]]]".54676>32.#">3232>54&#"cœk9 %~¤ÁgDxcH¦rQN‹rX<·qSf:H…¾þ”!@]75.54>2>54&#""32>54.À`œo<-SvJ2T 4K`;a¥yE9f‹RaŠ^6 &—gWŒa5ý–5Qa-bm@bD(O?(‹.StG3X@$)PwO,UB)FÿìI–'=@`u4…4z*Š*t!„!5/E/%:&*&Š&  †oo(((((? o2n@ Hs77_7o777 #s  -s ?í?3/]í9/]í2/+í3/í3/]3í10]]]]]]]]]]#".54>32#"&'732>4.#"32>76‚>©la”d3Jˆ¿v_™l; %€£¾b¡º$žv[P‡nT7"A[9HzY1">V42j]G ¬^mBn‘OqÈ•W>y°rDIL"¼þö¨M…-U\JÐÓ:bG(7g—`?`@!"FkI=Qç:#@––@ Hœœ?í/í/+í3/í107373û)Ã)þ“)Ã)kÏÏü•ÏÏ&þúô: B@ –  –Ÿ ¸ÿÀ@!%H   œ¨ › /3ýä?í/]+æí93/]í10]%#>7#7373, "*{9K X(ÃA(Ã(35WKB A„AÏœÏσšfª„@ 䯴•¸ÿØ@H(Hê(H‰å¸ÿØ@3H†0PpÀß?0p€?oŸÏ/]33Í]Í]/]/]310]+]]+]++]]]]5 ƒãü¦Z;Í¢šþ’þ‘™‚XeìP@:@`pÀÐO0¿Ïß­/_oß­PÐ/]]íÞ]í/]3/]]]q3105!5!‚ãüãX””þ””ƒšfª„@ ëÉ»š¸ÿØ@H(Hê(H‰å¸ÿØ@3H†0PpÀß0p€??oŸÏ/]Í]Í]33/]3/]10]+]]+]++]]]]75 5ƒZü¦ãš™onšþ^ÍŸm–'+}@&zŠ *ZzŠ ™+˜((#˜0¸ÿÀ@# H-"™Ÿ#¯##)(O"_"o"Ÿ"""¸±?í3/]/ýÎ]9/]í3/+qí99//íí9910]]]2#>7>54.#"'>73½e o<=ay<*O@- ¯ AYh30XD(&E`;Œ¶&¥Wƒ³þä'Ã'–6`‚Ma‰eJ#3;H.NqU@9F[=0Q9 Œz(TŒe9újÉÉÂþåÌ]r@&‰nv&†&fEvE†Ef\gWwWiTY4‰4\8J@¸ÿð@¡ H H}ee)e9e%U{‹ H H H":2:B:::-9 99u?…?Q??2?B?Š3 33Z3"^ $ ^$ hÔ%%i)y)‰)™)©)¹))Ó $$ ›ä ” H HRÒ1ä1«1»1Ë1„1+111tt¸ÿÀ³/2Ht¸ÿÀ@˜"*Hkt{t«t»t=Ó$R»RR@ HRGG$G GGB,kÖ %$cÖ$"B6ÖYBÖMÛ€tpttðtàtÐtÀt°t@t0t tttðtàtpt`tPt@t0t ttt<àtÐtÀt°t trrrrr^]]]]]]]]]]qqqqqqqqqqrr_r?í?í99//33í/333í29/^]/+]qí]q++3/]]]qí9///]q]3/í]q2/í9‡ÀÀ10]_]]]]]]]]+++]]]]++]]]]]]]]]#".5467##".54>3237332>54.#"32>7#"$&54>$324.#"32>7>Cv¤b8O1E]uGT}Q(G„¹r<`I6'œt+&>kO-S¡îœ†ã¸‹^0V¥ôi¶˜y+72‡¦Äo¾þÙÊj?vª×ÿÉ$¿\ý¢"?Y8UƒW-_cEy`E óï¬`/@&+ -YE+:gSxÝ©f0C( þTx10.QŽÀpÞ¢\@t¡ÀÚtî«`!09p?4!sΩ‹Ü´€FvÈþø›2Tf…F$Pÿ›è±@vI‰(XhxR \R ^  ) i  {+;»›«»@36H@ H/_ ?2?339/3í2/]_]++]3/]q9=/]‡+‡+ÄÀÀ‡+‡+ÄÀÀ10_]]]!!#3 .'!%KýðÐPÙ$þ $,þòœþdú )NA+,AO(þ(?*Â@+v j(UUeIYiI$O _ o ;   Z&¸ÿÀ@U H&&[/?O¿ @ H,*  R ^@ H *_ÀOß __lmX+?í?í9/]qqí9/+3//+<‡++ćÀÀ3/+]]qí9/+í9]]10]]]]]]]!2#!!2654&#!!2>54&#!Pþh¦u?¬§GmI%.Roƒ‘Jý­\Kµ®‰ƒþµ×pN“pDŸ•þ’,SxK’© 7Pd9S‚bC**‚€_]û±@pYkpqÿìÒ–+¡@(‡#‹Š yj Š e(…(f5*E*U*9I\¸ÿÀ@DH+\?¿`p€-!Z/  @H _O_0+@+P+€+À+Ð+++&_lmX+?í3/]?3/]í/+]í3/]]qí3/+í10]]]]]]]]]#".54>32.#"32>7N1zɔݒH6dµÖxŠT´>a…W’äžR4gšfZ–}c&QI‚a9\Ÿ×{|à¿›l;;`|B7/WE)k½þý™^žs@1Qi8?……@Y…‹ „Š +{‹{‹Td„[??O_¿^    @ H __ lmX+?í?í/+3//+<‡+}Ä]3/]qí10]]]]]]]2#!!2>54.+è”ö±b?rœºÑnþ5“ñ«]I€°fòOœç˜…ܰƒX+ûX¥í–x®r7?i ~@Pp€    /   R ^@ H_O¯ï¯ß _ _lmX+?í?í9/]qrí/+3//+<‡++ćÀÀ3/]99//]]103!!!!!?ü¦Xüâ_ƒœþ<šþœ?C l³¸ÿÀ@; 'H R^@ H_/_o@H_lmX+?3?í9/+]í/+3//+<‡++ćÀÀ3/+9/10!!#!ñfüän¿óåýôžýÅœeÿìá–-è@Ž…"‹ z&|‹}y ‰ j Š U'e'UZjZ!%!…!*)R)^--++--Z@H`À/[? O _  /  @H *_/-_----$__$_)lmX+?32í?3/]í9/]í/+]qí3/]q3/+í9/9/F·.(-. +</+<+H‡++Ä10]]]]]]]]]]]]]%#".546$32.#"32>?!7!n8ƒž½r¢ñŸOwÛ8Áƒ¿†SÁ8[‚X™í¢S6oªt[—x[3þ[ UÒ0T>$WœÚ„¼;ã6\xB6/S?%i»ÿ–a¢uB-8þ ?É ~@HW  R ^   R^@ H _ lmX+?2?39/3í2?3/+3//+<‡++ćÀÀ3/3//+<‡++ÄÀÀ]10!!#3!3ýý¿¿tÿtºþîýsý¬TúQ"Wµ°À¸ÿÀ³&*H¸ÿÀ@(#H?R^@ HlmX+?2?3/+2//+<‡++Ä]]++]1033Q¿þîúÿûÿì¢@[dt„)9p R ^OŸ¯¿0p/\/  __@PlmX+?2/]í?í99/]í3/]]]qq3/F·( +</+<+H‡++Ä9/]10]]"&'732>7!7!}ŸÉ¨pd767#.'&'#367>7!í´  2ýÜ|¹ ´ªì½ # )þï 3j,3043,`%üL´_-5987/f(ü`ü/C#(0,(#GÉú?Èû@+gºÊÚ(H­HI0 H´ Ä Ô  ¸ÿà@(H’ ¢ e u … F V  ¸ÿÐ@ HR ¸@  R¸@%O¯¿p€R¸@"   @ H   lmX+?33/22?3/3/+3//+<‡++Ä3/]]qq3//+<‡++ć+‡+Ä10+]]]+]+]+]+]]!#367>73ÛýíµªÔ µ¬þïº.0)]'üQûA+0)e3£úoÿì–3r@Q+2‹2+*$%„%$y‹‹Yi;v „ „ V f 4ZO/_///5"Z/@H'_ _?í?í/+]í3/]í10]]]]]]]]]]]]]]2#".5467>$"32>7>54.ªÞ™O ŽÑþó–à•K ŒÑ–ƒÌ—b 8k›b„Í–c :lš–UšÔ€1i0š÷®^WÚƒ.`1–ö¯_šJŒÊ€+W'k¡k5KÉ}*Z&k¡k6?Il@CzŠW[ /  R ^    @ H _@ H _ lmX+?3?í9/+í/+3//+<‡++ćÀÀ3/]]í10]]2#!#!2654.#!Tt¹‚FO“Ó„þXj¿6ƒÀ¾-RsFþ£6d‘Zn¯yAýÛý;œ›A\<eþ}ö–*Då@ †(…)v)y ¸ÿè@™HŠ'Y'i'V f † 5: J *CŠC);%6…6&. * * Z#Z@@/@@Ÿ@¯@$"32>7>54. Þ™O y°ã… $6H-F&R1UwN, †Ê†C ŒÑ–ƒÌ—b 8k›b„Í–c :lš–UšÔ€1i0ŠåªkBY6† 3_‰W _šÑ{.`1–ö¯_šJŒÊ€+W'k¡k5KÉ}*Z&k¡k6?ˆ¼@wv † {‹VfWR^€ dtP@H [ @ HR^@ H__lmX+?22/3?í9/í2/+3//+<‡++ćÀÀ3/+]í3/+9/]]]‡+Á‡+Ä10]]]]!!#!2 2654&#!óþGq¿dh¬{EØÓ þpµ¸•”þUeIý·3`‰V¼Üý¦à—‰pxýø:ÿì@–;Å@‰k:$7t7p6;3[-†"d"t"dt;;tDTDTy‰k%\$$9[/Zp€oÐ/?=\@ H„/V/I/xK/*`%% _@P?2/]í?3/í99]]]]]/+í3/]]q9/]íí2/í10]]]]]]]]]]]]]]]".'732>54.'.54>32.#"h‚ÈQ± 8^Š^bœm:"TlX›tD_ŸÍnyµL­6TuNhY()TXW¥€MþÊ/[…W%>\=?eK3H93;W|Zi“^+,OnA30L5#?W36G2):Y„cÎÞ¸\k@Dà¿€ /__oOßR^/_lmX+?3?í22/]3//+<‡++Ä33/]q/]]]]q10#!7!Zô¾ôþ†åû圜™ÿìÑ!þ@‘eu…YW) R^9°ðÏßP °_o¿0/# # R^   @6:HP`p_@ H _lmX+?í?399993/3/+qr+3/F·"( " +</+<+H‡++Ä]3/]]]qqrr^]3/F·"(" +</+<+H‡++Ä10^]]]]]".54>7332>73Žh·ˆN–¿¢ 2XzHW•wU¨¾ªsªÜ6pªs785üµ$MJlG#,`›odü‘ψB±õˆ@73¥ÆþÒÂÆ /DÐü -Y#)'%)#Y/à±.0³†!¸ÿÀ³%H!¸ÿÐ@=H„!”!´!v!T! %HO_ HÏß HvK[{9+/¸ÿà³H¸ÿà@ H•¥µ¸ÿè³H¸ÿè@ÿ H Hi X I  HR!)!L   R O  R/)/^000R^¦ — † G W H)X)™)x)g)()8))˜¨GWg )) 0V0f0002 2‰2©2¹2Ù2é22@-2H{292I2Y2)2I2Y2i2‰2É2ù22 @ H0/!  /) 2û2é2Ù2É2¹2©2™2‰2{2k@ÿ292 2ù2Ù2É2¹2©2‰2{2k2Y2K292 2Éé2Ù2É2¹2«2y2i2Y2I292)222æ2Æ2–2f2V2)22æ2Ô2Æ2¦2–2{2i2I2)22 2™ù2ë2Û2Ë2»2«2›2‰2y2k2]2I2;2-22 2û2í2Û2Ë2»2«2™2‹2y2k2[2K2;2+22 2û2é2Û2Í2»2©2›2@ž‰2y2i2Y2K2;2)22 2iû2ë2ß2Ë2¿2¯2›2‹2{2k2[2K2;2/22 2û2ï2Ë2¿2¯2›22{2;2+22 2ÿ2Û2Ë2»2«2Ÿ2‹2{2o2229ï2ß2¯2rrr_^]]]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrrrrrrrr_^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]qqqqqqqrrrrrrrrrrrrr^]]]]]]]]]]]]qqqqqqqqqqqqr?3/33?3/33/3/+^]^]]qq+qr3/]89=///]]]]]]]q]]]]‡+‡+ć+‡+ć+‡+ć+‡+Ä10+]]_]+++]++]]]]]+]+q+]]]++]!#.'&'#367>732>73~ßG/þ]ߎÅO  Ÿ·K,5§É057<@?=4n&üü?{2:4EC=<7mü“8;=CFEhy4ÿÙ– @  $-HH¸ÿà³$-H¸ÿð@H%,H¸ÿð@B%,H‰k      R KR L ¸ÿð@3@     O  ¿  @"&Hp €   / O _  ÿ ¸ÿð@@ H   ?22/3?33/39/+8]3/]]+]q8999//]88‡+‡+ć+‡+ćÀÀ‡ÀÀ‡ÀÀ‡ÀÀ10]]+q+q++++! # 3 3 çþÑýôÓŽþ¬ÇÛÓý¨p^ý¢ê—ýÙ'ý\ý#ÕÑÚ@i$$$ä„R^à¯RLRKO¿Ïï@p ¸ÿð@¿€@ HlmX+?3?33/39/33/+]]83/]]qq89=/‡+‡+ć+‡+Ä/]]q3/+<Á‡++Ä10]]qqq#3 3q¾sþ€Ä20ÖHý¸H9ý^¢ÿØ ¬@$4D %*H Hf†+;K¸ÿà³%*H¸ÿà@ HIYi‰¸ÿÀ@A H  €   RM/¿ @ H__?í2?í2/+3/3/]3/‡+‡+Ä99//]+10]++r]++r)7!7!!:ûžýêûâuVœ‹û¦ÿÙþWâÌu·%¸ÿè@F H *Zjz@@RðP`/?OO¿õõ?í?í/]qq3/]‡++Ä2/]3/]10]+]!#3'r—éþ¿éþWuù’ÿìØÌ5@r‚V} H¸ÿð´??/8/]810+]]]3@®”²àú ÿWþW`ÌF@(vRðO/õõ?í?í/]22/]/]‡++Ä3/10]73#7!©èAé—þþWsø‹(¡Õù@ :H¸ÿè³H¸ÿè@0Hv†Hy‰0@`p€à @P`¸ÿÀ³0AH¸ÿÀ@:H?Oo/_o@H €9 0@ðà¸ÿÀ¶?>54&#"'>32326732>7C ]U#K[pJNuP(/Qm{„?èj^1UC3²Bl›lYŠ^1 J'*þüÇ(VSK8!,A,W‚\5  ML#5T;2Sl9QvT5 $.[W'C3>gJ),NlAW'þ†.%$¢ 7N7 =/733>"32>7654&èP|T, X| c{š  ­ õ´S $KUb@sbK"?Y6>dQ>^N2\ƒQ2w?ŽË‚=h^;4% +7#".5467>32.#"Õ8ZF6œQoŽWg—a/ EUcim5Y‡^5±3J1EnW> gz!o˜Z(^-o¤uL+.TuG-J5(Z‘i0j&ŒEÿë©Ì'=®@@v†j%Ueu9,I,* *  */"RK"""""""/"o"¿""¸ÿÀ@$H""?;G@ H"/4P (PXYX+?í?í9?3?3/+í3/+q3/F·>(""> +</+<+H‡++ÄÀÀ10]]]]]]]".5467>323>73#467#'2>7654.#"‘P|T, X| c{›  R´õ ¬ $KTb@sbK"?Y6=eQ=^2\ƒQ-|?ŽË‚=h^ .3. £û'H<+ X4/D-‹&]žxbOAbC"%[™tyU{|Eÿì'N%3@t„{1‹1{+‹+*% I ¸ÿÀ@6 H FÏ)0)O)Ï)ß))))53F@@ H P33.PP?í?í9/í9//+rí23/]]qrí3/+í10]]]]]]32>7#".54>32'>54.#"…†8\K9ŠHk–hdžm9U—Íxn¢l5 Ÿ$B\80jaP÷9…Ž1A$?-YH-9mžež¶c:h‘W267Š#Ba?JbEêÌ‚¹ ÿØ@J H¯¿@ HRKà@ HP QXYX+?3?3í2?í99/+]33///+<‡++ÄÀÀ‡ÀÀ/+]9/10]+##737>32.#"3²¹´¹˜˜ &GpV C  &3!Ó·üI·ƒz;fL+‰*='aƒþWaM:Rã@xJ9Z9j9%#j„9BIBv5U'e'…'*" *F56R6K))))/pÀOT0T€TI@P`;G0@ H560/F)KP$¸ÿÀ@ H >P PXYX+?í?í9/+?í9?39/+rí3/]í]q3/]qr3/F·S()S +</+<+H‡++ÄÀÀ10]]]]]]]]]".'732>7>767##".5467323>7332>7>54.#"]Š_7 £udHnO5 ?RlHO~X/ 2ïÎ9fQ;  « ¡Jz¯þüif6ocO$AX3>eP< þW%B]8*LQ%LwS<(L:#7a‡P1m?5L0>7( +y.džp*Y CcB %Y•q;l"Ì#¤@   ¸ÿà@W H R K   / O Ÿ ß  %WRK@ H #  PXYX+?í?39?3/+3//+<‡++Ä]9‡ÀÀ3/]q3//+<‡++Ä10+]]]>32#>54&#"#3"HWiC”• µ~ T_@q\Av³ ´K /L5’Š$Z&ýs…'QOX3]ƒQý¢Ìþ~!B7(!õÌе€ Ð  ¸ÿÀ@U/2HO  / Ÿ ¯ ¿ ÿ FRK`€Ð@ HSXYXð à Ð À °   rrrrrr+?í?3?3/+qr3//+<‡++Ä3/í]q+q10733"´"þNÒ´Ó ¬¬úà:ûÆÿþWöÌ@N„  H/FRKÏßï@'-H@$H@ H@H PSXYX+?í?í?399/+/+++r3/F·( +</+<+H‡++Ä3/í]10+]73"&'732673!!´!ýÇ"E 2;<ç´í 'Bc ¬¬ù7 ˆT\¥û@>jN-"VÌ ¹ ÿà³&*H ¸ÿà@ H   ° WW’ ¢ ²  ¸ÿг&/H ¸ÿÐ@˜ H  u  e u  & F V f †   R  N  RK      ß ï ÿ / Ÿ ¯ ¿  ?O_RK@ H   XYX+?22/3?3?39/+3//+<‡++ćÀÀ]3}/]q83/]899‡++ć+‡+ćÀÀ10]]]]++]]]]++!#373 Ñþô¨H³ ´³ÌiÞýîPö|þ†Ìük¾Eþ/ý—!õÌp@KV`€ÐO/Ÿ¯¿ÿRK`€Ð_@ HXYX+?2?/+qqr2//+<‡+Á‡+Ä]qqr10]]33! ´þßÌú4"KMA_¹+ÿà³ H#¸ÿà@ÿ H9@ARAKB201R1K23233233 2ù2†2i2y222C–CiCTC&CFC CVC†C¶CÖCæCöC C)CùCæC™CÉCvCYC6CC$CCRK@ H;P*%@30 P"12A2XYXéCÙCÆC¶C¦C”C†CvCbCTCDC2C$CCCôCäCÖCÄC´C¤C’C„CvC@ÿdCVCFC6C$CCCÊôCäCÖCÄC´C¦C–C‚CtCfCTCDC6C CCCöCäCÖCÆC´C¤C–C„CvCdCVCDC6CCCöCäCÖC¤C’C†CrCdCVCDC4C&CCCšöCæCÔCÆC¦C†CfCVC6C&CCöCÄC¶C–C„CvCbCPCDC$CðCäCÄC¤C„CtCTCDC$C CjûC@`àCÐCÄC°C¤C€CtCdCDCCàCÔCÄC¤C‹CDC+CCôCÐCÄC C”C{CDC0C CC:ïCÐC¿Crrr^]]_]]]]]]]]qqqqqqqqrrrrrrrrrrr^]]]]]]]]]]qqq_qqqqqqqrrrrrrrrrrr^]]]]]]]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqq+?2/3/3??í93?í/+3//+<‡++ćÀ^]]]]]]]]qqrrrrr3/]]]q3//+<‡++Ä9/3//+<‡++Ä10_]++!>54&#"#>733>32>32#>54&#"”| LV9gR<v³¦ ª @L];yŽ DSe@‡‘ ²| LV9gR<vz00+KO3]…Qý¤S"KC0,9;/L5wq2T?#’Š$Z&ýsz00+KO2\„Qý¡"M'‘¹"ÿà@X H &'R'K/OŸß) R K@ H &P  'XYX+?2?3?í9/+3//+<‡++ćÀ3/]q3//+<‡++Ä10]]+!>54&#"#>733>32Í~ T_@q\Av´¦ ª "HWiC”• …'QOX3]ƒQý¢S"KC0,9;/L5’Š$Z&ýsCÿì2M3`@C/t*„*"{‹/  G0OÏß5`5p5'G @ H P,P?í?í/+íq3/]]qí10]]]]]]]]#".5>7>324.#"32>7>2 k°d`œo= fŒ±ij¡m8º"A\95kaP &C[66i^O «4i;„ºt5;q£h/d6~µv88l›cMlE LŒt7c*RtH!MŽu733>32"32>7654&*{›  R³ù §$KUbdQ>^h^#4>þY'H;* $-2/D-2\ƒQ2w?ŽË‚=×&]žxbO@cC"%[™tyU{|EþWeM'=ѵ%H¸ÿè@ HUeu¸ÿè@; H* *  */$RKÀÐào¿P/???¸ÿÀ³-2H?¸ÿÀ@$H;G@ H"/4P (PXYX ?r+?í?í9?3?3/+í++3/]]qq3/F·>(> +</+<+H‡++ÄÀÀ10]]]+]++".5467>323>73#>767#'2>7654.#"‘P|T, X| c{›  ­"î´U $KUb@sbK"?Y6=eQ=^2\ƒQ-|?ŽË‚=h^=7,†û6·4/D-‹&]žxbOAbC"%[™tyU{|"ïN!s@J†W ¯!_!o!!@(+H!@H!@ H!!#  R K   @ H   P XYX+?3??í9/+3//+<‡++ćÀ3/+++qr10]].#"#>733>32Î/@fM2 n´¢ ª =BK- ªJr‰>ýÌ>#FB;<>9>[;ÿìÖK;ª@.::d:49d8p6T5 !!+!+k‚5H2H¸ÿÀ@C H )I* *`*à*ð***= Io ¯ / ? O  @H 2-Q$ ****$Q ?3/í?3/]í99/+]qí3/]qí99//+íí10]]]]]]]]]#".'732>54.'.54>32.#"‹D}²o]ŒeC“/E_?@kM+&Ec=AuY5Gy¡ZRˆfB £zg5]F)&Ea<9u^<=UT) =[;8(?+.H3(9+%2F_@RsH!=aEOF$:))7*!0Ge]ÿì€, @T H /O_¯¿°À R  K    Q   PXYX+?í?3/39í29/]q33/F·(  +</+<+H‡+Á‡+ćÀÀ/]/]39/10+%#"&5467#73733#3267À%X0Ua ~}ix/ÈÈ}*0- fT Iƒòòƒý{:*.VÿíJ:'&@\l>N/?O¸ÿà@˜ H$4Dt„"& v †  &''$ RK  ? ß ? O Ï ß  @H )RK$'$$'$$''ÿ$$$/$$@#H$@H$$  P  'XYX+?22/3??í999/++]r3/F·(('$$( +</+<+H‡++Ä3/+]qr3/F·((  ( +</+<+H‡++Ä310]]]]]]]]]]]]+]]]32>73#4>7##"&5467Ÿ~ T_@q\Av´¦ ª "HWiC”• :ý{'QOX3]ƒQ^ü­"KC0,9;/L5’Š$Z&pb:–@Af HR MR K   H ` @P€¸ÿð@@),H0@H @ H ?3?339/3+/+q+8]3/]89=/+]‡+‡+ć+‡+Ä10+]!#3>73ûÕ¶»e !! €Ä:ý@?D??B?Âf5:(@ H¤™(¸ÿà³%H¸ÿÐ@Hfv–TÄÔä¸ÿà@Ö%H6† – ¦ 4 d t 9 %H0HŠª;[)&+';'›' H=(R!KR  OR'!'L(((RKW§·8!H!X!ˆ!¨!8HXˆ!!(((V(f(6(v(†(–(((*©*–*9*I*Y*y**ù*Ö*æ*i*y*‰*6*F**¸ÿÀ@ H’*„**¸ÿÀ@ H *9*¸ÿð@ÿ@H('!&6 @ H' ¶*¤*–*†*v*f*F*4*ö*¹*©*„*v*f*T*F*6* *Íô*æ*Ä*¶*¦*–*†*i*V*4***æ*¹*™*„*t*d*T*F*4*&** *ù*é*Û*Æ*¶*¦*†*v*V*)***›Ù*¹*«*™*†*v*d*R*@*0*$**û*´*¤*”*t*@d*T*$*ô*ä*Ä*«*›*@*4*$***ië*Ë*»*«*›*T*;*$*ä*Ð*´*t*D***ô*ä*Ô*Ä*«*‹*{*d* ***9à*Ï*rr^]]_]]]]]]]]]qqqqqqqrrrrrrrr^]]]]]]]]]]qqqqqqqqrrrr_rrrrrrrr^]]]]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrrrr^]]]]]]]]]]qqqqqqqq?33/3?399+^]3/3/3/+8^]+]]+qqqqrrrr3/]q89=///]]]‡+‡+ć+‡+ć+‡+ć+‡+Ä10_]]+]]]]++]]]]+]]++]]+!#.'&'#367>7367>73,Ñ%#þÇÐ\²(  UÁ, N°ºN(/3-,&RýJ:ý! 7=9 $#Bçý6d$$#Dßÿ®<: @F& †        R LR M  ºÿðÿð@,    P   /     Ð à  ¸ÿÀ@=-2HP@ H      9ð à Ð À °   rrrrrr^]]]?22/3?3393/3/+^]+^]3/^]]99//^]98888‡+‡+ć+‡+ćÀÀ‡ÀÀ‡ÀÀ‡ÀÀ10^]]]!# 33 ÂÑþ„Çìþø½Á^Îþ+¼þD,þ[¥ýôýÒÿŒþWg:Ô@6[*& RMRK;K[¸ÿð@'_o_P`P`€! !@!O¸ÿÀ@H/@H¸ÿÀ@H P?í?3?339]+/3/+]+q]3/]q89/qr89=/]‡+‡+ć+‡+Ä10]]]]]!#"&'7326?3>73õ7fpƒU!E+_‘FÙ·p  ')RÇ_œp>†€z/.ýª TSG?GK#lÿÔ: @*‰&6f†RL ¸ÿ€@#/2HW 6 F %   ' G g § Ç ç ÷  ¸ÿÀ³H ¸ÿÀ@H8   ¸ÿÀ@ÿH@H@ HPP÷ · § — w V G 7 '   ÷ × · § — ‡ w g W 7 (  ʸ ˜ x h  ø Ø È ¸ — ‡ g G ÷ ç Ç § G '  ™Ô à ´ £ “ ƒ s c S C 4 #   ô ä Ô à ´ £ ” ƒ t c S C 4 #   ð à @ÑÐ À °   ’ € r b R B 0    iò à Ò  ² ¢ ” ‚ t ` R B 2 "   ô â Ô Ä ´ ¤ ’ ‚ t b T D 2 "   ô â Ô À ² ¢ ’ ‚ t b T B 4 $   9ò â Ô  °   _rr_rrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qq_qqqqqqqqqqqqqqrrrrrrrrrrrrrr^]]]]]]]qqqqqqqqrrrrr^]]]]]]]]]]]]qqqqqqqqqqq?í2?í2/++33//+^]]]++qrrrr+3/]‡+‡+Ä3/]10_]]]#7!7!!,ý§8üᧉ&‹‰üÚ‹þWAÌ9¼@Vfv H H`p¸ÿÀ@] H_8Ÿ8¯888("#R#ð_,ð 4ð¿Ïï,48"#( 9(õ@>H8õ8õ9?í?í9|/+í999999999/]qí3/í/3/]‡++Ä/]33/]3/+]10++]".54>7654&'7>7>;#";n;[=8 ]U3VB. F—އ?1E1 E .@P+EQ=GM0þW&B\6   ,!SI8X>j–4Q8þœ2T@, dN þÁ!! H8õ9õ?í?í9|/+í999999999/+]]/]]33/]‡++Ä/3/]íí3/+]]2/]310++]2+732>7>75.547>56&+74;[=8 ]U3VB. F—އ?1E1 E .@P+EQ=GM0Ì&B\6   þá+"SI8X>þ––4Q8d2T@, dN?!! 323267jE‘IX&A<82„Q)OMK%233E{4<=D),-  &.  2*•@þº;^@B¹”¤H”¤x˜ ˜Ÿ@$H@H@ H/]?ýÎ]/+++]í3/]qí10]]+]]3##7”¬ÄØ(Â(®ü ÉÉžÿáD%Ú±?°3°/° Ͱ2°%/°3°Ͱ2°&/°Ö°Ͱ°#ܰ"Ͱ"°'Ö°6¹>ÕóÔ °.°À±ù°À°±°À°À°° À°À¹>ÕóÔ °°À°À°°À°%À² Š Š#9²...@  %............°@±#° 9°"° 9± ° 9°%µ "#$90167#7&'&54776?3&'í¡em>W¼ HœsþÒ |"›OJEqð33|Æ@± < q‘L€ÜvÅ1þ̧­rj¦Á¬/ ˜ž¨4>ž$ÿôš–,@u…{‹#%¸ÿà@} H   o,,"## #R#q   o.@ H#(" u  ¯ Ï ï / _ o Ÿ ¿ Ï ÿ  @ H (s(t,,,€X+?3/]í2?3/]í9/+]q993í299/+3/í9/3/F·-( - +</+<+H‡++ÄÀÀ‡ÀÀ9/í99]10+]]]]]#!7>?#73>32.#"!!!2673%È–ýDauºº7DnšgFz^@ ¤pIr8˜þh *=L-Ðg6˜žš.|\“f7;U82@Ds}þà“7dTAU`ás#7³@*:JZH,:JZH,5 E U  ¸ÿè@H # 5EU¸ÿè@!H#:"J"Z""H"-"5EU¸ÿè@H#5EU¸ÿè@ÿH#:JZH-.°$°¹@ HF9V9f9F9f9¶9Ö9æ9ö9Ö9ö9™9©9¹99@ H9 )°3° 9ô9æ9Ö9¶9¦9–9†9t9f9V9F969&99ö9ä9Ö9¶9–9„9t9d9R9B949"999Éô9ä9Ò9Â9´9¤9”9„9t9d9R9D929$999ö9æ9Ô9Â9´9¤9”9†9v949$9@ÿ99ô9ä9Ô9Ä9´9¤9–9‚9p9`9P9D909$999™ð9à9Ô9À9´9 99€9p9`9P9D949$999ð9ä9Ð9Ä9´9 99€9t9`9T9@949$999ð9ä9Ô9Ä9°9 9”9€9t9d9T9D909 999iô9ä9Ô9Ä9°9¤99„9t9d9@949 999ô9Ð9À@T9°9 99€9p9`9P9@909 999à9Ð9À9°99p9`9P9@9 999ð9à9Ð9°9rrrr^]]]]]]]]]]]qqqqqqqqqqqqq_qqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]_]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]qqqqqqqqqqqqqqr/íÜí^]+]]qr/+]íÜí10_]+]]+]]+]]+]]+]]+]]+]]+]467'7>327'#"&''7.732>54.#"¥)%dhc6IG~6ah`%+,&dfe6~GH€4iff%)š-Lf:9fM,,Mf9:fL-¬G6dge'+*&ai`6GG€5die%)*&iif6I:fL,,Lf::fM,,Mf-+@€pk+ ‹ › &6{‹((8šmK[ R^   RLRK  ¸ÿð@:@ H u  uO _ o ï  à     €X+?3?399//]]qqr33í23í2/+]83/8339/3/339=/‡+‡+ć+‡+Ä/+<‡++ÄÀÀ‡ÀÀ10]]]]_]]]_]]]]]]]!!!!#!7!7!7!33éAþþ;²;þƒ} þ@þãÁöôÍÅ}šþÑ/š}¼ýy‡Õþ9{Í*@« @?Í/+Mí9/3í21033Õ¦¦¦Ã üöûv üõÿÞÿT=ÌK_=@ª†uD…DjzŠcsƒl)|)Œ)‚NUNeNuNX\XlX|X   11*1BH/QLH,[//'V:Iï999HoVV@&7HàV/V?VOVVŸVVVVaLH'I/?'O'_''@H'"QG,[[¿[[@/2HQQ QÀQQ¸ÿÀ³',HQ¸ÿÀ@+HQ[Q[B =Q4::4Q `p€ ð€  /]3/]qí?3/í9999//++qr+q3333/+]3/]íí3/]]]+qí2/]í99//99í99í10]]]]]]]]]]]#".'732>54.'.54>7.54>32.#">54.'ò&He?9KD~³p[‹eC“/E_?@kM+'Fb;AvY5)If<8_D&¡=^E/$kPUT) =[;8(?+.H3(;-%8NhC=^E/ &mNRsH!=aEOF&>.$7-%2Klÿ> >>¸ÿÀ@3 H33Ÿ3ÿ33@ H3>3>Ã`p€?Y$Ã@ HR¸ÿÀ@ƒ HRRMÉ.CÉ8O>_>o>>>8._.o..ÿ.P8`888€88 .8.8)È)ÈYoY_YOY?Y/YYYÿYïYßYÏY¿Y¯YŸYYYoY_YOY?Y/YYM^]]]]]]]]]]]]]]]qqqqqqqq?í?í99//^]q]q3/]íí3/+/+í3/]]]í99//+q+qqí3/íí10]]]]]]]]]]]]]]#".54>324.#"32>".54>32.#"32>7å4^ƒ¡¹dc¹ …^44^„¡¸d–Åq\c¬åƒ‚ä«cc«ä‚ƒå¬cý”e•b00a’bKpP7r &7H/Ec@!CdC1K8's:RoÃd¹¡ƒ^44^ƒ¡¹dd¸¡„^4rÄþù–‚ä«cc«ä‚ƒå«bb«åþ×@rž^bœo;$;K'!2&.SvHHxV0-8#+Q?&Y‹.˜>OÄ@m}UMeM+;K H/¸ÿØ@' H?O  'à((0á>8á  à ¿  ¸ÿÀ@;H/ ?  QEã/?ä-o'ß''@H''"ä-Þ;Jå  `/]]]33í2?í3/+]q9/í/]í3/]+]]qí33/]í9/í‡ÀÀÀÀ10++]]]#".5467##".54>?654&#"'>323267'32>7%$4!9BN/6R9?gƒC³ D;!;0# „ 1NkG‹5  È‹+TA( ).UC.ž'#9(7L-Na8<51 4&1P: k\ þíú !<0%#;L(Lk¬‹@hgw‡hxˆgw‡h x ˆ   ìë; ë »  @ H   ìë_o¿@ H ï /o¿ß/]3ä2/+]íí2/]/]_]+]qíí2/]10]]]]%73 !73 2þõ šžþf ýƒþ÷ ˜þi m?s%þŒþ‘m?s&þŒþ‘d´GòC@/Ÿ¿ßª0­HæöÌ™©³?3]]]]qqí/]í/]10%!5!¶ü®ã´¬’ýÂ?ÿðå–-;D@E{t {t:!J!Š!5"E"…"5'E'…'5&E&…&5+E+…+:,J,Š,:JŠ:JŠ9¸ÿà@ H9 H6¸ÿà@µ H/::A;A1Ä2<Ä77.;;/22;2;Ã`p€?F$Ã@ H;..2:/`0p00ÈA@É3ßA`A_AoA_2o233 2A33A2)È)ÈFoF_FOF?F/FFFÿFïFßFÏF¿F¯FŸFFFoF_FOF?F/FFM^]]]]]]]]]]]]]]]qqqqqqqq?í?í9///^]]]qqííq223/3/+í3/]]]í99//]833/íí29310+++]]]]]]]]]]]]#".54>324.#"32>##!24&+326å4^ƒ¡¹dc¹ …^44^„¡¸d–Åq\c¬åƒ‚ä«cc«ä‚ƒå¬cþRÇ¡3Ž—hUÝŸ_Qª¶PTÃd¹¡ƒ^44^ƒ¡¹dd¸¡„^4rÄþù–‚ä«cc«ä‚ƒå«bb«åþáPþ°?~of{þ¢PEHþÓUÿïß|T´¯/í//10!5!|ûsßuÄ\–'V¹ÿè@ H  H H¸ÿè@& H¬ï¬ 0 ? _ o ¯  #¯@àÀ¯?íÜ]í/]qíÜ]í10++++#".54>324.#"32>-Ni;;hN..Nh;;iN-m0A&%A00A%&A0y;hM--Mh;7>54&#"'>32!HOS(3\G)DA ;1$} 3NkC?bB#8Zp9#D;/À3g.K>48>I.3H$5"4V=!":N-BhUF!**-q5'Ø:Õ¹ÿè³ H!¸ÿè@ H:á à á44¸ÿÀ@ÿH   :44: )&9I 54&#"'>32#".'732>54.+L9F<(B9Da})%B1 0:= #<00?FA:R47J+³,!.: @cD#,ER'6')>+#. ¯±ˆä.@u…Š@/?O•€/?ï/]í/]í]1073¯ýÙþбþêÿÿþWE:+¾@u…DTds+ƒ+E+U+e+¸ÿè@ž H;%K%{%; K { 6Fv†/Ou…W%5Eh%5!( H ##RK######h#x#È##@/2Hw#8###-v-†-e-6-F-V---'-ö-×-ç-Æ-·-¦--¸ÿÀ@F#H)---ç-÷-Æ-—-§-·-x-g-H--*++R+K7÷¸ÿÀ@-%2H(x  'P*# +XYXç-×--¸þ@ÿãéH-‡-€-p-a-P-@-0- ---ñ-à-Ð-À-±-§- ---p-a-Q-A-0-!---Éñ-à-Ñ-Á-±-¢-“-‚-r-c-R-A-2-!---ò-ã-Ò-Â-²-¢-‘-‚-s-b-S-C-3-"---ò-ã-Ò-Ã-³-£-”-ƒ-r-b-S-C-3-$---™ò-ã-Ô-Â-³-£-“-ƒ@ÿ-t-d-S-D-3-$---ô-ä-Ô-Ã-°- --‚-p-`-P-@-0- ---ò-à-Ò-Ä-°- --€-p-b-R-B-4-"---ið-â-Ò-Â-²-¤-”-„-t-b-R-@-2-$---ô-â-Ò-Ä-´-¤-”-‚-t-d-R-D-4-$---ö-ä-Ö-Â-´-¤-”-†-v-f-T-F-@"2-"---9ð-à-Ð-À-°- -rr_rrrr_^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqq_qqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]]qqqqqqqqqqq+qq+?2?39/9993í23/3/^]+]q3/F·,(, +</+<+H‡++ćÀÀ]]]]]]]qqq+qqqqqrrrr3/]]+]q3/F·,(##, +</+<+HÁ‡++Ä9‡À10_^]+]]]]]]]]]+]]]]332>733267#"&5##"&'%µ†*<&9cO8v´ " 8&J>A˜\>Z^þWãýR20C*2\‚QbüÙ-%# a\_^*%þþø5J@.ppPà _Ÿ¿ßŸ ¿  ¯/3?3/í2/]/]99//]íí10###".54>3!´pÙqP…`52_ŠW3ùÝ#ùݾ-X†XT…]2f¥¾“š&@–›/@+H@H@H/+++]í/í1073¥+Ã+¾ÜÜGþWàr@ScsScs¸ÿس H¸ÿà³ H¸ÿà@1 H ƒŸ¯¿   Œ@ HŒ 0À/]í/]9/+í/]/]í9/810+++]]#"&'732654&#*73>QQ"IsQ60([K7@ek`H;-H1[,-)®=3~ ê@Nx  Rà@H@ H©¹É&6F©  & 6 F – – ¦ ö d Ö  ¸ÿÀ@ÿH Y i ä ß9I Ü ö æ Ö Æ ¶ ¤ – † t f T D 6 &   ¶ † f V &   Éö Æ ¶ † t f V F 4 &   æ Ô Æ ¶ ¦ – † v F 6 &  ö æ † V 6 &  ™ö æ Ù ¹ © ™ ‹ y i [ K )   ý ë Û Ï@Ô ¿ « › ‹ { o P @ 4 $   ô ä Ô Ä ° ¤ ” € p ` P D 0    iô à Ð À °    „ t d T D 4  Ô Ä ´ ¤ ” „ p d T D $   ô à Ô Ä ´ ” „ d P D 0   9ð r^]_]]]]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqq_qrrrrrrrrrrrrrr^]]]]]]]qqqqqqqqqqqqrrrrrrrrrrrr^]]]]]]]qqqqqqqqqqqqqqqqr?3/^]]3?í2^]+]qqrr/qr2/+/+‡++ÄÀ3]1073?33=Óvåí{×3kaŠƒ‰ýke‹6˜1b@zŠzŠu … u … ¸ÿè@, H Hã¿//@/P///3"ãä Þ'ä `/]]]í?í/í3/]]í10++]]]]".5467>32"32>7>54&“LrK%Hh…OMqK%Hh„*J?2 *;$+K@3 W‹+OnCC ^†V(+OnCC ^†V(¢6`M*D1E+8dO*F^M%¬‘@Og w ‡ h x ˆ gw‡hxˆ   ìë4 Ä T „ ô ;  ìë4dð°¸ÿÀ@H? ï/o¿ß/]3ä2/]+]_]qýí2/]/]]qýí2/]10]]]]%#7 73#7 73€žšþøœ üŒ šþøž 'otþ?þ“'otþ?ÿÿ`0&y#'?“^ýÎ ³?55ÿÿ/q&yò' r‹ýβ?5ÿÿˆ0&sS'?“^ýÎ@ A?<ï<<]q5?55Aþ¥;'+ú@©…u…e … JŠE U e … € U e u € d t R % *H  ,™(˜+{+‹++@$H+@HK[k++,#™ "["»""@H""-˜û@Ho_O/?€*+@"P"`"€""""¸¶oP/]]í3/]?ýÎ]9/]_]]]+]í3/+]qí99//]++]íí9910_]+]]]]]]]]]]]]".54>7>733267#7ñd¡o<=ay<*O@- ¯ AYh30XD(&E`;Œ¶&¥Wƒ²'Ã'þ¥6`‚Ma‰eK"3;H.NqU@9FZ>0Q9 Œz(TŒe9–ÉÉÿÿÿ­úð&$š2@ &÷%+5+5ÿÿÿ­úð&$›Û´&¸´%+5+5ÿÿÿ­úþ&$œQ´&¸ ´%+5+5ÿÿÿ­&$Ÿ^´&¸6´ 0%+5+5ÿÿÿ­ú²&$žg¶&¸2´%+55+55ÿÿÿ›èû&$PŸˆµ8¸´%+55?55ÿ¯à@‹ Ho    R^   R ^ÿ/Ÿ¯¿_ _ O O  ¯ ï ¯ ß  ` _lmX+?2í?í229/]qr3/]í3í2/]3/]9/]3//+<‡++ÄÀÀ‡ÀÀ99‡+‡+ÄÀÀ99//]]q10+!!#!!!!!#!_QýáþéË¿¥ýX§ýY_ ý+— $!þÎÙœþdœþ<šþœî#2:3&þ3ÿÿqþWÒ–&&x†¹ÿx´7/ %+5ÿÿ?ið&(š,@  &p %+5+5ÿÿ?ið&(›Ë@  &î %+5+5ÿÿ?iþ&(œZ@  &• %+5+5ÿÿ?i²&(žZ@  &¥%+55+55ÿÿQTð&,šÿ{@ &Z%+5+5ÿÿQDð&,›a´&¸´%+5+5ÿÿQþ&,œ¾@ &” %+5+5ÿÿQ ²&,žÄ@ &©%+55+55"™#å@8ƒ‹ y ‰ y ‰ ‚Ueu *z[@°ÀÐÀ¸ÿÀ³<@H¸ÿÀ³47H¸ÿÀ@R,/HO_% # #^    @ H _O¯ï¯ß#__ lmX+?í?í9/]qr3í2/+3//+<‡+}ÄÀÀ‡ÀÀ3/]3/]+++]qí9/10]]]]]]]]2#!#73!!!2>54.#!ü”ö±b=m˜·ÎnýÛ}ššvI–þj`0“ñ«]I€°fþúOœç˜…ܰƒX+‡š`ý šþX¥í–x®r7ÿÿ?È&1ŸŽ@ &¶/%+5+5ÿÿoÿìð&2šM@ 4&.58%+5+5ÿÿoÿìð&2›%@ 4&å47%+5+5ÿÿoÿìþ&2œ•@ 5&m:4%+5+5ÿÿoÿì&2ŸÁ@ 4&µ?O%+5+5ÿÿoÿì²&2ž¡@ 4&ˆ86%+55+55¬á=s ¹ÿè³H¸ÿè@H H H¸ÿè³H¸ÿè@HHH¸ÿè@HH H¸ÿè@HÔä´ÄÔ /q/]]q10++++++++++++ 7   ¬bþ h^^iþ¢`fþŸþœJb`gþŸ_iþ¤þ iaþÿÈÿË›º!.<9@M‰-‰††„v y 1{191i1‚,t,6,f,Yi‰Vf†*8%%$¸ÿà@] H +  +  H$ 1-2,*/!!!Z/////Ÿ/¯/*Z¸ÿð@4?O_/@AFH@.2H@H2,1-5"_ 5_ ?3í?39í9/+++]q3/8í3/]qr^]í2/89910^]+]]+]]]]]]]]]]]]]]]]]]]]#"&'#%.5467>$3273"&4'32>7>34 ŽÑþó‚ÉJ¡½43 ŒÑŸÊK§ÀüüƒÌ—b .fmì.üš5‘[„Í–c µH³g1i0š÷®^@<þK»n.`1–ö¯_B=£¾JŒÊ€+W'ˆ_R^þS…^ü°.-KÉ}*Zÿÿ™ÿìÑð&8šY@ "&<#&%+5+5ÿÿ™ÿìÑð&8›ü@ "&¾"%%+5+5ÿÿ™ÿìÑþ&8œ…@ #&_("%+5+5ÿÿ™ÿìѲ&8žƒ@ "&m&$%+55+55ÿÿÕÑð&<›²@  &V %+5+5úŸ@Lk{‹Z Z j  [/R^@ !H__ ¸ÿÀ@HlmX+??99//]+]íí/+3//+<‡+Á‡+ćÀÀÀÀ3/]]í10]]]]]3#3!2#!7!2654.#!Ý¿¿1Gy»BO“Ó„þXƒÀ¾-RsFþ£ü6d‘Zn¯yA—œ›A\<"ÿã€ÌCÐ@Œy5‰5z@k{‹WCVJ3z3Š3;.*: 44%!!8H1H*/1?11*1* H?8O88@H888EBCRCK@ H*B8%Po"""=PCXYX+?2?í?3/]í9/+3//+<‡++Ä3/]+]í99//]íí9/10]]]]]]]]]]]36$32#".'732>54.54>54.#""È/Ü_‘c3.EPE.*>I>*4h˜e*TND8-J;V8)>G>)-DOD-8S6CoU=ÆíÜ.Oh;A]G624"$@@DPaDN2@U>/5D3 9+#MzXüÿÿ4ÿì3ä&DCU@ T&^UX@%+5+5ÿÿ4ÿì3ä&Dtm@ T&ÕTW@%+5+5ÿÿ4ÿì3Ó&DK @ U&oZT@%+5+5ÿÿ4ÿìF½&DR@ T&”]k@%+5+5ÿÿ4ÿì3{&Di @ T&‡XV@%+55+55ÿÿ4ÿì3s&DP"@ Y&©^T@%+55+55 ÿìÒNH[iå@MzhŠhzaŠajNzNŠN@@|0Œ0:< + !:‹ u…;iI*F[[*2Fp* *3*3*_ I ¸ÿÀ@5 H CF0_Ï_ß____kQG@ Hd-P8 PiiJQ%%8p2/22;¸ÿè@ H2;>8VP?33í2?3+/]]9/í3/í9/í2/+í3/]]qí3/+í99//]í3/í9í910]]]]]]]]]]]32>7#"&'#".54>?>54&#"'>32>32%32>7%>54.#"Ý{y3TD3ŠDeb—¾#'_vŽUPvN'0Sp~‡Aîmc4XF5²Eo¡pzœ/;®phšf3üsÎ)YVM:",?(Ye> þ!gJ)VHKS:h‘W267 6N7%?,?`t5Ä#Ba?JbÿÿCþWéN&Fx†¹ÿ„´;3%+5ÿÿEÿì'ä&HC*@ 4&058 %+5+5ÿÿEÿì'ä&Htf@ 4&Ë47 %+5+5ÿÿEÿì'Ó&HK@ 5&e:4 %+5+5ÿÿEÿì'{&Hiñ@ 4&l86 %+55+55ÿÿYóä&ñCü@ &%+5+5ÿÿYßä&ñtW@ &Ö%+5+5ÿÿ:ÓÓ&ñKí@ &j %+5+5ÿÿYÒ{&ñiù@ &Ž%+55+55CÿñÌ0JÜ@{H‹Ht:„:r‚¸ÿà@& H+"{"‹"6#F#V#$#*%  ./¸ÿð@;//FG)F/F/F?FOFF@!$HF@HFFFL9F@ H1P$)$. /¸ÿÀ@ H//$$P$$$7>54.q0]6°(P$©0P9  ]…­niŸj6(Þ"JE= +5þïFoT:~u;fUB  A`0-K$5flC9{£a@CA„»w7?p™ZD Öè '6i`V"qxþf&Q\ >‚ŒEuW3;=$K='ÿÿ"G½&QR@ (&¬1?#%+5+5ÿÿIÿì8ä&RC4@ 4&058 %+5+5ÿÿIÿì8ä&Rtf@ 4&Á47 %+5+5ÿÿIÿì8Ó&RK @ 5&d:4 %+5+5ÿÿIÿì8½&RR÷@ 4&j=K %+5+5ÿÿIÿì8{&Riý@ 4&m86 %+55+55Rß5u o@ « °€ Ð¸ÿÀ@5H_/??OÏ/?ï@ #H ®@­®OŸ³?Þ]íýÞ]í/+]qr/]+]q9/3í210535!53ï¨ý»ãýº¨¾··þ¢’’þ··,ÿÚ´\,:ç@ i7f) H ¸ÿè@ H@ H ¸ÿÀ³ H¸ÿÈ@c H0 H/ 66((t!„!f!}//i//"0!- G/-?-O--@H-@H---<G ¸ÿÀ@%H"/!0%3P  %P ?í??9í9?/+]r3í3/]++]í299]]]]10]]]+]+++++]]7.5>7>3273#"'#.#"%4'32>7>É%' fŒ±i¢iF§’J k°dšhP§  T35kaP |ýä!U26i^O ‘5ˆU/d6~µv8CR©g¡4i;„¸s3G^ÆI6sLŒt7cáB3ýJu32"32>7654&*{›  R³s´S $KUbdQ>^h^ %09þYuþY4/D-2\ƒQ2w?ŽË‚=×&]žxbO@cC"%[™tyU{|ÿÿÿŒþWg{&\iÙ@  &$"%+55+55ÿÿÿ›è¡&$M³N´&¸´%+5+5ÿÿ.ÿì-S&DM @ T&‹UW@%+5+5ÿÿÿ›èê&$¡½´&¸J´!%+5+5ÿÿ.ÿì-æ&DN@ T&¨Y`@%+5+5ÿÿÿ›þUè&$Q ¶%+5ÿÿ.þ_-N&DQ) ¶"]]99%+5ÿÿqÿìÒð&&›S´,&¸)´,/ %+5+5ÿÿCÿìïä&Ftg@ 0&ì03%+5+5ÿÿqÿìÒþ&&œ­@ -&›2, %+5+5ÿÿCÿìéÓ&FKä@ 1&g60%+5+5ÿÿqÿìÒ¦&&O Ú@ ,&¬,. %+5+5ÿÿCÿìéÌ&FO÷ ¶¢02%+5ÿÿqÿìÒþ&&¨@ ,&Ä.4 %+5+5ÿÿCÿìøÓ&FLÖ@ 0&•28%+5+5ÿÿ?…þ&'5@ &‘$ %+5+5ÿÿEÿëÇÌ&G˜ÁK@ G;FF%+5?5ÿÿ"™EÿëÌE@•w7‡7jCT%d%t%9I*#!3!C!6 *..136<2<0-(@1@1@2<R7654.#"".5467>323>?!7!733##467#Å@sbK"?Y6=eQ=^2P|T, X| c{›  þÔ,´„„À ¬ $KUbv&]žxbOAbC"%[™tyU{|‹2\ƒQ-|?ŽË‚=h^ .3. ƒ““ƒü)'H<+ X4/D-ÿÿ?i¡&(MÒN@  &¬ %+5+5ÿÿEÿì'S&HM@ 4&{57 %+5+5ÿÿ?iê&(¡¥@  &Ÿ%+5+5ÿÿEÿì+æ&HN@ 4&¨9@ %+5+5ÿÿ?i¦&(O·Ú@  &¤ %+5+5ÿÿEÿì'Ì&HO ¶‘46 %+5ÿÿ?þUi&(Qc¹ÿ]´ %+5ÿÿEþi'N&HQ9´==¸ÿ´== %+54î@ Wð¸ÿÀ@H/?O R^   oß   R^   ¿Ïß @ H __  lmX+?22/3?399//3í23í23/3/+r33/]//+<‡++ÄÀÀ‡ÀÀÀÀ3/qr3//+<‡++ÄÀÀÀÀ‡ÀÀ3/]+qr10]!!##7373!733# 7!ü~ý~¿Çšš,¿,ÿ,º,™™Ç)ý)ýsšææææšûÿ-ÔÔ" Ì+ù@VV%     ¸ÿà@D H## R K   / O Ÿ ß  -"%!!R ! K   ¸ÿÀ@7 H @ H%Q"ïÿ P    XYX+?33/3?9/]9í9/]q3í2/+33/+//+<‡+Á‡+ÄÀÀ‡ÀÀÀÀÀ3/]q3//+<‡++Ä9/10+]]]]]]>32#>54&#"##7373!!w"HWiC”• wµv T_@q\An³êƒƒ´-þÓ Y/L5’Š$Z&ý›]'QOX3]ƒQýʶƒ““ƒ”!B7(ÿÿQx&,ŸÎ@ &À%+5+5ÿÿ*'½&ñRõ¾¹!üÀ³ééH!¸ý³èèH!¸üÀ³ççH!¸üÀ³ææH!¸üÀ³ååH!¸ý³ääH!¸üÀ³ããH!¸üÀ³ââH!¸üÀ³ááH!¸ý³ààH!¸ý³ßßH!¸üÀ³ÞÞH!¸ý³ÝÝH!¸ý³ÜÜH!¸ý³ÛÛH!¸üÀ³ÚÚH!¸ý³ÙÙH!¸ý³ØØH!¸ý³××H!¸ý@³ÖÖH!¸ý³ÕÕH!¸ý³ÔÔH!¸ý³ÓÓH!¸ý@³ÒÒH!¸ý³ÑÑH!¸ý³ÐÐH!¸ý³ÏÏH!¸ý@³ÎÎH!¸ý@³ÍÍH!¸ý³ÌÌH!¸ý@³ËËH!¸ý@³ÊÊH!¸ý@³ÉÉH!¸ý³ÈÈH!¸ý@³ÇÇH!¸ý@³ÆÆH!¸ý@³ÅÅH!¸ý€³ÄÄH!¸ý@³ÃÃH!¸ý@³ÂÂH!¸ý@³ÁÁH!¸ý€³ÀÀH!¸ý@³¿¿H!¸ý@³¾¾H!¸ý@³½½H!¸ý€³¼¼H!¸ý€³»»H!¸ý@³ººH!¸ý€³¹¹H!¸ý€³¸¸H!¸ý€³··H!¸ý@³¶¶H!¸ý€³µµH!¸ý€³´´H!¸ý€³³³H!¸ýÀ³²²H!¸ý€³±±H!¸ý€³°°H!¸ý€³¯¯H!¸ýÀ³®®H!¸ý€³­­H!¸ý€³¬¬H!¸ý€³««H!¸ýÀ³ªªH!¸ýÀ³©©H!¸ý€³¨¨H!¸ýÀ³§§H!¸ýÀ³¦¦H!¸ýÀ³¥¥H!¸ý€³¤¤H!¸ýÀ³££H!¸ýÀ³¢¢H!¸ýÀ³¡¡H!¸þ³  H!¸ýÀ³ŸŸH!¸ýÀ³žžH!¸ýÀ³H!¸þ³œœH!¸ýÀ³››H!¸ýÀ³ššH!¸ýÀ³™™H!¸þ³˜˜H!¸þ³——H!¸ýÀ³––H!¸þ³••H!¸þ³””H!¸þ³““H!¸ýÀ³’’H!¸þ³‘‘H!¸þ³H!¸þ³H!¸þ@³ŽŽH!¸þ³H!¸þ³ŒŒH!¸þ³‹‹H!¸þ@³ŠŠH!¸þ³‰‰H!¸þ³ˆˆH!¸þ³‡‡H!¸þ@³††H!¸þ@³……H!¸þ³„„H!¸þ@³ƒƒH!¸þ@³‚‚H!¸þ@³H!¸þ³€€H!¸þ@³H!¸þ@³~~H!¸þ@³}}H!¸þ€³||H!¸þ@³{{H!¸þ@³zzH!¸þ@³yyH!¸þ€³xxH!¸þ@³wwH!¸þ@³vvH!¸þ@³uuH!¸þ€³ttH!¸þ€³ssH!¸þ@³rrH!¸þ€³qqH!¸þ€³ppH!¸þ€³ooH!¸þ@³nnH!¸þ€³mmH!¸þ€³llH!¸þ€³kkH!¸þÀ³jjH!¸þ€³iiH!¸þ€³hhH!¸þ€³ggH!¸þÀ³ffH!¸þ€³eeH!¸þ€³ddH!¸þ€³ccH!¸þÀ³bbH!¸þÀ³aaH!¸þ€³``H!¸þÀ³__H!¸þÀ³^^H!¸þÀ³]]H!¸þ€³\\H!¸þÀ³[[H!¸þÀ³ZZH!¸þÀ³YYH!¸ÿ³XXH!¸þÀ³WWH!¸þÀ³VVH!¸þÀ³UUH!¸ÿ³TTH!¸þÀ³SSH!¸þÀ³RRH!¸þÀ³QQH!¸ÿ³PPH!¸ÿ³OOH!¸þÀ³NNH!¸ÿ³MMH!¸ÿ³LLH!¸ÿ³KKH!¸þÀ³JJH!¸ÿ³IIH!¸ÿ³HHH!¸ÿ³GGH!¸ÿ@³FFH!¸ÿ³EEH!¸ÿ³DDH!¸ÿ³CCH!¸ÿ@³BBH!¸ÿ³AAH!¸ÿ³@@H!¸ÿ³??H!¸ÿ@³>>H!¸ÿ@³==H!¸ÿ³<>H ¸ÿ@³==H ¸ÿ³<>H¸ÿ@³==H¸ÿ³<jN-ÿÿ?þ9¡&.’i¹ÿX´ %+5ÿÿ"þ9VÌ&N’ѹÿt´ %+5"V: ¹ ÿà³&*H ¸ÿà@ H   °  ’ ¢ ²  ¸ÿг&/H ¸ÿÐ@‘ H   %     R  N  RK     o  ß ï ÿ Ÿ ¯ ¿ d „ / ?  RK@ H   XYX+?22/3?33/39/+3//+<‡++ćÀÀ3}/]]]q83/]899‡++ć+‡+ćÀÀ10]]]]]++]]]]++!#373 Ñþô¨H³Ò´eÌiÞýîPö|þ†:ýý¾Eþ/ý—ÿÿ?äð&/›­@ &“ %+5+5ÿÿ! ?&O›)O´&¸´%+5+5ÿÿ?þ9ä&/’¹ÿÖ´ %+5ÿÿÿ¼þ9õÌ&O’ÿd¹ÿÆ´ %+5ÿÿ?&/˜³¸‚´ %+5?5ÿÿ!Ì&O˜K@  > %+5?5ÿÿ?ä&/OOýŽ ¶þ%+5ÿÿ!õÌ&OOÉýŽ ¶*%+5â “@[‡ v†p €  @ H    R^    P` @ H     _lmX+?í?399//]9/+33/]//+<‡++ÄÀÀ‡ÀÀ3/+9/10]]]!!?3%«þÎ_Èüyi£¥Š¿u2•þœUžUÉý¥”úÌ ¢@W /  ð¸ÿà@=H   R K`€Ð_@ H ¸ÿð@ XYX+?2?399//889/+qqr3//+<‡++ÄÀÀ‡ÀÀ3/]+]3/]]10]3?37 i‡†™´„ŠŠ~DžDýXHŸGýzÿÿ?Èð&1›´&¸´%+5+5ÿÿ&ä&Qt„@ (&ÿ(+#%+5+5ÿÿ?þ9È&1’q¹ÿM´%+5ÿÿ&þ9M&Q’ѹÿ´,2#%+5ÿÿ?Èþ&1‹@ &Å%+5+5ÿÿ&*Ó&QL@ (&½*0#%+5+5ÿÿ3Ž&Qx ÿs¹ÿ´22%+5?ÿ쀕6ë¹ÿð@„H‰[9I%-5-E-e-(65 H/3R3^   Ë k { ‹ » _ / O  8&&R^@ H/3, _&,! _lmX+?2/í?3?39?3í99999/+3//+<‡++ćÀ3/]_]]q3/F·7( 7 +</+<+H‡++Ä9/10+]]]]]+"&'732>7>54&#"#>733>3 To,"_61eœkzEmu>i‹Mü…D%\ZL?EE>dF'þ›7Q þ–…ÑL"þWM5ù³‰ 1¸ÿè³ H¸ÿè@’ H  5RK`0€@P à9°ÀðO_/o¯¿ÿ?OŸÏß7)RK@ H)5/$#P/ PXYX+?í?í?3?39/+3//+<‡++ćÀ3/]qrr^]qr3/F·6(6 +</+<+H‡++Ä9/10^]++]#"&'73267>54&#"#>733>32g 'BcG"E 2;<’ T_@q\Av´¦ ª "HWiC”• †>jN- ˆT\ð'QOX3]ƒQý¢S"KC0,9;/L5’Š$Z&ÿÿoÿì¡&2MN@ 4&57%+5+5ÿÿCÿì2S&RMô@ 4&g57 %+5+5ÿÿoÿìê&2¡ @ 4&£9@%+5+5ÿÿCÿì2æ&RN@ 4&¤9@ %+5+5ÿÿoÿìñ&2 +@ 4&ê4=%+55+55ÿÿCÿì‹ä&RSK@ 4&¼4= %+55+55eÿöŒ6å@EŠ Z j Š 6 9%4…4%-@HR^$%$$%$$%% $0$@$`$€$$¸ÿÀ@DH$$/82Z?O_/@H_O¯ï¯ß*%_$_lmX+?í22?3í229/]qrí/+]qí3/]9/+]3/F·7(%$$7 +</+<+H‡++ćÀÀ99//+q10]]]]]]!#".547>$32!!!!!%2>7.#"}&i0‘á˜OÒ ›FKHiý:XŠýv_ïû >8.Õ;<9~˘e0(`($()&")  JJ‚====m *\G55R I ¸ÿÀ@5 H /F0RORÏRßRRRR^BG@ H P\\GW:P*'$GP?33í2?33í29/í9//+í3/]]qí3/+í9/í210]]]]]]]]]]]]]]]]]]]32>7#"&'#".5>7>32>32%4.#"32>7>%>54.#"…†8[J8ŠGj•h†¼3OÙ‚`œn< eŒ°iŽ¿1LÎyn¡k4 üO"A\95j`P %B[66i^O #@\80jaP÷?…Ž1A$?-YH-c^eW9o¢h/d6~µv8c]]d:h‘W267´MlE LŒt7c*RrGJuä&Ut¶@ "&É"% !%+5+5ÿÿ?þ9ˆ&5’йÿ†´# %+5ÿÿÿËþ9ïN&U’ÿs¹ÿÔ´** %+5ÿÿ?ˆþ&5B@ &œ! %+5+5ÿÿ"jÓ&ULH@ "&”$* !%+5+5ÿÿ:ÿì@-&6tI@ <&ïD$%+5+5ÿÿÿìâÓ&VLÀ@ <&§>D )%+5+5ÿÿ¸þW\'x×7ÿÿþW€,&x¹Wÿÿ¸\þ&7@ &K %+5+5ÿÿ]ÿìªÌ&W˜¤K@ 'G&&%+5?5¸\Ÿ@b /?Oà¿ /?__ o O ß   R^   / _ _  lmX+?3?9/3í2í22/]3//+<‡++ÄÀÀ‡ÀÀ3/]q3/]]]]qq9910!!#!7!!7!ZXþç}¾}þéXþ†åþ<šýy‡šÄœœÿì€,%¿@i H H  # #/O_¯¿%"!RK!Q %Q"P XYX+?í?39/93í29í23/3/]q3///F·&(& +</+<+H‡++ćÀÀÀÀ‡ÀÀ/]99//q310]++3267#"&546?#73#73733#3#!*0-%X0Ua *}};}ix/ÈÈ;ÈÉ2:*.… fT I܃0ƒòòƒþЃÿÿ™ÿìÑ&8Ÿ”@ "&Š-=%+5+5ÿÿVÿíJ½&XR@ (&r1?#%+5+5ÿÿ™ÿìÑœ&8MøI@ "&q#%%+5+5ÿÿVÿíJS&XM @ (&h)+#%+5+5ÿÿ™ÿìÑê&8¡ç@ "&€'.%+5+5ÿÿVÿíJæ&XN@ (&~-4#%+5+5ÿÿ™ÿìÑÁ&8PÝN@ '&c,"%+55+55ÿÿVÿíJs&XPö@ -&a2(#%+55+55ÿÿ™ÿìÑñ&8 ÷@ "&¸"+%+55+55ÿÿVÿí¡ä&XSa@ (&¼(1#%+55+55ÿÿ™þUÑ&8Q² ¶½++%+5ÿÿVþUJ:&XQÀ ¶00%+5ÿÿ±.þ&:œ]´2&¸ÿý´710%+5+5ÿÿf5Ó&ZK§´*&¸ÿó´/)(%+5+5ÿÿÕÑþ&<œP@  &  %+5+5ÿÿÿŒþWgÓ&\KÚ@ !&z& %+5+5ÿÿÕѲ&<ž@@  & %+55+55ÿÿÿØð&=› ´ &¸´ %+5+5ÿÿÿÔä&]t5@  &ã %+5+5ÿÿÿئ&=OcÚ@  &ª %+5+5ÿÿÿÔÌ&]OÑ ¶¥ %+5ÿÿÿØþ&= @  &Ï %+5+5ÿÿÿÉûÓ&]õLÈ@  &» %+5+5!²Ìy¹ÿØ@P H ð  ? O  Ÿ ¯ Ï ß  RK_?OŸÏß PXYX+?2?í99/]q2//+<‡++Ä/]]]]10+3>32.#"!ê %ClR?3$.æ´;fL+‰*='ûeþ8#®{¹ÿÀ@ !HY‰¸ÿè³ H ¸ÿè@ H ¸ÿè@Û H ?O¯/?_@H@p€0pÀßÀ   R q  0@ u   Q  €X° p`@0 ðа€p`@0 ðÀ°€p@ 9à°rr^]]]]]]]]qqqqqqqqqqqrrrrrrrrr+/3/^]í9/]993í2/]]q33/]]F·( +</+<+H‡++ÄÀÀ‡ÀÀ]]qqqr/+]q310+]++]+.#"3###737>32>.! ÓÕþþ´˜— (GmQ R#  (@-‰ƒú½Cƒ˜;fL+ ÿÿÿ›ï&$'Pˆ› -$´8¸¶=@%¸´%+55+5?55ÿÿ.ÿì„¥&D'P›¡µ*@ |&Y&¸k@ |@%¡^T@%+55+5+55+5ÿÿÿ¯ð&†›ä´&¸ú´%+5+5ÿÿ ÿìÒä&¦tÎ@ j&ðjmC%+5+5ÿÿÿÈÿË›ð&˜›K´=&¸´=@!%+5+5ÿÿ,ÿÚ´ä&¸t²@ ;&Ý;>%+5+5ÿÿ:þ9@–'’û6ÿÿþ9ÖK&’LVÿÿ¸þ9\'’û7ÿÿQþ9€,&’ùWM±æÓ  @ÿ‡ xˆUe „¤ +[ 4 d ” Ë D t „ ¤ « $ T „ ë@ H@$H@ ”€ +;{ë { ` P D 4    ô ä Ô Ä ´ ¤  „ p ` T D 0 $   Îô ä Ô Ä ´ ¤ „ p d P @ 4 $   ô ä Ô Ä ´ ¤ ” „ d P D 4  @ñ  ð ä Ô Ä ´ ¤ ” t d D 0 $   žô ä Ô Ä ´ ¤ „ t T D   ô ä Ô Ä ´ ¤ ” „ d T $ ð à Ð À °    p ` @ 0  nÐ À °    € p P @  à °    € ` P 0  ð  p ` @ 0  >À   rr^]]]]]]]qqqqqqqqqrrrrrrrrrr^]]]]]]]]]]]_]qqqqqqqqqqqrrrrrrrrrrrr^]]]]]]]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqq/^]3ýÍ+/+]]]qqr3/]]9=/3310_]]]#'##73æ\ºþ÷tÌÅ©©ˆ±"Ó @M—Šš†–DTt„” k  D T Û „  Ä [  4 K[‹”€¸ÿÀ@ÿ$H +;{ë ´ ” € t d T D 4 $  ô Ô Ä ´ ¤ ” t d 4 $   Îô ä Ô ´ ¤ t d T D 4 $  ô ä °    € ` P  ð à Ð À    ` 0    žà Ð   € p ` P @  °  € P  ð Ð À  @ 0   nÐ À @+   Ð p P @ ß ° €   9ð À rr^]]]]]qqqqrrrrr^]]]]]]]]qqqqqrrrrrrrrr^]]]]]]]]]]]qqqqqq_qqqrrrrrrrrrrrr^]]]]]]]]]]]]qqqqqqqqqq/^]Í+í2/]^]]]qqqrr3/]9=/]3310_]]#73373 ̵aÇüp±©©ŽÔÎSC@@ H«Td ëĸÿÀ@ÿHËûDt„¤´ ŒÿëÏß@$H/ ; @H@HôàÐÀ´ td@0$ôäÐÄ´ ”„tdTD4 ÊðàÔÀ´”€t`PD4 ðäÔÀ° €p`P@0/ÿÏŸ@@Ž/šÿïßÏ`P0￯`0ÿïo? jïß¿¯`ÿŸ€pP@ ÿß°€9¿r^]]]]]qqqqqqqqrrrrrrrr^]]]]]]qqqqqqqqrrrrrrrr^]]]]]]qqqqqqqqqqq_qqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqq/++^]q+qqqí/^]]]+qqrrr3/+10!7!´ýÚ&Ô‚±æ>@({ ‹   ‚ ‚@ •€ /?ï/]íí2/]í3/í10]]".'33273ªJnJ%tgS³@uA[v±3Vo=UN£=oV3V ,ÌN@ ´&¸ÿÀ@,1Hf¶ÆÖöFÖ¸ÿÀ³H¸ÿÀ@ÿH …S‰yYIùéɹ™iY9) ÍéÙ¹©‰YI9)ùɹ©™‰yi9) ùé©™iYI& œéÔ´¤™‰I6ûiY9òâÔ²¤”„tdTD2"iðàÐÀ@†´¤€p`P@0$ôäÐÀ° ”„pdTD$ôàÔÄ´”„dPD4$9ðäÔ _rrrr^]]]]]]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]_]]]]]]]]]]]]]]qqqqqrrrrrrrrr^]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrr^]]]]]]]]]]qqqq?í/í^]++]qr+rr1073V"´" ¬¬É­s'[¹ÿè@ H  H H¸ÿè@+ H‚@À‚ Œ@À#Œ/_/?OŸ¿ï/]qíÜí/íÜí10++++#".54>324.#"32>­&BX22XB&&BX22XB&l$12$$21$‚2XB&&BX22XA&&AX21$$12&&2GþU™t@ÿ( H)9I«{‹ëû@*.H@HÔ +;[k+ ; k { ‹  ƒ  Œ Ä”tdTD4ôäÔ´¤dTD$ÍôäÔÄ´„T4$ðäÔĤ›‹{k_+Ë»›‹{k[K;+ ÛË«›@Ó‹kK;$뻫‹{k_+Ë›‹{k[K; jûëÛË»¯Ÿ‹o_K;+ ëÛË»«›[K;/ûëË»«Ÿ‹k[;+:ïßÏ¿rrrr_^]]]]]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]qqqqqqqqrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqq/^]í/^]/í/]3/^]]++]qr10]+"&54>733267ùXZ)=H…D:((& 4FþU^J4V@- -32326737*LE@7CZ&9S;,LE>6D\%9S±%-%>9-_N2%-%?8,_N3±@ä @1“ £ “£ Šh¸ÈØ@ Hµ † – ¦ w f U  ¸ÿ€@'+H× ç ÷ Æ  ¸ÿÀ@ÿ"H  × ç ÷ ¦ — v † g  ( 8 Š@H˜¨¸@ H•€ (8xè  ÷ ç × Ç · — ‡ v g W F 7 ( æ × Ç · ‡ V G 7 '   É÷ Æ · ¦ ˆ x g 7  ÷ ç × · ¦ ‡ w F 7 &   ç ¨ — † w g W  ™÷ ç Ø È ¸ ¨ @ÿˆ 8 )   Æ ¶ ¦ — ‡ w f U E 6 &   ö æ Ö Æ ¶ ¦ – † w g W G 7 &   iö ç × Æ ¶ ¤ ” „ t c T C 3    ô ä Ð À °   ’ ‚ r b R B 4 "   ð à Ò  ² ¤ ” € r b R D 4 $   9ô ä @Ô Ä ¶ ¢ _rrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrr_rrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrrr^]]]]]]]]qqqqqqqqqqqqrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqqqqqr/^]3í2/+]qí^]]]]]]q+qq+rrrrr/+]qí_]]1073373üÏþ”ýýÏþ”±þêþêéÂ<µ»  ±€/í/í10]73é~ÏþÿÂ!$%þàÿü°‹A _@  ¸ ·€ ¸ÿÀ@#*/H  ƒ  O _ o Ÿ ¯  ƒ ޏ ² /3Öíí2/í/]í9/]+qí]10]73%73!73ÒŒ»üþß!–"B"–"°!p%þ”¬¬¬¬ÿÿÿ›è‚&$Tÿ§ÿ{³¸þø´%+5?5¥¾“š&@–›/@+H@H@H/+++]í/í1073¥+Ã+¾ÜÜÿÿLb‚'(ùTÿcÿ{³¸ÿV´%+5?5ÿÿIÇ‚'+þTÿ`ÿ{³¸ÿM´%+5?5ÿÿI‚',ãTÿ`ÿ{³¸ÿV´%+5?5ÿÿÿ÷ÿì!–&2!Tÿÿ{³6¸ÿg´44%+5?5ÿÿÆg‚'<–TÿÝÿ{³ ¸ÿ®´ %+5?5ÿÿÿÿí–&vTÿÿ{³<¸ÿB´::55%+5?5ÿÿ.½A&†U2@&„ %+555+555ÿÿÿ›è$ÿÿ?%?Ù‚Y@(@ HR^@ H_lmX+?3?í/+3/F·( +</+<+H‡++Ä3/+10!#Ùý7ô¿‚œûÿØÐ“@d‹ Y i y  ) R \R^  Ht „   +  Z?¿ßïÿp€_ ?33?í2/]3/3/]í9=/]]+‡++ć+‡+Ä10]]]'3!%.5 úÙû$:« $,þôû œ^)PC1 2FR(ü¤ÿÿ?i(ÿÿÿØ=ÿÿ?É+eÿìö–7í@?fijdVkY9Ie 6 F  5j5 .(e(! @H¸ÿÀ@k H Z33/33Ÿ3¯3$"32>7>54.Kýµ¢Þ™O ŽÑþó–à•K ŒÑ–ƒÌ—b 8k›b„Í–c :lš UšÔ€1i0š÷®^WÚƒ.`1–ö¯_šJŒÊ€+W'k¡k5KÉ}*Z&k¡k6ÿÿQ",ÿÿ?¡.ÿ¢å‚ë@L‰Xhx8Hx H(xˆw‡R  \R^é¶ÆI¸ÿà@[H™v† )„;K[{ËD+;‹»@Hdt›«»@ H/ ?22/3?33/_]+]q3/]+]qqrr9=/]]]+qqq‡++ć+‡+Ä]]10]+]]]%#.'&'#3åÃà /ý¹ÎPÆà/Y#)%'*$X,ü ÿÿ?ª0ÿÿ?È1ÿò_ o@¯ P   @H`/¸ÿÀ@,H @ H _ O  ¯ ï ¯ ß  __?í?í9/]qrí/+3/3/+3/]]+99//]]10!!!7!7&9ûLJû‚`ü·œû·œœ…ššÿÿoÿì–2?Î~@LWWR^oOß¿ R^@ H_lmX+?22/3?3í2/+3//+<‡++Ä3/]qr3//+<‡++Ä]]10]!!#!ýóýó¿}þîàû úÿÿ?I3ÿú ±@y L6)IÏ  @/5H @H [Ï@/5H@H[Ï@/5H\ /  @ H  {‹›»Ëû4 _ _?í2?í29=/]]q33/+3/3/]3/99//]í+qí++qí++q10]]+#7 7!!!!‹þYçüê€ý³c«Eù˜œþ7sýóœÿÿ¸\7ÿÿÕÑ<~ÿõc‹*7ã@ƒ…!iVfX+h+:&J&53E3*%***  +7 R^   [?$?$_$¿$ï$$$$$91[/@H`77*+`  7 7  lmX+?3?399//3í23í2/+]í3/]]qí9/3/F·8( 8 +</+<+H‡++ÄÀÀÀÀ‡ÀÀÀÀ10]]]]]]]]]]]%".54>;7332+#?32>54.+";€u½‡IVžÝ‡¡#·!1u½‡IWÞ‡ .·,Ô|cšk84ZwCE¹|cšj84ZvBFØAz®mÌŽL¶¶Ay®mÌLããŽ3e–cXQ'3d•cYR'ÿÿÿÙ–;ÐÂ+$@ V&f&:J¸ÿè@Ž H ''  *+++R+^ #%R%^ " " """`"¿"ß"ÿ"""/"?"""- R^   /_¿#"" % *`  +lmX+?2?39/993í2993/33/3/]3/F·,( , +</+<+H‡++Ä3/]]]qq3/F·,(" , +</+<+H‡++Ä9/3//+<‡++ÄÀÀ‡ÀÀ10]]]+]]!#"&54>73;3>73+S3åøZ¿Z.RtF8£¹£On’^6Z¿bV‘ÒiS«ÌÃ#! Ïþ- !#"C];Iü·3aŽYÓþl¯|DþUЖ9@»‰ƒ%„vvo222o333euo  E J:J  ( H0 H)„8p887) )9Iù|ì H0''( @ H((5Z ?O_¿;)"Z/55'@ H' +0'*_)_?í?3í2/+3/]í33/]qí299//+]3333+]]q]10]]]]]+]+]]]]]]]]]]]]]]267>;!7>54.#"!732.546$y‰ÝœUBŒ×–-(#Hþý³+ƒºv6;mš_gÀ”X$EfA-ýÝËP&-2F|\6rÅ –LÎ~à»’0œà*¤¿igk6FØ’Xt\&àœ'p°i¥·bÿÿQ²&,žË@ &°%+55+55ÿÿÕѲ&<ž@@  & %+55+55ÿÿFÿëÀ&~Td@ H&sHK* %+5+5ÿÿ"ÿìœ&‚T@ >&Å>A#%+5+5ÿÿ"þW&„T—´-&¸ ´-0(%+5+5ÿÿ?p&†T4@ &Õ %+5+5ÿÿhÿìA&’Uj@%&n+1 %+555+555FÿëÀM1G©@wŠFŠ4{=ooocsƒj>z>k66FV0%0. ((*(@ G H  @/Ïß@ HI9G*@ H*;P% 2P?2í???3í/+í3/+]q3/íí310]]]]]]]]]]]]]23>73#.=##".5467>"32>7>54.SFmP2 "¼010+#  ±!J\qHQ}V, _¡a:bQ?»4icX"7UM$@Y64;>Yfmi_%e–wa/@B=8cK,6f“].r6ŽÄy5„(_›srT÷8n¤l%I|Z2ÿÎþW`Ì >@ w‹#euZjZZjzYiye u V G „P`pA%$H// : 55H@::@H:::@%$$RK  Ï ß  @$H ) 9  %*P 4P$55!PXYX+?í?39/99í9í2?3/]+]3/F·?( ? +</+<+H‡++Ä9‡ÀÀÀ3/]+qí9/99/í10]]]]]]]]]]]]]]]6$32#"&'##"32>54.#7>54.å-ÜTˆ`43Sl96\E'G‡Ã}f¦7 :³}§!žDOW+M€\4&HkEHpM(4Oóæó.VwJS‚^: 8Rj@k±F8&9\5þ×褪üÜ )S~T7^D'Ž -JjF+G3oþXa:–@A+R  M  RK  H `   eu…¸ÿð@/@H ?2/?39]]/+]83/3]3/]]89=/+]‡+‡+ć+‡+Ä10]]>73#>7,r !"sÂý²630¿*Z*Í:ý]BD>;A@¥ûû-o|„AƒÕ[/Cÿì„Ì4Ç@,{.‹.t „  { ‹ dt„k6†r‚¸ÿà@Y H$#4#D#t#„#*$:$J$k00« Û 0 11+33!G/?O@H6G+@ H+1P0 (H 2P&?í?9+33í2/+í3/]+]qí3/9/993]10]]]]+]]]]]]]]]%2>54.'".'#".54>77!ÿY…Z-&4/jh_I,&D\/ )-) ý,I4R”Í{g¡o;a¢ÔsýÝqBsœZAn_R%+?.54>32.#"3"‘j¡FX+[h{LT„[0/UvG'D49h“Z>kYI‡)oK+N:#3XxE4h_S<#0CtPDi+B.+OnB?hN1 '9J,IoJ%(B/T?8*@+->% /I4$=+=þ’ Ì6c@>u … [ k 5E %%-%]%I55'.?8G'@ H'/5Q ""6/?93í22/+í3/]399//í210]]]]'>54.'.54>?#!7 L¬¨šuF=[<9aH))3f ;W8?nS0Fwœ­²P 061 þÕÌI¡«²³²U+;, #2F3+MG>H#)+' -EbC]¾»·­¡Hƒ"þWM,¹,ÿè³ H¸ÿè³ H&¸ÿà@_ H+,R,K,ÀÐ/o¯¿P/?. R K@ H  + P%XYX+???í?39/+3//+<‡++ćÀ3/]]qqr3/F·-(- +</+<+HÁ‡++Ä10+++>54&#"#>54.'33>32zÑ T_@q\Av´›¦"HWiC”• ÒþW.'QOX3]ƒQý¢.*" %'& ,56/L5’Š$Z&ûÊeÿìEÌ#1–@7!"!>54.ع´%o”¼rR„^3I$>pdV#ýÑ 3F&=pbT#0 3IÌéß@¤[¾þì²U;x³x:“Pvoú¥4€Ø¤Q„6SqDÚ3~Õ¡R†6PlA?£:y@C  €ÐO/Ÿ¯¿ïÿ RK    €@ H XYX+??399/+q33/F·(  +</+<+H‡++Ä3]qq10]7#.54673ôÆ¥´¦‹&HA(9Nü©2"V: ¹ ÿà³&*H ¸ÿà@ H   °  ’ ¢ ²  ¸ÿг&/H ¸ÿÐ@‘ H   %     R  N  RK     o  ß ï ÿ Ÿ ¯ ¿ d „ / ?  RK@ H   XYX+?22/3?33/39/+3//+<‡++ćÀÀ3}/]]]q83/]899‡++ć+‡+ćÀÀ10]]]]]++]]]]++!#373 Ñþô¨H³Ò´eÌiÞýîPö|þ†:ýý¾Eþ/ý—ÿ£ƒÌð´z¸ÿØ@b H3*)D 0    RKRM HC¸ÿð@/@ H@ H?P?í?33/39]]3/]+8/]+89=/]+‡+‡+ć++ćÀÀ9/]_]]]10_]]_]_]]]_]+_]'.#"'>32##,  0$*%)(6N;*δ|þÅÕcJc=‚$Qƒ_û‹þýÿÕþwA:-H@ …U…¸ÿè@ Hr‚DTd" H0 H‚¸ÿà@– H&%/(?(O(((%5Eu…h%5%&&%&'(R(K&&&&@ð_o¿Ïàð/RK@$Hà/?( '&& P XYX+??í?3?33/39/]]+3/F·.(. +</+<+H‡++ćÀÀÀ3/]qqr3/F·.(&. +</+<+H‡++Ä9}‡Ä10]]]]]]+]++]]+]]!>7##".'##332>73Ì 9DP2'H:*  Iµ¶} 0L654&'3#3¡b™j8±bŸÉh¨¶¼¦pûÁm#;3D}ùóëo:7þ’àÌNÁ@…„k{m}\k,Z,d t „ 6 F %E Z[1k11 H@@/@LLF>$I)8) ) )>) )>3`NpN€NN?NNNPG3@ H3CLQM.9 Q.) #M#/?9/9í93í22/+í3/]]9///]9í2í3/10]+]]]]]]]]]]]'>54.'.54>75.54>?"+7!È6neXB%5Ys>A…}mR/=[<9aH))3f ;W8?nS0LÌ€6dL.Cev3&295, JzO(8L2:K.ƒ/BWlC+;, #2F3+MG>H#)+' /HhH\¥„\ *BW6FaA& ƒÿÿCÿì2MR[ÿì{:4»@ky‰ HI /?O( HHO&&ÿ&&&224RKðŸ6++G/ 44&Q1P XYX+?í?3?í22/399/]í3/3/]]]3/F·5(5 +</+<+H‡++Ä3/9/]í10]+]]+]3267#"&5467!#>7>767"7>3!#ó+1"M+^VƒþnAGJ!¼"MLD'PG7-47%ê # 0" † gZ:¨H‚üäÃJLÅâ÷} ‹ ƒÿÎþWVN2Û@!Š+fŒ1j1z1h,x,‡uFVf¸ÿà@cHE<L, % !3!C!!GO00004$##RK/?Ïß@$H#)P PXYX+?í?í9?3/+]3/F·3(3 +</+<+H‡++ćÀÀÀ3/]]í10]]]]]]]+]]]]]]]]2#".'##>"32>7654&¨bŸp=bŒ¯d;`O> S´ÃVƒ³dKoQ7>?KT,GsW=‡N?t¦h$R*v¾…H'4= þWîxÁ‡I…8g‘XþÃ5)6f“\OG˜ŸCþ’ÞN5©@‹t„‹dt„dt„¸ÿà@XHY[/k/5E6 F % 44+4[4I''!I,,y ‰  p  7G@ H1,1&P0 p €  ?3/]í/93/+í3/]Í]9/í2]10]]]]]]+]]]]]4>32.#"'>54.'.C!Bdˆ«g>_K:ˆ"_?=kZG1<[<9aH))3f ;W8?nS0JJ¬« zI%3l-=6\z‰D.@."#2F3+MG>H#)+' 0MpDÿì:1{@RŠ t0„0+%u…+ |*Œ**j* G#�`#/##?##@H##3/G@ H'Q P?í?í22/+í3/+]qq3/]3í210]]]]]]]]".5467>3!#".''2>54&'#"êhžj6±×u(‘ #*+/EŒÕ‡iŽW&SRš€]~>p a$T(Äw4ƒ=£a†î±g…T–Ñ}Q‡6(]–n)I#‹Kÿìg:#€@B( H %RK # # ##ßÿ@ Ho ð O    PQ XYX+?í2?í99/]]]qÆ+]3/F·$(# $ +</+<+H‡++Ä3/9/10+"7>3!!3267#"&5467N'PG7-47DþÐ…+1"M+^V„· ‹ ƒýS# 0" † gZ9¨hÿì:$Â@ y‰f"¸ÿà³ H¸ÿà³ H¸ÿà³ H¸ÿà@U H )$$G/ ¯ ? O ¿ Ï ß  &RK!$!!$!!$$!ÿ!!@H!!P$XYX+?22/3?í99/+qr3/F·%($!!% +</+<+H‡++Ä3/]qí10]]]++++]]32>54&'3#".5467 ycjIpR9" ¼ <]€¥fP†a6s:ý“I8ep7_‚–¤RW˜02‘Xgʶ›q@,Xˆ[#K*OGþWöR(9@‰zŠ2j2c!s!ƒ!¸ÿè³ H¸ÿØ@€ H* %$ k{‹$./ -#-RM$$$$@P€ FO7Ï7ß7777; G@ H-$/#P )PXYX+?2/í2?3?3í299/+í3/]]í9/]]q3/F·:($: +</+<+H‡++ÄÀÀ‡ÀÀÀ10]]]]]]]]++]]]]2#.54>7>">7>54&ÑClM) qÇsOªO^“f5H…¿wЧ uvp9W{K":/%qNcH @P0_Œ\+j3—΀;þi—Bu¤eˆæ¯q… ½¤ZKŠŸD`—h6…@fJý¹.cpBp-ngÿkþXyPä@zzŠ9y  JZj @ P ` RMRN OŸ¯Ï߸ÿð@@ H P/33/3?í993?3/+83/]q89///‡+‡+ć+‡+ćÀÀ‡ÀÀ‡ÀÀ‡ÀÀ]10]]]]]%#.#"'>323 #þ(Åag$ !"#&&0@0'UqÁþ´ïýi9W6R7 | >fKþÙýGü×vþW¡<#£@+  z Š { ‹ 4#+#Y"y"4"+"""*!d ¸ÿà³ H¸ÿà³ H¸ÿà³ H¸ÿà@ H¸ÿà³ H¸ÿà³ H¸ÿà@— H†rTdEV) #!#RM""""FVfRK@H R KPo¯¿Ï% #"!P XYX+?3?3í2?33/3/393/]]q3/F·$($ +</+<+H‡++Ä/]+3/F·$($ +</+<+H‡++Ä9/]3/F·$("$ +</+<+H‡++ÄÀÀ‡ÀÀ10]]]]]]]+++]++++]]]]]]]]]]%>73#.546733è\ƒ[9~¶}VÍOªOo¢i3vµz ‰ŽíªwIy[†ý|z¬n5þk•/X€R H(dý#@q_ÅCÿìúOG©@sy }k{D‹DjDk3{3‹3* : " H44g4w4‡4 22 --`pF77=GI$FF/GOI=GÏ/ß//@ H/$FFBP*7P6?3í2?3í29/9/+]í3/]]í9/3í9/9/]10]]]+]]]]]]]32>7654&'7#".'##".54>7326?3f)=(AbI2Y^2UzN$Z|[B_B&CWlDNzT,7Uwš` Œ§# +D/g1¦Á51R;!4cŽZUFtŸ ‹V}™ROM€¾~>%Ec=>cE$9i–^O •†kJ‹×±0W)7[A$®œüÿÿ?™{&†iÀ@ &€ %+55+55ÿÿhÿì{&’iò@ %&d)' %+55+55ÿÿCÿì2&RT€@ 4&Ø47 %+5+5ÿÿhÿì&’Tm@ %&À%( %+5+5ÿÿCÿìú&–Tr@ H&æHK/%+5+5ÿÿ?i²&(žZ@  &¥%+55+55¸ÿìZ5#@ y y-¸ÿس H¸ÿè@I H)&   '' HO4Ÿ4444$0 R^$$$$0@P€ ¸ÿÀ³"FH¸ÿÀ@G H7.//R/^010110/222012_3$.)_ à 3/0_@lmX+?3/]í?3?9/]q399í299í22/3/]/+<‡++ćÀÀ3/++]q3/F·6($6 +</+<+H‡++Ä99//]q10+]]]]++]]]>32#"&'732>?>54&#"#!7!ZD"kz5ÃÆ%:]…\j—/€%.7!*>. 'wy3zyj#’¾óþ†åþ  ž˜8Ä]‹].K9x#4P7É RY ý 圜ÿÿ?Ùð&a›v@ &á %+5+5eÿì²–1Ó@5…$Š‹ ŠfvjŠU+6*F*V*†*:J9 6 "\¸ÿÀ@]H,\-/-?-¿-`-p-€---3"Z?O_/@H_O¯ß'_ O_ '_0,@,P,€,À,Ð,,,?2/]í?3/]í9/]qí/+]qí23/]]qí3/+í9/10]]]]]]]]]]]".54>32.#"!!32>7§’ÙG5c޲ÓvÀ‡S´<_ƒUs¾’dwý3e–d^–v\%0x›Æ\Ÿ×{|à¿›l;;`|B7/WE)F±lš$^žs@1Ri7YI‚a9ÿÿ:ÿì@–6ÿÿQ",ÿÿQ ²&,žÄ@ &©%+55+55ÿÿÿûÿì-ÿ“ÿð&01@Rˆ‹z††j,z,Z#j#U"e"u"W'W H{Jj6V%5 H &HH¸ÿè@ H)Iiy‰* 15H "&H¸ÿà@`H H0''R'^&&&O&&O&& [/**¿*ÿ***2 @ H 0_ÀOß'_&_ _ lmX+?í2?í3?í9/]qqí/+3/]í99//]]3//+<‡++ćÀÀÍ++++10]]+++]+]]]]+]]]]]]]]]]!#"&'732>7!!2#!7! 4.#!þ3x8_XV_lC.  " 8:>HV4¦1sEu´{?LÍý£Þvq+NnCþ§áþ¬þõljU%˜>k©î¡þý¬4a‹Xh¢p;—=Y9?_ é@—‡‡zZjUeu  R^   ?Oo@)H[/O¿/¿ïÿ"R^@ H  _ ÀOß_lmX+?í?3?39/]qq33í223/3/+3//+<‡++ćÀÀ3/]qrí9/+]3//+<‡++ćÀÀ‡ÀÀ10]]]]]!!#3!3!2#%! 4.#! ~ýô~¿¿s s¿su´{?LÍþ±Fq+NnCþ×ýsý¬Tý¬4a‹Xh¢p;—=Y9¸&!Ê@   ¸ÿس H ¸ÿè@ H`p¸ÿÀ³$)H¸ÿÀ@THR^#!R^O !_p ° À  _lmX+?2?í229/]3í2?399/33//]/+<‡++ćÀÀ3/3//+<‡++Ä9/++]10++]]!#!7!!>32#>54&#"g¾óþ³ýïD"^jr5½i¾jmy3mi]#圜þ  Ÿ—>ýã#9OW ÿÿ?ð&´›½´&¸ ´ %+5+5ÿÿÿýÿìÇ4&½—ÈJ@ &ž)%+5+5?þhÊ ò¹ÿè³H ¸ÿØ@w H R KP R ^_oÏßP` pÀ R^@ H_  lmX+/2?3í2?33/3/+3//+<‡++Ä3/]qqr3/F· ( +</+<+H‡++Ä9/]3/F· ( +</+<+H‡++Ä10++!3!3!ÒPþ¿òòºþïþPþh˜ûáúþhÿÿÿ›è$>î•@`‡Z U e u jz [/?/¿ÿR^@ H_ÀOß__lmX+?í?í9/]qqí/+r3//+<‡++ćÀÀ3/]3/]í10]]]]!!!2#!7! 4.#!Pžý!UDu´{?LÍý¥Üvq+NnCþ§œþH4a‹Xh¢p;—=Y9ÿÿ?%ÿÿ?Ù‚aÿCþhh]@ ‰HY i ‰ {-&¸ÿè³H¸ÿس H¸ÿè³H¸ÿØ@! HRK 15H "&H¸ÿà@bH Hp€R^/ÿ`p€ RK@ H__lmX+/33/3?3í2?3í2/+3/F·( +</+<+H‡++Ä2/Í]3]/3/F·( +</+<+H‡++Ä9/]Í++++3/3/F·( +</+<+H‡++Ä10++++]]]]]+]%3#!#3>7!!v¯o´PûôP³n3]YX.¦þTÓþKx,SQP* ýȘþh83еäþûAþ†Ý²‰3ÿÿ?i(ÿ­º+x@†%5eu…¸ÿè@"%H" 2 b r ‚  ¸ÿÐ@ "%H" 2  ¸ÿÐ@A"%He u … W*W6#F#R^$#R#^"!""!RL$!* ¸ÿð@/ +)**+*R*^+++++""@-H""¸ÿÀ@ H-¸ÿð@9/@ H  !$)`/ *++"##lmX+?33/33/3?39/]3í299333/33/399/+]83/]+83/+89/3//+<‡++ÄÀÀ‡ÀÀ9/89‡++ć++ć++Ä10]]]]+q+]q+]q]"&'#.'3332>73###b"X ýÐëG0ÑÂ’/CBN9x¿x&=99EV9Îþ™Sl!eÓþÓ13/~À“ýOo_šþÏc{Dký• ,FbB1þaagüýµ ýkÿìÀ•<ã@…6zy‰hxˆU#U:u:F2V2f250++3.[_o /?8[Ð>%\& &&&\Ïß@#H@H@ H3`O¯ß )O%_%O%_%%@H%% _) _@P?2/]í?í3/+]q9/]qí9/+++qí3/]í3/]]í3/]]9/]í910]]]]]]]]]".'732>54&+732>54.#"'6$32)u°€V¨:VzUX‹a3ž¥cG`—h7"A_=T~`F¦PÖb¢vA5]€L2_J.Q–Ö3[€NF:aG'&ImGi}”>gK-K6$B[6=©¬2Y}KO}Z8 /LhBi¥t=?»ú@V f YiJ Z  0H  HEU¸ÿгH¸ÿè@ H  R¸@   R¸@   O   p €  R¸@:@ HEU%JZ *   lmX+?2/3?33/33]q]q/+2//+<‡++Ä3/]qq3//+<‡++ć+‡+Ä]]10++q++q]]333#>767?¬³  ÑÞþ蝹 ü8üd3b'.(®ú¨'Y&-+ûZÿÿ?»4&²—öJ@ &±% %+5+5?Á@3DR^ R L    @-H  @ H ¸ÿÀ@? H  R^@ H  `/ lmX+?22/3?33/39/]í9999/+3//+<‡++ćÀÀ3/]++83/+89‡++ć++Ä10]32>73###P¿x&=99EV9Îþ™Sl!eÓþÑ13/|Àý• ,FbB1þaagüý¥ ý{ÿ“ÿð·@F‹jzFV9Š9y%EUe%EU*jzŠ( H  15H "&H¸ÿà@6H H R^ @ H __ lmX+?í?3í2?3/+3/3//+<‡++Ä9/Í++++10]+]]]]]]]]]!#"&'732>7!#¦þ x8_XV_lC.  " 8:>HV4¦Qþïºáþ¬þõljU%˜>k©î¡þúÿÿ?ª0ÿÿ?É+ÿÿoÿì–2ÿÿ?Înÿÿ?I3ÿÿqÿìÒ–&ÿÿ¸\7ÿýÿìÇ©³¸ÿð@HHR¸@R^ H¸ÿð@ €¸ÿÀ@ H@ H¸ÿÀ@ H _?í?39/+333/3/+3/+89/]89=/+33‡+‡+ć+‡+Ä++10]#"&'732>?3 3¿@noxK?x+UL0+DCM4Bþ}Ð)×>X€R(*#‰%9^EY¬üðzÿõ ‹*5@u!…!i:&J&51E1U1…*t-„-X+h+Š"%Vf**i*  +5 R^   @°ÀÐ[?$?$O$_$¿$$$$7/[/@H`55*+`  5 5  lmX+?3?399//3í23í2/+]í3/]]qí9/]q3/F·6( 6 +</+<+H‡++ÄÀÀÀÀ‡ÀÀÀÀ10]]]]]]]]]]]]]]]%".54>;7332+#?32>54.+";Wk°}E\¤á…d$¼#$qµ~C[£â†j,¼,ÕMbœn:2Sm;7¹=×Ü1Rk:9Ø?v¬mÎ’N¶¶>v«mÏ’OããŽ6g•_XQ'ÎÁYR'ÿÿÿÙ–;?þh– à¹ÿè³H¸ÿØ@i HRK R ^   ?O/o¯ÿ@$FH R^@ H  _lmX+/3?3í2?33/3/+3//+<‡++Ä3/+]q3/F· (  +</+<+H‡++Ä3/3/F· ( +</+<+H‡++Ä10++%#!3!3So´Pû¿¿òÍòºò ýȘûáûÎe³@aH0 H*R^Oß! R^  @ H _  lmX+?33/3?39/93í29/+3/F· (  +</+<+H‡++Ä3/q3//+<‡++ÄÀÀ10]]]]++#"&5467332>73#ø#anu7ÅÇj¾jy}4pk`#“¾þï¾ü ž˜8#ýÝ RY ôú?] Ö@h R^ R ^   Pp/?_ R^@ H _ lmX+?2í2?33/33/3/+3//+<‡++Ä3/]]]q3/F· (  +</+<+H‡++Ä9/3/F· ( +</+<+H‡++Ä10]33!3!3?¿òíòºòíòºþïûáûáú?þh(>¹ÿè³H¸ÿØ@™ HRK R ^   d R^   ; K » Ë û  @FH¤ ; [ k ‹ /   R^@ H   _lmX+/3?í2?3/3/33/+3//+<‡++Ä3/]_]]]+]q3/F·(   +</+<+H‡++Ä9/q3/F·(  +</+<+H‡++Ä3/3/F·( +</+<+H‡++Ä10++%#!3!3!3åo´Pú-¿òÓòºòÒòºò ýȘûáûáû¸ô«@wjzZ j WgU e u …WgR^ [/O¿/¿ïÿ/?O_ÀOß__lmX+?í?í9/]qqí/]3/]qrí9/]3//+<‡++ćÀÀ10]]]]]]!7!!2#!7! 4.#!ƒþ5Šs$u´{?LÍýÆÛVq+NnCþÇåœý¬4a‹Xh¢p;—=Y9>þð@£‡jzWgZ j U e u  [ ÐR^?O_Ÿ¯?O¿Ïÿ/o¯¿ÿR^@ H_ÀOß_lmX+?33/3?3/2í9/]qqí/+r3//+<‡++ćÀÀ3/]qr3//+<‡++Ä9/]í10]]]]]]!3 !2#!3! 4.#!.¿þïû¯Du´{?LÍý¥¿õvq+NnCþ§ú-4a‹Xh¢p;û=Y9>¸”@d‡jzZ Ueu[/O¿/¿ïÿR^    @ H _ÀOß _ lmX+?í?39/]qqí/+r3//+<‡++ćÀÀ3/]qrí10]]]]!2#!3! 4.#!œ9u´{?LÍý°¿õkq+NnCþ²-4a‹Xh¢p;û=Y9ÿìK–+×@–ƒUeuUJZJŠ<5 5 ""&!ZK';';'K'['»'''-\\Û;K[@#H@H/"_O#¯#ß### _0@P€Ð?O_@H_ ?í3/+]q?3/]í9/]qí/]_]++]qí3/í3/]qrí39/10]_]]]]]]]]]"'>32#".'732>7!7!>54. Ü<©(q—¿v†Ó’MjÇþà·kµe®*Æ™m¼“býŽc5cŽú…x"32>7>54.²‰Ô’K ‡Èÿ–ŽÖGþÜ~¿¿s"‰Ãù‰z¾Œ\Í·{¿Œ\6e–UšÔ€1i0š÷®^WÚƒ((ýsý¬Œä¡XšJŒÊ€+W'ÖÖKÉ}*Z&k¡k6ÿ¥v­@mUe g Zjz R^[?O R ^   o O ß ¿  @ H __  lmX+?22/3?í9/3í22/+3/]qr3//+<‡++ÄÀÀ99//]í‡++Ä10]]]]#.54$)#! !"3![*-aO4)5Zþï¿qþuýüþd¼Â2Tn;†e9Z~UÕÑúIý·è}ŒIb;ÿÿ.ÿì-NDiÿì¼ÞF–@PŠŠzz<Š<u … *#%!u!D?$?=+=$7 7€777G0OÏßHBH*¸ÿÀ@-H*BP 8R7 P%?í?í9/í3/+í23/]]qí3/]10]]]]]]]]]]]"32>7>54.'2#".5467>7>7>•:qcP%D]7BpZA "?VºÈ d²hašl9%l¢á™;g^X,X¥_S…kTD6OgO‡iHQsI"%T‰d,M"Hg@„ɾ&P,„¼w7:|À‡8˜N«æ—W  ¡ -El›l8`H)'ÿìðD*7»@‡-‡%‡{4I4  ¸ÿà@N H G&&.G .°.O....97*55RK@ H5*Q77#1P#PXYX+?3í2?í99/í99/+3/F·8(8 +</+<+H‡++ćÀÀ3/]]]í9]9/í10+]]]]]]#"&'>3232654&+72654&#"ð.Lc5,Q>%G´lpÚdt[}›ZUˆ_3üÿ=@>‡œ|…ÇÞŒ\\-WM>H@^B( $:Q4Z‚U)jƒ®i+ @^üÿdlP^‚^bAL?r^),ÿìÄO7›@#u,…,u…60F0V0++k+{+‹++' H ¸ÿà@ HI!I    ¸ÿÀ@( H  )Hà3339F)@ H)3 $ P$P ?í3/?í3/99/+í3/]í99//+]]íí10++]]]]]"'>3232>7#".54>7>54.C8V?,–&Õ±dY)4f”`RV,qr?_E/“&Û¸y\#;o£gey@1PÂ$9(0v}+Jc7FeK:)2@/NK'<(8v}3Sg4MoS?//3/#Cÿì,Í)B¢@ t@„@*(f! ¸ÿà@f Hx.ˆ.[-k-,{,‹,&i&:JZDT+ z Š 1#I/?¯¿Ï@P`D>F@ H6Q?  *Q *P?í?í9/q3í/+í3/]qrí39/10]]]]]]]]+]]]".5467>32654.#"'>32'2>7654.#"ìfžl9aƒŸW2`UE3Z{G%P*%c0õ bˆ®a`{L( :bMFoS;=_?s¡bC"}µt7'6"&#lšc. {þÒþÑ‘»™×‰?…FrH:;2`K-*Y‹b#CAhI'ÿÿEÿì'NHÿ¶Ë:) @’š"ª"º"š ª º šªºŸ¯¿ °v†Ue%'5'E'%5Eª!!!  RN R L  ( ) "!R!M  RL" ()  ( ¸ÿð@( '(()(R(K))))))¸ÿÀ@H/?+¸ÿð@7@ H    "'Q/ ()) !!XYX+?3333/3?39/]3í299333/3339/]+83/]+q89/]3//+<‡++ÄÀÀ‡ÀÀ9/89/89999‡++ć++Ä9999‡++ć++Ä10]]]]]]]]]]]]]"&'#.'3332>?3###a8þ€ÈØ /—¯e!/+-\´\2ÃÀþò8U뺺 "! _´å þW ICKïL]2Úþ&2]Lïþ»CWý¶úþÿóÿì€N;†@ †99*¸ÿè@G H1,G!I"7G""0@ÐOß=I@ H1P' ¯!!!P' P?2/í?í3/]9/í9/+í3/]]q9///ííí910+]]"&'732>54.#72>54&#"'>32©È¨ %:R7/VA&)NqHC€c=dR$F<0 ¥JgƒNQ‚\19Yj16U:;p¤z„,%=+0M72G-†*L=EF 8+Gb>&E_9EeD$,CT.L{W/ÿÿVÿíJ:XÿÿVÿíJê&X—@ (&n-9#%+5+5" :ð¹ ÿà³ H ¸ÿà³ H ¸ÿà@ˆ HŸ¯¿t„ °u … U e RM  RN     p €  /  RK@ H  Q/ XYX+?22/3?39/]í993/399/+3//+<‡++ćÀÀ3/]]89/89999‡++ć++Ä10]]]]]+++32>?3###ô´\!;GY>ÃÀþò8U뺽K.\´:þ&2]Lïþ»CWý¶ò þ#ÿžÿìY:´@zZŠ;Kk¸ÿè@^ HRKP RK?OŸß/ ? O  @H   QP XYX+?2?í?3í299/]+]3/]3//+<‡++Ä9/]q399‡++Ä10+]]]]!!#"&'732>7!Ò¸þ³DiWKOY8"= '047##!>7UÒ­Œ þ •Š Œ®Ò T E_:ûÆÔ<@=üG·==9ý,:ýº*gfYP™5•"?: Ÿ@bRK/o¿?OŸß  R K   @ H Q/  XYX+?22/3?339/]3í2/3/+3//+<‡++ćÀÀ3/]qr3//+<‡++ÄÀÀ10]!3#!#¨YãY´Ò´_þ_´Ò:þ6ÊûÆíþ:ÿÿCÿì2MR"@:ˆ@VWRK/¿?OŸß RK@ HQXYX+?33/3?3í2/+3//+<‡++Ä3/]qr3//+<‡++Ä10]]]#!#@Ò´¸þ¸´Ò:ûÆ·üI:ÿÿÿÍþW1NSÿÿCÿìéNFÿÿ"KMPÿÿÿŒþWg:\EþWnÌ=ShP@#ŠBjblA|AjGzGT\„\D[K;[;CS7¸ÿè³ H6¸ÿضHE6*¸ÿà@š H+)++++% 5 % WW!!$! H\/66\6E877E76R6K77777Ð7`7p7 7À7Ð77777$GÿfàfOfÏfßffffjQG@ H76TJP8/ _>P,XYX+/2í2?39í2?3?3/+í3/]]]qí9/]]q3/F·i(77i +</+<+H‡++Ä9‡ÀÀÀ9‡ÀÀÀ10+]]]]]]]]]+]++]]]]]]]]".5467>323>733>32#"&'###72>7654.#""32>7654&sIpM( Qr•\r R´n!DMY6HqL( Rr“\r R³q!DNZ9gWC9P07ZH7T®9gVC ua7YH7T2\ƒQ-|?ŽË‚=h^ .3. £ýÍ/D-2\ƒQ2w?ŽË‚=h^#4>þYI/D-‹&]žxbOAbC"%[™tvX{|M&]žx3X&‚†%[™twW{|ÿÿÿ®<:[YþhM:)X¹ÿè@ Hdt„EU<L\„¸ÿè@¡ H5Eu…†u#3C%5 $$  ))RL@RK   ?_ŸÏOŸ+RK&)&&)&&))&/&&@"H&@H& &P"Q )XYX+?22/3?3?í2?í999/++]3/F·*()&&* +</+<+H‡++Ä3/]q3/F·*( * +</+<+H‡++Ä2/]3/F·*(* +</+<+H‡++Ä10]]]]]]]]+]]]]+32>733##4>7##"&5467¢~ T_@q\Av´¦ “i£P• "HWiC”• :ý{'QOX3]ƒQ^ü­3ýå˜,9;/L5’Š$Z&‰ý:!@r‚r‚l|¸ÿг H¸ÿг H¸ÿг H¸ÿÐ@' H"2Bbr‚"2Br‚"2Br‚¸ÿÐ@V H&6FRK?OŸß#RK!!!!@ H P!XYX+?22/3?39/í399/+3/F·"(!" +</+<+H‡++Ä3/]3//+<‡++ÄÀÀ10]]+]]]++++]]]32>73##".54>7CMN#>?B'e´Ò´YR•R>dF&D:þ¨ A<  ûÆÍ*, @_?  PVÿí:AŠ@1d9t9„9dt„M]mM(](m(2$v†¸ÿà@ Ht„¸ÿà@ H$t4„44¸ÿà@• H3$3 $$‹$ ,,A A1 1%?RK?A??A??AA??.RK ÐàðC27R7K.1..1..11./..@H. ;P%7.? "*211AXYX+?22/32/3?3?39í2/+]3/F·B(1..B +</+<+H‡++Ä3/]]]3/F·B(B +</+<+H‡++Ä9/3/F·B(A??B +</+<+H‡++Ä310]]]]]]]+]]+]+]]]]]]]]]]32>73#4>7##"&'#"&5467332>7 | LV9gR<v³¦ ª @L];yŽESe@‡‘ ²| LV9gR<v:ý†00,KO3]…Q\ü­"KC0,9;/L5wq1U?#’Š$Z&ý†00,KO2\„Q_Vþh‰:Cê@M&]&m&Š0 HM ] m M]mB¸ÿè@ý HdAtA„AEAUAd2t2„2d"t"„"i9$99v<†<$<47##"&'#"&5467332>7332>733# AN_;yŽESe@‡– ²| QV9gR<v²| LV9hU=v³¦“i£P,9;/L5wq1U?#’Š$Z&ý†00,KO2\„Q_ý†00,KO3]…Q\ü­3ýå˜Bÿì€:!¸@ejzŠcsƒ¸ÿè@R H ! RK    G_o@H@H@ H# @ H !Q  Q PXYX+?3í2?3í29/í/+3/]+++qí9/3/F·"( " +</+<+H‡++ćÀÀ10+]]]]#"&'!7!3232654.+€C~µrpÛd´þ¥Y¸b¢s?ý2=@>‡œ>bEÇO[†X*¢ƒþ6 Enþèdl)A-&ÿìº:#ß@"eujzŠ csƒU¸ÿè@\ HG RKo?OŸß%#RK  @ H #QP  XYX+?2?33/3?3í29/í/+3/F·$(  $ +</+<+H‡++ćÀÀ3/]]q3//+<‡++Ä9/í10+]]]]]]]!3#"&'33232654.+4Ò´ÒþÕC~µrpÛdδY¸b¢s?ý2=@>‡œ>bEÇ:ûÆO[†X*%þ6 Enþèdl)A-&ÿì½:¶@eujzŠ csƒU¸ÿè@K HG_o@H@H@ H!  RK   @ HQ PXYX+?3í2?39/í/+3/F· (  +</+<+H‡++ćÀÀ3/]+++qí10+]]]]]]#"&'33232654.+½C~µrpÛdδY¸b¢s?ý2=@>‡œ>bEÇO[†X*%þ6 Enþèdl)A- ÿì²M)¤@ty‰  H)+%&I'/'''F@ O ß   +I/?@ HQP `p€ÀÐà &/&ß&ï&&@H&&#P?í3/+]?3/]í9/í/+qí3/]]qí399//]í10]]]+]2#"&'732>7!7!>54&#"'>#P‘n@4Ty¡h±Á¥ *=M,InQ4þr‰uki‰§#çM+bŸtL£Œk>¦ž:S52_‰Wƒ/†…_e š"ÿìÄM9®@r…0Š#v:5%  * -GÐ  / Ÿ ¯  G0 O Ï ß   ;RK@ H%PQ2PXYX+?í?3?39/3í2?í/+3//+<‡++ćÀÀ3/]]qí9/]]í310]]]]]]]#".547##33>324.#"32>7>Ä e‡¥^Z“h9á_´Ò´YÚ_„¦bc—g4½9R3/`VH ";R00^TF «4i;„ºt5;q£h#'þ:þ6}´t88l›cMlE LŒt7c*RtH!MŽu3!##"3!þ˜Ï‚C?.I®d´Ò´Y`áDlK(.D-Êþ6×&EcCa€LûÆÊñ/P=!<-ÿÿEÿì'{&Hiñ@ 4&l86 %+55+55"þW Ì9:¶V4V"0¸ÿè@z H77 22     26R6K   _ Ÿ ¯ <   0 p € À   ? O  Ÿ Ï  ;"(RK¸ÿÀ@; H@ H"Qïÿ6 P 2(.. ...PXYX+?í?3?9/]9í999/]q3í2/+33/+//+<‡+Á‡+ÄÀÀ‡ÀÀÀÀ3/]qqr^]3/F·:(  : +</+<+H‡++Ä9/10^]^]]]]+]]"&'73267>54&#"##7373!!3>32G"E 2;;Š T_@q\An³êƒƒ´-þÓ "HWiC”• ’ 'BcþW ˆT\È'QOX3]ƒQýʶƒ““ƒ”!B7(/L5’Š$Z&ý>jN-!ä @EVu …  Š@/?O@ H RK@ H•€¿ p Ð ð  ¸ÿÀ@ +.H¯ ` €  ¸ÿÀ@H S QXYX+?3?í?í/+qq+qrrí/+3//+<‡++Ä3/+/]í]10]]!#?3þ“·´ÐµýÙþŠ:ƒüI:wþêCÿìßN2™@5E *++H I¸ÿÀ@; H  4*0F@ H-Q**%P  / Ï ß ï  @H P ¸ÿÀ³H¸ÿÀ¶H ?3/++]í?3/+]í9/í/+í23/]3/+]íí9/10]]%2>7#".5467>32.#"!!Ñ7VD5šPm‹Wf”a. CUail4W‡]4±2H0AjS>“þsfz">T25KvR,>o˜Z(^-o¤uL+.TuG-J5%S„`ƒ5€…ÿÿÿìÖKVÿÿ!ôÌ&ñÈOÈÚ¹ ÿÀ³88H ¸ÿÀ³77H ¸ÿÀ³66H ¸ÿÀ³55H ¸ÿÀ³44H ¸ÿÀ³33H ¸ÿÀ³22H ¸ÿÀ³11H ¸ÿÀ³00H ¸ÿÀ³//H ¸ÿÀ³&&H ¸ÿÀ@)!!H @H @H @H @H @H @ H @ H¸ÿÀ³//H¸ÿÀ@$&&H@""H@ H@H@H@H%+5+++++++55+++++++++++++++++++ÿÿ+£{&ñÒiÊZ¹ ÿÀ³&&H ¸ÿÀ@8!!H @H @H @H @H @H @H @ H @ H&%+55+55++++++++++ÿÿÿþWöÌMÿžÿìÐ:&5@zk{‹Š H ¸ÿØ@ Hbr‚U%%¸ÿè@„ H R K  Ï!5' 'R'K   @°ÀàG/@H/@H/@ H///7/?O@H5Q!! Q P',PXYX+?3í2?í?3í29/í/]+]3/]+++í9/]q3/F·6( 6 +</+<+H‡++ćÀÀ9/]q99Á‡++Ä10+]]]+]+]]]#"&'!#"&'732>7!3232654.+ÐC~µrpÛd´þPDiWKOY8"= '04‡œ>bEÇO[†X*¢ÍþÑØŠO ‚ P‹×.Êþ6 Enþèdl)A-"ÿì':'î@j z Š c s ƒ   U¸ÿè@j H'RKG!@H!@H!@ H!!!)RK@ H'QP XYX+?22/3?3í29/33í22?3/+3//+<‡++ćÀÀ3/]+++í9/3/F·((( +</+<+H‡++ÄÀÀ‡ÀÀ10+]]]]]32#"&'!#3!32654.+Y¸b¢s?C~µrpÛd[þJ_´Ò´YµY=@>‡œ>bEÇ:þ6 EnN[†X*Øþ:þ6ÊüKdl)A-" Ì+ù@VV%   ¸ÿà@I H  ## R K   / O Ÿ ß  -"%!!R ! K   ¸ÿÀ@7 H @ H%Q"ïÿ P    XYX+?33/3?9/]9í9/]q3í2/+33/+//+<‡+Á‡+ÄÀÀ‡ÀÀÀÀÀ3/]q3//+<‡++Ä9/10]+]]]]]>32#>54&#"##7373!!w"HWiC”• wµv T_@q\An³êƒƒ´-þÓ Y/L5’Š$Z&ý›]'QOX3]ƒQýʶƒ““ƒ”!B7(ÿÿ" ä&ÔtG@ &Í %+5+5ÿÿÿŒþWgê&\—ß@  &%1%+5+5VþtJ:+|@%L!\!l!/?O++( &&¸ÿÀ³ H ¸ÿà@ H0 $$Td ¸ÿè@Ž H$4D RL(RKDàà_o¯¿à-RK(+((+((++ÿ((/((@#H(@H(( P$+XYX+?2/3?33/3?3?í9/++]r3/F·,(+((, +</+<+H‡++Ä3/]qqr^]3/F·,(, +</+<+H‡++Ä9/3/F·,(, +</+<+H‡++Ä10^]]+^]]^]]++]]]]]]#32>73#4>7##"&5467 G£W&~ T_@q\Av´¦ ª "HWiC”• Dþ¸H~ý{'QOX3]ƒQ^ü­"KC0,9;/L5’Š$Z&?²¬@S H™©¹ HJRK R^@ H__lmX+/]3?3?3í2/+3/F·( +</+<+H‡++Ä3/]3/F·( +</+<+H‡++Ä10]+]+3%#®P´ný­ó¿›ýÈû€"xÌ@V HRL¸ÿÀ@+ H RK@ HQXYX+?2?3í2?3/+3//+<‡++Ä3/+]3/F·( +</+<+H‡++Ä10+]3#!3!Ö´Ò”M£gþ}:’ýëÿÿ±.ð&:š´1&¸ÿº´250%+5+5ÿÿf5ä&ZCç´)&¸ÿÖ´*-(%+5+5ÿÿ±.ð&:›÷@ 1&140%+5+5ÿÿf5ä&Zt&@ )&t),(%+5+5ÿÿ±.²&:žo@ 1&530%+55+55ÿÿf5{&ZiÆ@ )&)-+(%+55+55ÿÿÕÑð&<š"´ &¸ÿè´ %+5+5ÿÿÿŒþWgä&\Cé@  &,!$%+5+5iÐ|p°/°ͰͰ/°Ö°Ͱ°Ö017!iôР iÐ|p°/°ͰͰ/°Ö°Ͱ°Ö017!iôР ÿóÃL9@*/?O@Hº?O/?o¯ß@&+H/+]qí/+]/107! rɉÿóà L9@*/?O@Hº?O/?o¯ß@&+H/+]qí/+]/107! ɉÿóà L+@º?O/?o¯ß@&+H/+]qí//107! ɉÿÿÿ`þúÿR'BþúBÇ¸é  @'7F–¦¶¸ÿÀ@ÿ"(Hi&6F–¦æö Ÿ —‰f 9@ H ž ©ôæÖƶtdVF6&öæÔƶ¦–vfVF6&ÉöæÖƶ–†tfVF6&ôäÖÆ¶VöæÔͦ–„tfVF6&™@ÿôäÖÆ¶¦”„tbRD4$ôäÔÄ´¤’‚tdTD4&òäÔÄ´¢”„tdVD4$iôäÔÆ¶¤”‚tdTD6&ôæÔIJ €p`TD4$ðàÐÀ°@. „t`P@0 9À° rrr^]]]]_]]]]]]]]]]]]qqqqqqqqqqq_qqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]qqqqqqqqqqqr?ôí2/+^]]]ýæ9^]qq+r10]7>733Ç #+y:K Y&¸’4VKB A„AÃÀ¸â K@†tVf¶æö”¸ÿÀ@!H4&†ÆÖæt¸ÿÀ@ H ) —ŸV – ¦  ¸ÿÀ³%*H ¸ÿÀ@ÿ"HI   @ H  ž© övfF6&ùéÒÄ´¤–vfVF6&ÉöæÖÄ´¦’‚tfVF4$ôäÖÄ´¤”dRD4$òâÐÀ²¢’‚rbRB2"™òâÔIJ¢’‚r@ÿ`P@0 ôâÒ²¢’‚rbRB2$òäÔÄ´¢”„tdVD2"iôâ䤔‚tbRB4$òäÒ² €p`TD4 ðàÐÀ° ”dP@0 @9ðàÐÀ°rrrrr^]]]]_]]]]]]]]]]qqqqqqqqqqq_qqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]qqqqqqr?äí2/+^]]++]æí9^]+]]qq+qqrrr10]#>7#73Æ "*{9K X&Ãð4WKB A„?ÅÿúþüÅ A@+  —Ÿô « Ë  Ÿ  @ H   © ž /3ýä/]+_]]]æí910]%#>7#73 "*{9K X&Ã45VKB A„?Åý¸ì$@— /ž ©?íí2/]3í9/910##.546?ì&X{Å)3Y.'U+ G*‘”¸ h@F Ÿ— { ; { ‹ › ¿  @ H Ÿ —¿¿@ H ž ©?3ô2í2/+]qýæ9/+_]qrýæ910]]7>733!7>733à "*z9K X&ýò #+y:K Y&¸’4VKB A„AÃ’4VKB A„Aɸö ˆ@ÿ+;+;¶7W‡—§GW—§·÷5&¦Gw‡——ŸH˜¨¸@Hw(HX —Ÿ ‡ ¸ I   ¸ È g w   ( H   ž© ØÈ¸©™ˆyiH9) ùêÚÊ·§–‡wg8)ËèØÇ·§@ÿ•†vfWF6'öæÖƶ¦—‡wgUE6&õåÓò£“ƒtdSD5#™ðâÔͦ’„t`P@2$öäÒİ ’‚rbRB4&ôâÔIJ¤”„vdT@¤B2$iòäÔͦ”‚p`RB2$öæÒÄ´¤–„rdTD6&ôäÖÆ¶†dR@0 9ð¿ rrr^]]_]]]_]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]_]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]qqqqqqqqqqqqq?3ä2í222/^]]]qqqqræí9/]]+qqæí9^]]]qqqqrr10_]]#>7#73#>7#73Ú "+y9K X&Âþ™ "*{9K X&Ãð4WKB A„AÑ4WKB A„AÃÿ¹þú&à q@(++w§F'7æö7G¸ÿÀ@. %H%öÇ×ç–gw‡(—Ÿ¸ÿÀ@H(˜ —Ÿ ¸ÿÀ@ÿH˜ ‡   (  © ž ȸ¨™ˆvgWGøèƶ§—‡W6&É÷ç×Ƕ¦”…ueUF5&õåÕÆ¶¦—‡wgUE4$òâÒ²£“ƒtdTE5#™òãÓÃ@ÿ¶¦”…ucTD4%öæÔų£€pbRB4$òâÔİ¢’‚tdTB2"iòäÔͦ’€p`RB2$öæÒÄ´¤–„pbRD6&ôäÖÆ¶ydP@B2"9ð¿ rr_r^]]_]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqq_qqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqqqqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]qqqqqqqqqqr/3ý2ä2/^]]]+æí9/]+æí9^]]]]]]qq+qqrrrr10_]]%#>7#73#>7#73 "+y9K X&Âþ™ "*{9K X&Ã25VKB A„AÑ5VKB A„AÃØÿvXÌ —@g‰ )){‹«{i{‹«g" ¾p € /  o/_¿ï Á Â/?ö2í2/]q3/]]9/3í2‡ÀÀ‡ÀÀ10]]]q]]]]]q]]]#73%ÜósÇþ› Z-×eg èûŽr¤xþˆ¤DÿsZÌ“@[ ¾° ¾àðp€/o/_¿ Á  ÁÂ?ö2í2/ö2í2/]q3/3/]]qr9/í3/9/]rí‡ÀÀÀÀ‡ÀÀÀÀ1073%% %%#7Gþ“ b9¯Yo þœZ%m þž:¯Zþ‘ dYè¤xþˆ¤þ¶þ¹¤þˆx¤Ga‘Œ¼¬@9ª¥ ¥ª¶‰6fvv¦¶I&ö¹6fv ¸ÿÀ@ H ¹  ¸ÿÀ@î H€   @HfVF&¹‰y&ÒÙ©™yö™iYƶY)Ÿ©–†)ùÖiVFé–})nÛË»©†;+ ûïÆ™‹{m]K=-àÀ°€_@0>ðÐÀrrr^]]]]]]]]_qqqqqqqqqqqrrrrrrrrr^]]]]]]qqqqqrrrr^]]]]]]qqqqrrrrr^]]]]]]qqqq/+^]qÍ+/^]Í+^]]]]qqqrrr10_]]]]#".54>32Œ,Mf:9cK++Kc9:fM,ª:fL--Lf:9dJ++Jdº¹Û H@2– ––?_o¿ß/_Ÿ¿Ïïÿ ›/22í22/]qí/í9/í10!73!73!73Ì+Â+ü·+À+üµ+Ã+ÛÛÛÛÛÛ3ÿôË-G[u‰ô@¦ŠgHue…et¸ÿè@HzrŠr9Hu7…7F¸ÿè@HzDŠD Hu … ¸ÿè@HzŠ›Œ«ŒyŒ‰Œl H_¸ÿà@ H> H1¸ÿà@ H H¸ÿà@ H–æI‡Y´3¸@ O´¦@¶@Æ@æ@@¸ÿÀ@ H@@}´n¸@za´y‡‰‡©‡¹‡É‡‡@&)H6‡‡@H‡‡©–yfI;& öÙĶ™†iV9$ùæ™É†i[F)+´»‹ÿð@ÿ ‹9‹ ‹‹!´6Ffv–¦¶ ŒŠ€R¶;vH¶\.·i;$¶ ·¶ éÛÍ©™†iV9+ ûÙË©›‹i[)ÉéÖ¹¦‰tfI6éÖ©–dV4& öÙÆ©–ym[K;$ ™ÿäË´›„k[D+@¹ûäË»¤‹t[@4ëÔ»¤‹[O0$iôÛÄ«”{dK;$ ôÛÄ´›„kT; ûäË´›„k_+9àп rrr_r^]]]]]]]]]]]qqqqqqqqqqqrrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqqqqrrrrrrrrrrr^]]]]]_]]]]]]]qqqqqqqqqrrrrrrrrrrr^]]]]]]]]]]]qqqqqqqqqqqr?íôí?3ô2í2í2??/^]í3/^]8ôí^]]]]]]]]]]qqqqqqqqqqqrrrrrrrr3/+q+qýôí9/+]qíôí9/]]810++++++_]]]+]+]+]+]+]+]2#".5467>"32>7654&2#".5467>"32>7654&%2#".5467>"32>7654&#3ý2XB' Vfi)3YB&Vei'!?8.;6<7/82XB' Vfi)3YB&Vei'!?8.;6<7/8c2XB' Vfi)3YB&Vei'!?8.;6<7/8ùÐ¥¢§;_EL&f‚I>bDJ%kFl2ZIN7IE3ZGP;H@ý©;_EL&f‚I>bDJ%kFl2ZIN7IE3ZGP;H@l;_EL&f‚I>bDJ%kFl2ZIN7IE3ZGP;H@ý¢¶zº5@# H6F )2B@€/À?Í/]]Í]10]]+3¶@Äžzýùÿÿ¶z&UV—¬]@Egw‡hxˆ ìë[›@#H@H/ï/o¿ß/]ä/]_]++]qíí2/]10]]%73 _þ÷ ˜ þi m?s(þŒþ‘R¬\@"fv†iy‰ìë`P¸ÿÀ³$+H¸ÿÀ@H/ï/o¿ß/]ä/]++]qýí2/]10]]7#7 73®žšþøœ 'otþ?ÿÿMí&ÈÿØöÒT´¼/í//10!5!Òýúö^ýÓë3@„{‹p/_o¸ÿð´??/8/]]]810]]!#3þl™~š\Ì%J¹ ÿÐ@VH_="M"]"9I#)#)$%R%à éùÙ@#H–9Y'6'†'–'V'f''¸ÿÀ³%(H'¸ÿÀ@; #Hù'Ö' ''I'™' R à    –   $ %¸ÿÀ@ÿ HIYy‰+;  ô'ä'Ö'Ä'´'¦'–'†'v'f'V'D'2'$'''ö'â'Ð'À'°'¤''€'t'd'P'D'4'''Êô'ä'Ô'°' ''€'t'`'P'D'4' '''ô'ä'Ð'Ä'´'¤'„'t'd'T'4'$''ð'à'Ð'À'´' '”'„'t'T'D'$'''šô'@Æ´'¤'”'t'`'T'D'$''ä'Ô'Ä'´'„'t'd'D'4'Û'´'¤'”'„'4'''jÄ'´'¤'”'„'t'd'4'$'''ð'à'Ô'Ä'´'¤''€'t'd'T'D'4''Ô'Ä'´'„'t'`'P'D'4' '''9Ð' 'rr^]]_]]]]]]]]]]qqqqqqqqqqqqqqrrrrrrrrrrr^]]]]]]]]qqqqqqqqqrrrrrrrrrr^]]]]]]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]_]]qqqqqqqqqqqqqqqq/^]]]]3/+299/99/]q3/]‡++ćÀ^]]]++qr3/]]]+]qr3/‡++Ä10]]]_]]+>54&#"#>533>32õI/4HiG€dw+4@*Q]Kv0/1d^þ”ÿ.("# . Y\0þÿÑÖ‰@Q     R ^    @ H  ` _/?/¯ßÿ _ lmX+?3?í9/]qí9/3í2/+33//+<‡++ćÀÀÀÀ‡ÀÀ/3/99//10!!!!##73!ñ\¯ýQ)’þn6´6¯¯Â{æþ$Õþéé›ÿô›–:c@6zŠzŠZ j %$%"2B"(B(R(b((   ¸ÿè@¢ H(,,& '*+./&/ &/R/q    o:0:@: 0  : :o<@ H /4. u+*u'&Ÿ_oŸ¯@Hÿ_oŸß 4#s4t:::€X+?3/]í2?3/í99//]]qr+]qr992í23í299/+3/]í99//]]í3/F·;( ; +</+<+H‡++ÄÀÀÀÀ‡ÀÀÀÀ939310+]]]]]]]]]]]#!7>?#737#737>32.#"!!!!!2>73NeyCýFbvººººEmšgFy^@¥$6D(r™þh˜þh +=M-Ø,O@06UwI!š. yŒ‚\“f7:V820$s}ŠŒ8gWD+E2Nÿì€ )_nÄ@ |Zj<¸ÿà@ H%5Eu…%(u(…(] H@¸ÿè@ù H( H %[# )$#)Rr#'##'##IoH`n>oQ4o[KH[HkHÛHëHH@H?HH/H/[?[o[¯[ß[ï[[@H¿#ß#ï##@!H#0#_0#H[QQ[H#h-o.@H..pfggRgqhihiihiih@ HhfPQV94C1u*O._.o...*#$u'* '())`)'P'`''))'LPighLuCC@IPI`IÀIIIC€X+?3/]3í2?3?í9///]]]]333í299/3/]í9í/+3//+<‡++ćÀÀ3/+í9/////]]]+]+]]_]+]ííííF·o('##o +</+<+H‡++ÄÀ‡ÀÀÀ93310+++_]]+]]4.+3263#3267#"&5467#73732.#"#".'732>54.'.54>%+#32g-RsF8l^À¾ÂLH*!"$Q^Ohodnéž  QKJX.K62VA%5dŽZKqS6™XX-K63P8+R@'5^€ý3O“Ô„‚jµÕt¹‚FóA\<ýÔœ+ƒþv1R~bV8šƒòçu`*:'/" $7M5CdB!0L54;8 +!$ "3I3B]<Än¯yAýÛ6d‘ÿîÌ–;ò@§zŠzŠ{:‹:Ueu6%6.%.5.% !%9o$8o9 90999=..%%n0'$@ H$$u''-u00_'o'ï'_'o''Ÿ'ß'0/0?0¯0Ï0/0¯0ÿ0'0'0399s3s`?3/]í?í3/99//]q]q3í23í2/+22í2233]3/]í9/]í9310]]]]]]]]]]&!!!!3267#".'#73>7>7#73$72.94lg]$ÐAþR ÏAþl @`Bj…*˜PnŒW]œqA«@p ’AqN'ÍWˆc> «sKy'J#VŒb5ia0BmO+@Ä#J' ú+OqE#[cƒÿôËŒ,0J^Å@”-¤-ª// Hz<Š<š<I¸ÿè³H¸ÿè@HEUe HA H4¸ÿൠH0.¸ÿð@0.0.6R´Cµ6´'\7\G\\\\¸ÿÀ@>!Hˆ\˜\\\`º`«`Š`š`{`L`\`l`-`=```ø`é`Ú`Ë`º`«``¸@@ÿ HH`9```€Hº`–`g`‡`(` ``´´µ(´ø@)6H@&H@HK¶1¸U¶>/-¶ ¸!¶ ç`×`¨`˜`ˆ`x`i`X`Ø`É`·`˜`h`X`H`9`(```ʸ`¨`ˆ`y`j`Z`I`9`)``÷`¨`g`H```÷`×`¸`¨`ˆ`y`j`Z`J`;`)`` `šè`Ø`È`¹`©`@¯š`‹`z`i`Y`I`8`)```ù`Ø`É`¸`¨`˜`ˆ`y`j`X`I`:`)`` `Ø`Ç`¨`˜`‰`y`i`Z`I`8`)`` `iý`í`Þ`Î`¹`ª`™`Ÿ`¯`¿`Ž`~`n`^`8`(```ù`ê``¸@vW]HÞ`Í`¾`®`ž``~`o`_`8`(`/`?`O`` `ü`ë`Ü`Í`½`®`ž``~`k`Y`J`;`+`` `9û`í`Þ`Î`¾`­`_r_rrrrr^]]]]]]]]]]]]]]]]qqqqqqqqqqqqqq+qqrrrrrrrrrrrrrrrr^]]]]]]]]]]]]]qqqqqqqqqqqqqqqrrrrrrrrrrrrrrr^]]]]]]]]]]]]]qqqqqqrrrrrrrrrr^]]]]]]]]]]]qqqqqqqq?3/^]íôí3/???íôí/+++]íôí3/í^]]]]]+qqq+qqqqqqrrrrrrrr3/]+qrýôí99//8810+++_]++]+]]267#".5467>32.#"#32#".5467>"32>7654&¦Ij:ToFLlF!VmDDfE$‹#6%4R?.$80¥¢§‹5^G) Zjq/7_F( Xjq0%F>4B<#C>4?|PY6^F(2XyG"G&}£b'*F^5 !9*#MwTUC-K6ý„ýô IvU%]0~ ["$MxT%[.ƒ WlCxbjHb\Dx_oK`Vÿóÿìß•*:Â@Š…)†1\lŒ?1O1¸ÿÐ@\ H ((Š(0 H!!%&"1"1 0 %0 R r&&@6666&&!! &"01%+!!++?Í?Í9/9/9Í999/3/3/3/]]Í2/͇++ÄÀÀ‡ÀÀ‡À‡À10+]+]]]]]232673#"&546?7>7>">54.2P]DtšV-0:V&E9EU6`mHH&G"r.HeE, aGtR.•dlrϰ‰-åA=6hmLuN(lnC›!IKJpK&L#37=R=¸@>?>??>??>>/>>¸@1Ÿ3¿3Ï3ß3@333K+¶¶?HG@G7?`=6IA>lmX+?3/í?3/399//íí3/]]í/]3//+<‡++Ä99//]3/3/+í3//+<‡++ć+‡+Ä10++]+]+]]+]+]]+]+]!7!".5467>32"32>7>54& #367>737{úLrK%Hh…OMqK%Hh„*J?2 *;$+K@3 WüJþµ Êî µ¢þï’’++OnCC ^†V(+OnCC ^†V(¢6`M*D1E+8dO*F^Mü3º.0)]'üQûA+0)e3£ú¼z)1@ Hˆ ¸ÿè@HYiy'H' H¸ÿè³H¸ÿð@• HÄ@,¯101@11+ .?.O..+Ä@,/,,)Ä'/_o¯Ï3o3*.Ê/'/  , ,P,€, ,/Ÿ33_3O333Ï33O33Ï33O33;ï3¯3rr^]]]]qqqqrrrrrr?Ì^]2/333/33í2r3/]33í/]]íÎ]]Î]]9/]í2210++++]+]+5#.'&'#367>53##5!›æl£ €¾ß ¨¸û(†ÿŠz©Â ýË$,6 ýÉýÍ3)"üù˜ýh˜oonº–9O@œy7ucsƒcsƒc%s%ƒ%c$s$ƒ$‹3Y3i32 H‹Yi H:&1 $H1]1m1}1;1K1 $H ] m } ; K  +[k  + [ k 0\( \€/O( (0((à(ð((¸ÿÀ@c H((#)3)))Ö)æ)ö))"[/5ß55JZr‚fT[ßïÿ@%H@H@ H;'@ H' 0'*_)_?í?3í2/+33/+++]í3]]]q/]í3]qq99//+]q]]íí10]]]]]+]]]+]+]]+]]]]]]]]267>;!5>54.#"!532.54>—ñ¨Z;mc*'!Gôý³`‹Y*=t©lmªt=*Y‹`ý³ôG!'*cm;Z¨ñ–V¢ê“j¿§Š6œà3~ŸUtµ|AA|µtUŸ~3àœ6Ч¿j“ê¢VXÿÞ|H"/r@KZ@¤#´#[#›#T#d#t##+#;##1€/Ô;K@H///) ?2]]Í?Í9/Í/]_]+]Í]2Ü]]]qqÍ210_]".54>32!32>7.#"k‚ƆE,Lfv€?qÁŽQüÅ@NX.Kt]M"H$SnË;L]53WJ<"]Ìob }]<O’уþœ-# ÿõN&s 'ù–nýÍ ´R?555ÿÿcÿõN&”'ù–nýÍ ´>?555ÿÿ|ÿõ:&•>'©–ZýÍ ´>?555¢d^D@  €/Í/ÍÌ29910#.'5>73!;H:‚RR‚:H;Ý)"bADp*$*pDAb"VÿÃð@ @ €/ÍÌ299/Í105>73.'#Õ"bADp*$*pDAb"V ;H:‚RR‚:H;ü#¢d^D@  €/Í/ÝÌ29910.'3#>7!5;H:‚RR‚:H;ü#"bADp*$*pDAb"VÿÃð@ @ €/ÝÌ299/Í10%>7#.'53+"bADp*$*pDAb"V¢;H:‚RR‚:H;Ý¢d^D$@€@ €/Í/Ì299ÝÌ29910#.'5>73!.'3#>7;H:‚RR‚:H;þ;H:‚RR‚:H;)"bADp*$*pDAb""bADp*$*pDAb"ÿÃð&@@€@ €/Ì299ÝÌ299/Í105>73.'>7#.'5Õ"bADp*$*pDAb""bADp*$*pDAb" ;H:‚RR‚:H;ý;H:‚RR‚:H;ÿHð#(@#  /Ì299ÝÞÍÌ299/3Í210!!5>73.'>7#.'5àþ Å"bADp*$*pDAb""bADp*$*pDAb"hPX;H:‚RR‚:H;ý;H:‚RR‚:H;8ÿåºÅ/E²@y‰  HZ2j2DH¸ÿè@ H+C{C‹C¸ÿà@ H DDD¸ÿà@ H  * '¸ÿð@*''0F@OßG323>54&#"7>32.#"32>º  `‚¢a]N#/If„S*M@2‚;:6$*tCqš^)Ó$3@$5VC1 *A,BlS8ª.gkj0€ÎM?kŠK<†h?0C*:"ÄÑ “'X•Ãþ“*J7 3Tntt05[C&c¡ÍÌh@AR KR K ¿€//O _?í2?33/]3/]]]9=/‡+‡+ć+‡+Ä10353.'!Ýôãþ""þÊ4‘ðû“å._N66N_.ü·ûþ9¼8@$Z?Oïÿ Z/?Ÿ¯¿_/2/?í/]í3/]qí10!#!ü¶¿Áþ9¦ùZHø¸Êþ9` ª@k { Ë  @Hé  ¸ÿð@Hk{Ë@Hé¸ÿð@EH[@H@H_O _ o  [ [/O_o_ß _/í2?9=/]3í2/]í3/í3/]99//]_]++í10+]]+qr+]+qr5 5!! !Ê{ý•Bü²Hý¨¢þ9m;6j˜üúü`fò7¶p¸ÿÀ@ HO0à¿Ïß­³?í/]q/]]+]q105!ƒã`’’3ÿòbTk@ H H¸ÿè@;H 9I$¯Ïï@ H@ H¯/3/9/]í/+3/]/+qr89=/]3310]++]##5!3njþå¶ò®uýN‡iËo×#3CN@óYiyVfv‰25CEC  !'4/?///32>32%"32>54..#"326o,RrGa¨FLTZ.EsS.,RtG^¨C JT^3ErQ-þ³Fw83wM,F33Gþ]3wN+F10G/FxNNj>…•?fH'7dXQŽh<‡”>fI(7e¨~‚€€(F^66\E'ú€€(F^63]E)~˜`Ç ³/Í/Í103!!˜^jû8Çû—^ÿþª_@ÿhxhx  ©‰yiI9+ ɹ©™‰iI)éÙɹ–iI)  ùëÛË»«™iV-ûëÛÏ¿‹k[K;/Éûïß«oK;/ÿëË»«‹k[O;/«›o[@»O;/ ™ûëËo[O;+ ë«›{o[O;+Ô»«k[K iëÛ´kTD4Ô‹tdT4 ô«Ÿ‹{kK;/ 9ûëÛÏ¿r_rrrr^]]]]]]]]]]qqqqqqqrrrrrrrr^]]]]]]]]qqqqqqqqqrrrrrrrrr^]]]]]]]]]qqqqqqqqqqqqqrrrrrrrrrr^]]]]]]]]]]]]]qq_qqqqqqqqqqr^]]]]]]]]]qqqqqqqqrrrrrrrr/2/Í/ÍÜÍ10]]4>32#4.#"Dz§bc©{Fg5_‚NN‚^4tÀŠLLŠÀtþb›l98lœdþÿžþ9”ã#8@#!!%! *F O   PP/í?í/]]3/í2/10]]"&'532>54>32.#"$$K>#3B'2Z}K"K=$3B'2Y|þ9 “%@T0Ñ^†V( ” (AT,û-^†V)LP@ô!CÇ@"H$X$ˆ$˜$HXˆ˜A HB0 H=0 H*¸ÿг H0¸ÿÐ@ H H 0 H0 H ¸ÿè³ H¸ÿг H¸ÿгH¸ÿÐ@ H?4Tt¸ÿÀ@3H[$- @ H $EDEdE„E¤EE$EDEdE„EE$EäE;­@-¸ÿÀ´#@)(­‹1$1411­@ ¸ÿÀ´'323267"&'.#"5>323267’þT"ýšÒª¶  H ¸´ //ÍÍ/íÌ10+#47632#"'.'&#"µ“TR€?K3% !$ ýšVÄ{{?0(4 ''#iýšµª ¹ÿà´ H ¸´//ÍÍ/ýÌ10+3#".54>3232765"“Z(g>2%!%ªø¨Í}86'"%)jÿö%µ¶´¸±ü?í33105! ¿%‘‘Øý“iH»´þú??öí103#Ø‘‘HöKý“µ¶"²º³þ¸±ü?í?öí310!!#(ýi‘¶‘ûnÿöý“¶"»µþ¸±ü?í?3öí105!# (‘%‘úÝ’%µH"²½³üú??íöí3103!!‘—üØHûn‘ÿö%H"»µú¸±ü?í?3ôí105!3 —‘%‘’úÝý“µH'³ º³þ¸³üú??í?öí23103!!#‘—ýi‘Hûn‘ûnÿöý“H'±º·þú¸±ü?í??3ôí3105!3# —‘‘%‘’öK’ÿöý“µ¶(² º¶þ¸±ü?í2?3öí3105!!# ¿ýi‘%‘‘ûn’ÿö%µH(² º¶ú¸±ü?í3?3ôí3105!3! —‘—%‘’ûn‘ÿöý“µH 3³ » @ þú ¸²ü?3í2??3ö2í23105!3!!# —‘—ýi‘%‘’ûn‘ûn’ÿöqµj%· ¸²ý¸±û?í?í3233105!5! ¿úA¿Ù‘‘þ˜‘‘Ùý“ÒH*A ¶þú?2?3öíôí103#3#Ù‘‘h‘‘HöK µöKý“µj 1µ º³ þ¸²ý¸±û?í?í?öí23310!!!!#(ýi—ýi‘j‘בü"Ùý“µ¶ 3² ¿  ² ¸´ üþ?3?í2ôíöí310!###µþ‘ב¶‘ûn’ûn#Ùý“µj ?´ A   µý þ¸±û?í?3?íöíôí3310!!#!!#ÙÜüµ‘htþ‘j‘úºo‘ü"ÿöý“j 1± º·  þ¸²û ¸±ý?í?í?33ôí3105!5!5!# —ýi(‘q‘בú)Þÿöý“Ò¶ 4A   · þ¸±ü?í2?33ôíöí105!### ܑב%‘úÝ’ûn’ÿöý“Òj ?´ A   µ ýþ¸±û?í?3?íôíöí3310#!5#!5!Ò‘üµt‘þtjú)F‘ú)Þ‘qµH 1µ ½  ²ý¸³ûú??í?íöí233103!!!!‘—ýi—üØHü"‘בÙ%µH 4² A    µüú?3?3íöíôí3103!!33A‘ãü$‘×Hûn‘#ûnÙqµH ?´  A    ²û¸´ýú?2?í?íöíôí33103!!3!!Ù‘Kü$h‘ãýŒHúº‘×ü"‘ÿöqH 2¼ ·  ú¸²û ¸±ý?í?í?33ô2í105!5!5!3 —ýi—‘q‘בÞú)ÿö%ÒH 4A  ·  ú¸±ü?í3?33ôíôí10!5!333Òü$ã‘ב%‘’ûn’ÿöqÒH ?A   µ  ¸µ ûú¸±ý?í?3?í33ôíôí10!5!3!3!5!Òü$K‘þ‘ýŒãq‘Fû‘‘ý“µH 6¶  º ³ þ ¸²ý¸³ûú??í?í?öí2233103!!!!#‘—ýi—ýi‘Hü"‘בü"Ùý“µH 8² º ² º·  þú¸±ü?í?3?3ôí2öí3103!!#3#A‘ãþ‘þ˜‘‘Hûn‘ûn µöKÙý“µH Iµ A  ² û¸·ý ú þ?3?3?í?íöíô2í23310#3!!#3!!j‘‘×tþ‘‘ãýŒý“ µúº‘ü" µü"‘ÿöý“H 8¹ ² ¸@  þú¸²û ¸±ý?í?í??33ö22í105!5!5!3# —ýi—‘‘q‘בÞöKÞÿöý“ÒH ;A   @ þú¸±ü?í?3?33ö2íôí105!3#3# ã‘‘h‘‘%‘’öK’#öKÿöý“ÒH Iµ  A   µý þ¸´ ûú?3?í?3?íôíö2í233103#3!5!#!5!A‘‘þ˜‘ýŒã‘‘þtHöK µû‘‘ú)Þ‘ÿöý“µj 9´  ºµ  ¸µ ûþ¸±ý?í2??í33öí33105!!#5! ¿ýi‘ýi¿q‘‘ü"Þh‘‘ÿöý“µ¶ :² ¿  @  þ¸±ü?í22?33ôíöí3105!!### ¿þ‘ב%‘‘ûn’ûn’ÿöý“µj J´  ºµ½³û ¸µý þ?3?3í2?íöí33ôí3310#!5!3!!#!5j‘þt×tþ‘túAý“Þ‘‘ü"ב‘ÿöqµH :@   ½ µ ýú¸±û?í3??íôí3333105!3!5! —‘—úA¿Ù‘Þü"‘þ˜‘‘ÿö%µH :² ¿ @ ú ¸±ü?í33?33ôíôí3105!333! ã‘בã%‘’ûn’ûn‘ÿöqµH L@  A   ³ ý ¸µ ûú?3?3í2?íôíôí3333103!!3!5!5!A‘ãýŒþ˜‘ýŒãþ¿Hü"‘oû‘‘þ‘‘ÿöý“µHL¶  ¸²¸@ þú ¸´ û¸² ý?3í2?3í2??33ö22í2233105!5!5!3!!!!# —ýi—‘—ýi—ýi‘q‘בÞü"‘בü"Þÿöý“µHM³ » ²»@  ú  ¸¶ü þ?3?33í22?33ô2í2ö2í23103!!###!5!33A‘ãþ‘בþã‘×Hûn‘ûn’ûn’‘’ûnÿöý“µH ]µ» ¶  »²¸·ûú ¸µ ýþ?3?3í2?3?3í2ö2í233ô2í233103!!#!5!3!!#3!5!A‘ãýŒ×‘þt×tþ‘þ˜‘ýŒãHü"‘úºÞ‘‘ü" µû‘‘m«H¶ú/?3310!!«úU«mÛý“«m¶þ?/3310!!«úU«ý“Úý“«H·úþ??3310!!«úU«ý“ µý“ÖH¶úþ??/310!!Öý*Öý“ µÕý“«H¶úþ??/310!!«ý*Öý“ µ*gýõ«£ #'+/37;?CGKOSW[_cgkosw{ƒ‡‹“—›Ÿ£§1µ¡™•‘¥¸¶¤mUE- y¸@ xlTD, xeM5‰¸@ ˆdL4ˆqYA)}¸@ |pX@(|aQ9 ¸@ Œ`P8Œu]=%¸@!€t\<$€xˆ|Œ€€Œ|ˆx„ œ˜”¤¤©iI1!…¸@hH0 „„§‹‡¸´„£gck¸·h d`h_[W¸·T\XTŸSOK¸·HœPLHC?G¸·D@§¢.)'.@D%T%K![!K[DT #/ÍÜÍ/ÍÜÍ10]]]]4>32#".732>54.#"§Fz¤^^¥{GG{¥^^¤zFV9b…LL†c::c†LL…b9d^¥{GG{¥^^¤zFFz¤^L„c99c„LL†c::c†²‰#ú¶ /]Í/Í102#"'&5467>76jnk5R·¶S4lú9R46n9··:m64R9)¬ƒ· /ÍÝÍ/ÍÝÍ103!32>54.#")ƒüEx [[¡xEEx¡[[ xEƒû}A[ xEEx [[¡xEEx¡)¬ƒ+"@" '/ÝÝÎÝÎ/ÝÝÎÝÎ103!4>32#".'32>54.#")ƒüQ:c…KK…c::c…KK…c:MEx [[¡xEEx¡[[ xEƒû}AK…c::c…KK…c::c…K[ xEEx [[¡xEEx¡s…cu"· /ÍÜÍ/ÍÜÍ10#"'.5476324'&#"3276c%%%V3eK#%HJfgGJL33FF3331HH13}5V%#%H%V5fHJJGgF3333FE6116±ÿåy¬!-9D“@] $ t $t+{+{D"(?4.(.(.1%+7+>:h:Y:G:::b¹^0Hþ²³³²þ€×[²²[×€Ù™šš™ÙØ™šš™W .. -- .. --þ¿‰‰#º_[Ñÿ噬)4`@7*/$'!04h4Y4K4=442-_oO-_--- /Ì99//]^]Î3]]]]33Î2/Í99//Î3Î310#"'&54676324&#"326%4&#"326327'#"'™´³ýý³´ZZ²þþ²ZZý. -- .Ó, // ,ý®0^¹b>L‘“LHþ²³³²þ€×[²²[× -- .. -- ..þÜ[_º#‰‰Fÿs;3F‹¹/ÿð@ H4.4$w##¸ÿð@M H H;;  H;/4#4;B ß p ?   9+>€Ðà0/43?3O33/^]ÍÜ]]]]Í/ÍÜ]]]]Í10]]]]+]]++]]]+373#'#5.''7.'#5367'7>7"327654'.‰B 965º-¸-,××,(¸1¶7:"B?n0¼+¶(.×× P´(½9p6Eu0bb0uE‹`cc1u;Ù  ¶-¸;q9>€_¸1¶(,=20dˆ‰b2/aaЉc02ÚP&/b@>+ï+ÿ++"à"ð""P'ð''€@%(H /Í+Ü^]2Íqr/]3Í2/ÍqrÜ]Íqr9/3Í210.'&547>32!!#!5!"327654&'&Ü7Z#GS,e>SW;=>B.*PlzS++VSzmQR ¦FþúF‘;G,+G>>=T,G;Qú¯AQF@(1A;NN?  33FF;A1?J7€77B??/^]Ì]ÍÜ]Í99/ÍrÜ]Ì]Ír9910.'.'.547>323267632#"'.'#"'&547632"327654'&ÿ6%( ? .@$    íTVWvvWTTUzGSšZ>==@XY<>><      "O-@" '*R*îQm}VXTTuuWV+ >=X[===>ZW>>;Ï/(@& 0 ` p  "@ H"O_/]//+3/]/10#"'!727>'#"'&547>7>76 (_E#%?BXc$&£‰üè}V+B,-„SZB?N9En&8Ï6_,+i?~BCF_?B¿“WVc %%1E[wK`_B?[J;*U/;q9S<ÇK/@9M?4=C /)//99//]923/]Î10)7>7>7654&5#"&'&547632.'.547>3267>32#"&'.'Fü¶Tl)@4:Z+X-;a)OII]P3N(a„2+C.=Ÿ#!K2dmy;*&StsOP"4&sN&(PNmVb(%)LtvSP<3=-Q}.-L'fÿéZy'&@) @ P p €  ///]Î10^]].'.'.'.547632>32b*gL8E+%DFfbN/"ŽX2U#F)N7>-qEEt/'xSEj( #&b<^Q2€P;`ÇN¥]]5(–o]ŸH: 9‡Pwc; kM”Ä;!0@! @O_o€! //ÍÌ]9/9/ÍÜ]ÍÍ2103#>54&'&'#"&547632éL™3:0./9@%%Hl9:Q0*ýÚ%#Jj9:;b&J5-L9<ð²þg•u˜ÿÿE.Ì&IL9ÿÿE.Ì&IO9TþDèÿªE¹ÿØ@+ H ƒ0 @ P  Œ?O Œ P`p/]í/]í/]/í9/810+#"&'732654&#*73~j$JoJ#10$ZL7@1>VMG.M8`:.!`Xþ9fÿž ,µ5E¸ÿд H ¸ @  Ž‘ /äí2/æí910+]#>7#73RC1u6D X ÃÌWu/0`.§'3Ò Ê@jVfxˆFVf¸ÿè@u H%U ë û  @HRà  _o¿¿ Ï  @*2H @!$H   /?å@H Üß?3?339/+]3í2/]]qq3/++]/]q3‡++ÄÀÀ‡ÀÀ+]10]]+]]]]#7!733!>?#ƒ#þkä¡l}–  õ 8å²²o-ýÕq %'# þá!&&"N'ï&œµv † ¸ÿè¶ H„¸ÿð³ H¸ÿè³ H ¸ÿØ@I H%à&@ H&& â/?Oß(á/?&&"äïÿä@P`ÝåÜ?í?3/]í9/]q3í2//]í3/]3í9/+í3Í10+++]+]!!>32#".'732654&#"#öùþrCV<8[A$(OvO@aG- ‡'9'QSM>2M|qø'"?Z8HuR,":M+1&b]QJ#£4R@6{ ‹   Y i à ã Ÿ  @H @ H å Üß?3?í2/++]3/]í9/í10]]]#>7!7!R–xU…VwNþ*aaµ³¹ff¼³¯XqK(à%7E޹ÿè@X H# H H H ; A3â!âA!A!Aâ?+O+¿+++++G;â¿p/?O 8ä&&>äÝ.äÞ?í?í9/í93/]]]í3/]]í99//íí9]910++++2#".54>75.54>2>54&#""32654.Û;`E%2G,7£HqXB“,;L14VD2gBdˆ° =[;=*D04G($2dO1ø -µ5E¸ÿд H ¸ @  Ž‘ ?äí2/æí910+]#>7#73òC1u6D X ÃWu/0`.§»+ +@( H0 H  ¸ ¶ Ž‘ /íí2/ýæ910++>733#1C1u6D X Ã%Wu/0`.§XúÙð0@r‚‹@’€0@À_@ H/+]]qí/í10]%73}þÛÏ­úÙâ úãð0@p€Š@’€0@À_@ H/+]]qí/í]107%3 Ïþ úâÙÃú\þ ˜@ f v † xˆ¸ÿè@_H `p€ / 0 ` Ï @ p €   ¯  P € ï@ H@$H@ “€0@À_@ H/+]]q3ýÍ+/+]]]qqr3/]]9=/3310+]]#'##7%3\_ÀþýqÌ‹‹ðñú‹þ –@Q—‹›Šš„”@Pp€ o  @ P ß €  À _  0 O_“€¸ÿÀ@$H0@À_@ H/+]]qÍ+í2/]^]]]qqqrr3/]9=/]3310]]]#'73373xÌ»]Íötúï‹‹÷úG²?@'„„0Ï0@À_@ H/+]]q3í2/]q3í2/3í21073!73w#­#ýÓ#¯#ú¸¸¸¸­úªB@)…% *‰! ‰ @“€ /2íýí3/í3/]í10]]]".#"#>3232>73¯*LE?) d&9S;,LD>) f%9Sú(1("/-_N2(1("/,_N3qú|ñ j´µ ¸ÿÐ@DH Š +K[kû@H³’¢p€Š@’€ 0@À_@ H/+]]q3í2/í]]_]/+]í+10_]?33?3qÞÏþ²ýßÏþ²úãÚãÚ‚ðê4@ ˆ ˆ ’ 0@À_@ H/+]]qíí2/í3/í10".'33273ªJnJ%tgS³@uA[vð)EZ1;6r1[E)$Y $ÿ´<ÿÛVÿ´\ÿÛ_ÿ´bÿ´iÿÛrÿÛxÿÛÿh$ÿ´$7ÿh$9ÿ$:ÿÛ$<ÿh$YÿÛ$ZÿÛ$\ÿî$ ÿ´)ÿÛ)þø)þø)$ÿh/ÿÛ/7ÿh/9ÿ/:ÿ´/<ÿD/\ÿÛ/ ÿ3ÿ´3þø3þø3$ÿh57ÿÛ59ÿÛ5:ÿÛ5<ÿ´7ÿD7ÿD7ÿD7ÿh7ÿh7$ÿh72ÿÛ7DÿD7FÿD7HÿD7Lÿî7RÿD7Uÿh7VÿD7Xÿh7Zÿh7\ÿh9ÿh9ÿ´9ÿh9ÿÛ9ÿÛ9$ÿ9Dÿ´9Hÿ´9LÿÛ9Rÿ´9UÿÛ9XÿÛ9\ÿÛ:ÿ´:ÿÛ:ÿ´:$ÿÛ:DÿÛ:HÿÛ:Lÿî<ÿÛ<ÿD<ÿh<ÿD<ÿ´<ÿ´<$ÿ<Dÿh<Hÿ<LÿÛ<Rÿ<Sÿ<Tÿ<Xÿ´<Yÿ´I LUÿUÿÛUÿ´U LYÿhYÿhZÿZÿ\ÿh\ÿhVÿ´Vfÿ–Vmÿ–Vqÿ9VrþøVsÿ‰VxþøV€ÿÛVŠÿÛV”ÿÛ[rÿ‘[xÿ‘\^Õ\_ÿh\bÿh\iÿh\yÿ\{ÿÛ\|ÿÛ\~ÿ\ÿ\„ÿÛ\†ÿÛ\‡ÿÛ\‰ÿÛ\Œÿ\ÿ\“ÿ\—j\™ÿ]rÿ‘]xÿ‘_ÿ´_fÿ–_mÿ–_qÿ9_rþø_sÿ‰_xþø_€ÿÛ_ŠÿÛ_”ÿÛ_ ÿ´aþúaþúa^Ña_ÿ=abÿ=aiÿ=a†ÿ a—^bÿ´bfÿ–bmÿ–bqÿ9brþøbxþøf_ÿéfbÿéfiÿéfrÿ‘fxÿ‘hfÿžhmÿžhsÿƒhyÿçh~ÿçhÿçhƒÿçh…ÿçh‹ÿçhŒÿçhÿçh“ÿçh–ÿçh™ÿçh›ÿçiÿÛifÿ–imÿ–iqÿ9irþøixþømVÿém_ÿémbÿémiÿémrÿ‘mxÿ‘oþúoþúo_ÿhobÿhoiÿhp‘ÿ¾qÿFqÿFqÿFqÿhqÿhq^Õq_ÿhqbÿhqfÿÛqiÿhqmÿÛqsÿÛqvÿÛqyÿFqzÿFq}ÿhq~ÿFq€ÿ¨qÿ¼q‚ÿFq„ÿhq†ÿðq‰ÿhqŠÿ¨qŒÿFqÿFq’ÿhq“ÿFq”ÿ¨q•ÿVq—^q˜ÿhq™ÿFqšÿhrÿFrÿhrÿFrÿ´rÿ´r^Õr_ÿhrbÿhriÿhryÿr{ÿÛr|ÿÛr~ÿr€ÿÛrÿr„ÿÛr†ÿÛr‡ÿÛr‰ÿÛrŒÿrÿr“ÿr—jr™ÿs_ÿ°srÿ‘sxÿ‘t–ÿÛt›ÿÛuyÿÕu~ÿÕuÿÕuŒÿÕuÿÕu“ÿÕu–ÿÕu™ÿÕu›ÿÕvrÿ‘vxÿ‘x^Õx_ÿhxbÿhxiÿhxyÿx{ÿÛx~ÿxÿx„ÿÛx†ÿÛx‡ÿÛx‰ÿÛxŒÿxÿx“ÿx—jx™ÿzÿÉ€ÿÛÿÓ‘ÿÓ”ÿÅ‚ÿɃyÿšƒzÿƒƒ{ÿƒ~ÿšƒ€ÿŃÿŃ‚ÿƒƒ„ÿƒ…ÿцÿƒŠÿŃŒÿ?ƒÿ‹ƒÿšƒ‘ÿ‹ƒ’ÿƒƒ“ÿšƒ–ÿšƒ—qƒ™ÿšƒšÿƒƒ›ÿš‡yÿç‡~ÿç‡ÿ燃ÿŇ‹ÿŇŒÿç‡ÿŇÿ燓ÿ燖ÿ燙ÿ燛ÿçˆyÿãˆ}ÿ¾ˆ~ÿãˆÿ㈃ÿ㈋ÿ㈌ÿãˆÿãˆÿ㈒ÿ¾ˆ“ÿÙˆ–ÿ㈘ÿ¾ˆ™ÿ㈚ÿ¾ˆ›ÿã‹yÿã‹~ÿã‹ÿ㋃ÿã‹‹ÿ㋌ÿã‹ÿã‹ÿã‹“ÿã‹™ÿ㌀ÿÛŒÿ㌑ÿ㌔ÿÅyÿã~ÿãÿãƒÿãŒÿãÿãÿã“ÿã–ÿã›ÿãŽÿÓŽ‘ÿÓ‘yÿã‘~ÿã‘ÿ㑃ÿ㑌ÿã‘ÿã‘ÿã‘“ÿã‘–ÿã‘›ÿã“€ÿÛ“ÿÓ“‘ÿÓ“”ÿÅ”yÿÝ”~ÿÝ”ÿÝ”ƒÿÝ”ŒÿÝ”ÿÝ”ÿÝ”“ÿÝ”–ÿÝ”™ÿÝ”›ÿÝ–€ÿÛ–ÿÓ–‘ÿÓ–”ÿÅ™€ÿÛ™ÿÓ™‘ÿÓ™”ÿÅ›€ÿÛ›ÿÓ›‘ÿÓ›”ÿÅžÿ3žÿ3žlÿž{ÿ¤ ÿ¥ ÿJª®ª±ÿ¦ª¸ÿª¹ÿѪ»ÿª¼ÿ3ª½ÿJª¾ÿ¤ªÁÿJªÇÿ¤ªËÿéªÏÿéªØÿéªÛÿéªÝÿéªÞÿéª ÿ`«ªÿ¼«®ÿÓ«°ÿÓ«±ÿÓ«µÿ¼«¸ÿÓ«»ÿÓ«¼ÿw«½ÿ«¾ÿÑ«¿ÿ¼«Áÿ«Äÿw«Çÿé«Éÿ¼«Î«Ýÿӫ鬪ÿ¼¬®ÿÓ¬°ÿ¼¬±ÿÓ¬µÿÓ¬¸ÿÓ¬»ÿÓ¬¼ÿw¬½ÿ¬¾ÿÓ¬¿ÿ¼¬Áÿº¬Äÿ3¬ÉÿÓ¬Ýÿé¬ßÿ¼¬áÿ¼­ÿ3­ÿ3­ÿÓ­ÿé­lÿ­{ÿ­ªÿ`­®ÿ¦­±ÿé­µÿ¼­¸ÿ¼­»ÿ¼­ÉÿÓ­Êÿ¼­Ìÿ¤­Îÿ¤­Ïÿ¦­Òÿ¦­Õÿ¦­Öÿ¦­×ÿ¦­Øÿ­Úÿ¦­Ýÿ¦­åÿ¦­æÿ¤­èÿ¤­éÿ¤®Áÿé®Ç®Ñ-®Ý¯±ÿé°±ÿé°¸ÿÓ°»ÿÓ°ÁÿӰİÝÿé±®ÿ¼±°ÿ¼±µÿ¼±¸ÿÓ±»ÿÓ±¼ÿ¤±½ÿ¤±¾ÿÓ±Áÿº±ÉÿÓ±Õÿé´¸ÿé´»ÿé´¾ÿÑ´Çÿé´Ýÿé´çÿéµ¾µË¶ÁÿӶʶݶáÿӶ縪ÿÓ¸®ÿº¸°ÿ¼¸µÿ¼¸½ÿw¸¿ÿ¼¸Áÿ¼¸ÉÿÓ¸Õÿé¸ßÿÓºþÁºþÁºÿéºÿéº{ÿ¼ºªÿ`º®ÿ`º°ÿ¦º±ÿÓºµÿwº¶ÿ麼ÿº½ÿ¤º¾ÿ麿ÿ¤ºÉÿéºÎÿéºÏÿéºØÿéºéÿ黪ÿ¼»®ÿ¼»±ÿ黵ÿ¼»¶ÿ黸ÿ黼ÿ¼»½ÿ»¿ÿÓ»Áÿ¦»Äÿw»Ê»Ýÿé»áÿÓ¼ÿJ¼ÿJ¼ÿé¼ÿ鼪ÿ¼¼®ÿÓ¼°¼±ÿé¼µÿ¼¼¶¼¸ÿÓ¼¾ÿ¼¼Çÿé¼É¼ÊÿÓ¼Ìÿ¼¼Ïÿ¼¼Òÿ¼¼Ôÿ¼¼Õÿ¼¼Öÿ¼¼Øÿ¼¼Ùÿ¼¼Úÿ¼¼Ûÿ¼¼Ýÿ¼¼ßÿ¼¼ãÿ¼¼åÿ¼¼æÿ¼¼èÿ¼¼éÿ¼½ÿ`½ÿ`½ÿÓ½ÿÓ½ªÿ¼½®ÿ¼½±½µÿÓ½¾ÿé½Ç½É½ÌÿÓ½ÍÿÓ½Îÿé½ÏÿÓ½Ðÿé½Ñÿé½Òÿé½Ôÿé½Õÿº½Öÿé½×ÿ齨ÿÓ½Ùÿé½Úÿé½ÛÿÓ½ßÿé½àÿé½âÿé½ãÿé½èÿé½éÿ龪ÿ¾®ÿw¾µÿ¾¶ÿé¾¼ÿ`¾½ÿJ¾¾¾Áÿº¾ÉÿÓ¾ÕÿÓ¿±ÿ鿸ÿº¿»ÿº¿¾ÿ¼¿ØÿÓ¿ÝÿÓÀÊDÀÏ-ÀØ-ÃÊ-ÃÏÃÝÄÉÿ¼Ä ÿƪÿ¦Æ®ÿÓÆ°ÿƱÿ¼ÆµÿÓÆ¶ÿÓÆ¸ÿ¤Æ»ÿ¤Æ¼ÿÆ¿ÿÆÁÿ3ÆÇÿ¼ÆÉÿ¤Æ ÿÇ®ÿºÇ°ÿÑǵÿ¤Ç¸Ç¾-Ç¿ÿºÇÉÿÓÇÎ-ÇÐÇÖÇéȪÿ¦È®ÿȰÿ¼ÈµÿȸÿéÈ»ÿéȼÿwÈ¿ÿ¼ÈÁÿ¤ÊÑÿÓÊÕÿéÊÙÿéÊÝÿ¼ÊáÿwÊçÿéËÎËÐÿéËÕÿÓËÝÿÓËßÿ¼Ëáÿ¼Ëäÿ¼ËéÿéÌÊÿÓÌËÿéÌÎÿÓÌÏÿÓÌÐÿÓÌÑÿÓÌÕÿ¼ÌÖÿÓÌØÿÓÌÛÿÓÌÜÿéÌÝÿ¼ÌÞÿÓÌáÿÌäÿ¤ÌéÿÓÍÊÿéÍÎÿéÍÏÿéÍÑÿéÍÕÿéÍÖÿéÍØÿéÍÛÿéÍéÿÓÎÝÿéÏÊÿéÏÎÿéÏÐÿéÏÑÿéÏÕÿ¼ÏÖÿéÏÛÿéÏÜÿéÏÝÿ¼ÏÞÿéÏßÿ¦ÏáÿÐÜÐÝÐáÿÓÐäÑÊÿéÑËÿéÑÎÿéÑÏÿéÑÐÿéÑÕÿÓÑÖÿéÑØÿéÑÛÿÓÑÝÿ¼ÑÞÿéÑáÿÑäÿ¼ÔËÔÛÿéÔÜÔáÿÓÕÝÿéÕáÿ¼ÖÑÿéÖÛÿéÖÝÿéÖÞÿéÖçÿéØÐÿÓØÑÿéØÕÿÓØÝÿ¼ØßÿÓØáÿ¤ØçÿéØéÿÓÚÐÿéÚÑÿéÚÕÿÓÚÖÿéÚÝÿ¼Úßÿ¼Úáÿ¤ÚçÿéÚéÿéÛÐÿéÛÝÿéÛßÿÓÛáÿ¼ÛäÿÓÜÿéÜÿéÜÊÿéÜÎÿéÜÐÿéÜÑÿéÜÕÿÓÜÖÿéÜØÿéÜÚÿéÜÛÿéÜÝÿÓÜçÿéÜéÿéÝÿwÝÿwÝË-ÝÐÝÕÿéÝçÞËÞÏÞÕÿÓÞØÞÝÿÓÞáÿ¤ßÊÿéßÏÿéßÑÿéߨÿéßÛÿéßÞÿÓßáÿ¤ßçÿéàÊàÝãÊãÝ-æáÿJçÐÿéçÕÿÓçßÿÑçéÿéèÐÿéèÕÿÓèßÿ¼èáÿ¤öÿöÿøÿøÿølÿÓø{ÿÓÿ´ ÿ VÿÛ  ÿ´ÿ¦ÿ¼þîÁþ×ÄÿV^¾=[!¦ö '`zl D  . 7+ ¼   M Bb ,È   *4 ôv (ç & 8S \ª þ7 V·Copyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.Copyright © 2007 Red Hat, Inc. All rights reserved. LIBERATION is a trademark of Red Hat, Inc.Liberation SansLiberation SansItalicItalicAscender - Liberation Sans ItalicAscender - Liberation Sans ItalicLiberation Sans ItalicLiberation Sans ItalicVersion 1.02Version 1.02LiberationSans-ItalicLiberationSans-ItalicLiberation is a trademark of Red Hat, Inc. registered in U.S. Patent and Trademark Office and certain other jurisdictions.Liberation is a trademark of Red Hat, Inc. registered in U.S. Patent and Trademark Office and certain other jurisdictions.Ascender CorporationAscender CorporationSteve MattesonSteve Mattesonhttp://www.ascendercorp.com/http://www.ascendercorp.com/http://www.ascendercorp.com/typedesigners.htmlhttp://www.ascendercorp.com/typedesigners.htmlUse of this Liberation font software is subject to the license agreement under which you accepted the Liberation font software.Use of this Liberation font software is subject to the license agreement under which you accepted the Liberation font software.http://www.ascendercorp.com/liberation.htmlhttp://www.ascendercorp.com/liberation.htmlÿôÿ'–¢  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a£„…½–膎‹©¤ŠÚƒ“ˆÞ žªõôö¢­ÉÇ®bcdËeÈÊÏÌÍÎéfÓÐѯgð‘ÖÔÕhëí‰jikmln oqprsutvwêxzy{}|¸¡~€ìîº    ýþÿ !"øù#$%&'()*+,-./012ú×3456789:;<=>?@AâãBCDEFGHIJKLMNOP°±QRSTUVWXYZûüäå[\]^_`abcdefghijklmnop»qrstæçu¦vwxyz{|}~Øá€ÛÜÝàÙß‚ƒ„…†‡ˆ‰Š‹Œލ‘’“”•–—˜™š›œžŸ ¡Ÿ¢£¤¥¦§¨©ª«¬­®¯°±²³—´µ¶›·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ      !"#$%&'()*+,²³-.¶·Ä/´µÅ‚‡«Æ01¾¿2345÷6789:;Œ<=>?@ABCDEFGH˜Iš™ï¥’JKœ§L”•MNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰¹Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬­uni00A0uni00ADuni037Euni00B2uni00B3uni00B5uni2219uni00B9AmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflex Tcommaaccent tcommaaccentTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongs Aringacute aringacuteAEacuteaeacute Oslashacute oslashacute Scommaaccent scommaaccentuni021Auni021Buni02C9tonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammaEpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsi IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdanuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonos afii10023 afii10051 afii10052 afii10053 afii10054 afii10055 afii10056 afii10057 afii10058 afii10059 afii10060 afii10061 afii10062 afii10145 afii10017 afii10018 afii10019 afii10020 afii10021 afii10022 afii10024 afii10025 afii10026 afii10027 afii10028 afii10029 afii10030 afii10031 afii10032 afii10033 afii10034 afii10035 afii10036 afii10037 afii10038 afii10039 afii10040 afii10041 afii10042 afii10043 afii10044 afii10045 afii10046 afii10047 afii10048 afii10049 afii10065 afii10066 afii10067 afii10068 afii10069 afii10070 afii10072 afii10073 afii10074 afii10075 afii10076 afii10077 afii10078 afii10079 afii10080 afii10081 afii10082 afii10083 afii10084 afii10085 afii10086 afii10087 afii10088 afii10089 afii10090 afii10091 afii10092 afii10093 afii10094 afii10095 afii10096 afii10097 afii10071 afii10099 afii10100 afii10101 afii10102 afii10103 afii10104 afii10105 afii10106 afii10107 afii10108 afii10109 afii10110 afii10193 afii10050 afii10098WgravewgraveWacutewacute Wdieresis wdieresisYgraveygraveuni2010uni2011 afii00208 underscoredbl quotereversedminutesecond exclamdbluni203Euni2215uni207FlirapesetaEuro afii61248 afii61289 afii61352uni2126 estimated oneeighth threeeighths fiveeighths seveneighths arrowleftarrowup arrowright arrowdown arrowboth arrowupdn arrowupdnbseuni2206 orthogonal intersection equivalencehouse revlogicalnot integraltp integralbtSF100000SF110000SF010000SF030000SF020000SF040000SF080000SF090000SF060000SF070000SF050000SF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000upblockdnblockblocklfblockrtblockltshadeshadedkshade filledboxH22073H18543H18551 filledrecttriaguptriagrttriagdntriaglfcircleH18533 invbullet invcircle openbullet smileface invsmilefacesunfemalemalespadeclubheartdiamond musicalnotemusicalnotedbluniFB01uniFB02uniF005middot commaaccent foursuperior fivesuperior sevensuperior eightsuperior cyrillicbrevecaroncommaaccentcommaaccentrotategrave.ucacute.uc circumflex.uccaron.uc dieresis.uctilde.uchungarumlaut.ucbreve.ucÿÿ¡ LNDFLTcyrl$grek.latn8ÿÿÿÿÿÿÿÿ TbDFLTcyrl&grek2latn>ÿÿÿÿÿÿÿÿkern„kà 2Dbt†Ì ^dv€vŠ´¾´6XrˆÆàú ´@†Œ†žø*l–¨Ò¨ŒÜŒŒŒ "(n¸þp‚ˆ¢Ðêô 4 † À B Ä î   $ . h – ¼ Ö ø : ` f ˜ ª à ò ü  4 Z p ª Ä Þ ,>HZ`n $ÿ´<ÿÛVÿ´\ÿÛ_ÿ´bÿ´iÿÛrÿÛxÿÛÿh ÿ´7ÿh9ÿ:ÿÛ<ÿhYÿÛZÿÛ\ÿî ÿ´ÿÛþøþø$ÿhÿÛ7ÿh9ÿ:ÿ´<ÿD\ÿÛ ÿÿ´þøþø$ÿh7ÿÛ9ÿÛ:ÿÛ<ÿ´ÿDÿDÿDÿhÿh$ÿh2ÿÛDÿDFÿDHÿDLÿîRÿDUÿhVÿDXÿhZÿh\ÿh ÿhÿ´ÿhÿÛÿÛ$ÿDÿ´Hÿ´LÿÛRÿ´UÿÛXÿÛ\ÿÛÿ´ÿÛÿ´$ÿÛDÿÛHÿÛLÿîÿÛÿDÿhÿDÿ´ÿ´$ÿDÿhHÿLÿÛRÿSÿTÿXÿ´Yÿ´ LÿÿÛÿ´ Lÿhÿhÿÿ ÿ´fÿ–mÿ–qÿ9rþøsÿ‰xþø€ÿÛŠÿÛ”ÿÛrÿ‘xÿ‘^Õ_ÿhbÿhiÿhyÿ{ÿÛ|ÿÛ~ÿÿ„ÿÛ†ÿÛ‡ÿÛ‰ÿÛŒÿÿ“ÿ—j™ÿ ÿ´fÿ–mÿ–qÿ9rþøsÿ‰xþø€ÿÛŠÿÛ”ÿÛ ÿ´þúþú^Ñ_ÿ=bÿ=iÿ=†ÿ —^ÿ´fÿ–mÿ–qÿ9rþøxþø_ÿébÿéiÿérÿ‘xÿ‘fÿžmÿžsÿƒyÿç~ÿçÿçƒÿç…ÿç‹ÿçŒÿçÿç“ÿç–ÿç™ÿç›ÿçÿÛfÿ–mÿ–qÿ9rþøxþøVÿé_ÿébÿéiÿérÿ‘xÿ‘þúþú_ÿhbÿhiÿh‘ÿ¾"ÿFÿFÿFÿhÿh^Õ_ÿhbÿhfÿÛiÿhmÿÛsÿÛvÿÛyÿFzÿF}ÿh~ÿF€ÿ¨ÿ¼‚ÿF„ÿh†ÿð‰ÿhŠÿ¨ŒÿFÿF’ÿh“ÿF”ÿ¨•ÿV—^˜ÿh™ÿFšÿhÿFÿhÿFÿ´ÿ´^Õ_ÿhbÿhiÿhyÿ{ÿÛ|ÿÛ~ÿ€ÿÛÿ„ÿÛ†ÿÛ‡ÿÛ‰ÿÛŒÿÿ“ÿ—j™ÿ_ÿ°rÿ‘xÿ‘–ÿÛ›ÿÛ yÿÕ~ÿÕÿÕŒÿÕÿÕ“ÿÕ–ÿÕ™ÿÕ›ÿÕ^Õ_ÿhbÿhiÿhyÿ{ÿÛ~ÿÿ„ÿÛ†ÿÛ‡ÿÛ‰ÿÛŒÿÿ“ÿ—j™ÿÿÉ€ÿÛÿÓ‘ÿÓ”ÿÅyÿšzÿƒ{ÿ~ÿš€ÿÅÿÅ‚ÿƒ„ÿ…ÿņÿŠÿÅŒÿ?ÿ‹ÿš‘ÿ‹’ÿƒ“ÿš–ÿš—q™ÿššÿƒ›ÿš yÿç~ÿçÿçƒÿÅ‹ÿÅŒÿçÿÅÿç“ÿç–ÿç™ÿç›ÿçyÿã}ÿ¾~ÿãÿãƒÿã‹ÿãŒÿãÿãÿã’ÿ¾“ÿÙ–ÿã˜ÿ¾™ÿãšÿ¾›ÿã yÿã~ÿãÿãƒÿã‹ÿãŒÿãÿãÿã“ÿã™ÿã€ÿÛÿã‘ÿã”ÿÅ yÿã~ÿãÿãƒÿãŒÿãÿãÿã“ÿã–ÿã›ÿãÿÓ‘ÿÓ yÿÝ~ÿÝÿ݃ÿÝŒÿÝÿÝÿÝ“ÿÝ–ÿÝ™ÿÝ›ÿÝÿ3ÿ3lÿ{ÿ ÿ ÿJ®±ÿ¦¸ÿ¹ÿÑ»ÿ¼ÿ3½ÿJ¾ÿ¤ÁÿJÇÿ¤ËÿéÏÿéØÿéÛÿéÝÿéÞÿé ÿ`ªÿ¼®ÿÓ°ÿÓ±ÿÓµÿ¼¸ÿÓ»ÿÓ¼ÿw½ÿ¾ÿÑ¿ÿ¼ÁÿÄÿwÇÿéÉÿ¼ÎÝÿÓéªÿ¼®ÿÓ°ÿ¼±ÿÓµÿÓ¸ÿÓ»ÿÓ¼ÿw½ÿ¾ÿÓ¿ÿ¼ÁÿºÄÿ3ÉÿÓÝÿéßÿ¼áÿ¼ÿ3ÿ3ÿÓÿélÿ{ÿªÿ`®ÿ¦±ÿéµÿ¼¸ÿ¼»ÿ¼ÉÿÓÊÿ¼Ìÿ¤Îÿ¤Ïÿ¦Òÿ¦Õÿ¦Öÿ¦×ÿ¦ØÿÚÿ¦Ýÿ¦åÿ¦æÿ¤èÿ¤éÿ¤ÁÿéÇÑ-ݱÿé±ÿé¸ÿÓ»ÿÓÁÿÓÄÝÿé ®ÿ¼°ÿ¼µÿ¼¸ÿÓ»ÿÓ¼ÿ¤½ÿ¤¾ÿÓÁÿºÉÿÓÕÿé¸ÿé»ÿé¾ÿÑÇÿéÝÿéçÿé¾ËÁÿÓÊÝáÿÓç ªÿÓ®ÿº°ÿ¼µÿ¼½ÿw¿ÿ¼Áÿ¼ÉÿÓÕÿéßÿÓþÁþÁÿéÿé{ÿ¼ªÿ`®ÿ`°ÿ¦±ÿÓµÿw¶ÿé¼ÿ½ÿ¤¾ÿé¿ÿ¤ÉÿéÎÿéÏÿéØÿééÿéªÿ¼®ÿ¼±ÿéµÿ¼¶ÿé¸ÿé¼ÿ¼½ÿ¿ÿÓÁÿ¦ÄÿwÊÝÿéáÿÓ ÿJÿJÿéÿéªÿ¼®ÿÓ°±ÿéµÿ¼¶¸ÿÓ¾ÿ¼ÇÿéÉÊÿÓÌÿ¼Ïÿ¼Òÿ¼Ôÿ¼Õÿ¼Öÿ¼Øÿ¼Ùÿ¼Úÿ¼Ûÿ¼Ýÿ¼ßÿ¼ãÿ¼åÿ¼æÿ¼èÿ¼éÿ¼ ÿ`ÿ`ÿÓÿÓªÿ¼®ÿ¼±µÿÓ¾ÿéÇÉÌÿÓÍÿÓÎÿéÏÿÓÐÿéÑÿéÒÿéÔÿéÕÿºÖÿé×ÿéØÿÓÙÿéÚÿéÛÿÓßÿéàÿéâÿéãÿéèÿééÿé ªÿ®ÿwµÿ¶ÿé¼ÿ`½ÿJ¾ÁÿºÉÿÓÕÿÓ±ÿé¸ÿº»ÿº¾ÿ¼ØÿÓÝÿÓÊDÏ-Ø-Ê-ÏÝÉÿ¼ ÿªÿ¦®ÿÓ°ÿ±ÿ¼µÿÓ¶ÿÓ¸ÿ¤»ÿ¤¼ÿ¿ÿÁÿ3Çÿ¼Éÿ¤ ÿ ®ÿº°ÿѵÿ¤¸¾-¿ÿºÉÿÓÎ-ÐÖé ªÿ¦®ÿ°ÿ¼µÿ¸ÿé»ÿé¼ÿw¿ÿ¼Áÿ¤ÑÿÓÕÿéÙÿéÝÿ¼áÿwçÿéÎÐÿéÕÿÓÝÿÓßÿ¼áÿ¼äÿ¼éÿéÊÿÓËÿéÎÿÓÏÿÓÐÿÓÑÿÓÕÿ¼ÖÿÓØÿÓÛÿÓÜÿéÝÿ¼ÞÿÓáÿäÿ¤éÿÓ ÊÿéÎÿéÏÿéÑÿéÕÿéÖÿéØÿéÛÿééÿÓÝÿé ÊÿéÎÿéÐÿéÑÿéÕÿ¼ÖÿéÛÿéÜÿéÝÿ¼Þÿéßÿ¦áÿÜÝáÿÓä ÊÿéËÿéÎÿéÏÿéÐÿéÕÿÓÖÿéØÿéÛÿÓÝÿ¼Þÿéáÿäÿ¼ËÛÿéÜáÿÓÝÿéáÿ¼ÑÿéÛÿéÝÿéÞÿéçÿéÐÿÓÑÿéÕÿÓÝÿ¼ßÿÓáÿ¤çÿééÿÓ ÐÿéÑÿéÕÿÓÖÿéÝÿ¼ßÿ¼áÿ¤çÿééÿéÐÿéÝÿéßÿÓáÿ¼äÿÓÿéÿéÊÿéÎÿéÐÿéÑÿéÕÿÓÖÿéØÿéÚÿéÛÿéÝÿÓçÿééÿéÿwÿwË-ÐÕÿéçËÏÕÿÓØÝÿÓáÿ¤ÊÿéÏÿéÑÿéØÿéÛÿéÞÿÓáÿ¤çÿéÊÝÊÝ-áÿJÐÿéÕÿÓßÿÑéÿéÐÿéÕÿÓßÿ¼áÿ¤ÿÿÿÿlÿÓ{ÿÓÿ´ÿVÿÛ ÿ´ÿ¦ÿ¼þîÁþ×Äÿk$)/3579:<IUYZ\V[\]_abfhimopqrstuvxz‚ƒ‡ˆ‹ŒŽ‘“”–™›ž¤¥ª«¬­®¯°±´µ¶¸º»¼½¾¿ÀÃÄÆÇÈÊËÌÍÎÏÐÑÔÕÖØÚÛÜÝÞßàãæçèöø ÆÔ.™¿ÿ€È VÉgosa-core-2.7.4/html/themes/default/style.css0000644000175000017500000010266411511573666020152 0ustar cajuscajus@font-face { font-family: 'LiberationSans'; src: local('LiberationSans Regular'), local('LiberationSans-Regular'), url('fonts/LiberationSans-Regular.ttf') format('truetype'); } @font-face { font-family: 'LiberationSans'; src: local('LiberationSans Italic'), local('LiberationSans-Italic'), url('fonts/LiberationSans-Italic.ttf') format('truetype'); font-style: italic; } @font-face { font-family: 'LiberationSans'; src: local('LiberationSans Bold'), local('LiberationSans-Bold'), url('fonts/LiberationSans-Bold.ttf') format('truetype'); font-weight: bold; } @font-face { font-family: 'LiberationSans'; src: local('LiberationSans Bold Italic'), local('LiberationSans-BoldItalic'), url('fonts/LiberationSans-BoldItalic.ttf') format('truetype'); font-weight: bold; font-style: italic; } body, html { border:0; margin:0; background-color:#FFF; color:#000; font-size:13px; font-family:"LiberationSans",Arial,Verdana,sans-serif; height:100%; min-width:1000px; min-height:700px; } span.highlight { font-weight:bold; } .left{ float:left; } .right{ float:right; } .v-spacer{ height:8px; } hr { border:0; border-bottom:1px solid #CCC; } a:link { text-decoration:none; color:#000; } a:visited { text-decoration:none; color:#000; } input[type=checkbox]{ border:1px solid #CCC; } input[type=text], input[type=password]{ border:1px solid #CCC; padding:3px; } input[type=text]:active, input[type=text]:focus, input[type=password]:active, input[type=password]:focus, textarea:focus, textarea:active, select:focus, select:active{ border:1px solid #777; } input[type=text]:hover, input[type=password]:hover, textarea:hover, select:hover{ border-color:#777; } input[type=password]{ background-repeat:no-repeat; background-position:right center; } textarea, select { border:1px solid #DDD; margin-bottom:2px; background-color:white; } textarea[disabled], select:disabled, select[size="1"]:disabled { color:#666; background-color:#F0F0F0; border-color:#CCC; } input[disabled] { background-color:#F0F0F0; color:#666; } select[size="1"]{ padding:2px; border:1px solid #CCC; margin:0; background-color:#FFF; } select[size="1"]:hover{ border:1px solid #777; } input[disabled]:hover, select[disabled]:hover, textarea[disabled]:hover { border:1px solid #CCC; } h1, h2, h3 { margin-top:2px; } h1, h3 { font-size:13px; font-weight:bold; } .required{ font-size:xx-small; vertical-align:top; color:red; } /* Error collector */ #errorbox { width:100%; } .error-collector { border-bottom:1px solid black; width:100%; z-index:150; padding:2px; height:32px; background-color:#FFA; -webkit-animation-name:error-collector; -webkit-animation-duration:0.5s; -webkit-animation-iteration-count:2; -webkit-animation-direction:alternate } @-webkit-keyframes error-collector{ from{background-color:#FFA;} to{background-color:red;} } .error-collector span { font-size:13px; font-weight:bold; } .error-collector td { vertical-align:middle; } div.scrollContainer { border:1px solid #CCC; padding:1px; overflow-x:hidden; overflow-y:auto; } /* Image with migration color */ input[type=submit].img{ border:0; padding:0; margin:0; margin-top:-2px; display:inline-block; display:-moz-inline-block; background-color:transparent; background-repeat:no-repeat; position:relative; cursor:pointer; } div.tooltip{ padding: 5px; width: 500px; border: 1px solid #000; background-color: #F0F0F0; } div.img{ display:inline-block; display:-moz-inline-block; background-color:transparent; background-repeat:no-repeat; position:relative; } div.img div { background-color:transparent; background-repeat:no-repeat; bottom:0; right:0; position:absolute; } /* Title bar definitions */ div.title-bar{ padding:0px; height:40px; border-top:1px solid #111; border-bottom:1px solid #222; background-color:#000; background:url('images/title-bar.png') repeat-x; color:#FFF; cursor:default; } div.title-bar ul, div.title-bar ul li{ list-style:none; display:inline; margin:0; padding:0; } div.logged-in-label span{ font-weight:bold; } li.table-wrapper { display:table; } div.logged-in-label { display:table-cell; height:40px; vertical-align:middle; padding:0 5px 0 5px; } div.logout-label { display:table-cell; height:40px; vertical-align:middle; padding:0 5px 0 5px; } /* Screen areas */ div.navigation { float:left; position:absolute; width:150px; min-height:600px; padding-left:6px; } div.plugin-area { position:relative; margin-left:164px; padding-right:6px; min-height:600px; min-width:700px; cursor:default; } div.plugin-area-noMenu { position:relative; margin-left:6px; padding-right:6px; min-height:600px; min-width:700px; cursor:default; } /* Plugin decorations */ .plugin { clear:both; padding:5px 8px; position:relative; border:1px solid #CCC; border-radius:5px; box-shadow: 0 1px 0 rgba(0,0,0,0.1); -webkit-border-radius:5px; -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.1); -moz-border-radius:5px; -moz-box-shadow: 0 1px 0px rgba(0,0,0,0.1); } .plugin-actions { padding-top:5px; text-align:right; } .plugin-disable-header { border-bottom:1px solid #DDD; } .plugin-enable-header { } /* Plugin navigation bar */ .plugin-path { margin-top:8px; margin-bottom:8px; height:32px; background-color:#F8F8F8; border:1px solid #CCC; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#EEEEEE')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#EEE)); background: -moz-linear-gradient(top, #F8F8F8, #EEE); } ul.path-navigation { list-style:none; cursor:pointer; padding:0; margin:0; color:#666; } ul.path-navigation li { display:inline; padding:5px; padding-top:9px; height:18px; } ul.path-navigation li.path-element { cursor:default; border-left:1px solid #C2C2C2; } ul.path-navigation li.path-element:hover { background:transparent; -ms-filter: "progid:DXImageTransform.Microsoft.gradient()"; background: -webkit-gradient(); background: -moz-linear-gradient(); } ul.path-navigation li.path-element[title]:hover { background-color: #E0E0E0; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#EEEEEE', endColorstr='#E0E0E0')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#EEE), to(#E0E0E0)); background: -moz-linear-gradient(top, #EEE, #E0E0E0); } ul.path-navigation li:hover { background-color: #E0E0E0; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#EEEEEE', endColorstr='#E0E0E0')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#EEE), to(#E0E0E0)); background: -moz-linear-gradient(top, #EEE, #E0E0E0); } .right-border { border-right:1px solid #C2C2C2; } .left-border { border-left:1px solid #C2C2C2; } /* Side menu */ div.menu { -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#F5F5F5')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#FFF), to(#F5F5F5)); background: -moz-linear-gradient(top, #FFF, #F5F5F5); } div.menu div { margin-top:-1px; height:3px; border-right:1px solid #C2C2C2; border-left:1px solid #C2C2C2; border-bottom:1px solid #C2C2C2; border-bottom-left-radius:5px; border-bottom-right-radius:5px; box-shadow: 0 1px 0 rgba(0,0,0,0.1); -webkit-border-bottom-left-radius:5px; -webkit-border-bottom-right-radius:5px; -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.1); -moz-border-radius:5px; -moz-box-shadow: 0 1px 0px rgba(0,0,0,0.1); } div.menu ul { list-style:none; margin:0; padding:0; } div.menu ul li { padding:5px; cursor:pointer; border-left:1px solid #C2C2C2; border-right:1px solid #C2C2C2; } div.menu ul li.current { padding:5px; cursor:pointer; background-color: rgba(0,0,0,0.1); border-left:1px solid #C2C2C2; border-right:1px solid #C2C2C2; } div.menu ul li:hover { background-color: #E0E0E0; } div.menu ul li.menu-header { cursor:default; text-align:center; font-weight:bold; color:#FFF; border:0; background-color: #415A84; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#5B6B8E', endColorstr='#2A4A79')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#5B6B8E), to(#2A4A79)); background: -moz-linear-gradient(top, #5B6B8E, #2A4A79); border-top-left-radius:5px; border-top-right-radius:5px; -moz-border-radius-topleft:5px; -moz-border-radius-topright:5px; -webkit-border-top-left-radius:5px; -webkit-border-top-right-radius:5px; } /* Buttons */ button { padding:2px 6px; margin:0; margin-bottom:6px; background-color:#F8F8F8; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#BBBBBB')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#FFF), to(#BBB)); background: -moz-linear-gradient(top, #FFF, #BBB); border:1px solid #BBB; border-radius:2px; -webkit-border-radius:2px; -moz-border-radius:2px; outline:none; min-width:60px; } button:active { background-color:#CCC; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#BBBBBB', endColorstr='#FFFFFF')"; background: -webkit-gradient(linear, 0 100%, 0 0, from(#FFF), to(#BBB)); background: -moz-linear-gradient(top, #BBB, #FFF); } button:hover { cursor:pointer; border-color:#777 !important; } button:focus, .button:active { border-color:#777; } /* Tabs */ .tabs { width:100%; height:25px; } .tab-content { padding:5px 8px; z-index:0; margin-top:-2px; position:relative; border:1px solid #CCC; border-top-right-radius:5px; border-bottom-right-radius:5px; border-bottom-left-radius:5px; box-shadow: 0 1px 0 rgba(0,0,0,0.1); -webkit-border-top-right-radius:5px; -webkit-border-bottom-right-radius:5px; -webkit-border-bottom-left-radius:5px; -webkit-box-shadow: 0 1px 1px rgba(0,0,0,0.1); -moz-border-radius-topright:5px; -moz-border-radius-bottomright:5px; -moz-border-radius-bottomleft:5px; -moz-box-shadow: 0 1px 0 rgba(0,0,0,0.1); } .tabs ul { margin:0; padding:0; list-style:none; } .tabs li { float:left; margin:0; padding:4px 8px; border-top:1px solid #C8C8C8; border-left:1px solid #C8C8C8; border-right:1px solid #C8C8C8; border-top-right-radius:5px; border-top-left-radius:5px; -webkit-border-top-right-radius:5px; -webkit-border-top-left-radius:5px; -moz-border-radius-topleft:5px; -moz-border-radius-topright:5px; background-color:#E8E8E8; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#EEEEEE', endColorstr='#DDDDDD')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#EEE), to(#DDD)); background: -moz-linear-gradient(top, #EEE, #DDD); color:#333; cursor:pointer; } .tabs li:hover { background-color:#FFF; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#FFF)); background: -moz-linear-gradient(top, #F8F8F8, #FFF); } .tabs li.current { background-color:#FFF; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#FFF)); background: -moz-linear-gradient(top, #F8F8F8, #FFF); margin-top:-2px; max-height:14px; padding-bottom:6px; border-bottom:1px solid #FFF; position:relative; z-index:1; color:#222; cursor:pointer; } /* Cleaner */ .clear-left{ clear:left; } .clear{ clear:both; } /* Icon menu */ .icon-menu-item{ float:left; padding-top:10px; padding-bottom:10px; min-height:70px; min-width:150px; cursor:pointer; } .icon-menu-item div.img{ float:left; } .icon-menu-item div.dsc{ margin-left:55px } .icon-menu-item:hover{ background-color: #E0E0E0; } .icon-menu-item h1{ font-size:13px; font-weight:bold; margin:0; color:#333; } h3.icon-menu-title{ font-size:15px; font-weight:bold; margin-top:8px; color:#333; } .icon-menu-item p{ margin:0; color:#777; } /* Errors */ .error { border-color:red ! important; } /* Date picker*/ div.datepicker { position:absolute; text-align:center; border:1px #CCC solid; font-family:"LiberationSans",Arial,Verdana,sans-serif; background:#FFF; font-size:11px; padding:0; box-shadow: 2px 2px 0 rgba(0,0,0,0.1); -webkit-box-shadow: 2px 2px 1px rgba(0,0,0,0.1); -moz-box-shadow: 2px 2px 0px rgba(0,0,0,0.1); } div.datepicker-calendar table { font-size:11px; border:1px solid #FFF; margin:0; padding:0; text-align:center; } div.datepicker div.datepicker-header { font-size:12px; font-weight:bold; background:#F0F0F0; border-bottom:1px solid #CCC; padding:2px; text-align:center; } div.datepicker table.header { width:175px; border:0; padding:0; text-align:center; } td { vertical-align:top; } td.prev,td.prev_year,td.next,td.next_year { width:8%; cursor:pointer; font-weight:bold; line-height:16px; } td.prev:hover,td.prev_year:hover,td.next:hover,td.next_year:hover { background-color:#DDD; } td.header { text-align:center; width:68%; font-weight:bold; line-height:16px; } div.datepicker-header { height:16px; } div.datepicker-calendar table tbody tr { border:1px solid #FFF; margin:0; padding:0; } div.datepicker-calendar table tbody tr td { border:1px #EEE solid; margin:0; padding:0; text-align:center; height:16px; line-height:16px; width:21px; cursor:pointer; } div.datepicker-calendar table tbody tr td:hover,div.datepicker-calendar table tbody tr td.outbound:hover,div.datepicker-calendar table tbody tr td.today:hover { border:1px #CCE9FF solid; background:#E9F5FF; cursor:pointer; } div.datepicker-calendar table tbody tr td.wday { border:1px #AAA solid; background:#CCC; cursor:text; width:21px; height:16px; line-height:16px; font-weight:bold; } div.datepicker-calendar table tbody tr td.outbound { background:#F3F3F3; } div.datepicker-calendar table tbody tr td.today { border:1px #CCE9FF solid; background:#E9F5FF; background-image:url(../../images/date_active.gif); background-repeat:no-repeat; position:top left; width:21px; height:16px; line-height:16px; } div.datepicker-calendar table tbody tr td.today:hover { border:1px #CCE9FF solid; background:#E9F5FF; background-image:url(../../images/date_active.gif); background-repeat:no-repeat; position:top left; } div.datepicker-calendar table tbody tr td.nclick,div.datepicker-calendar table tbody tr td.nclick_outbound { cursor:default; color:#aaa; width:21px; height:16px; line-height:16px; } div.datepicker-calendar table tbody tr td.nclick_outbound { background:#E8E4E4; width:21px; height:16px; line-height:16px; } div.datepicker-calendar table tbody tr td.nclick:hover,div.datepicker-calendar table tbody tr td.nclick_outbound:hover { border:1px #EAEAEA solid; background:#FFF; } div.datepicker-calendar table tbody tr td.nclick_outbound:hover { background:#E8E4E4; } div.datepicker div.datepicker-footer { font-size:11px; background:#F0F0F0; border-top:1px solid #AAA; cursor:pointer; text-align:center; padding:2px; } .date { float:left; } .datepicker-opener-table { border:1px solid transparent; padding:0; border-spacing:0; margin:0 0 0 3px; background:transparent url(../../images/datepicker.gif) no-repeat 0 0; width:18px; height:18px; cursor:pointer; } .Opera .datepicker-opener-table { float:right; } .IE7 .datepicker-opener-table { position:relative; top:0; left:3px; } .datepicker-opener-table:hover { background:transparent url(../../images/datepicker_ro.gif) no-repeat 0 0; } .datepicker-opener { width:16px; height:16px; margin:0 0 0 3px; cursor:pointer; } /* Lists */ div.listContainer { width:100%; border-top:1px solid #CCC; border-bottom:1px solid #CCC; border-left:1px solid #CCC; border-right:1px solid #CCC; border-top-left-radius:2px; border-top-right-radius:2px; -moz-border-radius-topleft:2px; -moz-border-radius-topright:2px; -webkit-border-top-left-radius:2px; -webkit-border-top-right-radius:2px; } .fixedListHeader tr { position:relative; height:auto; font-weight:bold; } .fixedListHeader a { color:#444; } .listHeaderFormat { margin:3px; padding:1px; white-space:nowrap; } .listHeaderFormat tr td { padding:4px; background-color:#F5F5F5; color:#444; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#EEE)); background: -moz-linear-gradient(top, #F8F8F8, #EEE); border-right:1px solid #CCC; border-bottom:1px solid #CCC; } .listScrollContent { height:100%; overflow-x:hidden; overflow-y:auto; } .listScrollContent tr { height:auto; white-space:nowrap; } .listScrollContent tr:nth-child(odd) { background-color:#FFF; } .listScrollContent tr:nth-child(even) { background-color:#F5F5F5; } .listScrollContent tr.entry-locked:nth-child(odd) { background-color:#FFC; } .listScrollContent tr.entry-locked:nth-child(even) { background-color:#F5F5CC; } .listScrollContent tr.entry-error:nth-child(odd) { background-color:#FCC; } .listScrollContent tr.entry-error:nth-child(even) { background-color:#F5C5C5; } .listScrollContent tr.entry-warning:nth-child(odd) { background-color:#FEC; } .listScrollContent tr.entry-warning:nth-child(even) { background-color:#F5E5C5; } .listScrollContent tr:last-child { background-color:#FFF; } .listScrollContent tr td:last-child { padding-right:20px; } .listScrollContent td div.img { margin-right:1px; } .listScrollContent td input[type=submit].img { margin-right:1px; } .listBodyFormat tr td { color:#000; margin:3px; padding:2px; border-right:1px solid #CCC; word-wrap:break-word; white-space:normal; max-width:500px; } .listScrollContent tr:hover { background-color:#DDD; } .listScrollContent tr:last-child:hover { background-color:#FFF; } div.nlistFooter { background-color:#F5F5F5; color:#444; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#EEE)); background: -moz-linear-gradient(top, #F8F8F8, #EEE); border-left:1px solid #CCC; border-right:1px solid #CCC; border-bottom:1px solid #CCC; border-bottom-left-radius:2px; border-bottom-right-radius:2px; -moz-border-radius-bottomleft:2px; -moz-border-radius-bottomright:2px; -webkit-border-bottom-left-radius:2px; -webkit-border-bottom-right-radius:2px; padding:0; width:100%; } /* List header, Filter, misc. */ #mainlist { height:100%; padding-right:3px; } .mainlist-header { background-color:#F8F8F8; border:1px solid #CCC; border-radius:2px; -moz-border-radius:2px; -webkit-border-radius:2px; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#EEE)); background: -moz-linear-gradient(top, #F8F8F8, #EEE); margin-bottom:4px; margin-right:-2px; } .mainlist-header p{ color:#444; font-weight:bold; font-size:15px; margin:4px; } .mainlist-header div.mainlist-nav{ border-top:1px solid #CCC; background-color:white; } div.mainlist-nav table{ border-collapse:collapse; } div.mainlist-nav td div.img{ margin-top:-2px; } div.mainlist-nav td{ padding:3px 5px; vertical-align:middle; } div.mainlist-nav td.left-border{ padding-left:5px; } /* Sortable Lists */ div.sortableListContainer { border:1px solid #CCC; overflow:auto; margin-bottom:2px; border-radius:2px; -moz-border-radius:2px; -webkit-border-radius:2px; } .sortableListContainer th { background-color:#F5F5F5; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#EEE)); background: -moz-linear-gradient(top, #F8F8F8, #EEE); padding:4px; text-align:left; border-left:1px solid #CCC; border-bottom:1px solid #CCC; } .sortableListContainer td { padding:3px; text-align:left; border-left:1px solid #CCC; } .sortableListContainer tr:nth-child(odd) { background-color:#FFF; } .sortableListContainer tr:nth-child(even) { background-color:#F5F5F5; } .sortableListContainer tr:last-child { background-color:#FFF; } .sortableListContainer tr td:last-child { padding-right:20px; } tr.sortableListItem { background-color:#FFF; cursor:move; color:#000; } tr.sortableListItemFill { background-color:#FFF; cursor:default; } tr.sortableListItemOdd ::-moz-selection,tr.sortableListItem ::-moz-selection { background:transparent; } tr.sortableListItemOdd ::selection,tr.sortableListItem ::selection { background:transparent; } tr.sortableListItemOdd code::-moz-selection,tr.sortableListItem code::-moz-selection { background:transparent; } tr.sortableListItemOdd code::selection,tr.sortableListItem code::selection { background:transparent; } tr.sortableListItemOdd { background-color:#F5F5F5; cursor:move; color:#000; } tr.sortableListItem:hover,tr.sortableListItemOdd:hover { background-color:#EEE; } tr.sortableListItemDisabled { cursor:default; color:#CCC; } table.sortableListTable { border:0; } tr.sortableListItemMarked { background-color:#FFD; } /* Tree List */ ul.treeList,ul.treeList ul { list-style-type:none; background:url(../../images/lists/vline.png) repeat-y; margin:0; padding:0; } ul.treeList ul { margin-left:10px; } ul.treeList a:hover { background-color:#DDD; } a.treeList { padding:2px; cursor:pointer; } a.treeListSelected { font-weight:bold; color:#1010AF; background-color:#DDD; padding:2px; cursor:pointer; } a.treeList:hover,a.treeListSelected:hover { background-color:#DDD; padding:2px; } ul.treeList a { padding:2px; cursor:pointer; } ul.treeList li { margin:0; padding:0 12px; line-height:20px; background:url(../../images/lists/node.png) no-repeat; } li.treeListSelected a { font-weight:bold; color:#1010AF; padding:2px; } ul.treeList li.last { background:#fff url(../../images/lists/lastnode.png) no-repeat; } ul.treeList li:last-child { background:#fff url(../../images/lists/lastnode.png) no-repeat; } div.treeList { background-color:#FFF; border:1px solid #AAA; padding:5px; position:absolute; z-index:500; overflow-y:auto; float:left; margin-top:-1px; margin-left:1px; } span.informal { color:#444; font-style:italic; } /* Max height for IE */ * html div.treeList { height: expression( this.scrollHeight > 500 ? "500px" : "auto" ); } span.mark { color:#B22; } /* Message dialog */ div.errorMsgTitle { width:100%; font-size:1.4em; padding-bottom:.3em; padding-top:.3em; font-weight:bold; background-color:#F0F0F0; } div.errorMsgDialog { width:60%; background-color:#FFF; border:4px solid red; z-index:150; display:none; position:absolute; } div.infoMsgDialog { width:60%; background-color:#FFF; border:2px solid #000; z-index:150; display:none; position:absolute; } /* Autocompleter */ div.autocomplete { position:absolute; background-color:#FFF; border:1px solid #AAA; margin:0; padding:0; z-index:600; overflow:hidden; word-wrap:break-word; } div.autocomplete ul { list-style-type:none; margin:0; padding:0; } div.autocomplete ul li { list-style-type:none; display:block; margin:0; padding:2px; padding-left:4px; cursor:pointer; } div.autocomplete li:hover { background-color:#F0F0F0; } div.autocomplete ul li.selected { background-color:#F0F0F0; } /* Pulldown menu */ #pulldown { display:inline-block; background-color:#FFF; height:23px; border:1px solid #CCC; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background:-webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#EEE)); background:-moz-linear-gradient(top, #F8F8F8, #EEE); } #pulldown ul { display:block; margin:0; padding:0; line-height:1em; list-style:none; z-index:90; } #pulldown ul li { float:left; margin:0 3px 0 0; padding:0; font-size:13px; line-height:1 5em; list-style-type:none; } #pulldown ul li a { float:left; display:block; width:auto; font-weight:normal; background:transparent; text-decoration:none; margin:0; padding:5px; } #pulldown ul li a:hover { text-decoration:none; } #pulldown ul li.sep { color:#AAA; padding:.8em 0 .5em; } /* Commented Backslash Hack hides rule from IE5-Mac \*/ #pulldown ul li a { float:none; } /* End IE5-Mac hack */ #pulldown ul.level2,#pulldown ul.level3 { position:absolute; top:0; left:0; visibility:hidden; border:1px #CCC solid; background:#FFF; box-shadow: 2px 2px 0 rgba(0,0,0,0.1); -webkit-box-shadow: 2px 2px 1px rgba(0,0,0,0.1); -moz-box-shadow: 2px 2px 0px rgba(0,0,0,0.1); } #pulldown ul.level2 li,#pulldown ul.level3 li { border-bottom:1px solid #fff; float:none; margin:0; padding:0; width:200px; } #pulldown ul.level2 li a,#pulldown ul.level3 li a { padding:5px 9px 5px 5px; } #pulldown ul.level2 li a:hover,#pulldown ul.level3 li a:hover { font-weight:normal; background-color:#418DD4; background-image:none; } /* Filter */ div.search-filter { border:1px solid #CCC; border-left:0; background-color:white; text-align:middle; padding:0; margin:0; float:left; } div.search-filter input[type=text]{ border:0; padding:3px; margin:0; height:17px; } button.search-filter { padding:4px 2px 3px 2px;; margin:0; text-align:middle; height:25px; } /* Filter menu */ table.filter-wrapper { border-collapse:collapse; padding:0; margin:0; } table.filter-wrapper tr, table.filter-wrapper td{ padding:0; margin:0; vertical-align:top; } #filtermenu { border:1px solid #CCC; border-right:0; display:inline-block; background-color:#EEE; height:23px; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background:-webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#EEE)); background:-moz-linear-gradient(top, #F8F8F8, #EEE); } #filtermenu ul { display:block; margin:0; padding:0; line-height:1em; list-style:none; z-index:90; } #filtermenu ul li { float:left; margin:0 3px 0 0; padding:0; font-size:13px; line-height:1 5em; list-style-type:none; } #filtermenu ul li a { float:left; display:block; /*width:auto; */ font-weight:normal; background:transparent; text-decoration:none; margin:0; padding:5px; } #filtermenu ul li a:hover { text-decoration:none; } #filtermenu ul li.sep { color:#AAA; padding:.8em 0 .5em; } /* Commented Backslash Hack hides rule from IE5-Mac \*/ #filtermenu ul li a { float:none; } /* End IE5-Mac hack */ #filtermenu ul.level2 { margin-top:-4px; position:absolute; top:0; left:0; visibility:hidden; border:1px #CCC solid; background:#FFF; box-shadow: 2px 2px 0 rgba(0,0,0,0.1); -webkit-box-shadow: 2px 2px 1px rgba(0,0,0,0.1); -moz-box-shadow: 2px 2px 0px rgba(0,0,0,0.1); } #filtermenu ul.level2 li{ border-bottom:1px solid #fff; float:none; margin:0; padding:0; width:200px; } #filtermenu ul.level2 li a { padding:5px 9px 5px 5px; } #filtermenu ul.level2 li a:hover { font-weight:normal; background-color:#418DD4; background-image:none; } /* Misc */ .copynotice, .copynotice a { color:#777; text-align:right; } .object-list li span { color:#666; font-style:italic; } .inline-warning { font-size:19px; text-align:bottom; } .inline-warning-text { display:inline-block; padding-top:13px; } /* Progress */ div.progress { text-align:center; display: block; color: rgba(255,255,255,0.9); padding:1px; border: 1px solid rgba(0,0,0,0.6); -moz-border-radius: 2px; -webkit-border-radius: 2px; border-radius: 2px; } .progress-low { background-color:#32CD32; } .progress-mid { background-color:#FFFF00; } .progress-high { background-color:#FFA500; } .progress-full { background-color:#FF0000; } /* Login */ .login-box-header { padding:8px 13px; font-size:20px; background-color:#EEE; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#F8F8F8', endColorstr='#FFFFFF')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#F8F8F8), to(#EEE)); background: -moz-linear-gradient(top, #F8F8F8, #EEE); border-top-left-radius:5px; border-top-right-radius:5px; -moz-border-radius-topleft:5px; -moz-border-radius-topright:5px; -webkit-border-top-left-radius:5px; -webkit-border-top-right-radius:5px; border-bottom:1px solid #CCC; } .login-box-container { padding:5% 10% 3% 10%; } .login-box { position:absolute; top:25%; left:30%; right:30%; background-color:#FFF; border:1px solid #CCC; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#F8F8F8')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#FFF), to(#F8F8F8)); background: -moz-linear-gradient(top, #FFF, #F8F8F8); } .login-element-container { padding:5px 8px; position:relative; height:30px; } .login-warning { } .login-warning a{ font-weight: bold; } .login-label { position:absolute; left:8px; width:10em; } .login-input { position:absolute; left:10em; right:30px } .login-input input{ position:absolute; width:100%; } .login-inline-message { padding:0 5px; color:red; text-align:center; } .login-warning { border:2px solid #F00; background-color:#FCC; padding:10px; margin:0 10px 10px 10px; text-align:center; } /* Logout */ .logout-box { position:absolute; top:25%; left:20%; right:20%; padding:10px; background-color:#F8F8F8; border:2px solid red; border-radius:5px; -moz-border-radius:5px; -webkit-border-radius:5px; -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#FFFFFF', endColorstr='#F0F0F0')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#FFF), to(#F0F0F0)); background: -moz-linear-gradient(top, #FFF, #F0F0F0); } h2 { font-size:14px; font-weight:bold; } /* ACL viewer */ div.acl-viewer-container { border:1px solid #CCC; padding:1px; height:100%; min-height:480px; overflow-x:hidden; overflow-y:auto; } .acl-viewer span { color:red; } table.acl-viewer{ width:100%; } .acl-viewer td { padding-top:5px; } tr.acl-viewer-head{ -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr='#EEEEEE', endColorstr='#DDDDDD')"; background: -webkit-gradient(linear, 0 0, 0 100%, from(#EEE), to(#DDD)); background: -moz-linear-gradient(top, #EEE, #DDD); } tr.acl-viewer-head td{ padding:6px; margin:0; } td.acl-viewer-blocked{ background:#FAA; } ul.acl-viewer-items, ul.acl-viewer-items li { list-style:none; display:inline; margin:0; padding:0; } ul.acl-list, ul.acl-list li { list-style:none; display:inline; margin:0; padding:0; } ul.acl-viewer-items li ul.acl-category-list { list-style:none; margin:0; padding-left:20px; } ul.acl-category-list { padding-bottom:10px; } ul.acl-list li { color:#777; } ul.acl-list li:after { content: ", "; } ul.acl-list li:last-child:after { content: ""; } /* Reference tab */ table.reference-tab { width:100%; } gosa-core-2.7.4/html/autocomplete.php0000644000175000017500000000631411475146440016567 0ustar cajuscajus $info) { if (!isset($pathMapping[$dn])) { continue; } if (mb_stristr($info['name'], $search) !== false) { $res.= "
  • ".mark($search, $pathMapping[$dn]).($info['description']==''?"" :" [".mark($search, $info['description'])."]")."
  • "; continue; } if (mb_stristr($info['description'], $search) !== false) { $res.= "
  • ".mark($search, $pathMapping[$dn]).($info['description']==''?"" :" [".mark($search, $info['description'])."]")."
  • "; continue; } if (mb_stristr($pathMapping[$dn], $search) !== false) { $res.= "
  • ".mark($search, $pathMapping[$dn]).($info['description']==''?"" :" [".mark($search, $info['description'])."]")."
  • "; continue; } } /* Return results */ if (!empty($res)) { echo "
      $res
    "; } } } else { $ui = session::global_get('ui'); $config = session::global_get('config'); /* Is there a filter object arround? */ if (session::is_set("autocomplete")){ $filter= session::get("autocomplete"); $filter->processAutocomplete(); } } ?> gosa-core-2.7.4/html/logout.php0000644000175000017500000000701211425521764015374 0ustar cajuscajusdn); /* Write something to log */ new log("security","logout","",array(),"User \"".$ui->username."\" logged out") ; } /* Language setup */ if ((!isset($config)) || $config->get_cfg_value("core","language") == ""){ $lang= get_browser_language(); } else { $lang= $config->get_cfg_value("core","language"); } // Try to keep track of logouts, this will fail if our session has already expired. // Nothing will be logged if config isn't present anymore. stats::log('global', 'global', array(), $action = 'logout', $amount = 1, 0); putenv("LANGUAGE="); putenv("LANG=$lang"); setlocale(LC_ALL, $lang); $GLOBALS['t_language']= $lang; $GLOBALS['t_gettext_message_dir'] = $BASE_DIR.'/locale/'; /* Set the text domain as 'messages' */ $domain = 'messages'; bindtextdomain($domain, LOCALE_DIR); textdomain($domain); /* Create smarty & Set template compile directory */ $smarty= new smarty(); if (isset($config)){ $smarty->compile_dir= $config->get_cfg_value("core","templateCompileDirectory"); } else { $smarty->compile_dir= '/var/spool/gosa/'; } if(!is_writeable($smarty->compile_dir)){ header('location: index.php'); exit(); } $smarty->assign ("title","GOsa"); /* If GET request is posted, the logout was forced by pressing the link */ if (isset($_POST['forcedlogout']) || isset($_GET['forcedlogout'])){ /* destroy old session */ session::destroy (); /* If we're not using htaccess authentication, just redirect... */ if (isset($config) && $config->get_cfg_value("core","htaccessAuthentication") == "true"){ /* Else notice that the user has to close the browser... */ $smarty->display (get_template_path('headers.tpl')); $smarty->display (get_template_path('logout-close.tpl')); exit; } header ("Location: index.php"); exit(); }else{ // The logout wasn't forced, so the session is invalid $smarty->display (get_template_path('headers.tpl')); $smarty->display (get_template_path('logout.tpl')); exit; } // vim:tabstop=2:expandtab:shiftwidth=2:filetype=php:syntax:ruler: ?> gosa-core-2.7.4/html/favicon.ico0000644000175000017500000000257610230726066015500 0ustar cajuscajush( @ÿÿÿ»üàÊúÖÄþêûþýgosa-core-2.7.4/update-locale0000755000175000017500000001050211423776534015056 0ustar cajuscajus#!/bin/bash generate_po() { ORIG=`pwd` TEMPDIR="/tmp/gosa-locale" TRUE=`which true` echo echo "Creating temporary directory..." [ -d $TEMPDIR ] && rm -rf $TEMPDIR mkdir $TEMPDIR echo "Creating copy of GOsa..." tar c . | tar x -C $TEMPDIR echo "Converting .tpl files..." pushd . &> /dev/null cd $TEMPDIR for template in $(find . -name '*.tpl'); do echo "* converting .tpl files: $(basename $template)" sed -e 's/{t}/!g' $template > $template.new mv $template.new $template done for template in $(find . -name '*.xml'); do echo "* converting .xml files: $(basename $template)" sed -e 's/