public void ProcessSample(string line, SolarixGrammarEngineNET.AnalysisResults tokens, int left_i, SolarixGrammarEngineNET.GrammarEngine2 gren)
    {
        // В контекст входят слова от left_i по left_i+ctx.len.

        /*
         * // ---- DEBUG
         * System.Text.StringBuilder b = new StringBuilder();
         * for( int i=0; i<ctx.len; ++i )
         * if( i>0 )
         *  b.AppendFormat( " {0}", tokens[left_i+i].GetWord() );
         * else
         *  b.AppendFormat( "{0}", tokens[left_i+i].GetWord() );
         *
         * string context_str = b.ToString();
         * // --- END DEBUG
         */

        // ... todo проверяем, не сопоставляются ли слова с уже имеющимися контекстами.
        for (int i = 0; i < recognizers.Count; ++i)
        {
            ContextRecognizer recognizer = recognizers[i];
            int match = recognizer.Match(tokens, left_i, gren);
            if (match == 1)
            {
                // правило правильно распознало контекст и сняло омонимию.
                recognizer.Success(new MatchedContextInfo(line, tokens, left_i, ctx.len));
            }
            else if (match == 0)
            {
                // правило распознало контекст, но неправильно сняло омонимию.
                recognizer.Fail(new MatchedContextInfo(line, tokens, left_i, ctx.len));
            }
        }

        // Используем сэмпл для генерации правил только в том случае, если омонимичный токен дал 1 вариант словарной статьи.
        bool generate_rule = true;
        int  omonym_ekey   = -1;

        SolarixGrammarEngineNET.SyntaxTreeNode omonym_token = tokens[left_i + ctx.position];
        int omonym_versions = omonym_token.VersionCount();

        for (int iver = 0; iver < omonym_versions; ++iver)
        {
            int ekey = omonym_token.GetVersionEntryID(iver);
            if (omonym_ekey == -1)
            {
                omonym_ekey = ekey;
            }
            else if (omonym_ekey != ekey)
            {
                // омонимичный токен распознан как несколько разных лемм, поэтому не будет генерировать для него правила.
                generate_rule = false;
                break;
            }
        }

        if (generate_rule)
        {
            // Генерируем варианты распознавания контекста, начиная от самого конкретного - через лексемы не-мононимичных слов, для самых
            // общих - частей речи для них же.
            OmonymContextEnumerator ctx_generator = new OmonymContextEnumerator(tokens, ctx.position, left_i, ctx.len, gren);

            for (int i = 0; i < ctx_generator.Count; ++i)
            {
                ContextRecognizer recognizer = ctx_generator[i];

                // проверим, что такого распознавателя еще нет.
                bool is_unique = true;
                foreach (ContextRecognizer r in recognizers)
                {
                    if (r.EqualTokens(recognizer))
                    {
                        is_unique = false;
                        break;
                    }
                }

                if (is_unique)
                {
                    recognizer.Success(new MatchedContextInfo(line, tokens, left_i, ctx.len));
                    recognizers.Add(recognizer);
                }
            }
        }

        return;
    }