function _submit($stationTag = null) { if ($stationTag === null) { trace("brata missing stationId", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(400, "missing stationId"); // doesn't return } $station = Station::getFromTag($stationTag); if ($station === false) { trace("brata can't find station stationTag=" . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "can't find station stationTag=" . $stationTag); // doesn't return } $json = json_getObjectFromRequest("POST"); // won't return if an error happens json_checkMembers("message,team_id", $json); $team = Team::getFromPin($json['team_id']); if ($team === false) { trace("can't find team from team " . $json['team_id']); rest_sendBadRequestResponse(404, "can't find team pin=" . $json['team_id']); } $stationType = new StationType($station->get('typeId'), -1); if ($stationType === false) { trace("can't find station type stationTag = " . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find station type stationTag=" . $stationTag); } try { $xxxData = XXXData::factory($stationType->get('typeCode')); $msg = $xxxData->brataSubmit($json['message'], $team, $station, $stationType); json_sendObject(array('message' => $msg)); } catch (InternalError $ie) { rest_sendBadRequestResponse($ie->getCode(), $ie->getMessage()); } }
function _start_challenge($stationTag = null) { if ($stationTag === null) { rest_sendBadRequestResponse(400, "missing station Tag"); // doesn't return } $station = Station::getFromTag($stationTag); if ($station === false) { rest_sendBadRequestResponse(404, "can find station stationTag=" . $stationTag); // doesn't return } $stationType = new StationType($station->get('typeId'), -1); if ($stationType === false) { trace("can't find station type stationTag = " . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find station type stationTag=" . $stationTag); } $json = json_getObjectFromRequest("POST"); json_checkMembers("team_id,message", $json); $teamPIN = $json['team_id']; $team = Team::getFromPin($teamPIN); if ($team === false) { trace("_start_challenge can't find team teamPin=" . $teamPIN, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "team not found PIN=" . $teamPIN); // doesn't return } try { $xxxData = XXXData::factory($stationType->get('typeCode')); $msg = $xxxData->startChallenge($team, $station, $stationType); json_sendObject(array('message' => $msg)); } catch (InternalError $ie) { rest_sendBadRequestResponse($ie->getCode(), $ie->getMessage()); } }
function _time_expired($stationId = null) { if ($stationId === null) { rest_sendBadRequestResponse(400, "missing stationId"); } error_log("time expired\n", 3, "/var/tmp/m.log"); // todo update score? rest_sendBadRequestResponse(501, "not implemented"); }
function _cpaMeasure($stationTag = null) { if ($stationTag === null) { rest_sendBadRequestResponse(400, "missing station Tag"); // doesn't return } $station = Station::getFromTag($stationTag); if ($station === false) { rest_sendBadRequestResponse(404, "can find station stationTag=" . $stationTag); // doesn't return } $stationType = new StationType($station->get('typeId'), -1); if ($stationType === false) { trace("can't find station type stationTag = " . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find station type stationTag=" . $stationTag); } $json = json_getObjectFromRequest("POST"); json_checkMembers("team_id,message", $json); $teamPIN = $json['team_id']; $team = Team::getFromPin($teamPIN); if ($team === false) { trace("_cpaMeasure can't find team teamPin=" . $teamPIN, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "team not found PIN=" . $teamPIN); // doesn't return } $stationId = $station->get('OID'); $parms = null; // compute challenge parameters into a message switch ($stationType->get('typeCode')) { case StationType::STATION_TYPE_CPA: $random = new CPAData(); $parms = $random->getItemsToMeasure(); trace("CPA measure generated for team " . $teamPIN . " this data " . print_r($parms, true)); // record the challenge data randomly generated $team->setChallengeData($parms); break; default: trace("_cpaMeasure can't find station tyecode=" . $teamPIN, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "station tyecode not found =" . $stationType->get('typeCode')); // doesn't return } if (Event::createEvent(Event::TYPE_START, $team, $station, 0) === false) { trace("create event failed", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "database create failed"); } $msg = $team->expandMessage("PA is trying to escape. Quickly measure [fence=[label]] [building=[label]] and scan Start QR Code.", $parms); trace("message before decode {$msg}", __FILE__, __LINE__, __METHOD__); $msg = $team->encodeText($msg); json_sendObject(array('message' => $msg)); }
function startChallenge($team, $station, $stationType) { $this->retrieveRandom(); // now replace that object with a real ramdon object. $state = $this->generateParameters(); trace("state " . print_r($state, true), __FILE__, __LINE__, __METHOD__); $team->startFSLChallenge($state); if (Event::createEvent(Event::TYPE_START, $team, $station, 0, $state) === false) { trace("create event failed", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "database create failed"); } $msg = $team->expandMessage($stationType->get('instructions'), $state['msg_values']); $msg = $team->encodeText($msg); return $msg; }
function _time_sync() { trace("start", __FILE__, __LINE__, __METHOD__); $json = json_getObjectFromRequest("POST"); if ($json === null) { trace("missing json", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(400, "missing json"); // doesn't return } json_checkMembers("message", $json); $message = $json['message']; if ($message === null) { trace("missing message", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(400, "missing message"); // doesn't return } //$n = sscanf($message, "%d", $time); //list($time) = sscanf($message, "[time=%d]"); $n = substr_compare($message, "[time=", 0, 6, TRUE); if ($n == 0 and strlen($message) == 11) { $timestr = substr($message, 6, 4); $time = (int) $timestr; } else { trace("createEvent Failes", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(400, "expected format of [time=nnnn] where nnnn is a number greater than 42"); // doesn't return } if ($time === null) { trace("createEvent Failes", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(400, "expected format of [time=nnnn] where nnnn is a number greater than 42"); // doesn't return } if ($time <= 42) { trace("createEvent Failes", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(400, "The time stamp is invalid! Please try again."); // doesn't return json_sendBadRequestResponse("The time stamp is invalid! Please try again."); } json_sendObject(array('message' => "Your timestamp has been synced!")); }
function _join($stationTag = null) { try { if ($stationTag === false) { trace("stationTag not present", __FILE__, __LINE__, __METHOD__); throw new RestException(400, "stationTag not present"); } $station = Station::getFromTag($stationTag); if ($station === false) { trace("_join station not found stationTag=" . $stationTag, __FILE__, __LINE__, __METHOD__); throw new RestException(500, "station not found stationTag=" . $stationTag); } trace("tag=" . $stationTag . " station OID=" . $station->get('OID'), __FILE__, __LINE__, __METHOD__); $json = json_getObjectFromRequest("POST"); // if ($json === NULL) return; json_checkMembers("message_version,station_type,station_url", $json); $rpi = RPI::getFromStationId($station->get('OID')); if ($rpi === false) { // output $rpi = new RPI(); $rpi->set('stationId', $station->get('OID')); $rpi->set_contact_data($stationTag, $json); if ($rpi->create() === false) { trace("create failed", __FILE__, __LINE__, __METHOD__); throw new RestException(500, "join create failed"); } } else { $rpi->set_contact_data($stationTag, $json); if ($rpi->update() === false) { trace("update failed", __FILE__, __LINE__, __METHOD__); throw new RestException(500, "join update failed"); } } rest_sendSuccessResponse(202, "Accepted", "{$stationTag} has joined M"); } catch (RestException $e) { rest_sendBadRequestResponse($e->statusCode, $e->statusMsg); // doesn't return } }
function _register() { $json = json_getObjectFromRequest("POST"); json_checkMembers("team_id,message", $json); $teamPIN = $json['team_id']; if ($teamPIN === null) { trace("missing PIN", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(400, "missing team PIN"); // doesn't return } $team = Team::getFromPin($teamPIN); if ($team === false) { trace("_can't find team PIN=" . $teamPIN, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "missing can't find team PIN=" . $teamPIN); // doesn't return } // we are assuming that the QR code won't include the station tag. $station = Station::getRegistrationStation(); if ($station === false) { trace("can't find registration station", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find registration station"); } $points = 3; if (Event::createEvent(Event::TYPE_REGISTER, $team, $station, $points) === false) { trace("createEvent Fails", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "could not create event object"); } $stationType = StationType::getFromTypeCode($station->get('tag')); trace("registration complete", __FILE__, __LINE__, __METHOD__); $team->endChallenge(); // clear any stale challenge data $team->_updateScore($stationType, $points); $msg = $team->expandMessage($stationType->get('instructions'), null); $msg = $team->encodeText($msg); json_sendObject(array('message' => $msg)); }
function _at_waypoint($waypointId = null) { if ($waypointId === null) { rest_sendBadRequestResponse(400, "missing waypointId"); // doesn't return } $json = json_getObjectFromRequest("POST"); json_checkMembers("team_id,message", $json); $teamPIN = $json['team_id']; $team = Team::getFromPin($teamPIN); if ($team === false) { trace("can't find team PIN=" . $teamPIN, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "missing can't find team PIN=" . $teamPIN); // doesn't return } $stationType = StationType::getFSLType(); if ($stationType === false) { trace("can't find team PIN=" . $teamPIN, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find the FSL StationType"); // doesn't return } $fslState = $team->getChallengeData(); switch ($fslState['index']) { case 0: // use "default" messages for waypoints 1 and 2 // use "default" messages for waypoints 1 and 2 case 1: break; case 2: // for waypoint 2 change success and failed messages, keep retry message the same $stationType->set('success_msg', 'Success! Use [radius1=[a_rad]], [radius2=[b_rad]], and [radius3=[c_rad]]. Find Secret Labatory marker.'); $stationType->set('failed_msg', 'Too bad, you failed. Use [radius1=[a_rad]], [radius2=[b_rad]], and [radius3=[c_rad]]. Find Secret Labatory marker'); break; case 3: // for the lab change $stationType->set('success_msg', 'Success! go quickly to the next queue'); $stationType->set('retry_msg', 'Wrong secret Laboratory marker, try again!'); $stationType->set('failed_msg', 'Too bad, you failed. Go quickly to the next queue.'); } $count = $team->get('count'); $isCorrect = FSLData::isMatch($fslState, $waypointId); $challengeComplete = false; $points = 1; // one for showing up if ($count >= 2) { $points = 2; // two for pushing all the way through } if ($isCorrect) { $points = 3; // full credit regardless of tries if get it right } if ($isCorrect || $count >= 2) { $team->updateFSLScore($points, $fslState['index']); $challengeComplete = !FSLData::nextSection($fslState); $team->set('count', 0); } else { $team->set('count', $count + 1); } $team->setChallengeData($fslState); // put the update state data back into the team object $team->update(); if ($challengeComplete) { $team->endChallenge(); } if ($isCorrect) { $msg = $stationType->get('success_msg'); } else { if ($count >= 2) { $msg = $stationType->get('failed_msg'); } else { $msg = $stationType->get('retry_msg'); } } $msg = $team->expandMessage($msg, $fslState['msg_values']); $msg = $team->encodeText($msg); $json = array("message" => $msg); json_sendObject($json); }
function startChallenge($team, $station, $stationType) { $this->fetchData($station->get('OID')); // polymorphic callback to derived class // putcomputed challenge parameters into a php hash which will be sent to rPI and used to populate message sent to team $parms = null; if ($stationType->get('typeCode') == StationType::STATION_TYPE_CPA) { $parms = $team->getChallengeData(); trace("CPA startChallenge for team " . $team->getPin() . " with " . print_r($parms, true)); } else { $parms = $this->generateParameters(); // polymorphic callback to derivce class } $rpi = null; if ($stationType->get('hasrPI')) { $rpi = RPI::getFromStationId($station->get('OID')); if ($rpi === false) { trace("_start_challenge can't find RPI stationTag=" . $stationTag, __FILE__, __LINE__, __METHOD__); throw new InternalError("can't find RPI stationTag=" . $stationTag); } $rpi->start_challenge($stationType->get('delay'), $parms); } //TODO transaction $this->markTeamAtStation($team, $station); // polymorphic callback so we know which team is at this station $this->teamStartChallenge($team, $parms); // polymorphic callback to derived class if (Event::createEvent(Event::TYPE_START, $team, $station, 0, $parms) === false) { trace("create event failed", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "database create failed"); } $msg = $team->expandMessage($stationType->get('instructions'), $parms); $msg = $team->encodeText($msg); return $msg; }
function _start_challengeOLD($stationTag = null) { if ($stationTag === null) { rest_sendBadRequestResponse(400, "missing station Tag"); // doesn't return } $station = Station::getFromTag($stationTag); if ($station === false) { rest_sendBadRequestResponse(404, "can find station stationTag=" . $stationTag); // doesn't return } $stationType = new StationType($station->get('typeId'), -1); if ($stationType === false) { trace("can't find station type stationTag = " . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find station type stationTag=" . $stationTag); } if ($stationType->get('hasrPI')) { $rpi = RPI::getFromStationId($station->get('OID')); if ($rpi === false) { trace("_start_challenge can't find RPI stationTag=" . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find RPI stationTag=" . $stationTag); } } else { $rpi = null; } $json = json_getObjectFromRequest("POST"); json_checkMembers("team_id,message", $json); $teamPIN = $json['team_id']; $team = Team::getFromPin($teamPIN); if ($team === false) { trace("_start_challenge can't find team teamPin=" . $teamPIN, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "team not found PIN=" . $teamPIN); // doesn't return } $stationId = $station->get('OID'); $parms = null; // compute challenge parameters into a php hash which will be sent to rPI and used to populate message sent to team $state = null; switch ($stationType->get('typeCode')) { case StationType::STATION_TYPE_CTS: $parms = CTSData::_startChallenge($stationId); break; case StationType::STATION_TYPE_HMB: $parms = HMBData::_startChallenge($stationId); break; case StationType::STATION_TYPE_CPA: $parms = CPAData::_startChallenge($stationId); break; case StationType::STATION_TYPE_FSL: $state = FSLData::_startChallenge($stationId); $parms = $state['msg_values']; break; case StationType::STATION_TYPE_EXT: $state = EXTData::_startChallenge($stationId); $parms = $state; break; } if ($rpi != null) { trace("sending to rPI"); $rpi->start_challenge($stationType->get('delay'), $parms); } trace("station and team start calls"); //TODO transaction $station->startChallenge($team); $team->startChallenge($parms, $stationType->get('typeCode'), $state); // $state if (Event::createEvent(Event::TYPE_START, $team, $station, 0, $state) === false) { trace("create event failed", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "database create failed"); } $msg = $team->expandMessage($stationType->get('instructions'), $parms); if ($GLOBALS['SYSCONFIG_ENCODE'] == 1) { // if not in student mode encode, if in student mode we only encrypt the even team numbers responses if ($GLOBALS['SYSCONFIG_STUDENT'] == 0 or $GLOBALS['SYSCONFIG_STUDENT'] == 1 and $teamPIN % 2 == 0) { $msg = $team->encodeText($msg); } } json_sendObject(array('message' => $msg)); }
function _submit($stationTag = null) { if ($stationTag === null) { trace("brata missing stationId", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(400, "missing stationId"); // doesn't return } $station = Station::getFromTag($stationTag); if ($station === false) { trace("brata can't find station stationTag=" . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "can't find station stationTag=" . $stationTag); // doesn't return } $stationType = new StationType($station->get('typeId'), -1); if ($stationType === false) { trace("can't find station type stationTag = " . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find station type stationTag=" . $stationTag); } if ($stationType->get('hasrPI')) { $rpi = RPI::getFromStationId($station->get('OID')); if ($rpi === false) { trace("_submit can't find RPI stationTag=" . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find RPI stationTag=" . $stationTag); } } else { $rpi = null; } $json = json_getObjectFromRequest("POST"); // won't return if an error happens json_checkMembers("message,team_id", $json); $team = Team::getFromPin($json['team_id']); if ($team === false) { trace("can't find team from team " . $json['team_id']); rest_sendBadRequestResponse(404, "can't find team pin=" . $json['team_id']); } $count = $team->get('count'); $isCorrect = false; $challengeComplete = false; $matches = array(); // for regex matches switch ($stationType->get('typeCode')) { case StationType::STATION_TYPE_FSL: break; case StationType::STATION_TYPE_HMB: preg_match("/.*answer.*=.*(\\d)/", $json['message'], $matches); trace('calling handle_challenge'); $json = $rpi->handle_submission($stationType->get('delay'), $isCorrect, $challengeComplete); //TODO if ($json === false) ERROR??? //TODO json_checkMembers("message,team_id", $json); //$isCorrect=$json['is_correct']; break; case StationType::STATION_TYPE_EXT: $ext = new ExtData(1, -1); //TODO get from team $ext->submit($json['message'], $team); goto hack; } $count = $team->get('count'); $points = 3 - $count; $team->updateScore($stationType, $points); if (!$json['is_correct']) { $count++; $team->set('count', $count); $challenge_complete = $count < 3 ? false : true; } else { $challenge_complete = true; } if ($challenge_complete) { $station->endChallenge(); $team->endChallenge(); } if (Event::createEvent(Event::TYPE_SUBMIT, $team, $station, $points) === false) { trace("can't create event object", __FILE__, __LINE__, __METHOD__); json_sendBadRequestResponse(500, "Can't create event object"); } if ($isCorrect) { $msg = $stationType->get('success_msg'); } else { if ($count >= 3) { $msg = $stationType->get('failed_msg'); } else { $msg = $stationType->get('retry_msg'); } } $msg = $team->expandMessage($msg, $parms); if ($GLOBALS['SYSCONFIG_ENCODE'] == 1) { // if not in student mode encode, if in student mode we only encrypt the even team numbers responses if ($GLOBALS['SYSCONFIG_STUDENT'] == 0 or $GLOBALS['SYSCONFIG_STUDENT'] == 1 and $teamPIN % 2 == 0) { $msg = $team->encodeText($msg); } } hack: json_sendObject(array('message' => $msg)); }
function _submit($stationTag = null) { if ($stationTag === null) { trace("missing station id"); rest_sendBadRequestResponse(401, "missing stationId"); // doesn't return } $station = Station::getFromTag($stationTag); if ($station === false) { trace("can't find station from tag"); rest_sendBadRequestResponse(404, "can find station stationTag=" . $stationTag); // doesn't return } $team = new Team($station->get('teamAtStation'), -1); if ($team === false) { trace("can't find team", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(404, "can find team at station stationTag=" . $stationTag . " teamId=" . $team->get('OID')); // doesn't return } $stationType = new StationType($station->get('typeId'), -1); if ($stationType === false) { trace("can't find station type stationTag = " . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find station type stationTag=" . $stationTag); } $rpi = RPI::getFromStationId($station->get('OID')); if ($rpi === false) { trace("_start_challenge can't find RPI stationTag=" . $stationTag, __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "can't find RPI stationTag=" . $stationTag); } $json = json_getObjectFromRequest("POST"); // won't return if an error happens json_checkMembers("candidate_answer,is_correct,fail_message", $json); $count = $team->get('count'); $team->setChallengeData($json); trace("count=" . $count); $points = 3 - $count; if (!$json['is_correct']) { $count++; $team->set('count', $count); trace("count=" . $count); $challenge_complete = $count > 2; $team->_updateScore($stationType, 0); //TODO add legacy update score } else { $challenge_complete = true; } if ($challenge_complete) { switch ($stationType->get('typeCode')) { case StationType::STATION_TYPE_HMB: // Leave scoring up to brata submit for CPA and CTS but HMB needs it $team->_updateScore($stationType, $points); $station->endChallenge(); $team->endChallenge(); break; default: // FSL does not have pi, CPA and CTS not done until scan last qr // so technically challenge not complete until the brata submit break; } } if (Event::createEvent(Event::TYPE_SUBMIT, $team, $station, $points) === false) { trace("create event failed " . $team->get('OID') . " " . $station->get('OID'), __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "database create failed"); } $json = array("message_version" => 0, "message_timestamp" => date("Y-m-d H:i:s"), "theatric_delay_ms" => $stationType->get('delay'), "challenge_complete" => $challenge_complete); json_sendObject($json); }
function brataSubmit($msg, $team, $station, $stationType) { $isCorrect = false; $challengeComplete = false; $json = $team->getChallengeData(); trace("the jsons is" . print_r($json, true)); $this->rs['_1st_on'] = $json['hmb_vibration_pattern_ms'][0]; $this->rs['_1st_off'] = $json['hmb_vibration_pattern_ms'][1]; $this->rs['_2nd_on'] = $json['hmb_vibration_pattern_ms'][2]; $this->rs['_2nd_off'] = $json['hmb_vibration_pattern_ms'][3]; $this->rs['_3rd_on'] = $json['hmb_vibration_pattern_ms'][4]; $this->rs['_3rd_off'] = $json['hmb_vibration_pattern_ms'][5]; // $this->rs['cycle'] = $json['hmb_vibration_pattern_ms'][6]; $count = $team->get('count'); $points = 1; // 1 for showing up $team->set('count', $count + 1); $team->updateHMBScore(0); // save count $isCorrect = $this->testSolution($msg); $challengeComplete = $count + 1 < 3 ? false : true; if ($challengeComplete) { $points = 2; } if ($isCorrect) { $points = 3; } $rpi = RPI::getFromStationId($station->get('OID')); if ($rpi != null) { $json = $rpi->handle_hmb_submission($stationType->get('delay'), $isCorrect, $challengeComplete); } else { trace("RPI null not allowed for HMB configuration see admin for DB integrity check.", __FILE__, __LINE__, __METHOD__); rest_sendBadRequestResponse(500, "MS DB configuration is suspect as HMB requires an RPI."); } trace("count before update = " . $count); $team->updateHMBScore($points); if ($challengeComplete) { $station->endChallenge(); $team->endChallenge(); } if (Event::createEvent(Event::TYPE_SUBMIT, $team, $station, $points) === false) { trace("can't create event object", __FILE__, __LINE__, __METHOD__); throw new InternalError("Can't create event object"); } if ($isCorrect) { $msg = $stationType->get('success_msg'); } else { if ($count >= 2) { $msg = $stationType->get('failed_msg'); } else { $msg = $stationType->get('retry_msg'); } } //$msg = $team->expandMessage($msg, $parms ); // nothing to expand $msg = $team->encodeText($msg); return $msg; }