Beispiel #1
0
        // extracted from the .jj grammar
        protected internal virtual Query HandleBoost(Query q, Token boost)
        {
            if (boost != null)
            {
                float f = (float)1.0;
                try
                {
                    // LUCENENET NOTE: Apparently a "feature" of Lucene is to always
                    // use "." as the decimal specifier for boost, even if the culture uses
                    // a different one, such as ",".

                    // LUCENENET TODO: It would probably be more intuitive to use
                    // the current Locale to specify the decimal identifier than
                    // to hard code it to be ".", but this would differ from Java Lucene.
                    // Perhaps just make it a non-default option?
                    f = float.Parse(boost.Image, CultureInfo.InvariantCulture);
                }
                catch (Exception /*ignored*/)
                {
                    /* Should this be handled somehow? (defaults to "no boost", if
                     * boost number is invalid)
                     */
                }

                // avoid boosting null queries, such as those caused by stop words
                if (q != null)
                {
                    q.Boost = f;
                }
            }
            return(q);
        }
Beispiel #2
0
        protected override Query HandleBareTokenQuery(
            string field,
            Token termToken,
            Token slopToken,
            bool prefix,
            bool wildcard,
            bool fuzzy,
            bool regexp)
        {
            (bool IsFloat, bool IsInt) numericTypeGetter()
            {
                if (prefix || wildcard || regexp || fuzzy)
                {
                    return(false, false);
                }

                return(getNumericTypes(termToken.Image));
            }

            Query queryFactory(string fld, bool anazyed) =>
            base.HandleBareTokenQuery(fld, termToken, slopToken, prefix, wildcard, fuzzy, regexp);

            var result = resolveField(field, numericTypeGetter, queryFactory);

            return(result);
        }
Beispiel #3
0
        protected internal virtual Query HandleBareFuzzy(string qfield, Token fuzzySlop, string termImage)
        {
            Query q;
            float fms = FuzzyMinSim;

            try
            {
                // LUCENENET NOTE: Apparently a "feature" of Lucene is to always
                // use "." as the decimal specifier for fuzzy slop, even if the culture uses
                // a different one, such as ",".

                // LUCENENET TODO: It would probably be more intuitive to use
                // the current Locale to specify the decimal identifier than
                // to hard code it to be ".", but this would differ from Java Lucene.
                // Perhaps just make it a non-default option?
                fms = float.Parse(fuzzySlop.Image.Substring(1), CultureInfo.InvariantCulture);
            }
            catch (Exception /*ignored*/) { }
            if (fms < 0.0f)
            {
                throw new ParseException("Minimum similarity for a FuzzyQuery has to be between 0.0f and 1.0f !");
            }
            else if (fms >= 1.0f && fms != (int)fms)
            {
                throw new ParseException("Fractional edit distances are not allowed!");
            }
            q = GetFuzzyQuery(qfield, termImage, fms);
            return(q);
        }
Beispiel #4
0
        // extracted from the .jj grammar
        protected internal virtual Query HandleBareTokenQuery(string qfield, Token term, Token fuzzySlop, bool prefix, bool wildcard, bool fuzzy, bool regexp)
        {
            Query q;

            string termImage = DiscardEscapeChar(term.Image);

            if (wildcard)
            {
                q = GetWildcardQuery(qfield, term.Image);
            }
            else if (prefix)
            {
                q = GetPrefixQuery(qfield, DiscardEscapeChar(term.Image.Substring(0, term.Image.Length - 1)));
            }
            else if (regexp)
            {
                q = GetRegexpQuery(qfield, term.Image.Substring(1, term.Image.Length - 2));
            }
            else if (fuzzy)
            {
                q = HandleBareFuzzy(qfield, fuzzySlop, termImage);
            }
            else
            {
                q = GetFieldQuery(qfield, termImage, false);
            }
            return(q);
        }
Beispiel #5
0
 private void Jj_rescan_token()
 {
     jj_rescan = true;
     for (int i = 0; i < 1; i++)
     {
         try
         {
             JJCalls p = jj_2_rtns[i];
             do
             {
                 if (p.gen > jj_gen)
                 {
                     jj_la      = p.arg;
                     jj_lastpos = jj_scanpos = p.first;
                     switch (i)
                     {
                     case 0:
                         Jj_3_1();
                         break;
                     }
                 }
                 p = p.next;
             } while (p != null);
         }
         catch (LookaheadSuccess)
         {
         }
     }
     jj_rescan = false;
 }
Beispiel #6
0
 /// <summary>
 /// This constructor is used by the method GenerateParseException()
 /// in the generated parser.  Calling this constructor generates
 /// a new object of this type with the fields <paramref name="currentToken"/>,
 /// <paramref name="expectedTokenSequences"/>, and <paramref name="tokenImage"/> set.
 /// </summary>
 public ParseException(Token currentToken,
                 int[][] expectedTokenSequences,
                 string[] tokenImage)
     : base(Initialize(currentToken, expectedTokenSequences, tokenImage))
 {
     this.currentToken = currentToken;
     this.expectedTokenSequences = expectedTokenSequences;
     this.tokenImage = tokenImage;
 }
 /// <summary>
 /// This constructor is used by the method "GenerateParseException"
 /// in the generated parser.  Calling this constructor generates
 /// a new object of this type with the fields "currentToken",
 /// "expectedTokenSequences", and "tokenImage" set.
 /// </summary>
 /// <param name="currentTokenVal"></param>
 /// <param name="expectedTokenSequencesVal"></param>
 /// <param name="tokenImageVal"></param>
 public ParseException(Token currentTokenVal,
     int[][] expectedTokenSequencesVal,
     string[] tokenImageVal)
     : base(Initialize(currentTokenVal, expectedTokenSequencesVal, tokenImageVal))
 {
     currentToken = currentTokenVal;
     expectedTokenSequences = expectedTokenSequencesVal;
     tokenImage = tokenImageVal;
 }
Beispiel #8
0
        protected override Query GetComplexPhraseQuery(string field, Token fuzzySlop, string phrase)
        {
            if (_adapter.IsNumericField(field))
            {
                return(_matchNothingQuery);
            }

            return(base.GetComplexPhraseQuery(field, fuzzySlop, phrase));
        }
Beispiel #9
0
        protected override Query HandleBareFuzzy(string field, Token slopToken, string termImage)
        {
            (bool IsFloat, bool IsInt) numericTypeGetter() => (false, false);
            Query queryFactory(string fld, bool anazyed) => base.HandleBareFuzzy(fld, slopToken, termImage);

            var result = resolveField(field, numericTypeGetter, queryFactory);

            return(result);
        }
Beispiel #10
0
 private int Jj_ntk()
 {
     if ((Jj_nt = Token.Next) == null)
     {
         return(jj_ntk = (Token.Next = TokenSource.GetNextToken()).Kind);
     }
     else
     {
         return(jj_ntk = Jj_nt.Kind);
     }
 }
Beispiel #11
0
        protected internal override Query HandleQuotedTerm(string field, Token termToken, Token slopToken)
        {
            string image = termToken.Image.Substring(1, termToken.Image.Length - 2);

            (bool IsFloat, bool IsInt) numericTypeGetter() =>
            (false, false);

            Query queryFactory(string fld, bool analyzed)
            {
                if (analyzed)
                {
                    int  slop;
                    bool inOrder;
                    if (slopToken == null)
                    {
                        slop    = 0;
                        inOrder = true;
                    }
                    else
                    {
                        string slopStr = slopToken.Image.Substring(1);
                        var    match   = _slopPattern.Match(slopStr);
                        if (!match.Success)
                        {
                            slop    = 0;
                            inOrder = true;
                        }
                        else
                        {
                            Group intGrp = match.Groups["int"];
                            slop = intGrp.Success
                                                                ? int.Parse(intGrp.Value, NumberStyles.Integer, CultureInfo.InvariantCulture)
                                                                : 0;
                            inOrder = !match.Groups["separator"].Success;
                        }
                    }

                    _phraseParser.Slop        = slop;
                    _phraseParser.InOrder     = inOrder;
                    _phraseParser.PhraseField = fld;
                    return(_phraseParser.Parse(image));
                }

                // not analyzed field cannot have phrases in value, so create TermQuery
                var unescaped = DiscardEscapeChar(image);

                return(GetFieldQuery(fld, unescaped, quoted: true));
            }

            var result = resolveField(field, numericTypeGetter, queryFactory);

            return(result);
        }
Beispiel #12
0
 /// <summary>Constructor with generated Token Manager. </summary>
 protected QueryParserPatched(QueryParserTokenManager tm)
 {
     TokenSource = tm;
     Token       = new Token();
     jj_ntk      = -1;
     jj_gen      = 0;
     for (int i = 0; i < 21; i++)
     {
         jj_la1[i] = -1;
     }
     for (int i = 0; i < jj_2_rtns.Length; i++)
     {
         jj_2_rtns[i] = new JJCalls();
     }
 }
Beispiel #13
0
 /// <summary>Reinitialize. </summary>
 public virtual void ReInit(QueryParserTokenManager tm)
 {
     TokenSource = tm;
     Token       = new Token();
     jj_ntk      = -1;
     jj_gen      = 0;
     for (int i = 0; i < 21; i++)
     {
         jj_la1[i] = -1;
     }
     for (int i = 0; i < jj_2_rtns.Length; i++)
     {
         jj_2_rtns[i] = new JJCalls();
     }
 }
Beispiel #14
0
 /// <summary>Reinitialize. </summary>
 public override void ReInit(ICharStream stream)
 {
     TokenSource.ReInit(stream);
     Token  = new Token();
     jj_ntk = -1;
     jj_gen = 0;
     for (int i = 0; i < 21; i++)
     {
         jj_la1[i] = -1;
     }
     for (int i = 0; i < jj_2_rtns.Length; i++)
     {
         jj_2_rtns[i] = new JJCalls();
     }
 }
Beispiel #15
0
 /// <summary>Constructor with user supplied <see cref="ICharStream"/>. </summary>
 protected internal QueryParserPatched(ICharStream stream)
 {
     TokenSource = new QueryParserTokenManager(stream);
     Token       = new Token();
     jj_ntk      = -1;
     jj_gen      = 0;
     for (int i = 0; i < 21; i++)
     {
         jj_la1[i] = -1;
     }
     for (int i = 0; i < jj_2_rtns.Length; i++)
     {
         jj_2_rtns[i] = new JJCalls();
     }
 }
Beispiel #16
0
        /// <summary>Get the specific Token. </summary>
        public Token GetToken(int index)
        {
            Token t = Token;

            for (int i = 0; i < index; i++)
            {
                if (t.Next != null)
                {
                    t = t.Next;
                }
                else
                {
                    t = t.Next = TokenSource.GetNextToken();
                }
            }
            return(t);
        }
Beispiel #17
0
 private bool Jj_scan_token(int kind)
 {
     if (jj_scanpos == jj_lastpos)
     {
         jj_la--;
         if (jj_scanpos.Next == null)
         {
             jj_lastpos = jj_scanpos = jj_scanpos.Next = TokenSource.GetNextToken();
         }
         else
         {
             jj_lastpos = jj_scanpos = jj_scanpos.Next;
         }
     }
     else
     {
         jj_scanpos = jj_scanpos.Next;
     }
     if (jj_rescan)
     {
         int   i   = 0;
         Token tok = Token;
         while (tok != null && tok != jj_scanpos)
         {
             i++;
             tok = tok.Next;
         }
         if (tok != null)
         {
             Jj_add_error_token(kind, i);
         }
     }
     if (jj_scanpos.Kind != kind)
     {
         return(true);
     }
     if (jj_la == 0 && jj_scanpos == jj_lastpos)
     {
         throw jj_ls;
     }
     return(false);
 }
Beispiel #18
0
        // extracted from the .jj grammar
        protected internal virtual Query HandleQuotedTerm(string qfield, Token term, Token fuzzySlop)
        {
            int s = PhraseSlop;  // default

            if (fuzzySlop != null)
            {
                try
                {
                    // LUCENENET NOTE: Apparently a "feature" of Lucene is to always
                    // use "." as the decimal specifier for fuzzy slop, even if the culture uses
                    // a different one, such as ",".

                    // LUCENENET TODO: It would probably be more intuitive to use
                    // the current Locale to specify the decimal identifier than
                    // to hard code it to be ".", but this would differ from Java Lucene.
                    // Perhaps just make it a non-default option?
                    s = (int)float.Parse(fuzzySlop.Image.Substring(1), CultureInfo.InvariantCulture);
                }
                catch (Exception /*ignored*/) { }
            }
            return(GetFieldQuery(qfield, DiscardEscapeChar(term.Image.Substring(1, term.Image.Length - 2)), s));
        }
Beispiel #19
0
        protected override Query HandleQuotedTerm(string field, Token termToken, Token slopToken)
        {
            string termImage = termToken.Image.Substring(1, termToken.Image.Length - 2);

            (bool IsFloat, bool IsInt) numericTypeGetter() => getNumericTypes(termImage);

            Query queryFactory(string fld, bool analyzed)
            {
                if (analyzed)
                {
                    return(base.HandleQuotedTerm(fld, termToken, slopToken));
                }

                var notAnalyzedQuery = GetFieldQuery(fld, termToken.Image.Substring(1, termToken.Image.Length - 2), true);

                return(notAnalyzedQuery);
            }

            var result = resolveField(field, numericTypeGetter, queryFactory);

            return(result);
        }
Beispiel #20
0
        /// <summary>
        /// It uses <paramref name="currentToken"/> and <paramref name="expectedTokenSequences"/> to generate a parse
        /// error message and returns it.  If this object has been created
        /// due to a parse error, and you do not catch it (it gets thrown
        /// from the parser) the correct error message
        /// gets displayed.
        /// </summary>
        private static string Initialize(Token currentToken,
            int[][] expectedTokenSequences,
            string[] tokenImage)
        {

            StringBuilder expected = new StringBuilder();
            int maxSize = 0;
            for (int i = 0; i < expectedTokenSequences.Length; i++)
            {
                if (maxSize < expectedTokenSequences[i].Length)
                {
                    maxSize = expectedTokenSequences[i].Length;
                }
                for (int j = 0; j < expectedTokenSequences[i].Length; j++)
                {
                    expected.Append(tokenImage[expectedTokenSequences[i][j]]).Append(' ');
                }
                if (expectedTokenSequences[i][expectedTokenSequences[i].Length - 1] != 0)
                {
                    expected.Append("...");
                }
                expected.Append(eol).Append("    ");
            }
            string retval = "Encountered \"";
            Token tok = currentToken.next;
            for (int i = 0; i < maxSize; i++)
            {
                if (i != 0)
                    retval += " ";
                if (tok.kind == 0)
                {
                    retval += tokenImage[0];
                    break;
                }
                retval += (" " + tokenImage[tok.kind]);
                retval += " \"";
                retval += Add_escapes(tok.image);
                retval += " \"";
                tok = tok.next;
            }
            retval += ("\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn);
            retval += ("." + eol);
            if (expectedTokenSequences.Length == 1)
            {
                retval += ("Was expecting:" + eol + "    ");
            }
            else
            {
                retval += ("Was expecting one of:" + eol + "    ");
            }
            retval += expected.ToString();
            return retval;
        }
Beispiel #21
0
        public Query Term(string field)
        {
            Token term, boost = null, fuzzySlop = null, goop1, goop2;
            bool  prefix   = false;
            bool  wildcard = false;
            bool  fuzzy    = false;
            bool  regexp   = false;
            bool  startInc = false;
            bool  endInc   = false;
            Query q;

            switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
            {
            case RegexpToken.BAREOPER:
            case RegexpToken.STAR:
            case RegexpToken.TERM:
            case RegexpToken.PREFIXTERM:
            case RegexpToken.WILDTERM:
            case RegexpToken.REGEXPTERM:
            case RegexpToken.NUMBER:
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.TERM:
                    term = Jj_consume_token(RegexpToken.TERM);
                    break;

                case RegexpToken.STAR:
                    term     = Jj_consume_token(RegexpToken.STAR);
                    wildcard = true;
                    break;

                case RegexpToken.PREFIXTERM:
                    term   = Jj_consume_token(RegexpToken.PREFIXTERM);
                    prefix = true;
                    break;

                case RegexpToken.WILDTERM:
                    term     = Jj_consume_token(RegexpToken.WILDTERM);
                    wildcard = true;
                    break;

                case RegexpToken.REGEXPTERM:
                    term   = Jj_consume_token(RegexpToken.REGEXPTERM);
                    regexp = true;
                    break;

                case RegexpToken.NUMBER:
                    term = Jj_consume_token(RegexpToken.NUMBER);
                    break;

                case RegexpToken.BAREOPER:
                    term       = Jj_consume_token(RegexpToken.BAREOPER);
                    term.Image = term.Image.Substring(0, 1);
                    break;

                default:
                    jj_la1[8] = jj_gen;
                    Jj_consume_token(-1);
                    throw new ParseException();
                }
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.FUZZY_SLOP:
                    fuzzySlop = Jj_consume_token(RegexpToken.FUZZY_SLOP);
                    fuzzy     = true;
                    break;

                default:
                    jj_la1[9] = jj_gen;
                    break;
                }
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.CARAT:
                    Jj_consume_token(RegexpToken.CARAT);
                    boost = Jj_consume_token(RegexpToken.NUMBER);
                    switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                    {
                    case RegexpToken.FUZZY_SLOP:
                        fuzzySlop = Jj_consume_token(RegexpToken.FUZZY_SLOP);
                        fuzzy     = true;
                        break;

                    default:
                        jj_la1[10] = jj_gen;
                        break;
                    }
                    break;

                default:
                    jj_la1[11] = jj_gen;
                    break;
                }
                q = HandleBareTokenQuery(field, term, fuzzySlop, prefix, wildcard, fuzzy, regexp);
                break;

            case RegexpToken.RANGEIN_START:
            case RegexpToken.RANGEEX_START:
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.RANGEIN_START:
                    Jj_consume_token(RegexpToken.RANGEIN_START);
                    startInc = true;
                    break;

                case RegexpToken.RANGEEX_START:
                    Jj_consume_token(RegexpToken.RANGEEX_START);
                    break;

                default:
                    jj_la1[12] = jj_gen;
                    Jj_consume_token(-1);
                    throw new ParseException();
                }
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.RANGE_GOOP:
                    goop1 = Jj_consume_token(RegexpToken.RANGE_GOOP);
                    break;

                case RegexpToken.RANGE_QUOTED:
                    goop1 = Jj_consume_token(RegexpToken.RANGE_QUOTED);
                    break;

                default:
                    jj_la1[13] = jj_gen;
                    Jj_consume_token(-1);
                    throw new ParseException();
                }
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.RANGE_TO:
                    Jj_consume_token(RegexpToken.RANGE_TO);
                    break;

                default:
                    jj_la1[14] = jj_gen;
                    break;
                }
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.RANGE_GOOP:
                    goop2 = Jj_consume_token(RegexpToken.RANGE_GOOP);
                    break;

                case RegexpToken.RANGE_QUOTED:
                    goop2 = Jj_consume_token(RegexpToken.RANGE_QUOTED);
                    break;

                default:
                    jj_la1[15] = jj_gen;
                    Jj_consume_token(-1);
                    throw new ParseException();
                }
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.RANGEIN_END:
                    Jj_consume_token(RegexpToken.RANGEIN_END);
                    endInc = true;
                    break;

                case RegexpToken.RANGEEX_END:
                    Jj_consume_token(RegexpToken.RANGEEX_END);
                    break;

                default:
                    jj_la1[16] = jj_gen;
                    Jj_consume_token(-1);
                    throw new ParseException();
                }
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.CARAT:
                    Jj_consume_token(RegexpToken.CARAT);
                    boost = Jj_consume_token(RegexpToken.NUMBER);
                    break;

                default:
                    jj_la1[17] = jj_gen;
                    break;
                }
                bool startOpen = false;
                bool endOpen   = false;
                if (goop1.Kind == RegexpToken.RANGE_QUOTED)
                {
                    goop1.Image = goop1.Image.Substring(1, goop1.Image.Length - 2);
                }
                else if ("*".Equals(goop1.Image))
                {
                    startOpen = true;
                }
                if (goop2.Kind == RegexpToken.RANGE_QUOTED)
                {
                    goop2.Image = goop2.Image.Substring(1, goop2.Image.Length - 2);
                }
                else if ("*".Equals(goop2.Image))
                {
                    endOpen = true;
                }
                q = GetRangeQuery(field, startOpen ? null : DiscardEscapeChar(goop1.Image), endOpen ? null : DiscardEscapeChar(goop2.Image), startInc, endInc);
                break;

            case RegexpToken.QUOTED:
                term = Jj_consume_token(RegexpToken.QUOTED);
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.FUZZY_SLOP:
                    fuzzySlop = Jj_consume_token(RegexpToken.FUZZY_SLOP);
                    break;

                default:
                    jj_la1[18] = jj_gen;
                    break;
                }
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.CARAT:
                    Jj_consume_token(RegexpToken.CARAT);
                    boost = Jj_consume_token(RegexpToken.NUMBER);
                    break;

                default:
                    jj_la1[19] = jj_gen;
                    break;
                }
                q = HandleQuotedTerm(field, term, fuzzySlop);
                break;

            default:
                jj_la1[20] = jj_gen;
                Jj_consume_token(-1);
                throw new ParseException();
            }
            { if (true)
              {
                  return(HandleBoost(q, boost));
              }
            }
            throw new Exception("Missing return statement in function");
        }
Beispiel #22
0
        public Query Clause(string field)
        {
            Query q;
            Token fieldToken = null, boost = null;

            if (Jj_2_1(2))
            {
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.TERM:
                    fieldToken = Jj_consume_token(RegexpToken.TERM);
                    Jj_consume_token(RegexpToken.COLON);
                    field = DiscardEscapeChar(fieldToken.Image);
                    break;

                case RegexpToken.STAR:
                    Jj_consume_token(RegexpToken.STAR);
                    Jj_consume_token(RegexpToken.COLON);
                    field = "*";
                    break;

                default:
                    jj_la1[5] = jj_gen;
                    Jj_consume_token(-1);
                    throw new ParseException();
                }
            }
            else
            {
                ;
            }
            switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
            {
            case RegexpToken.BAREOPER:
            case RegexpToken.STAR:
            case RegexpToken.QUOTED:
            case RegexpToken.TERM:
            case RegexpToken.PREFIXTERM:
            case RegexpToken.WILDTERM:
            case RegexpToken.REGEXPTERM:
            case RegexpToken.RANGEIN_START:
            case RegexpToken.RANGEEX_START:
            case RegexpToken.NUMBER:
                q = Term(field);
                break;

            case RegexpToken.LPAREN:
                Jj_consume_token(RegexpToken.LPAREN);
                q = Query(field);
                Jj_consume_token(RegexpToken.RPAREN);
                switch ((jj_ntk == -1) ? Jj_ntk() : jj_ntk)
                {
                case RegexpToken.CARAT:
                    Jj_consume_token(RegexpToken.CARAT);
                    boost = Jj_consume_token(RegexpToken.NUMBER);
                    break;

                default:
                    jj_la1[6] = jj_gen;
                    break;
                }
                break;

            default:
                jj_la1[7] = jj_gen;
                Jj_consume_token(-1);
                throw new ParseException();
            }
            {
                if (true)
                {
                    return(HandleBoost(q, boost));
                }
            }
            throw new Exception("Missing return statement in function");
        }