protected function detachIt(
        /*# string */ $eventName,
        $listener,
        $callable
    ) {
        // queue not found
        if ($eventName != '' && !$this->hasEventQueue($eventName)) {
            return;
        }

        // detach callable directly
        if (is_null($listener)) {
            $xc = [
                [ $callable, 50 ]
            ];
        } else {
            // get callables from listener object or static listener class
            $xc = $this->makeCallables($listener, $callable, 50);
        }

        if (empty($xc)) {
            throw new Exception\InvalidArgumentException(
                Message::get(Message::INVALID_EVENT_CALLABLE, $eventName),
                Message::INVALID_EVENT_CALLABLE
            );
        } else {
            if ($eventName != '') {
                $q = $this->getEventQueue($eventName);
                foreach ($xc as $c) {
                    $q->remove($c[0]);
                }
                if ($q->count() === 0) {
                    unset($this->events[$eventName]);
                }
            } else {
                $names = $this->getEventNames();
                foreach ($names as $n) {
                    $q = $this->getEventQueue($n);
                    foreach ($xc as $c) {
                        $q->remove($c[0]);
                    }
                    if ($q->count() === 0) {
                        unset($this->events[$n]);
                    }
                }
            }
        }
    }