智能闲聊.

基于文本的基础聊天能力，可以让您的应用快速拥有具备上下文语义理解的机器聊天功能.

@param string $question 上限300字节
@param string $session  上限32字节

@throws TencentAIException

@return array

@see   https://ai.qq.com/doc/nlpchat.shtml
326838
public function chat(string $question, string $session)
    {
        return Request::exec(self::CHAT, compact('question', 'session'));
    }
1068163
private static function setSessionId($sessionId){
        $sessionId = trim($sessionId);

        // 非法字符处理
        if (!$sessionId || preg_match("/[^0-9a-z_\\-\\,]/i", $sessionId)) {
            return false;
        }

        $sessionId = substr($sessionId, 0, 40);
        session_id($sessionId);

        return $sessionId;
    }
271848
function query( $request, $content = '', $doSpeedCheck = 0 )
	{
		$this->error = $this->warn = array();
		$this->result_status_code = NULL;

		$is_ssl = FALSE;

		// is our request a http:// ... ?
		if (preg_match('!^http://!i',$request) || preg_match('!^https://!i',$request))
		{
			$location = parse_url($request);
			if (preg_match('!^https://!i',$request))
			{
				$this->connect('https://'.$location['host'],$location['port']);
			}
			else
				$this->connect('http://'.$location['host'],$location['port']);

			$this->set_login($location['user'],$location['pass']);

			$request = $location['path'];
			$content = $location['query'];

			if ( strlen($request) < 1 )
			{
				$request = '/';
			}

		}

		if (preg_match('!^ssl://!i', $this->remote_host))
			$this->remote_host = 'https://'.substr($this->remote_host, 6);

		if (preg_match('!^tcp://!i', $this->remote_host))
			$this->remote_host = 'http://'.substr($this->remote_host, 6);

		if (preg_match('!^https://!i', $this->remote_host))
			$is_ssl = TRUE;

		$array_headers = array(
			'Host' => ( $this->remote_port == 80 ? $this->remote_host : "$this->remote_host:$this->remote_port" ),
			'Accept' => '*/*',
			'Connection' => 'Close' );

		foreach ( $this->extra_headers as $key => $value )
		{
			$array_headers[$key] = $value;
		}

		$this->result = $this->result_header = $this->result_body = '';

		// was content sent as an array? if so, turn it into a string
		if (is_array($content))
		{
			$pairs = array();

			foreach ( $content as $key => $value )
			{
				$pairs[] = "$key=".urlencode($value);
			}

			$content = join('&',$pairs);
			unset($pairs);
		}

		$OK = TRUE;

		if ($this->method == 'GET')
			$request .= '?'.$content;

		$ch = curl_init($this->remote_host.':'.$this->remote_port.$request);

		if ($is_ssl)
		{
			curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //1
			curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); //2
			//curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
		}

		curl_setopt($ch, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
		curl_setopt($ch, CURLOPT_USERAGENT, "DirectAdmin/$this->version");
		curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
		curl_setopt($ch, CURLOPT_TIMEOUT, 10);
		curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
		curl_setopt($ch, CURLOPT_HEADER, 1);

		curl_setopt($ch, CURLOPT_LOW_SPEED_LIMIT, 51200);
		curl_setopt($ch, CURLOPT_LOW_SPEED_TIME, 5);

		//if ($this->doFollowLocationHeader)
		//{
		//	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, TRUE);
		//	curl_setopt($ch, CURLOPT_MAXREDIRS, $this->max_redirects);
		//}

		// instance connection
		if ($this->bind_host)
		{
			curl_setopt($ch, CURLOPT_INTERFACE, $this->bind_host);
		}

		// if we have a username and password, add the header
		if ( isset($this->remote_uname) && isset($this->remote_passwd) )
		{
			curl_setopt($ch, CURLOPT_USERPWD, $this->remote_uname.':'.$this->remote_passwd);
		}

		// for DA skins: if $this->remote_passwd is NULL, try to use the login key system
		if ( isset($this->remote_uname) && $this->remote_passwd == NULL )
		{
			$array_headers['Cookie'] = "session={$_SERVER['SESSION_ID']}; key={$_SERVER['SESSION_KEY']}";
		}

		// if method is POST, add content length & type headers
		if ( $this->method == 'POST' )
		{
			curl_setopt($ch, CURLOPT_POST, 1);
			curl_setopt($ch, CURLOPT_POSTFIELDS, $content);

			//$array_headers['Content-type'] = 'application/x-www-form-urlencoded';
			$array_headers['Content-length'] = strlen($content);
		}

		curl_setopt($ch, CURLOPT_HTTPHEADER, $array_headers);


		if( !($this->result = curl_exec($ch)) )
		{
			$this->error[] .= curl_error($ch);
			$OK = FALSE;
		}

		$header_size			= curl_getinfo($ch, CURLINFO_HEADER_SIZE);
		$this->result_header	= substr($this->result, 0, $header_size);
		$this->result_body		= substr($this->result, $header_size);
		$this->result_status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);

		$this->lastTransferSpeed = curl_getinfo($ch, CURLINFO_SPEED_DOWNLOAD) / 1024;

		curl_close($ch);

		$this->query_cache[] = $this->remote_host.':'.$this->remote_port.$request;

		$headers = $this->fetch_header();

		// did we get the full file?
		if ( !empty($headers['content-length']) && $headers['content-length'] != strlen($this->result_body) )
		{
			$this->result_status_code = 206;
		}

		// now, if we're being passed a location header, should we follow it?
		if ($this->doFollowLocationHeader)
		{
			//dont bother if we didn't even setup the script correctly
			if (isset($headers['x-use-https']) && $headers['x-use-https']=='yes')
				die($this->ssl_setting_message);

			if (isset($headers['location']))
			{
				if ($this->max_redirects <= 0)
					die("Too many redirects on: ".$headers['location']);

				$this->max_redirects--;
				$this->redirectURL = $headers['location'];
				$this->query($headers['location']);
			}
		}

	}
995366
public function matchStatement($translatorevent, $questionAttempt, $question) {

        $translatorevent['interaction_type'] = 'matching';

        $targets = [];
        $sources = [];
        $correctResponses = [];
        $responseTargetsPos = [];
        $responseSourcesPos = [];

        foreach ($question->match->subquestions as $subquestion) {
            $target = strip_tags($subquestion->questiontext);
            $source = strip_tags($subquestion->answertext);
            $targetId = 'moodle_quiz_question_target_'.$subquestion->id;
            $sourceId = 'moodle_quiz_question_source_'.$subquestion->id;
            $targets[$targetId] = $target;
            $sources[$sourceId] = $source;
            array_push(
                $correctResponses, 
                $sourceId.'[.]'.$targetId
            );

            // Get the positions of the target and source within the response string.
            $responseTargetsPos[strpos($questionAttempt->responsesummary, $target)] = $targetId;
            $responseSourcesPos[strpos($questionAttempt->responsesummary, $source)] = $sourceId;
        }

        // Get ordered and indexed lists of target and source.
        ksort($responseTargetsPos);
        $responseTargets = array_values($responseTargetsPos);
        ksort($responseSourcesPos);
        $responseSources = array_values($responseSourcesPos);

        $translatorevent['attempt_response'] = '';
        if (count($responseTargets) == count($responseSources) && count($responseTargets) > 0) {
            $responses = [];
            foreach ($responseTargets as $index => $targetId) {
                array_push(
                    $responses,
                    $responseSources[$index].'[.]'.$targetId
                );
            }
            $translatorevent['attempt_response'] = implode('[,]', $responses);
        }

        $translatorevent['interaction_target'] = $targets;
        $translatorevent['interaction_source'] = $sources;
        $translatorevent['interaction_correct_responses'] = [implode('[,]', $correctResponses)];

        return $translatorevent;
    }
1166125
public QuestionStructure getMainPart(String question, List<edu.stanford.nlp.ling.Word> words) {
        QuestionStructure questionStructure = new QuestionStructure();
        questionStructure.setQuestion(question);

        Tree tree = LP.apply(words);
        LOG.info("句法树: ");
        tree.pennPrint();
        questionStructure.setTree(tree);

        GrammaticalStructure gs = GSF.newGrammaticalStructure(tree);
        if(gs == null){
            return null;
        }
        //获取依存关系
        Collection<TypedDependency> tdls = gs.typedDependenciesCCprocessed(true);
        questionStructure.setTdls(tdls);
        Map<String, String> map = new HashMap<>();
        String top = null;
        String root = null;
        LOG.info("句子依存关系：");
        //依存关系
        List<String> dependencies = new ArrayList<>();
        for (TypedDependency tdl : tdls) {
            String item = tdl.toString();
            dependencies.add(item);
            LOG.info("\t" + item);
            if (item.startsWith("top")) {
                top = item;
            }
            if (item.startsWith("root")) {
                root = item;
            }
            int start = item.indexOf("(");
            int end = item.lastIndexOf(")");
            item = item.substring(start + 1, end);
            String[] attr = item.split(",");
            String k = attr[0].trim();
            String v = attr[1].trim();
            String value = map.get(k);
            if (value == null) {
                map.put(k, v);
            } else {
                //有值
                value += ":";
                value += v;
                map.put(k, value);
            }
        }
        questionStructure.setDependencies(dependencies);

        String mainPartForTop = null;
        String mainPartForRoot = null;
        if (top != null) {
            mainPartForTop = topPattern(top, map);
        }
        if (root != null) {
            mainPartForRoot = rootPattern(root, map);
        }
        questionStructure.setMainPartForTop(mainPartForTop);
        questionStructure.setMainPartForRoot(mainPartForRoot);

        if (questionStructure.getMainPart() == null) {
            LOG.error("未能识别主谓宾：" + question);
        } else {
            LOG.info("主谓宾：" + questionStructure.getMainPart());
        }
        return questionStructure;
    }
540845
protected function get_array_of_placeholders($question) {
        $qtext = $question->questiontext;
        $error = '<b> ERROR</b>: Please check the form for this question. ';
        if (!$qtext) {
            echo $error . 'The question text is empty!';
            return false;
        }

        // Get the slots.
        $slots = $this->getEmbeddedTextArray($question);

        if (!$slots) {
            echo $error . 'The question text is not in the correct format!';
            return false;
        }

        $output = array();
        foreach ($slots as $slot) {
            $output[] = substr($slot, 2, strlen($slot) - 4); // 2 is for '[[' and 4 is for '[[]]'.
        }
        return $output;
    }
151003
public function getMissingQuestions(SessionConfigurationInterface $configuration)
    {
        /** @var QuestionRepository $questionRepository */
        $questionRepository = $this->manager->getRepository('QcmPublicBundle:Question');
        $missingQuestions = $configuration->getMaxQuestions() - $configuration->getQuestions()->count();

        if ($missingQuestions > 0) {
            $questions = $questionRepository->getMissingQuestions(
                $configuration->getCategories(),
                $missingQuestions,
                $configuration->getQuestions(),
                $configuration->getQuestionsLevel()
            );

            /** @var QuestionInterface $question */
            foreach ($questions as $question) {
                foreach ($question->getAnswers() as $answer) {
                    $question->addAnswer($answer);
                }
                $configuration->addQuestion($question);
            }
        }

        $missingQuestions = $configuration->getMaxQuestions() - $configuration->getQuestions()->count();

        if ($missingQuestions > 0) {
            $this->flashBag->add('danger', $this->translation->trans('qcm_core.questions.missing', array(
                '%questions%' => $missingQuestions
            )));
        }

        return $this;
    }
69282
public function ask(SimpleQuestion $question)
    {
        return $this->question->ask(
            $this->input,
            $this->output,
            new Question(
                $this->buildQuestionText($question),
                $this->getPreResponse($question)
            )
        );
    }
844938
protected function recode_legacy_response_data($question, $qsession, $qstates) {
        $qsession->questionid = $question->id;

        foreach ($qstates as &$state) {
            $state->question = $question->id;
            $state->answer = $this->restore_recode_legacy_answer($state, $question->qtype);
        }

        return array($qsession, $qstates);
    }
1347355
function query( $request, $content = '', $doSpeedCheck = 0 )
    {
        $this->error = $this->warn = array();
        $this->result_status_code = NULL;

        // is our request a http(s):// ... ?
        if (preg_match('/^(http|https):\/\//i',$request))
        {
            $location = parse_url($request);
            $this->connect($location['host'],$location['port']);
            $this->set_login($location['user'],$location['pass']);

            $request = $location['path'];
            $content = $location['query'];

            if ( strlen($request) < 1 )
            {
                $request = '/';
            }

        }

        $array_headers = array(
            'User-Agent' => "HTTPSocket/$this->version",
            'Host' => ( $this->remote_port == 80 ? parse_url($this->remote_host,PHP_URL_HOST) : parse_url($this->remote_host,PHP_URL_HOST).":".$this->remote_port ),
            'Accept' => '*/*',
            'Connection' => 'Close' );

        foreach ( $this->extra_headers as $key => $value )
        {
            $array_headers[$key] = $value;
        }

        $this->result = $this->result_header = $this->result_body = '';

        // was content sent as an array? if so, turn it into a string
        if (is_array($content))
        {
            $pairs = array();

            foreach ( $content as $key => $value )
            {
                $pairs[] = "$key=".urlencode($value);
            }

            $content = join('&',$pairs);
            unset($pairs);
        }

        $OK = TRUE;

        // instance connection
        if ($this->bind_host)
        {
            $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
            socket_bind($socket,$this->bind_host);

            if (!@socket_connect($socket,$this->remote_host,$this->remote_port))
            {
                $OK = FALSE;
            }

        }
        else
        {
            $socket = @fsockopen( $this->remote_host, $this->remote_port, $sock_errno, $sock_errstr, 10 );
        }

        if ( !$socket || !$OK )
        {
            $this->error[] = "Can't create socket connection to $this->remote_host:$this->remote_port.";
            return 0;
        }

        // if we have a username and password, add the header
        if ( isset($this->remote_uname) && isset($this->remote_passwd) )
        {
            $array_headers['Authorization'] = 'Basic '.base64_encode("$this->remote_uname:$this->remote_passwd");
        }

        // for DA skins: if $this->remote_passwd is NULL, try to use the login key system
        if ( isset($this->remote_uname) && $this->remote_passwd == NULL )
        {
            $array_headers['Cookie'] = "session={$_SERVER['SESSION_ID']}; key={$_SERVER['SESSION_KEY']}";
        }

        // if method is POST, add content length & type headers
        if ( $this->method == 'POST' )
        {
            $array_headers['Content-type'] = 'application/x-www-form-urlencoded';
            $array_headers['Content-length'] = strlen($content);
        }
        // else method is GET or HEAD. we don't support anything else right now.
        else
        {
            if ($content)
            {
                $request .= "?$content";
            }
        }

        // prepare query
        $query = "$this->method $request HTTP/1.0\r\n";
        foreach ( $array_headers as $key => $value )
        {
            $query .= "$key: $value\r\n";
        }
        $query .= "\r\n";

        // if POST we need to append our content
        if ( $this->method == 'POST' && $content )
        {
            $query .= "$content\r\n\r\n";
        }

        // query connection
        if ($this->bind_host)
        {
            socket_write($socket,$query);

            // now load results
            while ( $out = socket_read($socket,2048) )
            {
                $this->result .= $out;
            }
        }
        else
        {
            fwrite( $socket, $query, strlen($query) );

            // now load results
            $this->lastTransferSpeed = 0;
            $status = socket_get_status($socket);
            $startTime = time();
            $length = 0;
            while ( !feof($socket) && !$status['timed_out'] )
            {
                $chunk = fgets($socket,1024);
                $length += strlen($chunk);
                $this->result .= $chunk;

                $elapsedTime = time() - $startTime;

                if ( $elapsedTime > 0 )
                {
                    $this->lastTransferSpeed = ($length/1024)/$elapsedTime;
                }

                if ( $doSpeedCheck > 0 && $elapsedTime > 5 && $this->lastTransferSpeed < $doSpeedCheck )
                {
                    $this->warn[] = "kB/s for last 5 seconds is below 50 kB/s (~".( ($length/1024)/$elapsedTime )."), dropping connection...";
                    $this->result_status_code = 503;
                    break;
                }

            }

            if ( $this->lastTransferSpeed == 0 )
            {
                $this->lastTransferSpeed = $length/1024;
            }

        }

        list($this->result_header,$this->result_body) = preg_split("/\r\n\r\n/",$this->result,2);

        if ($this->bind_host)
        {
            socket_close($socket);
        }
        else
        {
            fclose($socket);
        }

        $this->query_cache[] = $query;


        $headers = $this->fetch_header();

        // what return status did we get?
        if (!$this->result_status_code)
        {
            preg_match("#HTTP/1\.. (\d+)#",$headers[0],$matches);
            $this->result_status_code = $matches[1];
        }

        // did we get the full file?
        if ( !empty($headers['content-length']) && $headers['content-length'] != strlen($this->result_body) )
        {
            $this->result_status_code = 206;
        }

        // now, if we're being passed a location header, should we follow it?
        if ($this->doFollowLocationHeader)
        {
            if ($headers['location'])
            {
                $this->redirectURL = $headers['location'];
                $this->query($headers['location']);
            }
        }
    }
1367625
public static function create_from_question_instance($question, $context = null, $other = null) {

        $params = ['objectid' => $question->id, 'other' => ['categoryid' => $question->category]];

        if (!empty($question->contextid)) {
            $params['contextid'] = $question->contextid;
        }

        $params['context'] = $context;

        if (!empty($other)) {
            $params['other'] = $other;
        }

        $event = self::create($params);
        return $event;
    }
1110731
private static function storage($session)
    {
        //Initiat the class
        static::session($session);

        $files = ['Storage'];
        $folder = static::$root.'Storage'.'/';

        self::call($files, $folder);

        $files = ['NotFoundStorageDiskException'];
        $folder = static::$root.'Storage/Exceptions'.'/';

        self::call($files, $folder);
    }
1045635
public function onSwooleRequest($request, $response)
    {
        if (Start::$testUnity) {
            $server_port = $request->server_port;
        } else {
            $server_port = $this->getServerPort($request->fd);
        }

        $middleware_names = $this->portManager->getMiddlewares($server_port);
        $context = [];
        $path = $request->server['path_info'];
        $middlewares = $this->middlewareManager->create($middleware_names, $context, [$request, $response], true);
        //before
        try {
            $this->middlewareManager->before($middlewares);
            //client_data进行处理
            $route = $this->portManager->getRoute($server_port);
            try {
                $route->handleClientRequest($request);
                $controller_name = $route->getControllerName();
                $method_name = $this->portManager->getMethodPrefix($server_port) . $route->getMethodName();
                $path = $route->getPath();
                if ($route->getMethodName() == ConsulHelp::HEALTH) {//健康检查
                    $response->end('ok');
                } else {
                    $controller_instance = ControllerFactory::getInstance()->getController($controller_name);
                    if ($controller_instance != null) {
                        $controller_instance->setContext($context);
                        $controller_instance->setRequestResponse($request, $response, $controller_name, $method_name, $route->getParams());
                    } else {
                        throw new \Exception('no controller');
                    }
                }
            } catch (\Throwable $e) {
                $route->errorHttpHandle($e, $request, $response);
            }
        } catch (\Exception $e) {
            //被中断
        }
        //after
        try {
            $this->middlewareManager->after($middlewares, $path);
        } catch (\Exception $e) {
            //被中断
        }
        $this->middlewareManager->destory($middlewares);
        if (Start::getDebug()) {
            secho("DEBUG", $context);
        }
        unset($context);
    }
144124
public function import_numerical($question) {
        // Get common parts.
        $qo = $this->import_headers($question);

        // Header parts particular to numerical.
        $qo->qtype = 'numerical';

        // Get answers array.
        $answers = $question['#']['answer'];
        $qo->answer = array();
        $qo->feedback = array();
        $qo->fraction = array();
        $qo->tolerance = array();
        foreach ($answers as $answer) {
            // Answer outside of <text> is deprecated.
            $obj = $this->import_answer($answer, false, $this->get_format($qo->questiontextformat));
            $qo->answer[] = $obj->answer['text'];
            if (empty($qo->answer)) {
                $qo->answer = '*';
            }
            $qo->feedback[]  = $obj->feedback;
            $qo->tolerance[] = $this->getpath($answer, array('#', 'tolerance', 0, '#'), 0);

            // Fraction as a tag is deprecated.
            $fraction = $this->getpath($answer, array('@', 'fraction'), 0) / 100;
            $qo->fraction[] = $this->getpath($answer,
                    array('#', 'fraction', 0, '#'), $fraction); // Deprecated.
        }

        // Get the units array.
        $qo->unit = array();
        $units = $this->getpath($question, array('#', 'units', 0, '#', 'unit'), array());
        if (!empty($units)) {
            $qo->multiplier = array();
            foreach ($units as $unit) {
                $qo->multiplier[] = $this->getpath($unit, array('#', 'multiplier', 0, '#'), 1);
                $qo->unit[] = $this->getpath($unit, array('#', 'unit_name', 0, '#'), '', true);
            }
        }
        $qo->unitgradingtype = $this->getpath($question, array('#', 'unitgradingtype', 0, '#'), 0);
        $qo->unitpenalty = $this->getpath($question, array('#', 'unitpenalty', 0, '#'), 0.1);
        $qo->showunits = $this->getpath($question, array('#', 'showunits', 0, '#'), null);
        $qo->unitsleft = $this->getpath($question, array('#', 'unitsleft', 0, '#'), 0);
        $qo->instructions['text'] = '';
        $qo->instructions['format'] = FORMAT_HTML;
        $instructions = $this->getpath($question, array('#', 'instructions'), array());
        if (!empty($instructions)) {
            $qo->instructions = $this->import_text_with_files($instructions,
                    array('0'), '', $this->get_format($qo->questiontextformat));
        }

        if (is_null($qo->showunits)) {
            // Set a good default, depending on whether there are any units defined.
            if (empty($qo->unit)) {
                $qo->showunits = 3; // This is qtype_numerical::UNITNONE, but we cannot refer to that constant here.
            } else {
                $qo->showunits = 0; // This is qtype_numerical::UNITOPTIONAL, but we cannot refer to that constant here.
            }
        }

        $this->import_hints($qo, $question, false, false, $this->get_format($qo->questiontextformat));

        return $qo;
    }
1293171
public function process_matching($quest, &$questions) {

        // Blackboard matching questions can't be imported in core Moodle without a loss in data,
        // as core match question don't allow HTML in subanswers. The contributed ddmatch
        // question type support HTML in subanswers.
        // The ddmatch question type is not part of core, so we need to check if it is defined.
        $ddmatchisinstalled = question_bank::is_qtype_installed('ddmatch');

        $question = $this->process_common($quest);
        $question = $this->add_blank_combined_feedback($question);
        $question->valid = true;
        if ($ddmatchisinstalled) {
            $question->qtype = 'ddmatch';
        } else {
            $question->qtype = 'match';
        }
        // Construction of the array holding mappings between subanswers and subquestions.
        foreach ($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
            foreach ($quest->responses as $rid => $resp) {
                if (isset($resp->ident) && $resp->ident == $subq->ident) {
                    $correct = $resp->correct;
                }
            }

            foreach ($subq->choices as $cid => $choice) {
                if ($choice == $correct) {
                    $mappings[$subq->ident] = $cid;
                }
            }
        }

        foreach ($subq->choices as $choiceid => $choice) {
            $subanswertext = $quest->RIGHT_MATCH_BLOCK->matchinganswerset[$choiceid]->text;
            if ($ddmatchisinstalled) {
                $subanswer = $this->cleaned_text_field($subanswertext);
            } else {
                $subanswertext = html_to_text($this->cleaninput($subanswertext), 0);
                $subanswer = $subanswertext;
            }

            if ($subanswertext != '') { // Only import non empty subanswers.
                $subquestion = '';

                $fiber = array_keys ($mappings, $choiceid);
                foreach ($fiber as $correctanswerid) {
                    // We have found a correspondance for this subanswer so we need to take the associated subquestion.
                    foreach ($quest->RESPONSE_BLOCK->subquestions as $qid => $subq) {
                        $currentsubqid = $subq->ident;
                        if (strcmp ($currentsubqid, $correctanswerid) == 0) {
                            $subquestion = $subq->text;
                            break;
                        }
                    }
                    $question->subquestions[] = $this->cleaned_text_field($subquestion);
                    $question->subanswers[] = $subanswer;
                }

                if ($subquestion == '') { // Then in this case, $choice is a distractor.
                    $question->subquestions[] = $this->text_field('');
                    $question->subanswers[] = $subanswer;
                }
            }
        }

        // Verify that this matching question has enough subquestions and subanswers.
        $subquestioncount = 0;
        $subanswercount = 0;
        $subanswers = $question->subanswers;
        foreach ($question->subquestions as $key => $subquestion) {
            $subquestion = $subquestion['text'];
            $subanswer = $subanswers[$key];
            if ($subquestion != '') {
                $subquestioncount++;
            }
            $subanswercount++;
        }
        if ($subquestioncount < 2 || $subanswercount < 3) {
                $this->error(get_string('notenoughtsubans', 'qformat_blackboard_six', $question->questiontext));
        } else {
            $questions[] = $question;
        }
    }
1127179
private function convertQuestion(Question $question)
    {
        $questionData = $question->toArray();

        $buttons = Collection::make($question->getButtons())->map(function ($button) {
            if ($button['type'] === 'select') {
                return $button;
            }

            return array_merge([
                'name' => $button['name'],
                'text' => $button['text'],
                'image_url' => $button['image_url'],
                'type' => $button['type'],
                'value' => $button['value'],
            ], $button['additional']);
        })->toArray();
        $questionData['actions'] = $buttons;

        return $questionData;
    }
1104434
public function import_calculated($question) {

        // Get common parts.
        $qo = $this->import_headers($question);

        // Header parts particular to calculated.
        $qo->qtype = 'calculated';
        $qo->synchronize = $this->getpath($question, array('#', 'synchronize', 0, '#'), 0);
        $single = $this->getpath($question, array('#', 'single', 0, '#'), 'true');
        $qo->single = $this->trans_single($single);
        $shuffleanswers = $this->getpath($question, array('#', 'shuffleanswers', 0, '#'), 'false');
        $qo->answernumbering = $this->getpath($question,
                array('#', 'answernumbering', 0, '#'), 'abc');
        $qo->shuffleanswers = $this->trans_single($shuffleanswers);

        $this->import_combined_feedback($qo, $question);

        $qo->unitgradingtype = $this->getpath($question,
                array('#', 'unitgradingtype', 0, '#'), 0);
        $qo->unitpenalty = $this->getpath($question, array('#', 'unitpenalty', 0, '#'), null);
        $qo->showunits = $this->getpath($question, array('#', 'showunits', 0, '#'), 0);
        $qo->unitsleft = $this->getpath($question, array('#', 'unitsleft', 0, '#'), 0);
        $qo->instructions = $this->getpath($question,
                array('#', 'instructions', 0, '#', 'text', 0, '#'), '', true);
        if (!empty($instructions)) {
            $qo->instructions = $this->import_text_with_files($instructions,
                    array('0'), '', $this->get_format($qo->questiontextformat));
        }

        // Get answers array.
        $answers = $question['#']['answer'];
        $qo->answer = array();
        $qo->feedback = array();
        $qo->fraction = array();
        $qo->tolerance = array();
        $qo->tolerancetype = array();
        $qo->correctanswerformat = array();
        $qo->correctanswerlength = array();
        $qo->feedback = array();
        foreach ($answers as $answer) {
            $ans = $this->import_answer($answer, true, $this->get_format($qo->questiontextformat));
            // Answer outside of <text> is deprecated.
            if (empty($ans->answer['text'])) {
                $ans->answer['text'] = '*';
            }
            $qo->answer[] = $ans->answer['text'];
            $qo->feedback[] = $ans->feedback;
            $qo->tolerance[] = $answer['#']['tolerance'][0]['#'];
            // Fraction as a tag is deprecated.
            if (!empty($answer['#']['fraction'][0]['#'])) {
                $qo->fraction[] = $answer['#']['fraction'][0]['#'];
            } else {
                $qo->fraction[] = $answer['@']['fraction'] / 100;
            }
            $qo->tolerancetype[] = $answer['#']['tolerancetype'][0]['#'];
            $qo->correctanswerformat[] = $answer['#']['correctanswerformat'][0]['#'];
            $qo->correctanswerlength[] = $answer['#']['correctanswerlength'][0]['#'];
        }
        // Get units array.
        $qo->unit = array();
        if (isset($question['#']['units'][0]['#']['unit'])) {
            $units = $question['#']['units'][0]['#']['unit'];
            $qo->multiplier = array();
            foreach ($units as $unit) {
                $qo->multiplier[] = $unit['#']['multiplier'][0]['#'];
                $qo->unit[] = $unit['#']['unit_name'][0]['#'];
            }
        }
        $instructions = $this->getpath($question, array('#', 'instructions'), array());
        if (!empty($instructions)) {
            $qo->instructions = $this->import_text_with_files($instructions,
                    array('0'), '', $this->get_format($qo->questiontextformat));
        }

        if (is_null($qo->unitpenalty)) {
            // Set a good default, depending on whether there are any units defined.
            if (empty($qo->unit)) {
                $qo->showunits = 3; // This is qtype_numerical::UNITNONE, but we cannot refer to that constant here.
            } else {
                $qo->showunits = 0; // This is qtype_numerical::UNITOPTIONAL, but we cannot refer to that constant here.
            }
        }

        $datasets = $question['#']['dataset_definitions'][0]['#']['dataset_definition'];
        $qo->dataset = array();
        $qo->datasetindex= 0;
        foreach ($datasets as $dataset) {
            $qo->datasetindex++;
            $qo->dataset[$qo->datasetindex] = new stdClass();
            $qo->dataset[$qo->datasetindex]->status =
                    $this->import_text($dataset['#']['status'][0]['#']['text']);
            $qo->dataset[$qo->datasetindex]->name =
                    $this->import_text($dataset['#']['name'][0]['#']['text']);
            $qo->dataset[$qo->datasetindex]->type =
                    $dataset['#']['type'][0]['#'];
            $qo->dataset[$qo->datasetindex]->distribution =
                    $this->import_text($dataset['#']['distribution'][0]['#']['text']);
            $qo->dataset[$qo->datasetindex]->max =
                    $this->import_text($dataset['#']['maximum'][0]['#']['text']);
            $qo->dataset[$qo->datasetindex]->min =
                    $this->import_text($dataset['#']['minimum'][0]['#']['text']);
            $qo->dataset[$qo->datasetindex]->length =
                    $this->import_text($dataset['#']['decimals'][0]['#']['text']);
            $qo->dataset[$qo->datasetindex]->distribution =
                    $this->import_text($dataset['#']['distribution'][0]['#']['text']);
            $qo->dataset[$qo->datasetindex]->itemcount = $dataset['#']['itemcount'][0]['#'];
            $qo->dataset[$qo->datasetindex]->datasetitem = array();
            $qo->dataset[$qo->datasetindex]->itemindex = 0;
            $qo->dataset[$qo->datasetindex]->number_of_items = $this->getpath($dataset,
                    array('#', 'number_of_items', 0, '#'), 0);
            $datasetitems = $this->getpath($dataset,
                    array('#', 'dataset_items', 0, '#', 'dataset_item'), array());
            foreach ($datasetitems as $datasetitem) {
                $qo->dataset[$qo->datasetindex]->itemindex++;
                $qo->dataset[$qo->datasetindex]->datasetitem[
                        $qo->dataset[$qo->datasetindex]->itemindex] = new stdClass();
                $qo->dataset[$qo->datasetindex]->datasetitem[
                        $qo->dataset[$qo->datasetindex]->itemindex]->itemnumber =
                                $datasetitem['#']['number'][0]['#'];
                $qo->dataset[$qo->datasetindex]->datasetitem[
                        $qo->dataset[$qo->datasetindex]->itemindex]->value =
                                $datasetitem['#']['value'][0]['#'];
            }
        }

        $this->import_hints($qo, $question, false, false, $this->get_format($qo->questiontextformat));

        return $qo;
    }