Example #1
0
 protected function returnResult()
 {
     if (Request::isAjax()) {
         Responder::sendJSON(array());
     }
     Responder::redirectToPage();
 }
Example #2
0
 public function main()
 {
     if (Request::isPost()) {
         $this->processShell();
     } else {
         $this->renderForm();
     }
 }
Example #3
0
 protected function checkIP()
 {
     $ip = \Lampcms\Request::getIP();
     d('checking IP: ' . $ip);
     $res = $this->Registry->Mongo->BANNED_IP->findOne(array('_id' => $ip));
     if (!empty($res)) {
         throw new \Lampcms\FilterException('Unable to add new content at this time');
     }
 }
Example #4
0
 protected function returnResult()
 {
     if (Request::isAjax()) {
         $ret = array('alert' => '@@Approved@@');
         $ret['reload'] = 1000;
         Responder::sendJSON($ret);
         exit;
     }
     Responder::redirectToPage();
 }
Example #5
0
 /**
  *
  */
 protected function main()
 {
     if (!Request::isAjax()) {
         e('Tweet called as non-ajax');
         throw new \Lampcms\Exception('This page can only be accessed using XHR request (ajax)');
     }
     try {
         $oTwitter = new Twitter($this->Registry);
         $aResponse = $oTwitter->prepareAndPost($this->Request->getUTF8('tweet'));
         Responder::sendJSON(array('tweet' => 'done'));
     } catch (\Lampcms\Exception $e) {
         e('Unable to post message to Twitter: ' . $e->getFile() . ' line: ' . $e->getLine() . ' ' . $e->getMessage());
         Responder::sendJSON(array('tweet' => 'error'));
     }
 }
Example #6
0
 /**
  * Get Location object for the ip address
  *
  * @param string $ip ip address
  *
  * @return object of type Location
  */
 public function getLocation($ip = null)
 {
     $ip = null !== $ip ? $ip : \Lampcms\Request::getIP();
     if (false === ($l = $this->isPublic($ip))) {
         d('ip not public');
         return new Location();
     }
     if (4 === PHP_INT_SIZE) {
         $l = sprintf("%u", $l);
     }
     $i = (double) $l;
     $a = $this->MongoDB->GEO_BLOCKS->findOne(array('s' => array('$lte' => $i), 'e' => array('$gte' => $i)), array('l'));
     if (is_array($a) && !empty($a['l'])) {
         /**
          * Important: must exclude _id from returned data, otherwise
          * it may override another _id when doing array_merge
          *
          */
         $loc = $this->MongoDB->GEO_LOCATION->findOne(array('_id' => $a['l']), array('_id' => 0));
         return new Location($loc);
     }
     return new Location();
 }
    error_reporting(E_ALL ^ E_WARNING);
    ini_set('display_errors', 0);
    ini_set('display_startup_errors', 0);
    ini_set('warn_plus_overloading', 0);
}
define('LOG_FILE_PATH', $oINI->LOG_FILE_PATH);
/**
 * Empty the log file if
 * necessary
 */
/**
 * LOG_PER_SCRIPT
 * will return string '1' for true
 * or empty string for false
 */
if (true === LAMPCMS_DEBUG && '' !== LOG_FILE_PATH && true === (bool) $oINI->LOG_PER_SCRIPT && !\Lampcms\Request::isAjax()) {
    file_put_contents(LOG_FILE_PATH, PHP_SAPI . ' ' . print_r($_SERVER, 1), LOCK_EX);
}
/**
 * Shortcuts to log debug and log error
 * MUST BE CALLED after DEBUG MODE and LOG_FILE_PATH
 * has been defined
 */
function d($message)
{
    if (defined('LAMPCMS_DEBUG') && true === LAMPCMS_DEBUG) {
        \Lampcms\Log::d($message, 2);
    }
}
function e($message)
{
Example #8
0
 /**
  * Set error message for the form as a whole.
  * This error message is not specific to any form field,
  * it usually appears on top of form as a general error message
  *
  * For example: You must wait 5 minutes between posting
  * This is not due to any element error, just a general error
  * message.
  *
  * The form template MUST have 'formError' variable in it!
  *
  * @param string $errMessage
  *
  * @return \Lampcms\Forms\Form
  */
 public function setFormError($errMessage)
 {
     if (Request::isAjax()) {
         \Lampcms\Responder::sendJSON(array('formError' => $errMessage));
     } else {
         $this->aErrors['formError'][] = $errMessage;
     }
     return $this;
 }
 protected function returnResult()
 {
     /**
      * @todo translate string
      */
     $message = 'Topic retagged successfully';
     if (Request::isAjax()) {
         $ret = array('reload' => 100);
         //'alert' => $message,
         Responder::sendJSON($ret);
     }
     Responder::redirectToPage($this->Question->getUrl());
 }
Example #10
0
 /**
  * Add extra div with "Join" form
  * where we ask to provide email address
  * after user joins with external provider
  *
  * @return object $this
  */
 protected function addJoinForm()
 {
     if (!$this->bInitPageVars || !Request::isAjax() && 'remindpwd' !== $this->action && 'logout' !== $this->action) {
         /**
          * If user opted out of continuing
          * registration, the special 'dnd' or "Do not disturb"
          * cookie was set via Javascritp
          * We will respect that and will not show that same
          * nagging prompt again
          *
          * This cookie is deleted on Logout
          * @todo set ttl for this cookie to last only a couple of days
          * so we can keep nagging user again after awhile until user
          * finally enters email address
          * Also do not have to check if user is UserExternal - if user
          * does not have email address then keep nagging the user
          * The thing is - only external user can possibly be logged in without
          * any email address because normal user will not know their password
          * since temp passwords are sent to email.
          */
         $cookie = Cookie::get('dnd');
         d('dnd: ' . $cookie);
         if (!$cookie) {
             if ($this->Registry->Viewer instanceof UserExternal) {
                 $email = $this->Registry->Viewer->email;
                 d('email: ' . $email);
                 if (empty($email)) {
                     $sHtml = RegBlock::factory($this->Registry)->getBlock();
                     d('$sHtml: ' . $sHtml);
                     $this->aPageVars['extra_html'] = $sHtml;
                 }
             }
         }
     }
     return $this;
 }
Example #11
0
 /**
  * Check Request object for required params
  * as well as for required form token
  *
  * @return object $this
  */
 protected function initParams()
 {
     if ($this->bRequirePost && 'POST' !== Request::getRequestMethod()) {
         throw new \Lampcms\HttpResponseCodeException('HTTP POST request method required', 405);
     }
     $this->Request->setRequired($this->aRequired);
     try {
         $this->Request->checkRequired();
     } catch (\Exception $e) {
         throw new \Lampcms\HttpResponseCodeException($e->getMessage(), 400);
     }
     return $this;
 }
 /**
  * Process the submitted "select default blog" form
  * This form is displayed to user when we detect that
  * user has more than one blog on Blogger, in which
  * case user is asked to pick one blog that will
  * be connected to this account
  *
  *
  * @throws \Exception if user does not have any blogs, which
  * is not really possible, so this would be totally unexpected
  */
 protected function selectBlog()
 {
     if ('POST' !== Request::getRequestMethod()) {
         throw new \Lampcms\Exception('POST method required');
     }
     \Lampcms\Forms\Form::validateToken($this->Registry);
     $a = $this->Registry->Viewer->getBloggerBlogs();
     d('$a: ' . print_r($a, 1));
     if (empty($a)) {
         throw new \Exception('No blogs found for this user');
     }
     $selectedID = (int) substr($this->Request->get('blog'), 4);
     d('$selectedID: ' . $selectedID);
     /**
      * Pull the selected blog from array of user blogs
      *
      * @var unknown_type
      */
     $aBlog = \array_splice($a, $selectedID, 1);
     d('$aBlog: ' . print_r($aBlog, 1));
     d('a now: ' . print_r($a, 1));
     /**
      * Now stick this blog to the
      * beginning of array. It will become
      * the first element, pushing other blogs
      * down in the array
      * User's "Connected" blog is always
      * the first blog in array!
      *
      */
     \array_unshift($a, $aBlog[0]);
     d('a after unshift: ' . print_r($a, 1));
     $this->Registry->Viewer->setBloggerBlogs($a);
     /**
      * Set b_bg to true which will result
      * in "Post to Blogger" checkbox to
      * be checked. User can uncheck in later
      */
     $this->Registry->Viewer['b_bg'] = true;
     $this->Registry->Viewer->save();
     $this->closeWindow();
 }
 /**
  * Insert record into VOTE_HACKS collection
  *
  * @todo move this to external class and make
  * this method static, accepting only Registry
  */
 protected function recordVoteHack()
 {
     $coll = $this->Registry->Mongo->VOTE_HACKS;
     $coll->ensureIndex(array('i_ts' => 1));
     $aData = array('i_uid' => $this->Registry->Viewer->getUid(), 'i_ts' => time(), 'ip' => Request::getIP());
     $coll->save($aData);
     return $this;
 }
Example #14
0
    protected function returnResult()
    {
        /**
         * @todo translate string
         */
        $message = '@@Item deleted@@';
        $requested = 'You cannot delete question that already has answers.<br>A request to delete
		this question has been sent to moderators<br>
		It will be up to moderators to either delete or edit or close the question';
        if (Request::isAjax()) {
            $res = !$this->requested ? $message : $requested;
            $ret = array('alert' => $res);
            if (!empty($this->posterDetails)) {
                $ret['alert'] .= $this->posterDetails;
            } else {
                /**
                 * If item was actually deleted then
                 * add 'reload' => 2 to return
                 * which will cause page reload
                 * in 1.5 seconds.
                 */
                if (!$this->requested) {
                    $ret['reload'] = 1500;
                }
            }
            Responder::sendJSON($ret);
        }
        Responder::redirectToPage($this->Resource->getUrl());
    }
Example #15
0
 protected function main()
 {
     $this->pageID = $this->Registry->Router->getPageID();
     $this->init()->getCursor()->paginate()->renderUsersHtml();
     /**
      * In case of Ajax request, just return
      * the content of the usersHtml
      * and don't proceed any further
      */
     if (Request::isAjax()) {
         Responder::sendJSON(array('paginated' => $this->usersHtml));
     }
     $this->setTitle()->makeSortTabs()->makeTopTabs()->setUsers();
 }
Example #16
0
 /**
  * Process submitted Answer
  *
  * @return void
  */
 protected function process()
 {
     $formVals = $this->Form->getSubmittedValues();
     d('formVals: ' . print_r($formVals, 1));
     $oAdapter = new AnswerParser($this->Registry);
     try {
         $Answer = $oAdapter->parse(new SubmittedAnswerWWW($this->Registry, $formVals));
         d('cp created new answer: ' . \print_r($Answer->getArrayCopy(), 1));
         d('ans id: ' . $Answer->getResourceId());
         /**
          * In case of ajax we need to send out a
          * parsed html block with one answer
          * under the 'answer' key
          *
          * In case of non-ajax redirect back to question page,
          * hopefully the new answer will show up there too
          */
         if (Request::isAjax()) {
             $aAnswer = $Answer->getArrayCopy();
             /**
              * Add edit and delete tools because
              * Viewer already owns this comment and is
              * allowed to edit or delete it right away.
              * Javascript that usually dynamically adds these tools
              * is not going to be fired, so these tools
              * must already be included in the returned html
              *
              */
             $aAnswer['edit_delete'] = ' <span class="ico del ajax" title="@@Delete@@">@@delete@@</span>  <span class="ico edit ajax" title="@@Edit@@">@@edit@@</span>';
             $a = array('answer' => \tplAnswer::parse($aAnswer));
             d('before sending out $a: ' . print_r($a, 1));
             Responder::sendJSON($a);
         } else {
             Responder::redirectToPage($this->Question->getUrl());
         }
     } catch (\Lampcms\AnswerParserException $e) {
         d('Got AnswerParserException ' . $e->getMessage());
         /**
          * The setFormError in Form sends our json in
          * case of Ajax request, so we don't have to
          * worry about it here
          */
         $this->Form->setFormError($e->getMessage());
         $this->showFormWithErrors();
     }
 }
Example #17
0
 /**
  * Insert record into VOTE_HACKS collection
  *
  * @todo move this to external class and make
  *       this method static, accepting only Registry
  * @return \Lampcms\Controllers\Accept
  */
 protected function recordVoteHack()
 {
     $coll = $this->Registry->Mongo->VOTE_HACKS;
     $coll->ensureIndex(array(Schema::CREATED_TIMESTAMP => 1));
     $aData = array(Schema::POSTER_ID => $this->Registry->Viewer->getUid(), Schema::CREATED_TIMESTAMP => time(), Schema::IP_ADDRESS => Request::getIP());
     $coll->save($aData);
     return $this;
 }
Example #18
0
 /**
  * Main entry point
  * (non-PHPdoc)
  *
  * @see WebPage::main()
  */
 protected function main()
 {
     $this->qid = $this->Router->getNumber(1, null, $this->Registry->Ini['URI_PARTS']['QID_PREFIX']);
     if (Request::isAjax()) {
         $this->getQuestion()->getAnswers();
         Responder::sendJSON(array('paginated' => $this->answers));
     }
     $this->pageID = $this->Router->getPageID();
     $this->tab = $this->Registry->Request->get('sort', 's', 'i_lm_ts');
     $this->Registry->registerObservers();
     $this->getQuestion()->validateSlug()->addMetas()->sendCacheHeaders()->configureEditor()->setTitle()->addMetaTags()->setAnswersHeader()->getAnswers()->setAnswers()->setSimilar()->makeForm()->setAnswerForm()->makeFollowButton()->setFollowersBlock()->setQuestionInfo()->setFooter()->increaseView()->makeTopTabs();
     $this->Registry->Dispatcher->post($this->Question, 'onQuestionView');
 }
Example #19
0
 /**
  * Create $this->User User object for user whose
  * profile is being edited
  *
  * @return object $this
  */
 protected function getUser()
 {
     $uid = !\Lampcms\Request::isPost() ? $this->Router->getSegment(1, 'i', 0) : $this->Request->get('uid', 'i', null);
     if ($uid && $uid !== $this->Registry->Viewer->getUid()) {
         /**
          * This is edit profile for another user
          * check Viewer permission here
          */
         $this->checkAccessPermission('edit_any_profile');
         $this->User = \Lampcms\User::userFactory($this->Registry)->by_id($uid);
     } else {
         $this->User = $this->Registry->Viewer;
     }
     return $this;
 }
 /**
  *
  * Add a small login block to the template
  * but ONLY for ajax based request
  *
  * for regular web page we don't need
  * to have yet another login block
  * in the registration block
  *
  * @return string html of login block
  * of empty string for non-ajax request
  */
 protected function makeLoginBlock()
 {
     if (Request::isAjax()) {
         return \tplLoginblock::parse(array());
     }
     return '';
 }
Example #21
0
 protected function returnResult()
 {
     $message = '@@Thank you for caring!<br>Moderators have been notified@@';
     if (Request::isAjax()) {
         Responder::sendJSON(array('alert' => $message));
     }
     Responder::redirectToPage($this->Resource->getUrl());
 }
Example #22
0
 protected function returnResult()
 {
     if (Request::isAjax()) {
         $message = '@@User Shredded@@<hr>@@Banned IPs@@:' . implode('<br>', array_keys($this->aIPs)) . '<hr><br>@@Countries@@: ' . implode('<br>', array_keys($this->aCountries));
         Responder::sendJSON(array('alert' => $message));
     }
     Responder::redirectToPage();
 }
Example #23
0
 /**
  * Main entry point
  * (non-PHPdoc)
  * @see WebPage::main()
  */
 protected function main()
 {
     if (Request::isAjax()) {
         $this->getQuestion()->getAnswers();
         Responder::sendJSON(array('paginated' => $this->answers));
     }
     $this->pageID = $this->Registry->Request->get('pageID', 'i', 1);
     $this->tab = $this->Registry->Request->get('sort', 's', 'i_lm_ts');
     $this->Registry->registerObservers();
     $this->getQuestion()->addMetas()->sendCacheHeaders()->configureEditor()->setTitle()->addMetaTags()->setAnswersHeader()->getAnswers()->setAnswers()->setSimilar()->makeForm()->setAnswerForm()->makeFollowButton()->setFollowersBlock()->setQuestionInfo()->setFooter()->increaseView()->makeTopTabs();
     $this->Registry->Dispatcher->post($this->Question, 'onQuestionView');
 }
Example #24
0
 /**
  *
  */
 protected function validateCaptcha()
 {
     if (!empty($_SESSION['reg_captcha'])) {
         return $this;
     }
     $oCaptcha = Captcha::factory($this->Registry->Ini);
     $res = $oCaptcha->validate_submit();
     /**
      * If validation good then
      * all is OK
      */
     if (1 === $res) {
         $_SESSION['reg_captcha'] = true;
         return $this;
     }
     /**
      * If 3 then reached the limit of attampts
      */
     if (3 === $res) {
         throw new \Lampcms\CaptchaLimitException('You have reached the limit of image verification attempts');
     }
     if (Request::isAjax()) {
         $aRet = array('exception' => self::CAPTCHA_ERROR, 'fields' => array('private_key'), 'captcha' => $oCaptcha->getCaptchaArray());
         \Lampcms\Responder::sendJSON($aRet);
     }
     /**
      * @todo translate string
      */
     $this->setFormError(self::CAPTCHA_ERROR);
     return $this;
 }
Example #25
0
 /**
  * Check for previous
  * failed attempts to reset password
  * by using incorrect code
  *
  *
  * @throws \Lampcms\Exception
  * @return object $this
  */
 protected function checkHacks()
 {
     $ipHacks = 0;
     $uidHacks = 0;
     $uid = $this->Router->getNumber(1);
     $timeOffset = time() - 86400;
     $cur = $this->Registry->Mongo->PASSWORD_CHANGE->find(array('i_ts' > $timeOffset));
     if ($cur && $cur->count(true) > 0) {
         $ip = Request::getIP();
         foreach ($cur as $aVal) {
             if ($ip == $aVal['ip']) {
                 $ipHacks += 1;
             }
             if ($uid == $aVal['i_uid']) {
                 $uidHacks += 1;
             }
             if ($uidHacks > 5 || $ipHacks > 5) {
                 e('LampcmsError: hacking of password reset link. $uidHacks: ' . $uidHacks . ' $ipHacks: ' . $ipHacks . ' from ip: ' . $ip);
                 $this->Registry->Dispatcher->post($this, 'onPasswordResetHack', $aVal);
                 throw new \Lampcms\Exception('@@Access denied@@');
             }
         }
     }
     return $this;
 }
 /**
  * Update ONLINE_USERS collection
  * @todo exit if useragent is of known Crawler
  * 
  * @todo make logging guests online configurable option via Ini
  *
  */
 protected function run()
 {
     $Viewer = $this->Registry->Viewer;
     $ip = Request::getIP();
     $uid = $Viewer->getUid();
     d('uid: ' . $uid);
     $aData = array('ip' => $ip, 'i_ts' => time(), 'ua' => Request::getUserAgent(), 'action' => 'request_' . $this->Registry->Request->get('a', 's', 'home'), 'uri' => $_SERVER['REQUEST_URI'], 'title' => $this->title, 'category' => $this->category, 'a_kw' => !empty($this->aInfo['keywords']) ? explode(', ', $this->aInfo['keywords']) : array());
     if ($uid > 0) {
         $aData['i_uid'] = $uid;
         $aData['username'] = $Viewer->getDisplayName();
         $aData['avtr'] = $Viewer->getAvatarSrc();
         $aData['profile'] = $Viewer->getProfileUrl();
         $aData['role'] = $Viewer->getRoleId();
         $aData['i_pp'] = $Viewer->getProfitPoint();
     }
     $Mongo = $this->Registry->Mongo->getDb();
     $Geo = $this->Registry->Geo;
     $func = function () use($aData, $Mongo, $Geo) {
         $aGeo = $Geo->getLocation($aData['ip'])->toArray();
         $aData = $aData + $aGeo;
         /**
          * Need unique index uid
          *
          */
         if (array_key_exists('i_uid', $aData)) {
             $coll = $Mongo->ONLINE;
             $coll->ensureIndex(array('i_uid' => 1), array('unique' => true));
             $coll->ensureIndex(array('i_ts' => 1));
             $coll->update(array('i_uid' => $aData['i_uid']), $aData, array('upsert' => true));
         } else {
             /**
              * For guests the value of ip2long (int)
              * will be used as uid
              */
             $aData['i_uid'] = ip2long($aData['ip']);
             $coll = $Mongo->GUESTS;
             $coll->ensureIndex(array('i_uid' => 1), array('unique' => true));
             $coll->ensureIndex(array('i_ts' => 1));
             $coll->update(array('ip' => $aData['ip']), $aData, array('upsert' => true));
         }
         /**
          * Remove old records
          * Cleanup runs 10% of requests
          * removes records older than 24 hours
          */
         if (1 === rand(0, 10)) {
             $offset = time() - 60 * 60 * 24;
             $coll->remove(array('i_ts' => array('$lt' => $offset)));
         }
     };
     \Lampcms\runLater($func);
 }
 /**
  * Main entry point
  * (non-PHPdoc)
  * @see WebPage::main()
  */
 protected function main()
 {
     if (Request::isAjax()) {
         $this->getQuestion()->getAnswers();
         Responder::sendJSON(array('paginated' => $this->answers));
     }
     $this->pageID = $this->Registry->Request->get('pageID', 'i', 1);
     $this->Registry->registerObservers();
     $this->getQuestion();
     /**
      * Make sorting order: oldest=>newest for topics
      * without tag `question'
      */
     if (!in_array('question', $this->Question['a_tags'])) {
         $this->Registry->Request['sort'] = 'i_ts';
         $this->withQuestionTag = false;
     }
     $this->tab = $this->Registry->Request->get('sort', 's', 'i_lm_ts');
     $this->addMetas()->sendCacheHeaders()->configureEditor()->setTitle()->addMetaTags()->setAnswersHeader()->getAnswers()->setAnswers()->setSimilar()->makeForm()->setAnswerForm()->makeFollowButton()->setFollowersBlock()->setQuestionInfo()->setFooter()->increaseView()->makeTopTabs();
     $this->Registry->Dispatcher->post($this->Question, 'onQuestionView');
 }
Example #28
0
    protected function returnResult()
    {
        /**
         * @todo translate string
         */
        $message = '@@Question closed@@';
        $requested = 'A request to close
		this question has been sent to moderators<br>
		The final decision about closing the question or leaving it open will be up to moderators';
        if (Request::isAjax()) {
            $res = !$this->requested ? $message : $requested;
            $ret = array('alert' => $res);
            /**
             * If item was actually deleted then
             * add 'reload' => 2 to return
             * which will cause page reload
             * in 1.5 seconds.
             */
            if (!$this->requested) {
                $ret['reload'] = 1500;
            }
            Responder::sendJSON($ret);
        }
        Responder::redirectToPage($this->Resource->getUrl());
    }
Example #29
0
 protected function handleReturn()
 {
     $isAjax = Request::isAjax();
     d('$isAjax: ' . $isAjax);
     if ($isAjax) {
         $ret = array('vote' => array('v' => $this->Resource->getScore(), 't' => $this->resType, 'rid' => $this->resID));
         Responder::sendJSON($ret);
     }
     Responder::redirectToPage($this->Resource->getUrl());
 }
Example #30
0
     }
     fastcgi_finish_request();
 } catch (\Exception $e) {
     $code = $e->getCode();
     session_write_close();
     if ($e instanceof \Lampcms\Lampcms404Exception) {
         $code = '404';
         header("HTTP/1.0 404 Not Found");
     } else {
         $code = '500';
         header("HTTP/1.0 500 Exception");
     }
     try {
         $extra = isset($_SERVER) ? ' $_SERVER: ' . print_r($_SERVER, 1) : ' no server';
         try {
             $extra .= "\n\nREQUEST HEADERS: " . \Lampcms\Request::getAllHeadersAsString() . "\n";
         } catch (\Exception $e) {
             // Unable to use Lampcms\Request class for some reason. Nothing we can do here
         }
         $extra .= "\nException class: " . get_class($e) . "\nMessage:" . $e->getMessage() . "\n in file: " . $e->getFile() . "\n line: " . $e->getLine() . "\n trace: " . $e->getTraceAsString();
         /**
          * @mail must be here before the Lampcms\Exception::formatException
          *       because Lampcms\Exception::formatException in case of ajax request will
          *       send out ajax and then throw \OutOfBoundsException in order to finish request (better than exit())
          */
         if (!$e instanceof \LogicException && $code >= 0 && defined('LAMPCMS_DEVELOPER_EMAIL') && strlen(trim(constant('LAMPCMS_DEVELOPER_EMAIL'))) > 7) {
             $subj = $code . ' Error in index.php';
             if (!is_object($Mailer) || $e instanceof \Lampcms\Mail\SwiftException || $e instanceof \Swift_SwiftException) {
                 @mail(LAMPCMS_DEVELOPER_EMAIL, $subj, $extra);
             } else {
                 try {