Example #1
0
 public function offsetUnset($offset)
 {
     if (!arr::hasKey($this->data, $offset)) {
         return;
     }
     unset($this->data[$offset]);
     sort($this->data);
 }
Example #2
0
 static function get($name, $default = null)
 {
     if (arr::hasKey(self::$cookies, $name)) {
         return self::$cookies[$name];
     } else {
         return $default;
     }
 }
Example #3
0
 /**
  * Constructor
  *
  * @param string $uri The URI to route
  * @param string $domain The domain to route
  * @param bool $secure True if connection made via SSL
  */
 public function __construct($buri = '/')
 {
     if (isset($_SERVER['REQUEST_URI'])) {
         $uri = $_SERVER['REQUEST_URI'];
     } else {
         $uri = $buri;
     }
     if (isset($_SERVER['HTTP_HOST'])) {
         $domain = strtolower($_SERVER['HTTP_HOST']);
     } else {
         if (isset($_SERVER['SERVER_NAME'])) {
             $domain = strtolower($_SERVER['SERVER_NAME']);
         } else {
             $domain = 'localhost';
         }
     }
     $secure = true;
     // Parse query string
     if (strpos($uri, '?')) {
         $base = substr($uri, 0, strpos($uri, '?'));
         $rest = substr($uri, strpos($uri, '?') + 1);
         // Apache mod_rewrite workaround for existing folders - requests
         // are routed as /uri/?/uri if the folder exists.
         if ($base != '/' && file_exists('.' . $base) && substr($rest, 0, strlen($base) - 1) . '/' == $base) {
             // folder match, reroute the $rest.
             // TODO: Query string arguments should be passed on
             if (strpos($rest, '&') > 0) {
                 $params = substr($rest, strpos($rest, '&') + 1);
             }
             response::redirect($base . '?' . $params);
         } else {
             // Parse the querystring
             $qsl = explode('&', $rest);
             foreach ($qsl as $qsi) {
                 if (preg_match('/^(.*)=(.*)$/', $qsi, $keys)) {
                     $_GET[$keys[1]] = urldecode($keys[2]);
                     $_REQUEST[$keys[1]] = urldecode($keys[2]);
                 }
             }
             $uri = $base;
         }
     }
     // Quick fix for first index being '/index_php' when invoked via
     // apache - hopefully sorts bug with php oauth.
     if (arr::hasKey($_GET, '/index_php')) {
         array_shift($_GET);
         array_shift($_GET);
     }
     // Assign the URI and start parsing
     $this->_uri = $uri;
     $this->_domain = $domain;
     $this->_secure = request::isSecure();
     foreach (explode('/', $this->_uri) as $segment) {
         if ($segment != '') {
             $this->_urisegments[] = $segment;
         }
     }
 }
Example #4
0
 public function addAnimator($property, ILpfAnimator $animator, $frstart, $frend)
 {
     if (arr::hasKey($this->_properties, $property)) {
         $this->_animators[$property][] = array('animator' => $animator, 'framestart' => $frstart, 'frameend' => $frend);
         console::writeLn("Attached animator: %s => %s", typeOf($animator), $property);
     } else {
         logger::warning("Animator attached to nonexisting property %s of object %s", $property, (string) $this->_object);
     }
 }
Example #5
0
 function __construct($structure = null)
 {
     $path = expandpath('app:' . $structure);
     if (file_exists($path) && $structure) {
         $strx = domdocument::load($path);
         $domx = new DOMXpath($strx);
         $cfgs = $domx->query('/configurationschema/config');
         foreach ($cfgs as $item) {
             $key = $item->getAttribute('key');
             if ($item->hasAttribute('type')) {
                 $vartype = $item->getAttribute('type');
             } else {
                 $vartype = 'string';
             }
             $description = null;
             $default = null;
             if ($item->childNodes->length > 0) {
                 foreach ($item->childNodes as $item) {
                     switch ($item->nodeName) {
                         case 'default':
                             $value = $item->getAttribute('value');
                             $type = $item->getAttribute('type');
                             if ($type == 'string') {
                                 $value = str_replace('${servername}', request::getDomain(), $value);
                                 $default = $value;
                             }
                             if ($type == 'integer') {
                                 $value = intval($value);
                                 $default = $value;
                             }
                             if ($type == 'float') {
                                 $value = floatval($value);
                                 $default = $value;
                             }
                             if ($type == 'generate') {
                                 if ($value == 'uuid') {
                                     $default = uuid::v4();
                                 } else {
                                     $default = '<unknown>';
                                 }
                             }
                             break;
                         case 'description':
                             $description = $item->nodeValue;
                             break;
                     }
                 }
             }
             if (!arr::hasKey($this->data, $key)) {
                 $this->data[$key] = $default;
             }
             $this->defs[$key] = array('description' => $description, 'vartype' => $vartype);
         }
         $this->flush();
     }
 }
 /**
  * @brief Return a pooled connection for the connectionstring
  *
  * @param mixed $connectionstring The connectionstring to request
  * @return DatabaseDriver the database driver
  */
 public static function getPooledConnection($connectionstring)
 {
     $csh = md5(serialize($connectionstring));
     if (!arr::hasKey(self::$pool, $csh)) {
         $driverclass = DatabaseDriver::getDriverClass($connectionstring['driver']);
         self::$pool[$csh] = array('instance' => new $driverclass($connectionstring), 'count' => 0);
         self::$pool[$csh]['instance']->setPoolIdentity($csh);
     }
     self::$pool[$csh]['count']++;
     return self::$pool[$csh]['instance'];
 }
Example #7
0
 /**
  * Invoke a specif event
  *
  * @param Mixed $event The event to invoke
  * @param Array $data The data to pass to the handler
  */
 static function invoke($event, array $data)
 {
     if (arr::hasKey(self::$_handlers, strtolower($event))) {
         foreach (self::$_handlers[$event] as $evt) {
             if ($evt->dispatch($event, $data) == true) {
                 return true;
             }
         }
     }
     return false;
 }
Example #8
0
 public function __set($property, $value)
 {
     if (arr::hasKey($this->properties, $property)) {
         $ptype = $this->properties[$property]['type'];
         $val = lpf::cast($value, $ptype);
         $this->properties[$property]['value'] = $val;
         list($type) = explode(':', $ptype);
         return;
     }
     printf("No such property %s\n", $property);
     return null;
 }
Example #9
0
 public function __get($property)
 {
     if (arr::hasKey($this->properties, $property)) {
         $propmeta = $this->properties[$property];
         if ($propmeta['propget']) {
             return $propmeta['propget']($property);
         } else {
             return $this->properties['value'];
         }
     } else {
         logger::warning("Ambient property %s requested object %s", $property, $this);
     }
 }
Example #10
0
 function __construct($pms)
 {
     if (!globals::get('pantonescale')) {
         die("pantone.dat not found!");
     }
     $vals = globals::get('pantonescale');
     if (!arr::hasKey($vals, strtoupper($pms))) {
         throw new ColorException(sprintf("Pantone color %s not known!", $pms));
     }
     $val = $vals[strtoupper($pms)];
     $this->red = $val['r'];
     $this->green = $val['g'];
     $this->blue = $val['b'];
 }
Example #11
0
 private function _streamDoRequest()
 {
     $options = $this->args;
     $ctxparam = array('http' => array('method' => strtolower($options['method']) == 'post' ? 'POST' : 'GET'));
     if (arr::hasKey($options, 'parameters')) {
         $ctxparam['http']['content'] = http_build_query($options['parameters']);
     }
     $ctx = stream_context_create($ctxparam);
     $cfh = fopen($url, 'r', false, $ctx);
     $buf = '';
     while (!feof($cfh)) {
         $buf .= fread($cfh, 8192);
     }
     fclose($cfh);
     $this->ret = array('content' => $buf);
 }
Example #12
0
 function parsefield($data)
 {
     $str = $data[1];
     $strx = explode(' ', $str);
     $svar = $strx[0];
     if (arr::hasKey($this->_vars, $svar)) {
         $rval = $this->_vars[$svar];
     } else {
         $rval = "[" . $svar . "]";
     }
     $indent = 0;
     $wrap = 0;
     foreach (array_slice($strx, 1) as $strs) {
         $alist = explode(':', $strs);
         switch ($alist[0]) {
             case 'indent':
                 $indent = intval($alist[1]);
                 break;
             case 'wrap':
                 $wrap = intval($alist[1]);
                 break;
         }
     }
     $buf = explode("\n", $rval);
     foreach ($buf as $bufitem) {
         $rval = $bufitem;
         if ($wrap > 0) {
             $rv = array();
             $rvalarr = explode("\n", $rval);
             foreach ($rvalarr as $line) {
                 $rv[] = wordwrap($line, $wrap - $indent);
             }
             $rval = join("\n", $rv);
         }
         if ($indent > 0) {
             $rv = array();
             $rvalarr = explode("\n", $rval);
             $indentstr = str_repeat(' ', $indent);
             foreach ($rvalarr as $line) {
                 $rv[] = $indentstr . $line;
             }
             $rval = join("\n", $rv);
         }
         $rvals[] = $rval;
     }
     return join("\n", $rvals);
 }
Example #13
0
 static function getRemoteIp()
 {
     if (arr::hasKey($_SERVER, "REMOTE_ADDR")) {
         $ip = $_SERVER["REMOTE_ADDR"];
     } else {
         if (arr::hasKey($_SERVER, "HTTP_X_FORWARDED_FOR")) {
             $ip = $_SERVER["HTTP_X_FORWARDED_FOR"];
         } else {
             if (arr::hasKey($_SERVER, "HTTP_CLIENT_IP")) {
                 $ip = $_SERVER["HTTP_CLIENT_IP"];
             } else {
                 $ip = null;
             }
         }
     }
     return $ip;
 }
Example #14
0
 /**
  * @brief Suid to another user.
  * 
  * The aim of this function is to allow the user to become another user,
  * for testing or administrative purposes. It is similar to the sudo and
  * su commands in the *nix world.
  * 
  * A user can only suid ONCE, and is only allowed to switch back to the
  * previous (original) user by passing NULL as the user record.
  * 
  * @todo Thorougly test
  * @param UserRecord $user The user to suid to or null to revert
  * @return boolean True on success
  */
 static function suid(UserRecord $user = null)
 {
     $suid = (array) session::get(User::KEY_USER_SUID, null);
     if (arr::hasKey($suid, 'issuid') && $user == null) {
         // Can unsuid
         $uid = $suid['uid'];
         session::set(User::KEY_USER_AUTH, $uid);
         session::clr(User::KEY_USER_SUID);
         // user::set
         return true;
     } elseif ($user) {
         // Can suid
         session::set(User::KEY_USER_SUID, array('issuid' => true, 'uid' => user::getActiveUser()->userid, 'suid' => $user->userid));
         session::set(User::KEY_USER_AUTH, $user->userid);
         return true;
     } else {
         throw new SecurityException("Invalid suid attempt");
     }
 }
Example #15
0
 function __set($property, $value)
 {
     if (!isset($this->properties)) {
         throw new RuntimeException("BasicContainer descendant doesn't have a protected variable properties");
     }
     if (arr::hasKey($this->properties, $property)) {
         if (is_array($this->properties[$property]) && !is_array($value)) {
             throw new RuntimeException("Attempting to assign non-array to array property");
         }
         $this->properties[$property] = $value;
     } else {
         throw new BadPropertyException("No such property: {$property}");
     }
 }
Example #16
0
 function __get($key)
 {
     if (arr::hasKey($this->metadata, $key)) {
         return $this->metadata[$key];
     } else {
         throw new BadPropertyException(__CLASS__, $key);
     }
 }
Example #17
0
 /**
  * @brief Get the full query URL
  * 
  * @return string The full query URL
  */
 static function getURL()
 {
     if (isset($_SERVER['HTTP_HOST'])) {
         if (request::isSecure()) {
             $proto = 'https://';
             $port = intval($_SERVER['SERVER_PORT']) != 443 ? ':' . $_SERVER['SERVER_PORT'] : '';
         } else {
             $proto = 'http://';
             $port = intval($_SERVER['SERVER_PORT']) != 80 ? ':' . $_SERVER['SERVER_PORT'] : '';
         }
         if (arr::hasKey($_SERVER, 'REQUEST_URI')) {
             $uri = $_SERVER['REQUEST_URI'];
         } else {
             if (arr::hasKey($_SERVER, 'REQUEST_URL')) {
                 $uri = $_SERVER['REQUEST_URL'];
                 $querystring = request::getRawQueryString();
                 $uri .= $querystring;
             }
         }
         return $proto . $_SERVER['HTTP_HOST'] . $port . $uri;
     } else {
         return null;
     }
 }
Example #18
0
 /**
  * @brief Retrieve the explicitly defined access record.
  *
  * This function is used internally to retrieve a complete list of roles
  * with the defined access modifiers included.
  *
  * @param String $suuid The subject UUID
  * @param String $ouuid The object UUID
  * @return Array The access record
  */
 private static function getExplicitAccessRecord($suuid, $ouuid, $rlist)
 {
     $db = new DatabaseConnection();
     $rolesraw = $db->getRows("SELECT role,access FROM aclconf WHERE object=%s AND subject=%s", $ouuid, $suuid);
     $rolesraw = arr::flip($rolesraw, 'role');
     // Translate access into tristate booleans
     foreach ($rlist as $role) {
         if (arr::hasKey($rolesraw, $role)) {
             $rf = $rolesraw[$role]['access'];
             if ($rf == 'Y') {
                 $access = self::ACL_ALLOW;
             } elseif ($rf == 'N') {
                 $access = self::ACL_DENY;
             } else {
                 $access = self::ACL_NULL;
             }
         } else {
             $access = self::ACL_NULL;
         }
         $roles[$role] = $access;
     }
     return $roles;
 }
Example #19
0
 static function defaults(array $array, $defaults)
 {
     foreach ($defaults as $key => $val) {
         if (!arr::hasKey($array, $key)) {
             $array[$key] = $val;
         }
     }
     return $array;
 }
Example #20
0
 /**
  * @brief Retrieve a component of the query string
  *
  * @param
  * @return
  */
 public function getParameter($key)
 {
     if (arr::hasKey($this->query, $key)) {
         return $this->query[$key];
     }
     return null;
 }
Example #21
0
 public function translate($tolang = null)
 {
     if (!$tolang) {
         throw new BadArgumentException("Translate requires a language!");
     }
     using('lepton.google.translate');
     using('app.manualtranslate');
     $this->openDatabase();
     $fromlang = $this->db['db:defaultlang'];
     // $to = new GoogleTranslate($fromlang,$tolang);
     $to = new ManualTranslate($fromlang, $tolang);
     $tstra = array();
     $err = 0;
     $tstra = $this->db['lang:' . $tolang];
     foreach ($this->db['lang:' . $fromlang] as $key => $str) {
         if (!arr::hasKey($tstra, $key)) {
             $tstr = $to->translate($str);
             if ($tstr) {
                 $tstra[$key] = $tstr;
             } else {
                 $err++;
             }
             console::writeLn(__astr("\\g{%s}: %s"), $key, $tstr);
             usleep(1000000);
         }
     }
     if ($err > 0) {
         console::writeLn(__astr("\\c{red %d strings could not be translated.}\nYou should run the script again."), $err);
     }
     $this->db['lang:' . $tolang] = $tstra;
     $this->saveDatabase();
 }
Example #22
0
 /**
  * @brief Push a value onto a key, making it an array.
  * 
  * @param String $key The key to push to
  * @param Mixed $value The value to push onto the key
  */
 function push($key, $value)
 {
     if (arr::hasKey($this->state, $key)) {
         $arr = (array) $this->state[$key];
     } else {
         $arr = array();
     }
     $arr[] = $value;
     $this->set($key, $arr);
 }
Example #23
0
 function main($argc, $argv)
 {
     if ($this->getParameterCount() == 0) {
         $this->usage();
         return 1;
     }
     switch ($this->getParameter(0)) {
         case 'call':
             if ($this->hasArgument('u')) {
                 $user = $this->getArgument('u');
                 $pass = null;
                 if ($this->hasArgument('p')) {
                     printf('Password: '******':', $paramlistitem . ':');
                 $data[$k] = $v;
             }
             $site = $this->conf->vs_siteurl;
             $xc = new XmlrpcClient($site . '/api/xmlrpc', $user, $pass);
             $ret = $xc->call($this->getParameter(1), $data);
             if ($ret) {
                 if (arr::hasKey($ret, 'faultCode')) {
                     printf("Error %d: %s\n", $ret['faultCode'], $ret['faultString']);
                 } else {
                     debug::inspect($ret, false, false);
                 }
             } else {
                 printf("Server error.\n");
             }
             break;
         case 'config':
             $editor = new ConfigEditor();
             $editor->loop();
             break;
         case 'set':
             $key = $this->getParameter(1);
             $defs = $this->conf->getDefs($key);
             $val = $this->getParameter(2);
             $this->printValue($key, $val);
             switch ($defs['vartype']) {
                 case 'boolean':
                     if ($val == "1") {
                         $this->conf->{$key} = true;
                     } else {
                         $this->conf->{$key} = false;
                     }
                     break;
                 case 'integer':
                     $this->conf->{$key} = intval($val);
                     break;
                 case 'float':
                     $this->conf->{$key} = floatval($val);
                     break;
                 default:
                     $this->conf->{$key} = $val;
             }
             break;
         case 'get':
             if ($this->getParameterCount() > 1) {
                 $key = $this->getParameter(1);
                 $val = $this->conf->{$key};
                 $this->printValue($key, $val);
             } else {
                 $keys = $this->conf->getAll();
                 ksort($keys);
                 foreach ($keys as $key => $val) {
                     if ($key) {
                         $this->printValue($key, $val);
                     }
                 }
             }
             break;
         case 'backup':
             $filename = $this->getParameter(1);
             printf("Backing up to %s...\n", $filename);
             $keys = $this->conf->getAll();
             file_put_contents($filename, serialize($keys));
             break;
         case 'restore':
             $filename = $this->getParameter(1);
             printf("Restoring from %s...\n", $filename);
             $keys = unserialize(file_get_contents($filename));
             foreach ($keys as $key => $value) {
                 printf("  %s: ", $key);
                 $this->conf->{$key} = $value;
                 printf("Ok\n");
             }
             break;
         case 'unset':
             $keys = $this->getParameters();
             $keys = array_slice($keys, 1);
             foreach ($keys as $key) {
                 printf("Unset key: %s\n", $key);
                 $this->conf->{$key} = null;
             }
             break;
         default:
             $params = $this->getParameters();
             $cmd = $params[0];
             $params = array_slice($params, 1);
             $cmdm = 'cmd_' . $cmd;
             if (is_callable(array($this, $cmdm))) {
                 call_user_func_array(array($this, $cmdm), $params);
             } else {
                 printf("Unknown command: %s, try -h\n", $cmd);
             }
             break;
     }
 }
Example #24
0
 function getRule($selector)
 {
     if (arr::hasKey($this->rules, $selector)) {
         return $this->rules[$selector];
     } else {
         return null;
     }
 }
Example #25
0
 /**
  * Check if a form field or the form as a whole is valid.
  *
  * @param string $field The field to query. If null, returns the state of
  *   the form.
  * @return bool True if set
  */
 public function isValid($field = null)
 {
     if ($field == null) {
         return $this->formvalid;
     } else {
         if (arr::hasKey($this->fieldvalid, $field)) {
             return $this->fieldvalid[$field];
         } else {
             return null;
         }
     }
 }
Example #26
0
 /**
  *
  *
  */
 function __toString()
 {
     // Resolve the content disposition as per RFC 2183
     if (arr::hasKey($this->options, 'inline') && $this->options['inline'] == true) {
         $disposition = 'inline';
     } else {
         $disposition = 'attachment; filename="' . basename($this->filename) . '"';
     }
     // Assemble the headers
     $headers = array('Content-Type' => response::contentTypeFromFile($this->filename), 'Content-Transfer-Encoding' => 'base64', 'Content-Disposition' => $disposition);
     if (arr::hasKey($this->options, 'contentid')) {
         $headers['Content-ID'] = $this->options['contentid'];
     }
     $headersstr = '';
     $content = chunk_split(base64_encode(file_get_contents($this->filename)));
     foreach ($headers as $k => $v) {
         $headersstr .= $k . ': ' . $v . "\r\n";
     }
     return $headersstr . "\r\n" . $content . "\r\n";
 }
Example #27
0
 /**
  * @todo Document
  * @param array $meta
  * @return type 
  */
 public function validate(array $meta)
 {
     $formdata = $meta['formdata'];
     foreach ($this->_items as $ci) {
         if (is_a($ci, WizardLayoutControl)) {
             $ci->validate($meta);
         } else {
             $key = $ci->getKey();
             $formdata[$key]['changed'] = true;
             // Do the validation here
             if (arr::hasKey($formdata, $key) && request::has($key) && $formdata[$key]['value'] == (string) request::get($key)) {
                 // Not changed, so query previous state of validation
                 $formdata[$key]['changed'] = false;
                 if ($formdata[$key]['valid'] != true) {
                     // Do validation
                 }
             } else {
                 // Insert into array
                 $formdata[$key] = array('value' => (string) request::get($key), 'valid' => $formdata[$key]['valid']);
             }
         }
     }
     return $formdata;
 }
Example #28
0
 function __get($key)
 {
     switch ($key) {
         case 'genderstr':
             return WowQuery::genderIdToString($this->_data['gender']);
         case 'classstr':
             return WowQuery::classIdToString($this->_data['class']);
         case 'racestr':
             return WowQuery::raceIdToString($this->_data['race']);
         default:
             if (arr::hasKey($this->_data, $key)) {
                 return $this->_data[$key];
             }
             throw new WowException("No such key in character: " . $key);
     }
     return null;
 }
Example #29
0
    function render(array $meta = null) {
        
        
        $attrs = '';
        if ($this->getOption('autoselect',true) == true) {
            $attrs.= ' onmouseup="this.focus(); this.select();"';
        }
        $dattrs = ' class="fp -formrow"';
        $attrs = '';
        $cssclass = $this->getOption('class',null);
        $cssclass = 'fp'.($cssclass?' '.$cssclass:'');
        $cssstyle = $this->getOption('style','width:80px;');
        $attrs.=sprintf(' class="%s"', $cssclass);
        if ($cssstyle) $attrs.=sprintf(' style="%s"', $cssstyle);
        $key = $this->getKey();
        $formtoken = $meta['token'];
        $curform = $meta['formdata'];
        $curform = $curform[$formtoken];
        if (arr::hasKey($meta['formdata'],$formtoken)) {
            $value = $meta['formdata'][$formtoken][$this->getKey()]['value'];
        } else {
            $value = null;
        }
        $captchaurl = $this->getOption('captchaurl','/meta/captcha?cid={cid}');
        $captchaurl = str_replace('{cid}',$this->captchaid, $captchaurl);

        $str = sprintf('<div%s>', $dattrs);
        $str.= sprintf('<label for="%s" class="fp">%s</label>', $key, $this->label);
        $str.= sprintf('<img src="%s"><br>', $captchaurl);
        $str.= sprintf('<input id="%s_cid" name="%s_cid" class="fp" type="hidden" value="%s">', $key, $key, $this->captchaid);
        $str.= sprintf('<input id="%s" name="%s" class="fp" type="text" %s>', $key, $key, $attrs);
        $str.= sprintf('</div>');
        return $str;
        
    }
Example #30
0
 /**
  * @brief Render the chart in 3D
  * 
  * @return Canvas 
  */
 private function render3D()
 {
     $c = new Canvas($this->width, $this->height, rgb($this->getProperty('background', '#FFFFFF')));
     $radiusx = 180;
     $radiusy = 90;
     $cx = $c->getWidth() / 2;
     $cy = $c->getHeight() / 2;
     $explode = $this->getProperty('explode', 0);
     $palette = $this->getProperty('palette');
     list($label, $vals) = $this->dataset->getSeries(0);
     $labels = $this->dataset->getLabels();
     $sum = $vals->getSum();
     $ci = 0;
     $sa = 0;
     for ($n = 0; $n < $vals->getCount(); $n++) {
         list($val, $key) = $vals->getValue($n);
         $a = 360 / $sum * $val;
         // Get angle
         $ea = $sa + $a;
         $ch = rgb($palette[$ci]);
         $cs = hsv($ch);
         $cs->value = $cs->value - 30;
         if (arr::hasKey($labels, $n)) {
             $l = $labels[$n];
         } else {
             $l = $n;
         }
         $data[] = array('key' => $key, 'label' => $l, 'c1' => $ch, 'c2' => $cs, 'sa' => $sa, 'ea' => $ea);
         $sa = $ea;
         $ci++;
     }
     $offs = array();
     foreach ($data as $id => $slice) {
         $avg = ($slice['sa'] + $slice['ea']) / 2;
         $data[$id]['ox'] = cos(($avg - 90) % 360 * PI / 180) * $explode;
         $data[$id]['oy'] = sin(($avg - 90) % 360 * PI / 180) * $explode;
         $data[$id]['dx'] = cos(($avg - 180) % 360 * PI / 180);
         $data[$id]['dy'] = sin(($avg - 180) % 360 * PI / 180);
     }
     $f = new BitmapFont(3);
     $f->setTextEffect(BitmapFont::EFFECT_OUTLINE, rgb(255, 255, 255));
     $p = $c->getPainter();
     for ($yp = 20; $yp >= 0; $yp--) {
         foreach ($data as $slice) {
             $ox = $slice['ox'];
             $oy = $slice['oy'];
             $p->drawFilledArc($cx + $ox, $cy + $oy + $yp, $radiusx * 2, $radiusy * 2, $slice['sa'], $slice['ea'], $yp == 0 ? $slice['c1'] : $slice['c2']);
         }
     }
     for ($yp = 20; $yp >= 0; $yp--) {
         foreach ($data as $slice) {
             // TODO: Labels
             $m = $f->measure($slice['label']);
             $dx = $slice['dx'];
             $dy = $slice['dy'];
             $c->drawText($f, rgb(0, 0, 0), $cx + $dx * $radiusx / 1.5 - $m['width'] / 2, $cx + $dy * $radiusy / 1.5 - $m['height'] / 2, $slice['label']);
         }
     }
     $this->renderObjects($c);
     // Return the canvas
     return $c;
 }